From 7c6d49e1df73c3f56ea7841a6404a6ddb0d0e23e Mon Sep 17 00:00:00 2001 From: Thaumy Date: Wed, 19 Jul 2023 16:34:33 +0800 Subject: [PATCH 001/157] Squashed commit of the following: commit 4fb9d226f8634c2435f55636bd5d6c7943199a2e Author: Thaumy Date: Wed Jul 19 16:13:29 2023 +0800 style: reformat for CI linting check commit 44ad6c2177d37acdf79b7da749ffcea433e08e0d Author: Thaumy Date: Wed Jul 19 16:11:05 2023 +0800 refactor: simplify code commit d62d6aef86db8c450d729533eea37b4ed181468d Author: Thaumy Date: Wed Jul 19 11:24:50 2023 +0800 chore: reduce diff commit 4961476b41f5261fbb1381c15caa70f38a5812fd Merge: d2286bd c5da965 Author: Thaumy Date: Wed Jul 19 11:24:19 2023 +0800 Squashed commit of the following: commit edd4af201518b5f9cea23308ee436e4175d8dbd0 Author: Thaumy Date: Mon Jul 17 11:11:52 2023 +0800 fix: make img tag self-closing pattern optional commit 2adb755ee77aaa9c0a905a6b24afb572e9270db9 Author: Thaumy Date: Fri Jul 14 16:41:44 2023 +0800 feat: extract data url image commit 101ea2f79442c338ec9fa8824e5dc386b2c03feb Author: Thaumy Date: Thu Jul 13 18:19:25 2023 +0800 fix: fix web img extract btn not work commit d2286bdce7a7a460a22ecaa4db4ff3bb60e42329 Merge: d24be59 edd4af2 Author: Thaumy Date: Wed Jul 19 11:14:03 2023 +0800 Merge branch 'dataurl-img-extract' into fix-login-no-response commit c5da9653a72a2baa11d296e7d9649cccd6b39e70 Author: Thaumy Date: Wed Jul 19 10:32:39 2023 +0800 feat: add setting option for confirm msg commit d24be59ac4d42c967021e7ac112be2f09daf9c44 Author: Thaumy Date: Wed Jul 19 09:58:03 2023 +0800 chore: rename `GlobalGontext` to `GlobalCtx` commit 87ce5bfc44e51d6a989d6959a0918e737f952340 Author: Thaumy Date: Tue Jul 18 17:39:21 2023 +0800 style: reformat for CI linting check commit 0f130d1a47fc5d20caf15fb00add0eed45340195 Author: Thaumy Date: Tue Jul 18 17:32:39 2023 +0800 refactor: simplify code commit b95914b81fff9ab6c7a1eaa7d899eb99d1d850f9 Author: Thaumy Date: Tue Jul 18 16:22:09 2023 +0800 chore: enable ext in launch.json commit 895d891bd1ff6754c171df275153c8f5aa95485c Author: Thaumy Date: Tue Jul 18 15:56:51 2023 +0800 feat: centering confirm msg commit 2b987477d33b3121d1a52834d2ab614b99be1060 Author: Thaumy Date: Tue Jul 18 15:38:19 2023 +0800 refactor: update auth commit 03b6c3a575af39d8c54bdb9b5d608ac3766070d2 Author: Thaumy Date: Tue Jul 18 12:24:28 2023 +0800 chore: remove test for check-workspace commit d20d93744b7ff3505fb5ef2fd796fce5902a59dd Author: Thaumy Date: Tue Jul 18 11:19:07 2023 +0800 style: reformat for CI linting check commit bad44874ad357677bea36557377b2b228a741a1f Author: Thaumy Date: Tue Jul 18 11:15:15 2023 +0800 ci(build-check): enable trigger on all branches commit 1af39a15ae73c742d2a8801e32a5d1ff649ba13f Author: Thaumy Date: Tue Jul 18 11:06:25 2023 +0800 refactor: update auth commit c5e56a9b6d217bd244b891f12dc2d791203e7902 Author: Thaumy Date: Mon Jul 17 18:09:51 2023 +0800 chore: update err msg commit 65484f3ee1d40806c505847eb67cb3681cb10925 Author: Thaumy Date: Mon Jul 17 18:04:53 2023 +0800 chore: rename `isDev` to `isDevEnv` commit 51c243865fffbf700aabe4d5690d3cd2a535053d Author: Thaumy Date: Mon Jul 17 15:06:16 2023 +0800 refactor: update auth commit edd4af201518b5f9cea23308ee436e4175d8dbd0 Author: Thaumy Date: Mon Jul 17 11:11:52 2023 +0800 fix: make img tag self-closing pattern optional commit cbe7f86c313f0ea961c103d0afa5457998b82d7f Author: Thaumy Date: Mon Jul 17 10:44:53 2023 +0800 refactor: update auth commit 37cb0b41bf5fa97fed3a42a4b5f607021995576e Author: Thaumy Date: Mon Jul 17 09:52:04 2023 +0800 chore: rename `save` to `upload` commit fde9394655682ccfc8855962a233e9cfa912ddd0 Author: Thaumy Date: Fri Jul 14 18:10:02 2023 +0800 feat: add confirm msg for upload post commit a597164f78c5047dbe7abf9c9630f02cccc9ea0e Author: Thaumy Date: Fri Jul 14 17:46:20 2023 +0800 chore: rename 'save' to 'upload' commit 2adb755ee77aaa9c0a905a6b24afb572e9270db9 Author: Thaumy Date: Fri Jul 14 16:41:44 2023 +0800 feat: extract data url image commit 101ea2f79442c338ec9fa8824e5dc386b2c03feb Author: Thaumy Date: Thu Jul 13 18:19:25 2023 +0800 fix: fix web img extract btn not work --- .github/workflows/build-check.yml | 2 +- .vscode/launch.json | 2 +- README.md | 24 +- __mocks__/vscode.ts | 4 +- package.json | 82 +++-- src/auth/access-token.ts | 3 + src/auth/account-info.ts | 49 +++ src/auth/account-manager.ts | 123 +++++++ src/auth/auth-provider.ts | 282 ++++++++++++++++ src/auth/auth-session.ts | 34 ++ src/authentication/access-token.ts | 3 - src/authentication/account-information.ts | 61 ---- src/authentication/account-manager.ts | 136 -------- src/authentication/authentication-provider.ts | 301 ------------------ src/authentication/index.ts | 4 - src/authentication/session.ts | 36 --- src/commands/blog-export/create.ts | 5 +- src/commands/blog-export/delete.ts | 2 +- src/commands/blog-export/download.ts | 13 +- src/commands/blog-export/edit.ts | 2 +- src/commands/blog-export/index.ts | 6 +- src/commands/blog-export/open-local.ts | 5 +- src/commands/blog-export/refresh.ts | 4 +- src/commands/commands-registration.ts | 16 +- src/commands/extract-images.ts | 87 ++--- src/commands/ing/comment-ing.ts | 3 +- .../ing/ings-list-commands-registration.ts | 4 +- src/commands/ing/open-ing-in-browser.ts | 4 +- src/commands/ing/publish-ing.ts | 16 +- src/commands/login.ts | 2 +- src/commands/open-my-blog.ts | 4 +- src/commands/open-my-home-page.ts | 4 +- src/commands/pdf/export-pdf.command.ts | 30 +- src/commands/pdf/post-pdf-template-builder.ts | 8 +- src/commands/posts-list/copy-link.ts | 4 +- src/commands/posts-list/delete-post.ts | 8 +- .../posts-list/modify-post-settings.ts | 4 +- .../posts-list/open-post-in-vscode.ts | 6 +- src/commands/posts-list/refresh-posts-list.ts | 92 +++--- src/commands/posts-list/rename-post.ts | 10 +- .../{save-post.ts => upload-post.ts} | 46 ++- src/commands/pull-post-remote-updates.ts | 33 +- src/commands/show-local-file-to-post-info.ts | 4 +- .../upload-image/upload-clipboard-image.ts | 2 +- src/commands/upload-image/upload-image.ts | 2 +- src/commands/view-post-online.ts | 4 +- src/extension.ts | 20 +- src/models/config.ts | 2 +- .../{token-information.ts => token-info.ts} | 2 +- src/models/webview-commands.ts | 2 +- src/models/webview-message.ts | 2 +- src/services/alert.service.ts | 19 +- src/services/blog-export.api.ts | 4 +- src/services/blog-settings.service.ts | 28 +- src/services/check-workspace.test.ts | 48 --- src/services/check-workspace.ts | 8 +- src/services/code-challenge.service.ts | 11 +- src/services/downloaded-export.store.ts | 7 +- .../fetch-json-response-to-camel-case.ts | 2 + src/services/global-ctx.ts | 54 ++++ src/services/global-state.ts | 54 ---- src/services/image.service.ts | 16 +- src/services/images-extractor.service.ts | 184 ----------- src/services/ing.api.ts | 24 +- src/services/ings-list-webview-provider.ts | 29 +- src/services/mkd-img-extractor.service.ts | 244 ++++++++++++++ src/services/oauth.api.ts | 62 ++-- src/services/parse-webview-html.ts | 11 +- src/services/post-category.service.ts | 17 +- .../post-configuration-panel.service.ts | 14 +- src/services/post-file-map.ts | 6 +- src/services/post-tag.service.ts | 4 +- src/services/post-title-sanitizer.service.ts | 8 +- src/services/post.service.ts | 64 ++-- src/services/search-post-by-title.ts | 4 +- src/services/settings.service.ts | 42 ++- src/services/site-category.service.ts | 4 +- src/services/webview.service.ts | 14 - .../account-view-data-provider.ts | 4 +- .../blog-export-provider.ts | 19 +- src/tree-view-providers/converters.ts | 4 +- .../models/blog-export/downloaded.ts | 8 +- .../models/blog-export/record.ts | 3 +- .../models/post-metadata.ts | 8 +- .../post-categories-tree-data-provider.ts | 25 +- .../posts-data-provider.ts | 23 +- .../tree-view-registration.ts | 4 +- src/utils/get-clipboard-image.ts | 8 +- src/utils/http-client.ts | 10 +- src/utils/input-post-settings.ts | 2 +- src/utils/uri-handler.ts | 6 +- .../components/NestCategoriesSelect.tsx | 8 +- ui/post-configuration/components/PostForm.tsx | 4 +- ui/webpack.config.mjs | 12 +- webpack.config.mjs | 4 +- 95 files changed, 1365 insertions(+), 1373 deletions(-) create mode 100644 src/auth/access-token.ts create mode 100644 src/auth/account-info.ts create mode 100644 src/auth/account-manager.ts create mode 100644 src/auth/auth-provider.ts create mode 100644 src/auth/auth-session.ts delete mode 100644 src/authentication/access-token.ts delete mode 100644 src/authentication/account-information.ts delete mode 100644 src/authentication/account-manager.ts delete mode 100644 src/authentication/authentication-provider.ts delete mode 100644 src/authentication/index.ts delete mode 100644 src/authentication/session.ts rename src/commands/posts-list/{save-post.ts => upload-post.ts} (79%) rename src/models/{token-information.ts => token-info.ts} (76%) delete mode 100644 src/services/check-workspace.test.ts create mode 100644 src/services/global-ctx.ts delete mode 100644 src/services/global-state.ts delete mode 100644 src/services/images-extractor.service.ts create mode 100644 src/services/mkd-img-extractor.service.ts delete mode 100644 src/services/webview.service.ts diff --git a/.github/workflows/build-check.yml b/.github/workflows/build-check.yml index 40753e72..cf11f6c6 100644 --- a/.github/workflows/build-check.yml +++ b/.github/workflows/build-check.yml @@ -3,7 +3,7 @@ name: Build and check the code format on: push: branches: - - main + - '*' pull_request_target: types: - opened diff --git a/.vscode/launch.json b/.vscode/launch.json index 1c875ae0..6111824d 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -9,7 +9,7 @@ "name": "Run Extension", "type": "extensionHost", "request": "launch", - "args": ["--extensionDevelopmentPath=${workspaceFolder}", "--disable-extensions"], + "args": ["--extensionDevelopmentPath=${workspaceFolder}"], "outFiles": ["${workspaceFolder}/dist/**/*.js"], "preLaunchTask": "${defaultBuildTask}", "env": { diff --git a/README.md b/README.md index c8d00f26..9ec5025c 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ - [拉取远程博文内容更新本地文件](#拉取远程博文内容更新本地文件) - [图片上传](#图片上传) - [博文分类管理](#博文分类管理) - - [导出 pdf](#导出-pdf) + - [导出 PDF](#导出-PDF) - [提取图片](#提取图片) - [博文设置面板](#博文设置面板) - [闪存](#闪存) @@ -47,13 +47,13 @@ 若本地文件已经关联到一篇博客园博文,那么会直接更新这篇博文。 -也通过 vscode 的 `Command Palette`(唤起 `Command Palette` 快捷键,windows:`ctrl+shift+p`,macos:`command+shift+p`)调用 `Cnblogs: 保存到博客园`命令,将当前正在编辑的 markdown 文件保存到博客园上 +也通过 vscode 的 `Command Palette`(唤起 `Command Palette` 快捷键,windows:`ctrl+shift+p`,macos:`command+shift+p`)调用 `Cnblogs: 上传到博客园`命令,将当前正在编辑的 markdown 文件上传到博客园上 ### 博客园博文列表 -当点击列表中的博文时,会自动将博文内容下载到工作空间一个本地文件中(此时这个本地文件就关联到了这篇博文),完成编辑后可以再将本地的内容保存到博客园博文 +当点击列表中的博文时,会自动将博文内容下载到工作空间一个本地文件中(此时这个本地文件就关联到了这篇博文),完成编辑后可以再将本地的内容上传到博客园 @@ -75,23 +75,23 @@ ### 拉取远程博文内容更新本地文件 -本地文件和博文关联后,如果通过博客后台更新了这篇博文,此时本地文件是不会自动更新的,但是可以通过 `Cnblogs: 拉取远程更新`命令来更新本地博文 +本地文件和博文关联后,如果通过博客后台更新了这篇博文,此时本地文件是不会自动更新的,但是可以通过 `Cnblogs: 拉取博文`命令来更新本地博文 -可以在下面这些地方可以调用 `Cnblogs: 拉取远程更新` +可以在下面这些地方可以调用 `Cnblogs: 拉取博文` -- 博客园随笔列表视图中的博文的上下文菜单`拉取远程更新`(仅已关联本地文件的博文) +- 博客园随笔列表视图中的博文的上下文菜单`拉取博文`(仅已关联本地文件的博文) -- 编辑器上下文菜单中的`拉取远程更新`(仅针对 markdown 文件) +- 编辑器上下文菜单中的`拉取博文`(仅针对 markdown 文件) -- 文件浏览器上下文菜单中的`拉取远程更新`(仅针对 markdown 文件) +- 文件浏览器上下文菜单中的`拉取博文`(仅针对 markdown 文件) -- vscode 命令面板 `Cnblogs: 拉取远程更新`,此时会尝试去寻找当前正在编辑的文件对其进行更新 +- vscode 命令面板 `Cnblogs: 拉取博文`,此时会尝试去寻找当前正在编辑的文件对其进行更新 @@ -109,9 +109,9 @@ -### 导出 pdf +### 导出 PDF -支持将博文导出为 pdf 格式的文件到本地,此功能依赖于 [Chromium](https://www.chromium.org/chromium-projects/),vscode-cnb 默认会先从本地寻找是否有已安装的 Chrome 或基于 Chromium 的 Edge 浏览器,若有的话则会直接使用本地的 Chrome 或基于 Chromium 的 Edge; 若未找到,那么会提示用户手动选择本地的 Chromium 或其他基于 Chromium 的浏览器 +支持将博文导出为 PDF 格式的文件到本地,此功能依赖于 [Chromium](https://www.chromium.org/chromium-projects/),vscode-cnb 默认会先从本地寻找是否有已安装的 Chrome 或基于 Chromium 的 Edge 浏览器,若有的话则会直接使用本地的 Chrome 或基于 Chromium 的 Edge; 若未找到,那么会提示用户手动选择本地的 Chromium 或其他基于 Chromium 的浏览器 @@ -129,7 +129,7 @@ ![image](https://img2022.cnblogs.com/blog/1596066/202209/1596066-20220917215536822-836105648.png) -也可以在设置中配置保存到博客园时自动提取图片 +也可以在设置中配置上传到博客园时自动提取图片 ![image](https://img2022.cnblogs.com/blog/1596066/202209/1596066-20220917215650930-372126612.png) diff --git a/__mocks__/vscode.ts b/__mocks__/vscode.ts index b52cac41..372fd4e0 100644 --- a/__mocks__/vscode.ts +++ b/__mocks__/vscode.ts @@ -110,12 +110,12 @@ const QuickPickItemKind = { const TreeItem = jest.fn() const Disposable = jest.fn() ;(Disposable as any).from = jest.fn() -const authentication = { registerAuthenticationProvider: jest.fn() } +const auth = { registerAuthenticationProvider: jest.fn() } export = { ThemeColor, Disposable, - authentication, + auth, CodeLens, languages, StatusBarAlignment, diff --git a/package.json b/package.json index 1ddb2978..9a3518ef 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "vscode-cnb", - "displayName": "博客园Cnblogs客户端", - "description": "A vscode extension used to write and publish blog post to cnblogs", + "displayName": "博客园 VSCode 扩展", + "description": "VSCode extension for CNBlogs", "version": "0.0.1", "license": "LICENSE.txt", "preview": false, @@ -148,8 +148,8 @@ "category": "Cnblogs Posts List" }, { - "command": "vscode-cnb.save-post", - "title": "保存博文", + "command": "vscode-cnb.upload-post", + "title": "上传博文", "icon": "$(cloud-upload)", "category": "Cnblogs Posts List", "enablement": "vscode-cnb.isAuthorized" @@ -199,15 +199,15 @@ "category": "Cnblogs" }, { - "command": "vscode-cnb.save-post-file-to-cnblogs", - "title": "保存到博客园", + "command": "vscode-cnb.upload-post-file-to-cnblogs", + "title": "上传到博客园", "icon": "$(vscode-cnb-cloud-upload)", "enablement": "vscode-cnb.isAuthorized", "category": "Cnblogs" }, { "command": "vscode-cnb.pull-post-remote-updates", - "title": "拉取远程更新", + "title": "拉取博文", "category": "Cnblogs", "enablement": "vscode-cnb.isAuthorized", "icon": "$(cloud-download)" @@ -274,7 +274,7 @@ }, { "command": "vscode-cnb.export-post-to-pdf", - "title": "导出PDF", + "title": "导出 PDF", "category": "Cnblogs", "enablement": "vscode-cnb.isAuthorized" }, @@ -473,17 +473,19 @@ "enum": [ "disable", "local", + "dataurl", "web", "any" ], "enumItemLabels": [ "禁用", "自动提取本地图片", + "自动提取由 Base64 编码的图片", "自动提取网络图片", "自动提取全部图片" ], "editPresentation": "singlelineText", - "markdownDescription": "提取图片, 配置保存到博客园时要自动提取上传到博客园的图片" + "markdownDescription": "提取图片, 配置上传到博客园时要自动提取上传到博客园的图片" }, "cnblogsClientForVSCode.pageSize.postsList": { "order": 7, @@ -527,11 +529,27 @@ "editPresentation": "singlelineText", "markdownDescription": "博客园 Markdown 语法扩展: 代码块指定行高亮\n\n \n\n使用示例:\n\n```markdown\n\n```typescript {1, 3-4}\nconsole.log(1)\nconsole.log(2)\nconsole.log(3)\nconsole.log(4)\nconsole.log(5)\n```\n\n```" }, + "cnblogsClientForVSCode.markdown.showConfirmMsgWhenUploadPost": { + "order": 11, + "type": "boolean", + "scope": "application", + "default": true, + "editPresentation": "singlelineText", + "markdownDescription": "在上传博文时显示确认消息" + }, + "cnblogsClientForVSCode.markdown.showConfirmMsgWhenPullPost": { + "order": 12, + "type": "boolean", + "scope": "application", + "default": true, + "editPresentation": "singlelineText", + "markdownDescription": "在拉取博文时显示确认消息" + }, "cnblogsClientForVSCode.menus.context.explorer": { "type": "object", "additionalProperties": false, "default": { - "save-post-file-to-cnblogs": true, + "upload-post-file-to-cnblogs": true, "pull-post-remote-updates": true, "modify-post-settings": true, "show-post-to-local-file-info": true, @@ -540,16 +558,16 @@ "copy-post-link": true }, "markdownDescription": "控制要在资源管理器右键菜单中显示的命令", - "order": 12, + "order": 13, "properties": { - "save-post-file-to-cnblogs": { - "description": "保存到博客园", + "upload-post-file-to-cnblogs": { + "description": "上传到博客园", "type": "boolean", "order": 0, "default": true }, "pull-post-remote-updates": { - "description": "拉取远程更新", + "description": "拉取博文", "type": "boolean", "order": 1, "default": true @@ -573,7 +591,7 @@ "default": true }, "export-post-to-pdf": { - "description": "导出pdf", + "description": "导出 PDF", "type": "boolean", "order": 5, "default": true @@ -589,7 +607,7 @@ "cnblogsClientForVSCode.menus.context.editor": { "type": "object", "default": { - "save-post-file-to-cnblogs": true, + "upload-post-file-to-cnblogs": true, "pull-post-remote-updates": true, "modify-post-settings": true, "show-post-to-local-file-info": true, @@ -602,13 +620,13 @@ "ing:publish-selection": false }, "properties": { - "save-post-file-to-cnblogs": { - "description": "保存到博客园", + "upload-post-file-to-cnblogs": { + "description": "上传到博客园", "type": "boolean", "order": 0 }, "pull-post-remote-updates": { - "description": "拉取远程更新", + "description": "拉取博文", "type": "boolean", "order": 1 }, @@ -629,7 +647,7 @@ "order": 4 }, "export-post-to-pdf": { - "description": "导出pdf", + "description": "导出 PDF", "type": "boolean", "order": 5 }, @@ -662,7 +680,7 @@ "scope": "application", "additionalProperties": false, "markdownDescription": "控制要在编辑器右键菜单中显示的命令", - "order": 13 + "order": 14 } } } @@ -826,7 +844,7 @@ "when": "false" }, { - "command": "vscode-cnb.save-post", + "command": "vscode-cnb.upload-post", "when": "false" }, { @@ -838,7 +856,7 @@ "when": "false" }, { - "command": "vscode-cnb.save-post-file-to-cnblogs", + "command": "vscode-cnb.upload-post-file-to-cnblogs", "when": "true" }, { @@ -944,7 +962,7 @@ ], "view/item/context": [ { - "command": "vscode-cnb.save-post", + "command": "vscode-cnb.upload-post", "group": "inline@1", "when": "viewItem == cnb-post-cached" }, @@ -988,7 +1006,7 @@ "group": "delete@2" }, { - "command": "vscode-cnb.save-post", + "command": "vscode-cnb.upload-post", "group": "0@1", "when": "viewItem == cnb-post-cached" }, @@ -1093,8 +1111,8 @@ "group": "cnblogs@1" }, { - "command": "vscode-cnb.save-post-file-to-cnblogs", - "when": "resourceLangId == markdown && config.cnblogsClientForVSCode.menus.context.editor.save-post-file-to-cnblogs", + "command": "vscode-cnb.upload-post-file-to-cnblogs", + "when": "resourceLangId == markdown && config.cnblogsClientForVSCode.menus.context.editor.upload-post-file-to-cnblogs", "group": "cnblogs@2" }, { @@ -1145,7 +1163,7 @@ "group": "navigation" }, { - "command": "vscode-cnb.save-post-file-to-cnblogs", + "command": "vscode-cnb.upload-post-file-to-cnblogs", "when": "resourceLangId == markdown", "group": "navigation" } @@ -1157,8 +1175,8 @@ "group": "cnblogs@1" }, { - "command": "vscode-cnb.save-post-file-to-cnblogs", - "when": "resourceLangId == markdown && config.cnblogsClientForVSCode.menus.context.explorer.save-post-file-to-cnblogs", + "command": "vscode-cnb.upload-post-file-to-cnblogs", + "when": "resourceLangId == markdown && config.cnblogsClientForVSCode.menus.context.explorer.upload-post-file-to-cnblogs", "group": "cnblogs@2" }, { @@ -1219,7 +1237,7 @@ "viewsWelcome": [ { "view": "cnblogs-authorize", - "contents": "欢迎使用博客园vscode插件! 请先登录授权!" + "contents": "欢迎使用博客园 VSCode 插件!请先登录授权!" }, { "view": "cnblogs-authorize", @@ -1231,7 +1249,7 @@ }, { "view": "vscode-cnb-workspace", - "contents": "[在vscode中打开工作空间](command:vscode-cnb.open-workspace)", + "contents": "[在 VSCode 中打开工作空间](command:vscode-cnb.open-workspace)", "when": "!vscode-cnb.isTargetWorkspace" }, { diff --git a/src/auth/access-token.ts b/src/auth/access-token.ts new file mode 100644 index 00000000..4cfda70f --- /dev/null +++ b/src/auth/access-token.ts @@ -0,0 +1,3 @@ +export type AccessToken = { + exp: number +} diff --git a/src/auth/account-info.ts b/src/auth/account-info.ts new file mode 100644 index 00000000..a7316a22 --- /dev/null +++ b/src/auth/account-info.ts @@ -0,0 +1,49 @@ +import { UserInfoSpec } from '@/services/oauth.api' +import { trim } from 'lodash-es' +import { AuthenticationSessionAccountInformation } from 'vscode' +import { AuthProvider } from './auth-provider' + +export class AccountInfo implements AuthenticationSessionAccountInformation { + readonly label: string + readonly id: string + + private _blogApp: string | null = null + + private constructor( + public readonly name: string, + public readonly avatar: string, + public readonly website: string, //The user blog home page url + public readonly blogId: number, + public readonly sub: string, //UserId(data type is Guid) + public readonly accountId: number //SpaceUserId + ) { + this.id = `${this.accountId}-${AuthProvider.providerId}` + this.label = name + } + + get userId() { + return this.sub + } + + get blogApp(): string | null { + this._blogApp ??= this.parseBlogApp() + return this._blogApp + } + + static newAnonymous = () => new AccountInfo('anonymous', '', '', -1, '', -1) + + static from = (userInfo: UserInfoSpec) => + new AccountInfo( + userInfo.name, + userInfo.picture, + userInfo.website, + parseInt(userInfo.blog_id, 10), + userInfo.sub, + parseInt(userInfo.account_id, 10) + ) + + private parseBlogApp = () => + trim(this.website ?? '', '/') + .split('/') + .pop() ?? null +} diff --git a/src/auth/account-manager.ts b/src/auth/account-manager.ts new file mode 100644 index 00000000..83d88173 --- /dev/null +++ b/src/auth/account-manager.ts @@ -0,0 +1,123 @@ +import { AccountInfo } from './account-info' +import { globalCtx } from '@/services/global-ctx' +import vscode, { authentication, AuthenticationGetSessionOptions, Disposable } from 'vscode' +import { accountViewDataProvider } from '@/tree-view-providers/account-view-data-provider' +import { postsDataProvider } from '@/tree-view-providers/posts-data-provider' +import { postCategoriesDataProvider } from '@/tree-view-providers/post-categories-tree-data-provider' +import { Oauth } from '@/services/oauth.api' +import { AuthProvider } from '@/auth/auth-provider' +import { AuthSession } from '@/auth/auth-session' +import { BlogExportProvider } from '@/tree-view-providers/blog-export-provider' +import { AlertService } from '@/services/alert.service' + +const isAuthorizedStorageKey = 'isAuthorized' + +export const ACQUIRE_TOKEN_REJECT_UNAUTHENTICATED = 'unauthenticated' +export const ACQUIRE_TOKEN_REJECT_EXPIRED = 'expired' + +class AccountManager extends vscode.Disposable { + private readonly _disposable = Disposable.from( + AuthProvider.instance.onDidChangeSessions(async ({ added }) => { + this._session = null + if (added != null && added.length > 0) await this.ensureSession() + + await this.updateAuthStatus() + + accountViewDataProvider.fireTreeDataChangedEvent() + postsDataProvider.fireTreeDataChangedEvent(undefined) + postCategoriesDataProvider.fireTreeDataChangedEvent() + + BlogExportProvider.optionalInstance?.refreshRecords({ force: false, clearCache: true }).catch(console.warn) + }) + ) + + private _session: AuthSession | null = null + + constructor() { + super(() => { + this._disposable.dispose() + }) + } + + get isAuthorized() { + return this._session !== null + } + + get currentUser(): AccountInfo { + return this._session?.account ?? AccountInfo.newAnonymous() + } + + /** + * Acquire the access token. + * This will reject with a human-readable reason string if not sign-in or the token has expired. + * @returns The access token of the active session + */ + async acquireToken(): Promise { + const session = await this.ensureSession({ createIfNone: false }) + + if (session == null) return Promise.reject(ACQUIRE_TOKEN_REJECT_UNAUTHENTICATED) + + if (session.isExpired) return Promise.reject(ACQUIRE_TOKEN_REJECT_EXPIRED) + + return session.accessToken + } + + async login() { + await this.ensureSession({ createIfNone: false, forceNewSession: true }) + } + + async logout() { + if (!this.isAuthorized) return + + const session = await authentication.getSession(AuthProvider.providerId, []) + + // WRN: For old version compatibility, **never** remove this line + await globalCtx.storage.update('user', undefined) + + if (session === undefined) return + + try { + await AuthProvider.instance.removeSession(session.id) + await Oauth.revokeToken(session.accessToken) + } catch (e: any) { + AlertService.err(`登出发生错误: ${e}`) + } + } + + async updateAuthStatus() { + await this.ensureSession({ createIfNone: false }) + + await vscode.commands.executeCommand( + 'setContext', + `${globalCtx.extName}.${isAuthorizedStorageKey}`, + this.isAuthorized + ) + + if (this.isAuthorized) { + await vscode.commands.executeCommand('setContext', `${globalCtx.extName}.user`, { + name: this.currentUser.name, + avatar: this.currentUser.avatar, + }) + } + } + + private async ensureSession(opt?: AuthenticationGetSessionOptions): Promise { + const session = await authentication.getSession(AuthProvider.instance.providerId, [], opt).then( + session => (session ? AuthSession.from(session) : null), + e => { + AlertService.err(`创建/获取 Session 失败: ${e}`) + } + ) + + if (session != null && session.account.accountId < 0) { + this._session = null + await AuthProvider.instance.removeSession(session.id) + } else { + this._session = session + } + + return this._session + } +} + +export const accountManager = new AccountManager() diff --git a/src/auth/auth-provider.ts b/src/auth/auth-provider.ts new file mode 100644 index 00000000..12180076 --- /dev/null +++ b/src/auth/auth-provider.ts @@ -0,0 +1,282 @@ +import { AuthSession } from '@/auth/auth-session' +import { genVerifyChallengePair } from '@/services/code-challenge.service' +import { isArray, isUndefined } from 'lodash-es' +import { + authentication, + AuthenticationProvider, + AuthenticationProviderAuthenticationSessionsChangeEvent as VscAuthProviderAuthSessionChEv, + CancellationToken, + CancellationTokenSource, + Disposable, + env, + EventEmitter, + ProgressLocation, + Uri, + window, +} from 'vscode' +import { globalCtx } from '@/services/global-ctx' +import RandomString from 'randomstring' +import { Oauth } from '@/services/oauth.api' +import extensionUriHandler from '@/utils/uri-handler' +import { AccountInfo } from '@/auth/account-info' +import { TokenInfo } from '@/models/token-info' +import { Optional } from 'utility-types' + +export class AuthProvider implements AuthenticationProvider, Disposable { + static readonly providerId = 'cnblogs' + static readonly providerName = '博客园Cnblogs' + + private static _instance: AuthProvider | null + + readonly providerId = AuthProvider.providerId + readonly providerName = AuthProvider.providerName + + protected readonly sessionStorageKey = `${AuthProvider.providerId}.sessions` + protected readonly allScopes = globalCtx.config.oauth.scope.split(' ') + + private _allSessions?: AuthSession[] | null + + private readonly _sessionChangeEmitter = new EventEmitter() + private readonly _disposable = Disposable.from( + this._sessionChangeEmitter, + authentication.registerAuthenticationProvider(AuthProvider.providerId, AuthProvider.providerName, this, { + supportsMultipleAccounts: false, + }), + this.onDidChangeSessions(() => { + this._allSessions = null + }) + ) + + static get instance() { + this._instance ??= new AuthProvider() + return this._instance + } + + get onDidChangeSessions() { + return this._sessionChangeEmitter.event + } + + protected get context() { + return globalCtx.extCtx + } + + protected get secretStorage() { + return globalCtx.secretsStorage + } + + protected get config() { + return globalCtx.config + } + + async getSessions(scopes?: readonly string[] | undefined): Promise { + const sessions = await this.getAllSessions() + const parsedScopes = this.ensureScopes(scopes) + + return sessions + .map(x => AuthSession.from(x)) + .filter(({ scopes: sessionScopes }) => parsedScopes.every(x => sessionScopes.includes(x))) + } + + createSession(scopes: readonly string[]): Thenable { + const parsedScopes = this.ensureScopes(scopes) + const options = { + title: `${globalCtx.displayName} - 登录`, + cancellable: true, + location: ProgressLocation.Notification, + } + + let disposable: Disposable | null + const cancelTokenSrc = new CancellationTokenSource() + + let isTimeout = false + + const timeoutId = setTimeout(() => { + clearTimeout(timeoutId) + isTimeout = true + cancelTokenSrc.cancel() + }, 30 * 60 * 1000) // 30 min + + const verifyCode = this.signInWithBrowser({ scopes: parsedScopes }) + + return window.withProgress(options, async (progress, cancelToken) => { + progress.report({ message: '等待用户在浏览器中进行授权...' }) + + const fut = new Promise((resolve, reject) => { + disposable = Disposable.from( + cancelToken.onCancellationRequested(() => cancelTokenSrc.cancel()), + cancelTokenSrc.token.onCancellationRequested(() => { + reject(`${isTimeout ? '由于超时, ' : ''}登录操作已取消`) + }), + cancelTokenSrc, + extensionUriHandler + ) + extensionUriHandler.onUri(uri => { + if (cancelTokenSrc.token.isCancellationRequested) return + + const authorizationCode = this.parseOauthCallbackUri(uri) + if (authorizationCode == null) return + + progress.report({ message: '已获得授权, 正在获取令牌...' }) + + Oauth.fetchToken(verifyCode, authorizationCode, cancelTokenSrc.token) + .then(token => + this.onAccessTokenGranted(token, { + cancelToken: cancelTokenSrc.token, + onStateChange(state) { + progress.report({ message: state }) + }, + }) + ) + .then(resolve) + .catch(reject) + }) + }) + + try { + return await fut + } finally { + disposable?.dispose() + } + }) + } + + async removeSession(sessionId: string): Promise { + const data = (await this.getAllSessions()).reduce( + ({ removed, keep }, c) => { + c.id === sessionId ? removed.push(c) : keep.push(c) + return { removed, keep } + }, + { removed: [], keep: [] } + ) + await this.context.secrets.store(this.sessionStorageKey, JSON.stringify(data.keep)) + this._sessionChangeEmitter.fire({ removed: data.removed, added: undefined, changed: undefined }) + } + + dispose() { + this._disposable.dispose() + } + + protected async getAllSessions(): Promise { + const legacyToken = LegacyTokenStore.getAccessToken() + if (legacyToken != null) { + await this.onAccessTokenGranted({ accessToken: legacyToken }, { shouldFireSessionAddedEvent: false }) + .then(undefined, console.warn) + .finally(() => void LegacyTokenStore.remove()) + } + + if (this._allSessions == null || this._allSessions.length <= 0) { + const sessions = JSON.parse((await this.secretStorage.get(this.sessionStorageKey)) ?? '[]') as + | AuthSession[] + | null + | undefined + | unknown + this._allSessions = isArray(sessions) ? sessions.map(x => AuthSession.from(x)) : [] + } + + return this._allSessions + } + + private signInWithBrowser({ scopes }: { scopes: readonly string[] }) { + const [verifyCode, challengeCode] = genVerifyChallengePair() + const { clientId, responseType, authorizeEndpoint, authority, clientSecret } = this.config.oauth + + const search = new URLSearchParams([ + ['client_id', clientId], + ['response_type', responseType], + ['redirect_uri', globalCtx.extensionUrl], + ['nonce', RandomString.generate(32)], + ['code_challenge', challengeCode], + ['code_challenge_method', 'S256'], + ['scope', scopes.join(' ')], + ['client_secret', clientSecret], + ]) + + env.openExternal(Uri.parse(`${authority}${authorizeEndpoint}?${search.toString()}`)).then( + undefined, + console.warn + ) + + return verifyCode + } + + private ensureScopes( + scopes: readonly string[] | null | undefined, + { default: defaultScopes = this.allScopes } = {} + ): readonly string[] { + return scopes == null || scopes.length <= 0 ? defaultScopes : scopes + } + + private parseOauthCallbackUri = (uri: Uri) => new URLSearchParams(`?${uri.query}`).get('code') // authorizationCode + + private async onAccessTokenGranted( + { accessToken, refreshToken }: TokenInfo, + { + cancelToken, + onStateChange, + shouldFireSessionAddedEvent = true, + }: { + onStateChange?: (state: string) => void + cancelToken?: CancellationToken + shouldFireSessionAddedEvent?: boolean + } = {} + ) { + const ifNotCancelledThen = (f: () => TR): TR | undefined => { + if (cancelToken?.isCancellationRequested) return + return f() + } + + let session: AuthSession | undefined + + try { + onStateChange?.('正在获取账户信息...') + + const spec = await ifNotCancelledThen(() => Oauth.fetchUserInfo(accessToken, cancelToken)) + + onStateChange?.('即将完成...') + + session = ifNotCancelledThen(() => { + if (isUndefined(spec)) return + + return AuthSession.from({ + accessToken, + refreshToken, + account: AccountInfo.from(spec), + scopes: this.ensureScopes(null), + id: `${this.providerId}-${spec.account_id}`, + }) + }) + + const hasStored = await ifNotCancelledThen(() => { + if (isUndefined(session)) return Promise.resolve(false) + + return this.secretStorage.store(this.sessionStorageKey, JSON.stringify([session])).then( + () => true, + () => false + ) + }) + + ifNotCancelledThen(() => { + if (!hasStored || isUndefined(session) || !shouldFireSessionAddedEvent) return + + return this._sessionChangeEmitter.fire({ + added: [session], + removed: undefined, + changed: undefined, + }) + }) + } finally { + if (session != null && cancelToken?.isCancellationRequested) await this.removeSession(session.id) + } + + if (session == null) throw new Error('Failed to create session') + + return session + } +} + +class LegacyTokenStore { + static getAccessToken = () => + globalCtx.storage.get>('user')?.authorizationInfo?.accessToken + + static remove = () => globalCtx.storage.update('user', undefined).then(undefined, console.error) +} diff --git a/src/auth/auth-session.ts b/src/auth/auth-session.ts new file mode 100644 index 00000000..667b1fa7 --- /dev/null +++ b/src/auth/auth-session.ts @@ -0,0 +1,34 @@ +import { AccessToken } from '@/auth/access-token' +import { AccountInfo } from '@/auth/account-info' +import { keys, merge, pick } from 'lodash-es' +import { AuthenticationSession } from 'vscode' + +export class AuthSession implements AuthenticationSession { + private _parsedAccessToken: AccessToken | null = null + + private constructor( + public readonly account: AccountInfo, + public readonly id = '', + public readonly accessToken = '', + public readonly refreshToken = '', + public readonly scopes: readonly string[] = [] + ) {} + + get isExpired() { + if (this._parsedAccessToken == null) { + const buf = Buffer.from(this.accessToken.split('.')[1], 'base64') + this._parsedAccessToken ??= JSON.parse(buf.toString()) + } + + if (this._parsedAccessToken == null) return true + return this._parsedAccessToken.exp * 1000 <= Date.now() + } + + static from>(t?: T) { + const session = new AuthSession(AccountInfo.newAnonymous()) + + merge(session, pick(t, keys(session))) + + return session + } +} diff --git a/src/authentication/access-token.ts b/src/authentication/access-token.ts deleted file mode 100644 index f790313f..00000000 --- a/src/authentication/access-token.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface AccessToken { - exp?: number -} diff --git a/src/authentication/account-information.ts b/src/authentication/account-information.ts deleted file mode 100644 index a46daf92..00000000 --- a/src/authentication/account-information.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { UserInformationSpec } from '@/services/oauth.api' -import { trim } from 'lodash-es' -import { AuthenticationSessionAccountInformation } from 'vscode' -import { CnblogsAuthenticationProvider } from './authentication-provider' - -export class CnblogsAccountInformation implements AuthenticationSessionAccountInformation { - readonly label: string - readonly id: string - - private _blogApp?: string | null - - /** - * Creates an instance of {@link CnblogsAccountInformation}. - * @param {string} [name='unknown'] - * @param {string} [avatar=''] - * @param {string} [website=''] The user blog home page url - * @param {number} [blogId=-1] - * @param {string} [sub=''] UserId(data type is Guid) - * @param {number} [accountId=-1] SpaceUserId - */ - private constructor( - public readonly name: string, - public readonly avatar: string, - public readonly website: string, - public readonly blogId: number, - public readonly sub: string, - public readonly accountId: number - ) { - this.id = `${this.accountId}-${CnblogsAuthenticationProvider.providerId}` - this.label = name - } - - get userId() { - return this.sub - } - - get blogApp(): string | null { - if (this._blogApp == null) this._blogApp = this.parseBlogApp() - - return this._blogApp - } - - static parse(userInfo: Partial = {}) { - return new CnblogsAccountInformation( - userInfo.name || 'anonymous', - userInfo.picture || userInfo.avatar || '', - userInfo.website || '', - userInfo.blog_id ? parseInt(userInfo.blog_id, 10) : userInfo.blogId ?? -1, - userInfo.sub || '', - userInfo.account_id ? parseInt(userInfo.account_id, 10) : userInfo.accountId ?? -1 - ) - } - - private parseBlogApp() { - return ( - trim(this.website ?? '', '/') - .split('/') - .pop() ?? null - ) - } -} diff --git a/src/authentication/account-manager.ts b/src/authentication/account-manager.ts deleted file mode 100644 index 1c5352d8..00000000 --- a/src/authentication/account-manager.ts +++ /dev/null @@ -1,136 +0,0 @@ -import { CnblogsAccountInformation } from './account-information' -import { globalContext } from '@/services/global-state' -import vscode, { authentication, AuthenticationGetSessionOptions, Disposable } from 'vscode' -import { accountViewDataProvider } from '@/tree-view-providers/account-view-data-provider' -import { postsDataProvider } from '@/tree-view-providers/posts-data-provider' -import { postCategoriesDataProvider } from '@/tree-view-providers/post-categories-tree-data-provider' -import { OauthApi } from '@/services/oauth.api' -import { CnblogsAuthenticationProvider } from '@/authentication/authentication-provider' -import { CnblogsAuthenticationSession } from '@/authentication/session' -import { BlogExportProvider } from '@/tree-view-providers/blog-export-provider' -import { AlertService } from '@/services/alert.service' - -const isAuthorizedStorageKey = 'isAuthorized' - -class AccountManager extends vscode.Disposable { - // eslint-disable-next-line @typescript-eslint/naming-convention - static readonly ACQUIRE_TOKEN_REJECT_UNAUTHENTICATED = 'unauthenticated' - // eslint-disable-next-line @typescript-eslint/naming-convention - static readonly ACQUIRE_TOKEN_REJECT_EXPIRED = 'expired' - - private readonly _authenticationProvider: CnblogsAuthenticationProvider - private readonly _disposable: vscode.Disposable - - private _oauthClient?: OauthApi | null - private _session?: CnblogsAuthenticationSession | null - - constructor() { - super(() => { - this._disposable.dispose() - }) - - this._disposable = Disposable.from( - (this._authenticationProvider = CnblogsAuthenticationProvider.instance), - this._authenticationProvider.onDidChangeSessions(async ({ added }) => { - this._session = null - if (added != null && added.length > 0) await this.ensureSession() - - await this.updateAuthorizationStatus() - - accountViewDataProvider.fireTreeDataChangedEvent() - postsDataProvider.fireTreeDataChangedEvent(undefined) - postCategoriesDataProvider.fireTreeDataChangedEvent() - BlogExportProvider.optionalInstance - ?.refreshRecords({ force: false, clearCache: true }) - .catch(console.warn) - }) - ) - } - - get isAuthorized() { - return this._session != null - } - - get curUser(): CnblogsAccountInformation { - return this._session?.account ?? CnblogsAccountInformation.parse() - } - - protected get oauthClient() { - return (this._oauthClient ??= new OauthApi()) - } - - /** - * Acquire the access token. - * This will reject with a human-readable reason string if not sign-in or the token has expired. - * @returns The access token of the active session - */ - async acquireToken(): Promise { - const session = await this.ensureSession({ createIfNone: false }) - return session == null - ? Promise.reject(AccountManager.ACQUIRE_TOKEN_REJECT_UNAUTHENTICATED) - : session.hasExpired - ? Promise.reject(AccountManager.ACQUIRE_TOKEN_REJECT_EXPIRED) - : session.accessToken - } - - async login() { - await this.ensureSession({ createIfNone: false, forceNewSession: true }) - } - - async logout() { - if (!this.isAuthorized) return - - const session = await authentication.getSession(CnblogsAuthenticationProvider.providerId, []) - if (session) await this._authenticationProvider.removeSession(session.id) - - // For old version compatibility, **never** remove this line - await globalContext.storage.update('user', undefined) - - if (session) { - return this.oauthClient - .revoke(session.accessToken) - .catch(console.warn) - .then(ok => (!ok ? console.warn('Revocation failed') : undefined)) - } - } - - setup() { - this.updateAuthorizationStatus().catch(console.warn) - } - - private async updateAuthorizationStatus() { - await this.ensureSession({ createIfNone: false }) - await vscode.commands.executeCommand( - 'setContext', - `${globalContext.extensionName}.${isAuthorizedStorageKey}`, - this.isAuthorized - ) - if (this.isAuthorized) { - await vscode.commands.executeCommand('setContext', `${globalContext.extensionName}.user`, { - name: this.curUser.name, - avatar: this.curUser.avatar, - }) - } - } - - private async ensureSession( - opt?: AuthenticationGetSessionOptions - ): Promise { - const session = await authentication.getSession(this._authenticationProvider.providerId, [], opt).then( - session => (session ? CnblogsAuthenticationSession.parse(session) : null), - reason => AlertService.warning(`创建/获取 session 失败, ${reason}`) - ) - - if (session != null && session.account.accountId < 0) { - this._session = null - await this._authenticationProvider.removeSession(session.id) - } else { - this._session = session - } - - return this._session ?? CnblogsAuthenticationSession.parse() - } -} - -export const accountManager = new AccountManager() -export default accountManager diff --git a/src/authentication/authentication-provider.ts b/src/authentication/authentication-provider.ts deleted file mode 100644 index 20458a70..00000000 --- a/src/authentication/authentication-provider.ts +++ /dev/null @@ -1,301 +0,0 @@ -import { CnblogsAuthenticationSession } from '@/authentication/session' -import { generateCodeChallenge } from '@/services/code-challenge.service' -import { isArray, isUndefined } from 'lodash-es' -import { - authentication, - AuthenticationProvider, - AuthenticationProviderAuthenticationSessionsChangeEvent, - CancellationToken, - CancellationTokenSource, - Disposable, - env, - EventEmitter, - ProgressLocation, - Uri, - window, -} from 'vscode' -import { globalContext } from '@/services/global-state' -import RandomString from 'randomstring' -import { OauthApi } from '@/services/oauth.api' -import extensionUriHandler from '@/utils/uri-handler' -import { AlertService } from '@/services/alert.service' -import { CnblogsAccountInformation } from '@/authentication/account-information' -import { TokenInformation } from '@/models/token-information' -import { Optional } from 'utility-types' - -export class CnblogsAuthenticationProvider implements AuthenticationProvider, Disposable { - static readonly providerId = 'cnblogs' - static readonly providerName = '博客园Cnblogs' - - private static _instance?: CnblogsAuthenticationProvider | null - - readonly providerId = CnblogsAuthenticationProvider.providerId - readonly providerName = CnblogsAuthenticationProvider.providerName - - protected readonly sessionStorageKey = `${CnblogsAuthenticationProvider.providerId}.sessions` - protected readonly allScopes = globalContext.config.oauth.scope.split(' ') - - private _allSessions?: CnblogsAuthenticationSession[] | null - private _oauthClient?: OauthApi | null - private readonly _sessionChangeEmitter = new EventEmitter() - private readonly _disposable: Disposable - - private constructor() { - this._disposable = Disposable.from( - this._sessionChangeEmitter, - authentication.registerAuthenticationProvider( - CnblogsAuthenticationProvider.providerId, - CnblogsAuthenticationProvider.providerName, - this, - { - supportsMultipleAccounts: false, - } - ), - this.onDidChangeSessions(() => (this._allSessions = null)) - ) - } - - static get instance() { - return (this._instance ??= new CnblogsAuthenticationProvider()) - } - - get onDidChangeSessions() { - return this._sessionChangeEmitter.event - } - - protected get context() { - return globalContext.extensionContext - } - - protected get secretStorage() { - return globalContext.secretsStorage - } - - protected get config() { - return globalContext.config - } - - protected get oauthClient() { - return (this._oauthClient ??= new OauthApi()) - } - - async getSessions(scopes?: readonly string[] | undefined): Promise { - const sessions = await this.getAllSessions() - const parsedScopes = this.ensureScopes(scopes) - return isArray(sessions) - ? sessions - .map(x => CnblogsAuthenticationSession.parse(x)) - .filter(({ scopes: sessionScopes }) => parsedScopes.every(x => sessionScopes.includes(x))) - : [] - } - - createSession(scopes: readonly string[]): Thenable { - const parsedScopes = this.ensureScopes(scopes) - return window.withProgress( - { - title: `${globalContext.displayName} - 登录`, - cancellable: true, - location: ProgressLocation.Notification, - }, - (progress, cancellationToken) => { - let disposable: Disposable | undefined | null - - return new Promise((resolve, reject) => { - const cancellationSource = new CancellationTokenSource() - let isTimeout = false - const timeoutId = setTimeout(() => { - clearTimeout(timeoutId) - isTimeout = true - cancellationSource.cancel() - }, /* 30min */ 1800000) - const { codeVerifier } = this.signInWithBrowser({ scopes: parsedScopes }) - progress.report({ message: '等待用户在浏览器中进行授权...' }) - - disposable = Disposable.from( - cancellationSource, - extensionUriHandler.onUri(uri => { - if (cancellationSource.token.isCancellationRequested) return - - const { authorizationCode } = this.parseOauthCallbackUri(uri) - if (!authorizationCode) return - - progress.report({ message: '已获得授权, 正在获取令牌...' }) - - this.oauthClient - .fetchToken({ - codeVerifier, - authorizationCode, - cancellationToken: cancellationSource.token, - }) - .then(token => - this.onAccessTokenGranted(token, { - cancellationToken: cancellationSource.token, - onStateChange(state) { - progress.report({ message: state }) - }, - }) - ) - .then(resolve) - .catch(reject) - }), - cancellationToken.onCancellationRequested(() => cancellationSource.cancel()), - cancellationSource.token.onCancellationRequested(() => { - reject(`${isTimeout ? '由于超时, ' : ''}登录操作已取消`) - }) - ) - }) - .catch(reason => Promise.reject(AlertService.error(`${reason}`))) - .finally(() => { - disposable?.dispose() - }) - } - ) - } - - async removeSession(sessionId: string): Promise { - const data = (await this.getAllSessions()).reduce<{ - removed: CnblogsAuthenticationSession[] - keep: CnblogsAuthenticationSession[] - }>( - (p, c) => { - c.id === sessionId ? p.removed.push(c) : p.keep.push(c) - return p - }, - { removed: [], keep: [] } - ) - await this.context.secrets.store(this.sessionStorageKey, JSON.stringify(data.keep)) - this._sessionChangeEmitter.fire({ removed: data.removed, added: undefined, changed: undefined }) - } - - dispose() { - this._disposable.dispose() - } - - protected async getAllSessions(): Promise { - const legacyToken = LegacyTokenStore.getAccessToken() - if (legacyToken != null) { - await this.onAccessTokenGranted({ accessToken: legacyToken }, { shouldFireSessionAddedEvent: false }) - .then(undefined, console.warn) - .finally(() => LegacyTokenStore.remove()) - } - - if (this._allSessions == null || this._allSessions.length <= 0) { - const sessions = JSON.parse((await this.secretStorage.get(this.sessionStorageKey)) ?? '[]') as - | CnblogsAuthenticationSession[] - | null - | undefined - | unknown - this._allSessions = isArray(sessions) ? sessions.map(x => CnblogsAuthenticationSession.parse(x)) : [] - } - - return this._allSessions - } - - private signInWithBrowser({ scopes }: { scopes: readonly string[] }) { - const { codeVerifier, codeChallenge } = generateCodeChallenge() - const { clientId, responseType, authorizeEndpoint, authority, clientSecret } = this.config.oauth - - const search = new URLSearchParams([ - ['client_id', clientId], - ['response_type', responseType], - ['redirect_uri', globalContext.extensionUrl], - ['nonce', RandomString.generate(32)], - ['code_challenge', codeChallenge], - ['code_challenge_method', 'S256'], - ['scope', scopes.join(' ')], - ['client_secret', clientSecret], - ]) - env.openExternal(Uri.parse(`${authority}${authorizeEndpoint}?${search.toString()}`)).then( - undefined, - console.warn - ) - return { codeVerifier } - } - - private ensureScopes( - scopes: readonly string[] | null | undefined, - { default: defaultScopes = this.allScopes } = {} - ): readonly string[] { - return scopes == null || scopes.length <= 0 ? defaultScopes : scopes - } - - private parseOauthCallbackUri(uri: Uri) { - const authorizationCode = new URLSearchParams(`?${uri.query}`).get('code') - return { authorizationCode } - } - - private async onAccessTokenGranted( - { accessToken, refreshToken }: TokenInformation, - { - cancellationToken, - onStateChange, - shouldFireSessionAddedEvent = true, - }: { - onStateChange?: (state: string) => void - cancellationToken?: CancellationToken - shouldFireSessionAddedEvent?: boolean - } = {} - ) { - const run = (func: () => TResult, predicate = () => true): TResult | undefined => - cancellationToken?.isCancellationRequested !== true && predicate() ? func() : undefined - - let session: CnblogsAuthenticationSession | undefined - try { - onStateChange?.('正在获取账户信息...') - const userInfo = await run(() => - this.oauthClient.fetchUserInformation(accessToken, { - cancellationToken: cancellationToken, - }) - ) - - onStateChange?.('即将完成...') - session = run(() => - isUndefined(userInfo) - ? undefined - : CnblogsAuthenticationSession.parse({ - accessToken, - refreshToken, - account: CnblogsAccountInformation.parse(userInfo), - scopes: this.ensureScopes(null), - id: `${this.providerId}-${userInfo.account_id}`, - }) - ) - const hasStored = await run(() => - isUndefined(session) - ? Promise.resolve(false) - : this.secretStorage.store(this.sessionStorageKey, JSON.stringify([session])).then( - () => true, - () => false - ) - ) - run( - () => - isUndefined(session) || !shouldFireSessionAddedEvent - ? undefined - : this._sessionChangeEmitter.fire({ - added: [session], - removed: undefined, - changed: undefined, - }), - () => hasStored === true - ) - } finally { - if (session != null && cancellationToken?.isCancellationRequested) await this.removeSession(session.id) - } - if (session == null) throw new Error('Failed to create session') - return session - } -} - -class LegacyTokenStore { - private static readonly _key = 'user' - - static getAccessToken() { - return globalContext.storage.get>(this._key) - ?.authorizationInfo?.accessToken - } - - static remove() { - globalContext.storage.update(this._key, undefined).then(undefined, console.error) - } -} diff --git a/src/authentication/index.ts b/src/authentication/index.ts deleted file mode 100644 index b45f108b..00000000 --- a/src/authentication/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from './authentication-provider' -export * from './session' -export * from './access-token' -export * from './account-information' diff --git a/src/authentication/session.ts b/src/authentication/session.ts deleted file mode 100644 index 8b3c2fb2..00000000 --- a/src/authentication/session.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { AccessToken } from '@/authentication/access-token' -import { CnblogsAccountInformation } from '@/authentication/account-information' -import { keys, merge, pick } from 'lodash-es' -import { AuthenticationSession } from 'vscode' - -export class CnblogsAuthenticationSession implements AuthenticationSession { - private _parsedAccessToken?: AccessToken | null - - private constructor( - public readonly account: CnblogsAccountInformation, - public readonly id = '', - public readonly accessToken = '', - public readonly refreshToken = '', - public readonly scopes: readonly string[] = [] - ) {} - - get hasExpired() { - const { exp } = this.parsedAccessToken - return typeof exp === 'number' ? exp * 1000 <= Date.now() : true - } - - private get parsedAccessToken() { - return (this._parsedAccessToken ??= JSON.parse( - Buffer.from(this.accessToken.split('.')[1], 'base64').toString() - )) as AccessToken - } - - static parse>(data?: T) { - const obj = new CnblogsAuthenticationSession(CnblogsAccountInformation.parse({})) - merge(obj, pick(data, keys(obj))) - - return obj.account instanceof CnblogsAccountInformation - ? obj - : merge(obj, { account: CnblogsAccountInformation.parse(obj.account) }) - } -} diff --git a/src/commands/blog-export/create.ts b/src/commands/blog-export/create.ts index 3125e43b..2905075d 100644 --- a/src/commands/blog-export/create.ts +++ b/src/commands/blog-export/create.ts @@ -10,7 +10,8 @@ export class CreateBlogExportCommandHandler extends CommandHandler { private _blogExportApi?: BlogExportApi | null protected get blogExportApi() { - return (this._blogExportApi ??= new BlogExportApi()) + this._blogExportApi ??= new BlogExportApi() + return this._blogExportApi } async handle(): Promise { @@ -18,7 +19,7 @@ export class CreateBlogExportCommandHandler extends CommandHandler { if ( (await this.blogExportApi.create().catch((e: unknown) => { - AlertService.httpError(typeof e === 'object' && e ? e : {}, { message: '创建博客备份失败' }) + AlertService.httpErr(typeof e === 'object' && e ? e : {}, { message: '创建博客备份失败' }) return false })) !== false ) diff --git a/src/commands/blog-export/delete.ts b/src/commands/blog-export/delete.ts index 1e7717ad..2c4be4a5 100644 --- a/src/commands/blog-export/delete.ts +++ b/src/commands/blog-export/delete.ts @@ -87,7 +87,7 @@ export class DeleteCommandHandler extends TreeViewCommandHandler true) .catch((e: unknown) => { - AlertService.httpError(typeof e === 'object' && e != null ? e : {}) + AlertService.httpErr(typeof e === 'object' && e != null ? e : {}) return false }) if (hasDeleted) if (downloaded) await this.removeDownloadedBlogExport(downloaded, { shouldDeleteLocal }) diff --git a/src/commands/blog-export/download.ts b/src/commands/blog-export/download.ts index a6f7891b..6eb3ce9a 100644 --- a/src/commands/blog-export/download.ts +++ b/src/commands/blog-export/download.ts @@ -2,7 +2,7 @@ import { TreeViewCommandHandler } from '@/commands/command-handler' import { AlertService } from '@/services/alert.service' import { BlogExportApi } from '@/services/blog-export.api' import { DownloadedExportStore } from '@/services/downloaded-export.store' -import { globalContext } from '@/services/global-state' +import { globalCtx } from '@/services/global-ctx' import { Settings } from '@/services/settings.service' import { BlogExportProvider } from '@/tree-view-providers/blog-export-provider' import { BlogExportRecordTreeItem } from '@/tree-view-providers/models/blog-export' @@ -23,7 +23,8 @@ export class DownloadExportCommandHandler extends TreeViewCommandHandler { - if (msg) AlertService.warning(msg) + if (msg) AlertService.warn(msg) if (!isFileExist) fs.rmSync(zipFilePath) blogExportProvider?.refreshItem(treeItem) this.setIsDownloading(false).then(undefined, console.warn) @@ -115,10 +116,6 @@ export class DownloadExportCommandHandler extends TreeViewCommandHandler { const target = this.parseInput() - if (!target) return AlertService.warning('不支持的参数输入') + if (!target) return AlertService.warn('不支持的参数输入') const { post: { title, isMarkdown, id: postId }, diff --git a/src/commands/blog-export/index.ts b/src/commands/blog-export/index.ts index 46fb3bfe..1bce5495 100644 --- a/src/commands/blog-export/index.ts +++ b/src/commands/blog-export/index.ts @@ -1,5 +1,5 @@ import { RefreshExportRecordsCommandHandler } from './refresh' -import { globalContext } from '@/services/global-state' +import { globalCtx } from '@/services/global-ctx' import { commands, Disposable } from 'vscode' import { OpenLocalExportCommandHandler } from '@/commands/blog-export/open-local' import { EditExportPostCommandHandler } from '@/commands/blog-export/edit' @@ -9,9 +9,9 @@ import { ViewPostCommandHandler } from '@/commands/blog-export/view-post' import { DeleteCommandHandler } from '@/commands/blog-export/delete' export function registerCommandsForBlogExport(disposables: Disposable[]) { - const { extensionName } = globalContext + const { extName } = globalCtx disposables.push( - commands.registerCommand(`${extensionName}.blog-export.refresh-records`, () => + commands.registerCommand(`${extName}.blog-export.refresh-records`, () => new RefreshExportRecordsCommandHandler().handle() ), commands.registerCommand(OpenLocalExportCommandHandler.commandName, () => diff --git a/src/commands/blog-export/open-local.ts b/src/commands/blog-export/open-local.ts index 6055840c..823cc7d3 100644 --- a/src/commands/blog-export/open-local.ts +++ b/src/commands/blog-export/open-local.ts @@ -28,8 +28,7 @@ export class OpenLocalExportCommandHandler extends CommandHandler { })) ?? [] if (fileUri == null) return const filePath = fileUri.fsPath - if (filePath.endsWith('.zip') && !filePath.endsWith('.db.zip')) - return AlertService.warning('不支持的博客备份文件') + if (filePath.endsWith('.zip') && !filePath.endsWith('.db.zip')) return AlertService.warn('不支持的博客备份文件') const fileName = path.basename(filePath.replace(/\.db(\.zip)?$/, '')) const dirname = path.dirname(filePath) @@ -56,7 +55,7 @@ export class OpenLocalExportCommandHandler extends CommandHandler { const dbFileName = path.basename(dbFilePath) const isExist = await promisify(fs.exists)(dbFilePath) - if (!isExist) return AlertService.warning('文件不存在') + if (!isExist) return AlertService.warn('文件不存在') const treeProvider = BlogExportProvider.optionalInstance const dbFileSize = (await promisify(fs.stat)(dbFilePath)).size diff --git a/src/commands/blog-export/refresh.ts b/src/commands/blog-export/refresh.ts index ce871cf0..ab41a7de 100644 --- a/src/commands/blog-export/refresh.ts +++ b/src/commands/blog-export/refresh.ts @@ -1,5 +1,5 @@ import { CommandHandler } from '@/commands/command-handler' -import { globalContext } from '@/services/global-state' +import { globalCtx } from '@/services/global-ctx' import { BlogExportProvider } from '@/tree-view-providers/blog-export-provider' import { commands } from 'vscode' @@ -15,7 +15,7 @@ export class RefreshExportRecordsCommandHandler extends CommandHandler { private setIsRefreshing(value: boolean) { return commands.executeCommand( 'setContext', - `${globalContext.extensionName}.blog-export.records.isRefreshing`, + `${globalCtx.extName}.blog-export.records.isRefreshing`, value || undefined ) } diff --git a/src/commands/commands-registration.ts b/src/commands/commands-registration.ts index 049802aa..d28b2fe8 100644 --- a/src/commands/commands-registration.ts +++ b/src/commands/commands-registration.ts @@ -4,14 +4,14 @@ import { openMyWebBlogConsole } from './open-my-blog-management-background' import { openMyHomePage } from './open-my-home-page' import { login, logout } from './login' import { openMyBlog } from './open-my-blog' -import { globalContext } from '@/services/global-state' +import { globalCtx } from '@/services/global-ctx' import { gotoNextPostsList, gotoPreviousPostsList, refreshPostsList, seekPostsList, } from './posts-list/refresh-posts-list' -import { savePostFileToCnblogs, savePostToCnblogs } from './posts-list/save-post' +import { uploadPostFileToCnblogs, uploadPostToCnblogs } from './posts-list/upload-post' import { createLocalDraft } from './posts-list/create-local-draft' import { deleteSelectedPosts } from './posts-list/delete-post' import { modifyPostSettings } from './posts-list/modify-post-settings' @@ -39,8 +39,10 @@ import { CopyPostLinkCommandHandler } from '@/commands/posts-list/copy-link' import { registerCommandsForBlogExport } from '@/commands/blog-export' export const registerCommands = () => { - const context = globalContext.extensionContext - const appName = globalContext.extensionName + const context = globalCtx.extCtx + const appName = globalCtx.extName + + // TODO: simplify register const disposables = [ commands.registerCommand(`${appName}.login`, login), commands.registerCommand(`${appName}.open-my-blog`, openMyBlog), @@ -53,11 +55,11 @@ export const registerCommands = () => { commands.registerCommand(`${appName}.seek-posts-list`, seekPostsList), commands.registerCommand(`${appName}.next-posts-list`, gotoNextPostsList), commands.registerCommand(`${appName}.edit-post`, openPostInVscode), - commands.registerCommand(`${appName}.save-post`, savePostToCnblogs), + commands.registerCommand(`${appName}.upload-post`, uploadPostToCnblogs), commands.registerCommand(`${appName}.modify-post-settings`, modifyPostSettings), commands.registerCommand(`${appName}.delete-post`, deleteSelectedPosts), commands.registerCommand(`${appName}.create-local-draft`, createLocalDraft), - commands.registerCommand(`${appName}.save-post-file-to-cnblogs`, savePostFileToCnblogs), + commands.registerCommand(`${appName}.upload-post-file-to-cnblogs`, uploadPostFileToCnblogs), commands.registerCommand(`${appName}.pull-post-remote-updates`, pullPostRemoteUpdates), commands.registerCommand(`${appName}.upload-clipboard-image`, () => uploadImage(true, 'clipboard')), commands.registerCommand(`${appName}.upload-local-disk-image`, () => uploadImage(true, 'local')), @@ -88,7 +90,9 @@ export const registerCommands = () => { new PublishIngCommandHandler('selection').handle() ), ] + registerCommandsForIngsList(disposables) registerCommandsForBlogExport(disposables) + context?.subscriptions.push(...disposables) } diff --git a/src/commands/extract-images.ts b/src/commands/extract-images.ts index 043cabbd..48f68280 100644 --- a/src/commands/extract-images.ts +++ b/src/commands/extract-images.ts @@ -1,15 +1,9 @@ import { MessageItem, MessageOptions, ProgressLocation, Range, Uri, window, workspace, WorkspaceEdit } from 'vscode' -import { ImageSrc, MarkdownImagesExtractor, ImageInfo, newImageSrcFilter } from '@/services/images-extractor.service' +import { ImageInfo, ImageSrc, MkdImgExtractor, newImageSrcFilter } from '@/services/mkd-img-extractor.service' type ExtractOption = MessageItem & Partial<{ imageSrc: ImageSrc }> -const extractOptions: readonly ExtractOption[] = [ - { title: '提取本地图片', imageSrc: ImageSrc.local }, - { title: '提取网络图片', imageSrc: ImageSrc.web }, - { title: '提取全部', imageSrc: ImageSrc.any }, - { title: '取消', imageSrc: undefined, isCloseAffordance: true }, -] - -export async function extractImages(arg: unknown, inputImageSrc: ImageSrc | undefined) { + +export async function extractImages(arg: unknown, inputImageSrc?: ImageSrc) { if (!(arg instanceof Uri && arg.scheme === 'file')) return const editor = window.visibleTextEditors.find(x => x.document.fileName === arg.fsPath) @@ -19,40 +13,58 @@ export async function extractImages(arg: unknown, inputImageSrc: ImageSrc | unde await textDocument.save() const markdown = (await workspace.fs.readFile(arg)).toString() - const extractor = new MarkdownImagesExtractor(markdown, arg) + const extractor = new MkdImgExtractor(markdown, arg) const images = extractor.findImages() if (images.length <= 0) void (!inputImageSrc != null ? window.showWarningMessage('没有找到可以提取的图片') : undefined) - const availableWebImagesCount = images.filter(newImageSrcFilter(ImageSrc.web)).length - const availableLocalImagesCount = images.filter(newImageSrcFilter(ImageSrc.local)).length - const result = - extractOptions.find(x => inputImageSrc != null && x.imageSrc === inputImageSrc) ?? - (await window.showInformationMessage( + const getExtractOption = () => { + const webImgCount = images.filter(newImageSrcFilter(ImageSrc.web)).length + const dataUrlImgCount = images.filter(newImageSrcFilter(ImageSrc.dataUrl)).length + const fsImgCount = images.filter(newImageSrcFilter(ImageSrc.fs)).length + + const displayOptions: ExtractOption[] = [ + { title: '提取全部', imageSrc: ImageSrc.any }, + { title: '提取网络图片', imageSrc: ImageSrc.web }, + { title: '提取 Data Url 图片', imageSrc: ImageSrc.dataUrl }, + { title: '提取本地图片', imageSrc: ImageSrc.fs }, + { title: '取消', imageSrc: undefined, isCloseAffordance: true }, + ] + + if (inputImageSrc !== undefined) + return Promise.resolve(displayOptions.find(ent => ent.imageSrc === inputImageSrc)) + + // if src is not specified: + return window.showInformationMessage( '要提取哪些图片? 此操作会替换源文件中的图片链接!', { modal: true, detail: - `共找到 ${availableWebImagesCount} 张可以提取的网络图片\n` + - `${availableLocalImagesCount} 张可以提取的本地图片`, + '共找到:\n' + + `${webImgCount} 张可以提取的网络图片\n` + + `${dataUrlImgCount} 张可以提取的 Data Url 图片\n` + + `${fsImgCount} 张可以提取的本地图片`, } as MessageOptions, - ...extractOptions - )) + ...displayOptions + ) + } + + const extractImageSrc = (await getExtractOption())?.imageSrc - if (!(result && result.imageSrc !== undefined)) return + if (extractImageSrc === undefined) return - extractor.imageSrc = result.imageSrc + extractor.imageSrc = extractImageSrc const failedImages = await window.withProgress( - { title: '提取图片', location: ProgressLocation.Notification }, + { title: '正在提取图片', location: ProgressLocation.Notification }, async progress => { - extractor.onProgress = (idx, images) => { - const total = images.length - const image = images[idx] + extractor.onProgress = (count, info) => { + const total = info.length + const image = info[count] progress.report({ - increment: (idx / total) * 80, - message: `[${idx + 1} / ${total}] 正在提取 ${image.link}`, + increment: (count / total) * 80, + message: `[${count + 1} / ${total}] 正在提取 ${image.data}`, }) } @@ -65,12 +77,13 @@ export async function extractImages(arg: unknown, inputImageSrc: ImageSrc | unde // eslint-disable-next-line @typescript-eslint/no-non-null-assertion .map(([src, dst]) => [src, dst!]) .map(([src, dst]) => { - const startPos = textDocument.positionAt(src.startOffset) - const endPos = textDocument.positionAt( - src.startOffset + src.prefix.length + src.link.length + src.postfix.length + const posL = textDocument.positionAt(src.startOffset) + const posR = textDocument.positionAt( + src.startOffset + src.prefix.length + src.data.length + src.postfix.length ) - const range = new Range(startPos, endPos) + const range = new Range(posL, posR) + // just for ts type inferring const ret: [Range, ImageInfo] = [range, dst] return ret }) @@ -78,12 +91,12 @@ export async function extractImages(arg: unknown, inputImageSrc: ImageSrc | unde if (range) { progress.report({ increment: (idx / extractedLen) * 20 + 80, - message: `[${idx + 1} / ${extractedLen}] 正在替换图片链接 ${dst.link}`, + message: `[${idx + 1} / ${extractedLen}] 正在替换图片链接 ${dst.data}`, }) - const newText = dst.prefix + dst.link + dst.postfix + const newText = dst.prefix + dst.data + dst.postfix we.replace(textDocument.uri, range, newText, { needsConfirmation: false, - label: dst.link, + label: dst.data, }) } @@ -96,10 +109,10 @@ export async function extractImages(arg: unknown, inputImageSrc: ImageSrc | unde } ) - if (failedImages && failedImages.length > 0) { + if (failedImages.length > 0) { const info = failedImages - .map(x => [x.link, extractor.errors.find(([link]) => link === x.link)?.[1] ?? ''].join(',')) + .map(info => [info.data, extractor.errors.find(([link]) => link === info.data)?.[1] ?? ''].join(',')) .join('\n') - window.showErrorMessage(`${failedImages.length}张图片提取失败: ${info}`).then(undefined, console.warn) + window.showErrorMessage(`${failedImages.length} 张图片提取失败: ${info}`).then(undefined, console.warn) } } diff --git a/src/commands/ing/comment-ing.ts b/src/commands/ing/comment-ing.ts index 93767815..ce9e2360 100644 --- a/src/commands/ing/comment-ing.ts +++ b/src/commands/ing/comment-ing.ts @@ -17,7 +17,8 @@ export class CommentIngCommandHandler extends CommandHandler { } private get ingApi() { - return (this._ingApi ??= new IngApi()) + this._ingApi ??= new IngApi() + return this._ingApi } async handle(): Promise { diff --git a/src/commands/ing/ings-list-commands-registration.ts b/src/commands/ing/ings-list-commands-registration.ts index e381ba95..8beb4056 100644 --- a/src/commands/ing/ings-list-commands-registration.ts +++ b/src/commands/ing/ings-list-commands-registration.ts @@ -1,6 +1,6 @@ import { commands } from 'vscode' import { RefreshIngsList } from 'src/commands/ing/refresh-ings-list' -import { globalContext } from 'src/services/global-state' +import { globalCtx } from 'src/services/global-ctx' import { IDisposable } from '@fluentui/react' import { GotoIngsListFirstPage, @@ -11,7 +11,7 @@ import { SelectIngType } from '@/commands/ing/select-ing-type' import { OpenIngInBrowser } from '@/commands/ing/open-ing-in-browser' export const registerCommandsForIngsList = (disposables: IDisposable[]) => { - const appName = globalContext.extensionName + const appName = globalCtx.extName disposables.push( ...[ diff --git a/src/commands/ing/open-ing-in-browser.ts b/src/commands/ing/open-ing-in-browser.ts index 66186841..c0107a28 100644 --- a/src/commands/ing/open-ing-in-browser.ts +++ b/src/commands/ing/open-ing-in-browser.ts @@ -1,9 +1,9 @@ import { CommandHandler } from '@/commands/command-handler' -import { globalContext } from '@/services/global-state' +import { globalCtx } from '@/services/global-ctx' import { commands, Uri } from 'vscode' export class OpenIngInBrowser extends CommandHandler { async handle(): Promise { - await commands.executeCommand('vscode.open', Uri.parse(globalContext.config.ingSite)) + await commands.executeCommand('vscode.open', Uri.parse(globalCtx.config.ingSite)) } } diff --git a/src/commands/ing/publish-ing.ts b/src/commands/ing/publish-ing.ts index c2e97545..5bab626e 100644 --- a/src/commands/ing/publish-ing.ts +++ b/src/commands/ing/publish-ing.ts @@ -1,7 +1,7 @@ import { CommandHandler } from '@/commands/command-handler' import { IngPublishModel, IngType } from '@/models/ing' import { AlertService } from '@/services/alert.service' -import { globalContext } from '@/services/global-state' +import { globalCtx } from '@/services/global-ctx' import { IngApi } from '@/services/ing.api' import { IngsListWebviewProvider } from '@/services/ings-list-webview-provider' import { InputStep, MultiStepInput, QuickPickParameters } from '@/services/multi-step-input' @@ -147,7 +147,7 @@ export class PublishIngCommandHandler extends CommandHandler { } private warnNoSelection() { - AlertService.warning(`无法${this.operation}, 当前没有选中的内容`) + AlertService.warn(`无法${this.operation}, 当前没有选中的内容`) } private async onPublished(isPublished: boolean): Promise { @@ -163,26 +163,22 @@ export class PublishIngCommandHandler extends CommandHandler { const options = [ [ '打开闪存', - (): Thenable => - commands.executeCommand('vscode.open', Uri.parse(globalContext.config.ingSite)), + (): Thenable => commands.executeCommand('vscode.open', Uri.parse(globalCtx.config.ingSite)), ], [ '我的闪存', (): Thenable => - commands.executeCommand('vscode.open', Uri.parse(globalContext.config.ingSite + '/#my')), + commands.executeCommand('vscode.open', Uri.parse(globalCtx.config.ingSite + '/#my')), ], [ '新回应', (): Thenable => - commands.executeCommand( - 'vscode.open', - Uri.parse(globalContext.config.ingSite + '/#recentcomment') - ), + commands.executeCommand('vscode.open', Uri.parse(globalCtx.config.ingSite + '/#recentcomment')), ], [ '提到我', (): Thenable => - commands.executeCommand('vscode.open', Uri.parse(globalContext.config.ingSite + '/#mention')), + commands.executeCommand('vscode.open', Uri.parse(globalCtx.config.ingSite + '/#mention')), ], ] as const const option = await window.showInformationMessage( diff --git a/src/commands/login.ts b/src/commands/login.ts index e02bd3ff..204c3352 100644 --- a/src/commands/login.ts +++ b/src/commands/login.ts @@ -1,4 +1,4 @@ -import { accountManager } from '@/authentication/account-manager' +import { accountManager } from '@/auth/account-manager' export const login = () => accountManager.login() diff --git a/src/commands/open-my-blog.ts b/src/commands/open-my-blog.ts index bf1bd279..a7f4a00b 100644 --- a/src/commands/open-my-blog.ts +++ b/src/commands/open-my-blog.ts @@ -1,7 +1,7 @@ -import { accountManager } from '@/authentication/account-manager' +import { accountManager } from '@/auth/account-manager' import vscode from 'vscode' export const openMyBlog = () => { - const userBlogUrl = accountManager.curUser?.website + const userBlogUrl = accountManager.currentUser?.website if (userBlogUrl) return vscode.commands.executeCommand('vscode.open', vscode.Uri.parse(userBlogUrl)) } diff --git a/src/commands/open-my-home-page.ts b/src/commands/open-my-home-page.ts index 319938d0..feae1216 100644 --- a/src/commands/open-my-home-page.ts +++ b/src/commands/open-my-home-page.ts @@ -1,8 +1,8 @@ -import { accountManager } from '@/authentication/account-manager' +import { accountManager } from '@/auth/account-manager' import vscode from 'vscode' export const openMyHomePage = () => { - const { accountId } = accountManager.curUser + const { accountId } = accountManager.currentUser if (!accountId || accountId <= 0) return const userHomePageUrl = `https://home.cnblogs.com/u/${accountId}` diff --git a/src/commands/pdf/export-pdf.command.ts b/src/commands/pdf/export-pdf.command.ts index d9fdb26c..f4c12c7f 100644 --- a/src/commands/pdf/export-pdf.command.ts +++ b/src/commands/pdf/export-pdf.command.ts @@ -5,11 +5,11 @@ import os from 'os' import { MessageOptions, Progress, ProgressLocation, Uri, window, workspace } from 'vscode' import { Post } from '@/models/post' import { PostFileMapManager } from '@/services/post-file-map' -import { postService } from '@/services/post.service' +import { PostService } from '@/services/post.service' import { extensionViews } from '@/tree-view-providers/tree-view-registration' import { chromiumPathProvider } from '@/utils/chromium-path-provider' import { Settings } from '@/services/settings.service' -import { accountManager } from '@/authentication/account-manager' +import { accountManager } from '@/auth/account-manager' import { AlertService } from '@/services/alert.service' import { PostTreeItem } from '@/tree-view-providers/models/post-tree-item' import { PostEditDto } from '@/models/post-edit-dto' @@ -125,7 +125,7 @@ const retrieveChromiumPath = async (): Promise => { path = op ? await op[1]() : undefined } - if (path && path !== Settings.chromiumPath) await Settings.setChromiumPath(path) + if (path !== undefined && path !== Settings.chromiumPath) await Settings.setChromiumPath(path) return path } @@ -135,7 +135,7 @@ const inputTargetFolder = async (): Promise => canSelectFiles: false, canSelectFolders: true, canSelectMany: false, - title: '请选择用于保存pdf的目录', + title: '请选择用于保存 PDF 的目录', })) ?? [])[0] const handlePostInput = (post: Post | PostTreeItem): Promise => { @@ -151,7 +151,7 @@ const handleUriInput = async (uri: Uri): Promise => { const posts: Post[] = [] const { fsPath } = uri const postId = PostFileMapManager.getPostId(fsPath) - const { post: inputPost } = (await postService.fetchPostEditDto(postId && postId > 0 ? postId : -1)) ?? {} + const { post: inputPost } = (await PostService.fetchPostEditDto(postId && postId > 0 ? postId : -1)) ?? {} if (!inputPost) { return [] @@ -169,13 +169,17 @@ const handleUriInput = async (uri: Uri): Promise => { } const mapToPostEditDto = async (posts: Post[]) => - (await Promise.all(posts.map(p => postService.fetchPostEditDto(p.id)))) + (await Promise.all(posts.map(p => PostService.fetchPostEditDto(p.id)))) .filter((x): x is PostEditDto => x != null) .map(x => x?.post) const reportErrors = (errors: string[] | undefined) => { - if (errors && errors.length > 0) - void window.showErrorMessage('导出pdf时遇到错误', { modal: true, detail: errors.join('\n') } as MessageOptions) + if (errors && errors.length > 0) { + void window.showErrorMessage('导出 PDF 时遇到错误', { + modal: true, + detail: errors.join('\n'), + } as MessageOptions) + } } const exportPostToPdf = async (input: Post | PostTreeItem | Uri | unknown): Promise => { @@ -185,10 +189,10 @@ const exportPostToPdf = async (input: Post | PostTreeItem | Uri | unknown): Prom if (!chromiumPath) return const { - curUser: { blogApp }, + currentUser: { blogApp }, } = accountManager - if (!blogApp) return AlertService.warning('无法获取到博客地址, 请检查登录状态') + if (!blogApp) return AlertService.warn('无法获取到博客地址, 请检查登录状态') reportErrors( await window.withProgress( @@ -197,7 +201,7 @@ const exportPostToPdf = async (input: Post | PostTreeItem | Uri | unknown): Prom }, async progress => { const errors: string[] = [] - progress.report({ message: '导出pdf - 处理博文数据' }) + progress.report({ message: '导出 PDF - 处理博文数据' }) let selectedPosts = await (input instanceof Post || input instanceof PostTreeItem ? handlePostInput(input) : handleUriInput(input)) @@ -208,9 +212,9 @@ const exportPostToPdf = async (input: Post | PostTreeItem | Uri | unknown): Prom const dir = await inputTargetFolder() if (!dir || !chromiumPath) return - progress.report({ message: '启动Chromium' }) + progress.report({ message: '启动 Chromium' }) const { browser, page } = (await launchBrowser(chromiumPath)) ?? {} - if (!browser || !page) return ['启动Chromium失败'] + if (!browser || !page) return ['启动 Chromium 失败'] let idx = 0 const { length: total } = selectedPosts diff --git a/src/commands/pdf/post-pdf-template-builder.ts b/src/commands/pdf/post-pdf-template-builder.ts index b808aeed..62e7647f 100644 --- a/src/commands/pdf/post-pdf-template-builder.ts +++ b/src/commands/pdf/post-pdf-template-builder.ts @@ -1,8 +1,8 @@ import { Post } from '@/models/post' import { PostFileMapManager } from '@/services/post-file-map' import fs from 'fs' -import { blogSettingsService } from '@/services/blog-settings.service' -import { accountManager } from '@/authentication/account-manager' +import { BlogSettingsService } from '@/services/blog-settings.service' +import { accountManager } from '@/auth/account-manager' import { postCategoryService } from '@/services/post-category.service' import { PostCategory } from '@/models/post-category' import { markdownItFactory } from '@cnblogs/markdown-it-presets' @@ -61,8 +61,8 @@ export namespace postPdfTemplateBuilder { codeHighlightTheme, enableCodeLineNumber: isCodeLineNumberEnabled, blogId, - } = await blogSettingsService.getBlogSettings() - const { userId } = accountManager.curUser + } = await BlogSettingsService.getBlogSettings() + const { userId } = accountManager.currentUser return ` ${post.title} diff --git a/src/commands/posts-list/copy-link.ts b/src/commands/posts-list/copy-link.ts index efaad2e2..28fb51f2 100644 --- a/src/commands/posts-list/copy-link.ts +++ b/src/commands/posts-list/copy-link.ts @@ -2,7 +2,7 @@ import { TreeViewCommandHandler } from '@/commands/command-handler' import { Post } from '@/models/post' import { AlertService } from '@/services/alert.service' import { PostFileMapManager } from '@/services/post-file-map' -import { postService } from '@/services/post.service' +import { PostService } from '@/services/post.service' import { PostTreeItem } from '@/tree-view-providers/models/post-tree-item' import { env, MessageItem, Uri, window } from 'vscode' @@ -54,7 +54,7 @@ export class CopyPostLinkCommandHandler extends TreeViewCommandHandler void AlertService.fileNotLinkedToPost(input)) - : postService.fetchPostEditDto(postId).then(v => v?.post) + : PostService.fetchPostEditDto(postId).then(v => v?.post) } return Promise.resolve(undefined) diff --git a/src/commands/posts-list/delete-post.ts b/src/commands/posts-list/delete-post.ts index 89ea2835..0536dd30 100644 --- a/src/commands/posts-list/delete-post.ts +++ b/src/commands/posts-list/delete-post.ts @@ -1,7 +1,7 @@ import { MessageOptions, ProgressLocation, Uri, window, workspace } from 'vscode' import { Post } from '@/models/post' import { AlertService } from '@/services/alert.service' -import { postService } from '@/services/post.service' +import { PostService } from '@/services/post.service' import { PostFileMap, PostFileMapManager } from '@/services/post-file-map' import { postsDataProvider } from '@/tree-view-providers/posts-data-provider' import { extensionViews } from '@/tree-view-providers/tree-view-registration' @@ -55,7 +55,7 @@ export const deleteSelectedPosts = async (arg: unknown) => { if (selectedPosts.length <= 0) return if (isDeleting) { - AlertService.warning('休息会儿再点吧~') + AlertService.warn('休息会儿再点吧~') return } @@ -72,13 +72,13 @@ export const deleteSelectedPosts = async (arg: unknown) => { increment: 0, }) try { - await postService.deletePosts(selectedPosts.map(p => p.id)) + await PostService.deletePosts(selectedPosts.map(p => p.id)) if (isToDeleteLocalFile) { selectedPosts .map(p => PostFileMapManager.getFilePath(p.id) ?? '') .filter(x => !!x) .forEach(path => { - workspace.fs.delete(Uri.file(path)).then(undefined, ex => console.error(ex)) + workspace.fs.delete(Uri.file(path)).then(undefined, e => console.error(e)) }) } await PostFileMapManager.updateOrCreateMany({ diff --git a/src/commands/posts-list/modify-post-settings.ts b/src/commands/posts-list/modify-post-settings.ts index 888c0525..cd1002f7 100644 --- a/src/commands/posts-list/modify-post-settings.ts +++ b/src/commands/posts-list/modify-post-settings.ts @@ -1,7 +1,7 @@ import { Uri } from 'vscode' import { Post } from '@/models/post' import { AlertService } from '@/services/alert.service' -import { postService } from '@/services/post.service' +import { PostService } from '@/services/post.service' import { PostFileMapManager } from '@/services/post-file-map' import { revealPostsListItem } from '@/services/posts-list-view' import { postConfigurationPanel } from '@/services/post-configuration-panel.service' @@ -29,7 +29,7 @@ export const modifyPostSettings = async (input: Post | PostTreeItem | Uri) => { if (post) await revealPostsListItem(post) - const editDto = await postService.fetchPostEditDto(postId) + const editDto = await PostService.fetchPostEditDto(postId) if (!editDto) return const postEditDto = editDto.post diff --git a/src/commands/posts-list/open-post-in-vscode.ts b/src/commands/posts-list/open-post-in-vscode.ts index ecde374d..6c5d12b4 100644 --- a/src/commands/posts-list/open-post-in-vscode.ts +++ b/src/commands/posts-list/open-post-in-vscode.ts @@ -3,7 +3,7 @@ import path from 'path' import { FileSystemError, MessageOptions, Uri, window, workspace } from 'vscode' import { Post } from '@/models/post' import { AlertService } from '@/services/alert.service' -import { postService } from '@/services/post.service' +import { PostService } from '@/services/post.service' import { PostFileMapManager } from '@/services/post-file-map' import { Settings } from '@/services/settings.service' import { openPostFile } from './open-post-file' @@ -51,7 +51,7 @@ export const openPostInVscode = async (postId: number, forceUpdateLocalPostFile mappedPostFilePath = undefined } - const postEditDto = await postService.fetchPostEditDto(postId) + const postEditDto = await PostService.fetchPostEditDto(postId) if (!postEditDto) return false const post = postEditDto.post @@ -97,7 +97,7 @@ const createDirectoryIfNotExist = async (uri: Uri) => { } catch (err) { if (err instanceof FileSystemError) await workspace.fs.createDirectory(uri) - AlertService.error('create workspace directory failed') + AlertService.err('Create workspace directory failed') console.error(err) } } diff --git a/src/commands/posts-list/refresh-posts-list.ts b/src/commands/posts-list/refresh-posts-list.ts index 489869d9..23462f83 100644 --- a/src/commands/posts-list/refresh-posts-list.ts +++ b/src/commands/posts-list/refresh-posts-list.ts @@ -1,58 +1,50 @@ -import { globalContext } from '@/services/global-state' -import { postService } from '@/services/post.service' -import vscode from 'vscode' +import { globalCtx } from '@/services/global-ctx' +import { PostService } from '@/services/post.service' +import vscode, { window } from 'vscode' import { postsDataProvider } from '@/tree-view-providers/posts-data-provider' import { AlertService } from '@/services/alert.service' import { PostsListState } from '@/models/posts-list-state' -import { window } from 'vscode' import { extensionViews } from '@/tree-view-providers/tree-view-registration' let refreshTask: Promise | null = null -export const refreshPostsList = ({ queue = false } = {}): Promise => { +export const refreshPostsList = async ({ queue = false } = {}): Promise => { if (isRefreshing && !queue) { alertRefreshing() - return refreshTask || Promise.resolve(false) + await refreshTask + return false } else if (isRefreshing && refreshTask != null) { - return refreshTask.then(() => refreshPostsList()) + await refreshTask + return refreshPostsList() } - refreshTask = setRefreshing(true) - .catch() - .then(() => - postsDataProvider - .loadPosts() - .catch() - .then(pagedPosts => - setPostListContext( - pagedPosts?.pageCount ?? 0, - pagedPosts?.hasPrevious ?? false, - pagedPosts?.hasNext ?? false - ) - .catch() - .then(() => pagedPosts) + refreshTask = setRefreshing(true).then(() => + postsDataProvider + .loadPosts() + .then(pagedPosts => + setPostListContext( + pagedPosts?.pageCount ?? 0, + pagedPosts?.hasPrevious ?? false, + pagedPosts?.hasNext ?? false ) - .then(pagedPosts => - pagedPosts == null - ? Promise.resolve(false).finally(() => AlertService.error('刷新博文列表失败')) - : postService - .updatePostsListState(pagedPosts) - .catch() - .then(() => updatePostsListViewTitle()) - .catch() - .then(() => true) - ) - .catch(() => false) - .then(x => - postsDataProvider - .refreshSearch() - .catch() - .then(() => x) - ) - .then(x => setRefreshing(false).then(() => x)) - .catch(() => false) - .finally(() => (refreshTask = null)) - ) + .catch() + .then(() => pagedPosts) + ) + .then(pagedPosts => { + if (pagedPosts == null) { + return Promise.resolve(false).finally(() => AlertService.err('刷新博文列表失败')) + } else { + return PostService.updatePostsListState(pagedPosts) + .then(() => updatePostsListViewTitle()) + .then(() => true) + } + }) + // TODO: impl `always` fn + .then(ok => postsDataProvider.refreshSearch().then(() => ok)) + .then(ok => setRefreshing(false).then(() => ok)) + .catch(() => false) + .finally(() => (refreshTask = null)) + ) return refreshTask } @@ -72,7 +64,7 @@ export const seekPostsList = async () => { const n = Number.parseInt(i) if (isNaN(n) || !n) return '请输入正确格式的页码' - const state = postService.postsListState + const state = PostService.getPostsListState() if (!state) return '博文列表尚未加载' if (isPageIndexInRange(n, state)) return undefined @@ -86,7 +78,7 @@ export const seekPostsList = async () => { let isRefreshing = false const setRefreshing = async (value = false) => { - const extName = globalContext.extensionName + const extName = globalCtx.extName await vscode.commands .executeCommand('setContext', `${extName}.posts-list.refreshing`, value) .then(undefined, () => false) @@ -94,7 +86,7 @@ const setRefreshing = async (value = false) => { } const setPostListContext = async (pageCount: number, hasPrevious: boolean, hasNext: boolean) => { - const extName = globalContext.extensionName + const extName = globalCtx.extName await vscode.commands.executeCommand('setContext', `${extName}.posts-list.hasPrevious`, hasPrevious) await vscode.commands.executeCommand('setContext', `${extName}.posts-list.hasNext`, hasNext) await vscode.commands.executeCommand('setContext', `${extName}.posts-list.pageCount`, pageCount) @@ -109,7 +101,7 @@ const gotoPage = async (pageIndex: (currentIndex: number) => number) => { alertRefreshing() return } - const state = postService.postsListState + const state = PostService.getPostsListState() if (!state) { console.warn('Cannot goto previous page posts list because post list state not defined') return @@ -122,14 +114,14 @@ const gotoPage = async (pageIndex: (currentIndex: number) => number) => { return } state.pageIndex = idx - await postService.updatePostsListState(state) + await PostService.updatePostsListState(state) await refreshPostsList() } const isPageIndexInRange = (pageIndex: number, state: PostsListState) => pageIndex <= state.pageCount && pageIndex >= 1 const updatePostsListViewTitle = () => { - const state = postService.postsListState + const state = PostService.getPostsListState() if (!state) return const { pageIndex, pageCount } = state @@ -137,8 +129,8 @@ const updatePostsListViewTitle = () => { for (const view of views) { let title = view.title ?? '' const idx = title.indexOf('(') - const pager = `第${pageIndex}页,共${pageCount}页` + const pager = `${pageIndex}/${pageCount}` title = idx >= 0 ? title.substring(0, idx) : title - view.title = `${title}(${pager})` + view.title = `${title} (${pager})` } } diff --git a/src/commands/posts-list/rename-post.ts b/src/commands/posts-list/rename-post.ts index 017ce59d..ec0d4d0b 100644 --- a/src/commands/posts-list/rename-post.ts +++ b/src/commands/posts-list/rename-post.ts @@ -2,7 +2,7 @@ import { escapeRegExp } from 'lodash-es' import path from 'path' import { MessageOptions, ProgressLocation, Uri, window, workspace } from 'vscode' import { Post } from '@/models/post' -import { postService } from '@/services/post.service' +import { PostService } from '@/services/post.service' import { PostFileMapManager } from '@/services/post-file-map' import { postsDataProvider } from '@/tree-view-providers/posts-data-provider' import { revealPostsListItem } from '@/services/posts-list-view' @@ -55,7 +55,7 @@ export const renamePost = async (arg: Post | PostTreeItem) => { }, async progress => { progress.report({ increment: 10 }) - const editDto = await postService.fetchPostEditDto(post.id) + const editDto = await PostService.fetchPostEditDto(post.id) if (!editDto) return false progress.report({ increment: 60 }) @@ -64,14 +64,14 @@ export const renamePost = async (arg: Post | PostTreeItem) => { editingPost.title = input let hasUpdated = false try { - await postService.updatePost(editingPost) + await PostService.updatePost(editingPost) post.title = input postsDataProvider.fireTreeDataChangedEvent(post) hasUpdated = true } catch (err) { - void window.showInformationMessage('更新博文失败', { + void window.showErrorMessage('更新博文失败', { modal: true, - detail: err instanceof Error ? err.message : '服务器返回了异常', + detail: err instanceof Error ? err.message : '服务器返回异常', } as MessageOptions) } finally { progress.report({ increment: 100 }) diff --git a/src/commands/posts-list/save-post.ts b/src/commands/posts-list/upload-post.ts similarity index 79% rename from src/commands/posts-list/save-post.ts rename to src/commands/posts-list/upload-post.ts index 03aa741d..ab95bd59 100644 --- a/src/commands/posts-list/save-post.ts +++ b/src/commands/posts-list/upload-post.ts @@ -1,8 +1,8 @@ -import { Uri, workspace, window, ProgressLocation, MessageOptions } from 'vscode' +import vscode, { Uri, workspace, window, ProgressLocation, MessageOptions } from 'vscode' import { Post } from '@/models/post' import { LocalDraft } from '@/services/local-draft.service' import { AlertService } from '@/services/alert.service' -import { postService } from '@/services/post.service' +import { PostService } from '@/services/post.service' import { PostFileMapManager } from '@/services/post-file-map' import { postsDataProvider } from '@/tree-view-providers/posts-data-provider' import { openPostInVscode } from './open-post-in-vscode' @@ -34,14 +34,14 @@ const parseFileUri = async (fileUri: Uri | undefined): Promise return fileUri } -export const savePostFileToCnblogs = async (fileUri: Uri | undefined) => { +export const uploadPostFileToCnblogs = async (fileUri: Uri | undefined) => { fileUri = await parseFileUri(fileUri) if (!fileUri) return const { fsPath: filePath } = fileUri const postId = PostFileMapManager.getPostId(filePath) if (postId && postId >= 0) { - await savePostToCnblogs(await postService.fetchPostEditDto(postId)) + await uploadPostToCnblogs(await PostService.fetchPostEditDto(postId)) } else { const options = [`新建博文`, `关联已有博文`] const selected = await window.showInformationMessage( @@ -61,13 +61,13 @@ export const savePostFileToCnblogs = async (fileUri: Uri | undefined) => { }) if (selectedPost) { await PostFileMapManager.updateOrCreate(selectedPost.id, filePath) - const postEditDto = await postService.fetchPostEditDto(selectedPost.id) + const postEditDto = await PostService.fetchPostEditDto(selectedPost.id) if (postEditDto) { const fileContent = Buffer.from(await workspace.fs.readFile(fileUri)).toString() if (!fileContent) await workspace.fs.writeFile(fileUri, Buffer.from(postEditDto.post.postBody)) - await savePostToCnblogs(postEditDto.post) + await uploadPostToCnblogs(postEditDto.post) } } } @@ -84,10 +84,10 @@ export const saveLocalDraftToCnblogs = async (localDraft: LocalDraft) => { // check format if (!['.md'].some(x => localDraft.fileExt === x)) { - AlertService.warning('不受支持的文件格式! 只支持markdown格式') + AlertService.warn('不受支持的文件格式! 只支持markdown格式') return } - const editDto = await postService.fetchPostEditTemplate() + const editDto = await PostService.fetchPostEditTemplate() if (!editDto) return const { post } = editDto @@ -112,7 +112,7 @@ export const saveLocalDraftToCnblogs = async (localDraft: LocalDraft) => { await saveFilePendingChanges(localDraft.filePath) // 本地文件已经被删除了 if (!localDraft.exist && panel) { - AlertService.warning('本地文件已删除, 无法新建博文') + AlertService.warn('本地文件已删除, 无法新建博文') return false } if (Settings.automaticallyExtractImagesType) @@ -124,19 +124,19 @@ export const saveLocalDraftToCnblogs = async (localDraft: LocalDraft) => { }) } -export const savePostToCnblogs = async (input: Post | PostTreeItem | PostEditDto | undefined) => { +export const uploadPostToCnblogs = async (input: Post | PostTreeItem | PostEditDto | undefined) => { input = input instanceof PostTreeItem ? input.post : input const post = input instanceof PostEditDto ? input.post : input - ? (await postService.fetchPostEditDto(input.id))?.post + ? (await PostService.fetchPostEditDto(input.id))?.post : undefined if (!post) return const { id: postId } = post const localFilePath = PostFileMapManager.getFilePath(postId) - if (!localFilePath) return AlertService.warning('本地无该博文的编辑记录') + if (!localFilePath) return AlertService.warn('本地无该博文的编辑记录') if (Settings.automaticallyExtractImagesType) await extractImages(Uri.file(localFilePath), Settings.automaticallyExtractImagesType).catch(console.warn) @@ -147,10 +147,22 @@ export const savePostToCnblogs = async (input: Post | PostTreeItem | PostEditDto if (!validatePost(post)) return false + if (Settings.showConfirmMsgWhenUploadPost) { + const answer = await vscode.window.showWarningMessage( + '确认上传吗?', + { + modal: true, + detail: '本地博文将对远程博文进行覆盖, 操作不可逆!(此消息可在设置中关闭)', + }, + '确认' + ) + if (answer !== '确认') return false + } + return window.withProgress( { location: ProgressLocation.Notification, - title: '正在保存博文', + title: '正在上传博文', cancellable: false, }, async progress => { @@ -159,17 +171,17 @@ export const savePostToCnblogs = async (input: Post | PostTreeItem | PostEditDto }) let hasSaved = false try { - const { id: postId } = await postService.updatePost(post) + const { id: postId } = await PostService.updatePost(post) await openPostInVscode(postId) post.id = postId hasSaved = true progress.report({ increment: 100 }) - AlertService.info('保存成功') + AlertService.info('上传成功') await refreshPostsList() } catch (err) { progress.report({ increment: 100 }) - AlertService.error(`保存失败\n${err instanceof Error ? err.message : JSON.stringify(err)}`) + AlertService.err(`上传失败\n${err instanceof Error ? err.message : JSON.stringify(err)}`) console.error(err) } return hasSaved @@ -179,7 +191,7 @@ export const savePostToCnblogs = async (input: Post | PostTreeItem | PostEditDto const validatePost = (post: Post): boolean => { if (!post.postBody) { - AlertService.warning('文件内容为空!') + AlertService.warn('文件内容为空!') return false } diff --git a/src/commands/pull-post-remote-updates.ts b/src/commands/pull-post-remote-updates.ts index 0488ee52..18b48517 100644 --- a/src/commands/pull-post-remote-updates.ts +++ b/src/commands/pull-post-remote-updates.ts @@ -3,11 +3,12 @@ import { Post } from '@/models/post' import { PostFileMapManager } from '@/services/post-file-map' import { openPostInVscode } from './posts-list/open-post-in-vscode' import fs from 'fs' -import { postService } from '@/services/post.service' +import { PostService } from '@/services/post.service' import { AlertService } from '@/services/alert.service' import path from 'path' import { revealPostsListItem } from '@/services/posts-list-view' import { PostTreeItem } from '@/tree-view-providers/models/post-tree-item' +import { Settings } from '@/services/settings.service' const pullPostRemoteUpdates = async (input: Post | PostTreeItem | Uri | undefined | null): Promise => { const ctxs: CommandContext[] = [] @@ -16,7 +17,19 @@ const pullPostRemoteUpdates = async (input: Post | PostTreeItem | Uri | undefine if (parsePostInput(input) && input.id > 0) await handlePostInput(input, ctxs) else if ((uri = parseUriInput(input))) await handleUriInput(uri, ctxs) - if (ctxs.length <= 0 || !(await confirmOperation(ctxs))) return + if (Settings.showConfirmMsgWhenPullPost) { + const answer = await window.showWarningMessage( + '确认要拉取远程博文吗?', + { + modal: true, + detail: `本地文件 ${resolveFileNames(ctxs)} 将被覆盖, 请谨慎操作!(此消息可在设置中关闭)`, + } as MessageOptions, + '确认' + ) + if (answer !== '确认') return + } + + if (ctxs.length <= 0) return await update(ctxs) @@ -63,24 +76,10 @@ const handleUriInput = (fileUri: Uri, contexts: CommandContext[]): Promise return Promise.resolve() } -const confirmOperation = async (ctxs: CommandContext[]): Promise => { - const options = ['确定'] - return ( - (await window.showWarningMessage( - '确定要拉取远程博文内容更新本地文件吗?', - { - modal: true, - detail: `本地文件${resolveFileNames(ctxs)}的内容将被覆盖, 数据无价, 请谨慎操作`, - } as MessageOptions, - ...options - )) === options[0] - ) -} - const update = async (contexts: CommandContext[]) => { for (const ctx of contexts) { const { fileUri, postId } = ctx - const { post } = (await postService.fetchPostEditDto(postId)) ?? {} + const { post } = (await PostService.fetchPostEditDto(postId)) ?? {} if (post) { const textEditors = window.visibleTextEditors.filter(x => x.document.uri.fsPath === fileUri.fsPath) await Promise.all(textEditors.map(editor => editor.document.save())) diff --git a/src/commands/show-local-file-to-post-info.ts b/src/commands/show-local-file-to-post-info.ts index f736cada..bad8d357 100644 --- a/src/commands/show-local-file-to-post-info.ts +++ b/src/commands/show-local-file-to-post-info.ts @@ -1,7 +1,7 @@ import path from 'path' import { MessageOptions, Uri, window } from 'vscode' import { AlertService } from '@/services/alert.service' -import { postService } from '@/services/post.service' +import { PostService } from '@/services/post.service' import { postCategoryService } from '@/services/post-category.service' import { PostFileMapManager } from '@/services/post-file-map' import { searchPostsByTitle } from '@/services/search-post-by-title' @@ -49,7 +49,7 @@ export const showLocalFileToPostInfo = async (input: Uri | number): Promise= 0)) return - const post = (await postService.fetchPostEditDto(postId))?.post + const post = (await PostService.fetchPostEditDto(postId))?.post if (!post) return let categories = await postCategoryService.listCategories() diff --git a/src/commands/upload-image/upload-clipboard-image.ts b/src/commands/upload-image/upload-clipboard-image.ts index 693e3f10..315f79cf 100644 --- a/src/commands/upload-image/upload-clipboard-image.ts +++ b/src/commands/upload-image/upload-clipboard-image.ts @@ -9,7 +9,7 @@ const noImagePath = 'no image' export const uploadImageFromClipboard = async () => { const clipboardImage = await getClipboardImage() if (clipboardImage.imgPath === noImagePath) { - AlertService.warning('剪贴板中没有找到图片') + AlertService.warn('剪贴板中没有找到图片') return } diff --git a/src/commands/upload-image/upload-image.ts b/src/commands/upload-image/upload-image.ts index 196e257b..78a912ed 100644 --- a/src/commands/upload-image/upload-image.ts +++ b/src/commands/upload-image/upload-image.ts @@ -19,7 +19,7 @@ export const uploadImage = async (autoInsertToActiveEditor = true, from?: 'local let imageUrl: string | undefined const caughtFailedUpload = (e: unknown) => - void AlertService.httpError(typeof e === 'object' && e != null ? e : {}, { message: '上传图片失败' }) + void AlertService.httpErr(typeof e === 'object' && e != null ? e : {}, { message: '上传图片失败' }) switch (selected) { case 'local': case options[0]: diff --git a/src/commands/view-post-online.ts b/src/commands/view-post-online.ts index 4b24cc14..81b2b003 100644 --- a/src/commands/view-post-online.ts +++ b/src/commands/view-post-online.ts @@ -1,6 +1,6 @@ import { commands, Uri, window } from 'vscode' import { Post } from '@/models/post' -import { postService } from '@/services/post.service' +import { PostService } from '@/services/post.service' import { PostFileMapManager } from '@/services/post-file-map' import { PostTreeItem } from '@/tree-view-providers/models/post-tree-item' @@ -10,7 +10,7 @@ export const viewPostOnline = async (input?: Post | PostTreeItem | Uri) => { if (input instanceof Uri) { const postId = PostFileMapManager.getPostId(input.fsPath) - if (postId) post = (await postService.fetchPostEditDto(postId))?.post + if (postId !== undefined) post = (await PostService.fetchPostEditDto(postId))?.post } if (!post) return diff --git a/src/extension.ts b/src/extension.ts index 5220b6b1..9104c943 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -1,10 +1,10 @@ import { registerTreeViews } from '@/tree-view-providers/tree-view-registration' import { registerCommands } from '@/commands/commands-registration' -import { globalContext } from '@/services/global-state' +import { globalCtx } from '@/services/global-ctx' // The module 'vscode' contains the VS Code extensibility API // Import the module and reference it with the alias vscode in your code below import vscode from 'vscode' -import { accountManager } from '@/authentication/account-manager' +import { accountManager } from '@/auth/account-manager' import { observeConfigurationChange, observeWorkspaceFolderAndFileChange as observeWorkspaceFolderChange, @@ -17,22 +17,26 @@ import { Settings } from '@/services/settings.service' // this method is called when your extension is activated // your extension is activated the very first time the command is executed export function activate(context: vscode.ExtensionContext) { - globalContext.extensionContext = context - accountManager.setup() + globalCtx.extCtx = context + context.subscriptions.push(accountManager) registerCommands() registerTreeViews() - setTimeout(() => { + + const timeoutId = setTimeout(() => { IngsListWebviewProvider.ensureRegistered() + clearTimeout(timeoutId) }, 1000) + observeConfigurationChange() observeWorkspaceFolderChange() + Settings.migrateEnablePublishSelectionToIng().catch(console.warn) + vscode.window.registerUriHandler(extensionUriHandler) - return { - extendMarkdownIt, - } + + return { extendMarkdownIt } } // this method is called when your extension is deactivated diff --git a/src/models/config.ts b/src/models/config.ts index e086fe74..128dd3fd 100644 --- a/src/models/config.ts +++ b/src/models/config.ts @@ -17,7 +17,7 @@ export interface IExtensionConfig { readonly cnblogsOpenApiUrl: string } -export const isDev = () => process.env.NODE_ENV === 'Development' +export const isDevEnv = () => process.env.NODE_ENV === 'Development' declare const CNBLOGS_CLIENTID: string declare const CNBLOGS_CLIENTSECRET: string diff --git a/src/models/token-information.ts b/src/models/token-info.ts similarity index 76% rename from src/models/token-information.ts rename to src/models/token-info.ts index e895ccc6..64d32a4b 100644 --- a/src/models/token-information.ts +++ b/src/models/token-info.ts @@ -1,4 +1,4 @@ -export interface TokenInformation { +export interface TokenInfo { idToken?: string accessToken: string refreshToken?: string diff --git a/src/models/webview-commands.ts b/src/models/webview-commands.ts index a3c3b78c..2d8ec259 100644 --- a/src/models/webview-commands.ts +++ b/src/models/webview-commands.ts @@ -12,7 +12,7 @@ export namespace webviewCommands { } export enum ExtensionCommands { - savePost = 'savePost', + uploadPost = 'uploadPost', disposePanel = 'disposePanel', uploadImage = 'uploadImage', refreshPost = 'refreshPost', diff --git a/src/models/webview-message.ts b/src/models/webview-message.ts index 46d0db19..b0613233 100644 --- a/src/models/webview-message.ts +++ b/src/models/webview-message.ts @@ -22,7 +22,7 @@ export namespace webviewMessage { fileName: string } - export interface SavePostMessage extends Message { + export interface UploadPostMessage extends Message { post: Post } diff --git a/src/services/alert.service.ts b/src/services/alert.service.ts index 8adbac54..107002ba 100644 --- a/src/services/alert.service.ts +++ b/src/services/alert.service.ts @@ -3,20 +3,20 @@ import { isArray } from 'lodash-es' import path from 'path' import vscode, { Uri } from 'vscode' -export class AlertService { - static error(message: string) { +export namespace AlertService { + export function err(message: string) { void vscode.window.showErrorMessage(message) } - static info(message: string) { + export function info(message: string) { vscode.window.showInformationMessage(message).then(undefined, undefined) } - static warning(message: string) { + export function warn(message: string) { vscode.window.showWarningMessage(message).then(undefined, undefined) } - static httpError(httpError: Partial, { message = '' } = {}) { + export function httpErr(httpError: Partial, { message = '' } = {}) { const body = httpError.response?.body as | { errors: (string | unknown)[] | undefined | unknown } | undefined @@ -27,20 +27,21 @@ export class AlertService { else if (httpError.message) parsedError = httpError.message else parsedError = '未知网络错误' - AlertService.warning((message ? message + (parsedError ? ', ' : '') : '') + parsedError) + AlertService.warn((message ? message + (parsedError ? ', ' : '') : '') + parsedError) } /** * alert that file not linked to the post * @param file the file path, could be a string or {@link Uri} object + * @param trimExt */ - static fileNotLinkedToPost(file: string | Uri, { trimExt = true } = {}) { + export function fileNotLinkedToPost(file: string | Uri, { trimExt = true } = {}) { file = file instanceof Uri ? file.fsPath : file file = trimExt ? path.basename(file, path.extname(file)) : file - this.warning(`本地文件"${file}"未关联博客园博文`) + AlertService.warn(`本地文件"${file}"未关联博客园博文`) } - static async alertUnauthenticated({ onLoginActionHook }: { onLoginActionHook?: () => unknown } = {}) { + export async function alertUnAuth({ onLoginActionHook }: { onLoginActionHook?: () => unknown } = {}) { const options = ['立即登录'] const input = await vscode.window.showWarningMessage( '登录状态已过期, 请重新登录', diff --git a/src/services/blog-export.api.ts b/src/services/blog-export.api.ts index 23b69234..448aa9ab 100644 --- a/src/services/blog-export.api.ts +++ b/src/services/blog-export.api.ts @@ -1,8 +1,8 @@ import { BlogExportRecord, BlogExportRecordList } from '@/models/blog-export' -import { globalContext } from '@/services/global-state' +import { globalCtx } from '@/services/global-ctx' import got from '@/utils/http-client' -const basePath = `${globalContext.config.apiBaseUrl}/api/blogExports` +const basePath = `${globalCtx.config.apiBaseUrl}/api/blogExports` const downloadOrigin = 'https://export.cnblogs.com' export class BlogExportApi { diff --git a/src/services/blog-settings.service.ts b/src/services/blog-settings.service.ts index f2e82f0f..f97f73be 100644 --- a/src/services/blog-settings.service.ts +++ b/src/services/blog-settings.service.ts @@ -1,29 +1,21 @@ import fetch from '@/utils/fetch-client' import { BlogSettings, BlogSiteDto, BlogSiteExtendDto } from '@/models/blog-settings' -import { globalContext } from './global-state' +import { globalCtx } from './global-ctx' -export class BlogSettingsService { - private static _instance?: BlogSettingsService +let settingCache: BlogSettings | null = null - private _settings?: BlogSettings +export namespace BlogSettingsService { + export async function getBlogSettings(refresh = false) { + if (settingCache != null && !refresh) return settingCache - protected constructor() {} - - static get instance() { - if (!this._instance) this._instance = new BlogSettingsService() - return this._instance - } - - async getBlogSettings(forceRefresh = false): Promise { - if (this._settings && !forceRefresh) return this._settings - - const url = `${globalContext.config.apiBaseUrl}/api/settings` + const url = `${globalCtx.config.apiBaseUrl}/api/settings` const res = await fetch(url) if (!res.ok) throw Error(`Failed to request ${url}, statusCode: ${res.status}, detail: ${await res.text()}`) const data = (await res.json()) as { blogSite: BlogSiteDto; extend: BlogSiteExtendDto } - return new BlogSettings(data.blogSite, data.extend) + + settingCache ??= new BlogSettings(data.blogSite, data.extend) + + return settingCache } } - -export const blogSettingsService = BlogSettingsService.instance diff --git a/src/services/check-workspace.test.ts b/src/services/check-workspace.test.ts deleted file mode 100644 index 74f41084..00000000 --- a/src/services/check-workspace.test.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { workspace } from 'vscode' - -// eslint-disable-next-line @typescript-eslint/no-misused-promises -describe('isTargetWorkspace', () => { - const testItems: [current: string, target: string, result: boolean][] = [ - ['c:/test', 'C:/test', true], - ['C:/test', 'c:/test', true], - ['c:/test', 'c:/test', true], - ['D:/test', 'D:/test', true], - ['c:/test', 'd:/test', false], - ['d:/test', 'd:/test/', false], - ] - let mockSettings: jest.Mock - - beforeAll(() => { - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - const actualGlobalContext = jest.requireActual('./global-state.ts').globalContext - Object.defineProperty(actualGlobalContext, 'extensionName', { - get: jest.fn().mockReturnValue(''), - }) - jest.mock('./global-state', () => ({ - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - globalContext: actualGlobalContext, - })) - - jest.mock('os', () => ({ platform: jest.fn().mockReturnValue('win32') })) - mockSettings = jest.fn() - jest.mock('./settings.service', () => ({ - // eslint-disable-next-line @typescript-eslint/naming-convention - Settings: mockSettings, - })) - }) - - for (const item of testItems) { - const [current, target, isInTargetWorkspace] = item - - it(`should${isInTargetWorkspace ? '' : ' not'} in target workspace, ${current}, ${target}`, async () => { - const mockedWorkspace = jest.mocked(workspace) - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - mockedWorkspace.workspaceFolders = [{ name: '', uri: { path: current } }] - ;(mockSettings as any).workspaceUri = { path: target } - - const { isTargetWorkspace } = await import('@/services/check-workspace') - expect(isTargetWorkspace()).toStrictEqual(isInTargetWorkspace) - }) - } -}) diff --git a/src/services/check-workspace.ts b/src/services/check-workspace.ts index 8b9d34dc..bad99d6c 100644 --- a/src/services/check-workspace.ts +++ b/src/services/check-workspace.ts @@ -2,7 +2,7 @@ import os from 'os' import { commands, workspace } from 'vscode' import { refreshPostCategoriesList } from '@/commands/post-category/refresh-post-categories-list' import { refreshPostsList } from '@/commands/posts-list/refresh-posts-list' -import { globalContext } from './global-state' +import { globalCtx } from './global-ctx' import { PostFileMapManager } from './post-file-map' import { Settings } from './settings.service' @@ -20,12 +20,12 @@ export const isTargetWorkspace = (): boolean => { targetFolder = targetFolder.replace(diskSymbolRegex, replacer) } const isTarget = !!currentFolder && currentFolder === targetFolder - void commands.executeCommand('setContext', `${globalContext.extensionName}.isTargetWorkspace`, isTarget) + void commands.executeCommand('setContext', `${globalCtx.extName}.isTargetWorkspace`, isTarget) return isTarget } export const observeConfigurationChange = () => { - globalContext.extensionContext?.subscriptions.push( + globalCtx.extCtx?.subscriptions.push( workspace.onDidChangeConfiguration(ev => { if (ev.affectsConfiguration(Settings.prefix)) isTargetWorkspace() @@ -43,7 +43,7 @@ export const observeConfigurationChange = () => { } export const observeWorkspaceFolderAndFileChange = () => { - globalContext.extensionContext?.subscriptions.push( + globalCtx.extCtx?.subscriptions.push( workspace.onDidRenameFiles(e => { for (const item of e.files) { const { oldUri, newUri } = item diff --git a/src/services/code-challenge.service.ts b/src/services/code-challenge.service.ts index b3f2299d..ba8716df 100644 --- a/src/services/code-challenge.service.ts +++ b/src/services/code-challenge.service.ts @@ -2,11 +2,10 @@ import base64url from 'base64url' import crypto from 'crypto' import RandomString from 'randomstring' -export const generateCodeVerifier = () => RandomString.generate(128) +export const genVerifyChallengePair = () => { + const verifyCode = RandomString.generate(128) + const base64Digest = crypto.createHash('sha256').update(verifyCode).digest('base64') + const challengeCode = base64url.fromBase64(base64Digest) -export const generateCodeChallenge = (codeVerifier?: string): { codeVerifier: string; codeChallenge: string } => { - codeVerifier ??= generateCodeVerifier() - const base64Digest = crypto.createHash('sha256').update(codeVerifier).digest('base64') - const codeChallenge = base64url.fromBase64(base64Digest) - return { codeVerifier, codeChallenge } + return [verifyCode, challengeCode] } diff --git a/src/services/downloaded-export.store.ts b/src/services/downloaded-export.store.ts index b9cd2314..7b06212c 100644 --- a/src/services/downloaded-export.store.ts +++ b/src/services/downloaded-export.store.ts @@ -1,5 +1,5 @@ import { DownloadedBlogExport } from '@/models/blog-export' -import { globalContext } from '@/services/global-state' +import { globalCtx } from '@/services/global-ctx' import { exists, existsSync } from 'fs' import { take } from 'lodash-es' import { promisify } from 'util' @@ -10,10 +10,11 @@ export class DownloadedExportStore { readonly listKey = 'downloadExports' readonly metadataKey = 'downloadedExport-' - private readonly _storage = globalContext.storage + private readonly _storage = globalCtx.storage static get instance(): DownloadedExportStore { - return (this._instance ??= new DownloadedExportStore()) + this._instance ??= new DownloadedExportStore() + return this._instance } async add(filePath: string, id?: number | null): Promise { diff --git a/src/services/fetch-json-response-to-camel-case.ts b/src/services/fetch-json-response-to-camel-case.ts index 2e278fe4..797b9f1c 100644 --- a/src/services/fetch-json-response-to-camel-case.ts +++ b/src/services/fetch-json-response-to-camel-case.ts @@ -1,6 +1,7 @@ export const convertObjectKeysToCamelCase = (obj: T) => { const anyObj = >obj const splitters = ['-', '_'] + for (const oldKey of Object.keys(obj)) { const newKey = oldKey .split(new RegExp(`(${splitters.join('|')})`)) @@ -10,5 +11,6 @@ export const convertObjectKeysToCamelCase = (obj: T) => { anyObj[newKey] = anyObj[oldKey] if (oldKey !== newKey) delete anyObj[oldKey] } + return obj } diff --git a/src/services/global-ctx.ts b/src/services/global-ctx.ts new file mode 100644 index 00000000..928aaafc --- /dev/null +++ b/src/services/global-ctx.ts @@ -0,0 +1,54 @@ +import { env, ExtensionContext, Uri } from 'vscode' +import { defaultConfig, devConfig, IExtensionConfig, isDevEnv } from '@/models/config' +import path from 'path' + +class GlobalCtx { + private _extensionContext?: ExtensionContext + private readonly _config: IExtensionConfig = defaultConfig + private readonly _devConfig: IExtensionConfig = devConfig + + get secretsStorage() { + return this.extCtx.secrets + } + + get storage() { + return this.extCtx.globalState + } + + get config(): IExtensionConfig { + return isDevEnv() ? this._devConfig : this._config + } + + get extCtx(): ExtensionContext { + if (this._extensionContext == null) throw Error('extension context not exist') + return this._extensionContext + } + + set extCtx(v: ExtensionContext | undefined) { + this._extensionContext = v + } + + get extName(): string { + const { name } = <{ name?: string }>this.extCtx.extension.packageJSON + return name ?? 'vscode-cnb' + } + + get publisher(): string { + const { publisher } = <{ publisher?: string }>this.extCtx.extension.packageJSON + return publisher ?? 'cnblogs' + } + + get displayName() { + return this.extCtx.extension.packageJSON.displayName as string + } + + get assetsUri() { + return Uri.file(path.join(globalCtx.extCtx.extensionPath, 'dist', 'assets')) + } + + get extensionUrl() { + return `${env.uriScheme}://${this.publisher}.${this.extName}` + } +} + +export const globalCtx = new GlobalCtx() diff --git a/src/services/global-state.ts b/src/services/global-state.ts deleted file mode 100644 index f1f905ee..00000000 --- a/src/services/global-state.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { env, ExtensionContext, Uri } from 'vscode' -import { defaultConfig, devConfig, IExtensionConfig, isDev } from '@/models/config' -import path from 'path' - -class GlobalContext { - private _extensionContext?: ExtensionContext - private readonly _config: IExtensionConfig = defaultConfig - private readonly _devConfig: IExtensionConfig = devConfig - - get secretsStorage() { - return this.extensionContext.secrets - } - - get storage() { - return this.extensionContext.globalState - } - - get config(): IExtensionConfig { - return isDev() ? this._devConfig : this._config - } - - get extensionContext(): ExtensionContext { - if (this._extensionContext == null) throw Error('extension context not exist') - return this._extensionContext - } - - set extensionContext(v: ExtensionContext | undefined) { - this._extensionContext = v - } - - get extensionName(): string { - const { name } = <{ name?: string }>this.extensionContext.extension.packageJSON - return name ?? 'vscode-cnb' - } - - get publisher(): string { - const { publisher } = <{ publisher?: string }>this.extensionContext.extension.packageJSON - return publisher ?? 'cnblogs' - } - - get displayName() { - return this.extensionContext.extension.packageJSON.displayName as string - } - - get assetsUri() { - return Uri.file(path.join(globalContext.extensionContext.extensionPath, 'dist', 'assets')) - } - - get extensionUrl() { - return `${env.uriScheme}://${this.publisher}.${this.extensionName}` - } -} - -export const globalContext = new GlobalContext() diff --git a/src/services/image.service.ts b/src/services/image.service.ts index d0bb7f13..b32b7503 100644 --- a/src/services/image.service.ts +++ b/src/services/image.service.ts @@ -1,4 +1,4 @@ -import { globalContext } from './global-state' +import { globalCtx } from './global-ctx' import { Readable } from 'stream' import { isString, merge, pick } from 'lodash-es' import httpClient from '@/utils/http-client' @@ -7,18 +7,20 @@ import path from 'path' class ImageService { async upload( file: T - ): Promise { + ) { // eslint-disable-next-line @typescript-eslint/naming-convention - const FormData = (await import('form-data')).default - const form = new FormData() const { name, fileName, filename, path: _path } = file const finalName = path.basename(isString(_path) ? _path : fileName || filename || name || 'image.png') const ext = path.extname(finalName) + const mime = await import('mime') const mimeType = mime.lookup(ext, 'image/png') - form.append('image', file, { filename: finalName, contentType: mimeType }) - const response = await httpClient.post(`${globalContext.config.apiBaseUrl}/api/posts/body/images`, { - body: form, + + const fd = new (await import('form-data')).default() + fd.append('image', file, { filename: finalName, contentType: mimeType }) + + const response = await httpClient.post(`${globalCtx.config.apiBaseUrl}/api/posts/body/images`, { + body: fd, }) return response.body diff --git a/src/services/images-extractor.service.ts b/src/services/images-extractor.service.ts deleted file mode 100644 index 6f5611fb..00000000 --- a/src/services/images-extractor.service.ts +++ /dev/null @@ -1,184 +0,0 @@ -import path from 'path' -import fs from 'fs' -import { Uri, workspace } from 'vscode' -import { imageService } from './image.service' -import { isErrorResponse } from '@/models/error-response' -import { isString } from 'lodash-es' -import { promisify } from 'util' -import { Readable } from 'stream' - -export interface ImageInfo { - startOffset: number - prefix: string - link: string - postfix: string -} - -const imgTagImgRegExp = /()/gi -const mkdImgRegExp = /(!\[.*?\]\()(.*?\.(?:png|jpg|jpeg|webp|svg|gif))(\))/gi -const cnblogsDomainRegExp = /\.cnblogs\.com\//gi - -export const enum ImageSrc { - web, - local, - any, -} - -export const newImageSrcFilter = (type: ImageSrc) => { - const isWebImage = (imgInfo: ImageInfo) => /https?:\/\//.test(imgInfo.link) - const isLocalImage = (imgInfo: ImageInfo) => !isWebImage(imgInfo) - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const isAnyImage = (_: ImageInfo) => true - - switch (type) { - case ImageSrc.web: - return isWebImage - case ImageSrc.local: - return isLocalImage - case ImageSrc.any: - return isAnyImage - } -} - -enum ExtractorSt { - pending, - extracting, - extracted, -} - -export class MarkdownImagesExtractor { - private _imageSrc = ImageSrc.any - private _status = ExtractorSt.pending - private _errors: [imageLink: string, msg: string][] = [] - private _images: ImageInfo[] | null | undefined = null - private readonly _workspaceDirs: string[] | undefined - - constructor( - private readonly markdown: string, - private readonly targetFileUri: Uri, - public onProgress?: (index: number, images: ImageInfo[]) => void - ) { - this._workspaceDirs = workspace.workspaceFolders?.map(({ uri: { fsPath } }) => fsPath) - } - - get imageSrc() { - return this._imageSrc - } - - set imageSrc(v) { - this._imageSrc = v - } - - get status() { - return this._status - } - - get errors() { - return this._errors - } - - async extract(): Promise<[src: ImageInfo, dst: ImageInfo | null][]> { - this._status = ExtractorSt.extracting - - const srcInfoArr = this.findImages() - let count = 0 - - const result: ReturnType extends Promise ? U : never = [] - - for (const srcInfo of srcInfoArr) { - if (this.onProgress) this.onProgress(count++, srcInfoArr) - - // reuse resolved link - const resolvedLink = result.find(([src, dst]) => dst != null && src.link === srcInfo.link)?.[1]?.link - - const stream = resolvedLink ?? (await this.resolveImageFile(srcInfo)) - - const dstInfo = await (async () => { - if (stream == null) return null - - try { - const newLink = isString(stream) ? stream : await imageService.upload(stream) - - return { - ...srcInfo, - link: newLink, - } - } catch (e) { - const errMsg = `上传图片失败, ${isErrorResponse(e) ? e.errors.join(',') : JSON.stringify(e)}` - this._errors.push([srcInfo.link, errMsg]) - return null - } - })() - - result.push([srcInfo, dstInfo]) - } - - this._status = ExtractorSt.extracted - - return result - } - - findImages(): ImageInfo[] { - const mkdImgMatchGroup = Array.from(this.markdown.matchAll(mkdImgRegExp)) - const imgTagImgMatchGroup = Array.from(this.markdown.matchAll(imgTagImgRegExp)) - const matchGroupAcc = mkdImgMatchGroup.concat(imgTagImgMatchGroup) - - this._images ??= matchGroupAcc - .map(mg => ({ - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - startOffset: mg.index!, - prefix: mg[1], - link: mg[2], - postfix: mg[3], - })) - .filter(x => !cnblogsDomainRegExp.test(x.link)) - - return this._images.filter(x => newImageSrcFilter(this._imageSrc)(x)) - } - - private async resolveImageFile(info: ImageInfo): Promise { - // for web img - if (newImageSrcFilter(ImageSrc.web)(info)) { - const stream = await imageService.download(info.link) - // TODO: fix warning here - if (stream instanceof Array) { - this._errors.push([info.link, `无法下载网络图片, ${stream[0]} - ${stream[2]}`]) - return - } - return stream - } - - // for local img - const checkReadAccess = (filePath: string) => - promisify(fs.access)(filePath).then( - () => true, - () => false - ) - - let iPath: string | undefined | null = info.link - let iDir = 0 - let searchingDirs: string[] | undefined | null - let triedPath: string[] | undefined - let isEncodedPath = false - - while (iPath != null) { - if (await checkReadAccess(iPath)) { - return fs.createReadStream(iPath) - } else { - triedPath ??= [] - triedPath.push(iPath) - - if (!isEncodedPath) { - iPath = decodeURIComponent(iPath) - isEncodedPath = true - continue - } - } - - searchingDirs ??= [path.dirname(this.targetFileUri.fsPath), ...(this._workspaceDirs ?? [])] - iPath = iDir >= 0 && searchingDirs.length > iDir ? path.resolve(searchingDirs[iDir], info.link) : undefined - iDir++ - isEncodedPath = false - } - } -} diff --git a/src/services/ing.api.ts b/src/services/ing.api.ts index b4ea02e4..d1caa667 100644 --- a/src/services/ing.api.ts +++ b/src/services/ing.api.ts @@ -1,26 +1,26 @@ import { Ing, IngComment, IngPublishModel, IngType } from '@/models/ing' import { AlertService } from '@/services/alert.service' -import { globalContext } from '@/services/global-state' +import { globalCtx } from '@/services/global-ctx' import fetch from '@/utils/fetch-client' import { URLSearchParams } from 'url' import { isArray, isNumber, isObject } from 'lodash-es' export class IngApi { async publishIng(ing: IngPublishModel): Promise { - const resp = await fetch(`${globalContext.config.cnblogsOpenApiUrl}/api/statuses`, { + const resp = await fetch(`${globalCtx.config.cnblogsOpenApiUrl}/api/statuses`, { method: 'POST', body: JSON.stringify(ing), headers: [['Content-Type', 'application/json']], - }).catch(reason => void AlertService.warning(JSON.stringify(reason))) + }).catch(reason => void AlertService.warn(JSON.stringify(reason))) if (!resp || !resp.ok) - AlertService.error(`闪存发布失败, ${resp?.statusText ?? ''} ${JSON.stringify((await resp?.text()) ?? '')}`) + AlertService.err(`闪存发布失败, ${resp?.statusText ?? ''} ${JSON.stringify((await resp?.text()) ?? '')}`) return resp != null && resp.ok } async list({ pageIndex = 1, pageSize = 30, type = IngType.all } = {}): Promise { const resp = await fetch( - `${globalContext.config.cnblogsOpenApiUrl}/api/statuses/@${type}?${new URLSearchParams({ + `${globalCtx.config.cnblogsOpenApiUrl}/api/statuses/@${type}?${new URLSearchParams({ pageIndex: `${pageIndex}`, pageSize: `${pageSize}`, }).toString()}`, @@ -28,9 +28,9 @@ export class IngApi { method: 'GET', headers: [['Content-Type', 'application/json']], } - ).catch(reason => void AlertService.warning(JSON.stringify(reason))) + ).catch(reason => void AlertService.warn(JSON.stringify(reason))) if (!resp || !resp.ok) { - AlertService.error( + AlertService.err( `获取闪存列表失败, ${resp?.statusText ?? ''} ${JSON.stringify((await resp?.text()) ?? '')}` ) return null @@ -44,7 +44,7 @@ export class IngApi { return x }) .catch(reason => { - AlertService.error(JSON.stringify(reason)) + AlertService.err(JSON.stringify(reason)) return null }) } @@ -53,14 +53,14 @@ export class IngApi { const arr = isNumber(ingIds) ? [ingIds] : ingIds return Promise.all( arr.map(id => - fetch(`${globalContext.config.cnblogsOpenApiUrl}/api/statuses/${id}/comments`, { + fetch(`${globalCtx.config.cnblogsOpenApiUrl}/api/statuses/${id}/comments`, { method: 'GET', headers: [['Content-Type', 'application/json']], }).then( resp => resp?.json().then(obj => [id, obj as IngComment[] | null | undefined] as const) ?? Promise.resolve(undefined), - reason => void AlertService.warning(JSON.stringify(reason)) + reason => void AlertService.warn(JSON.stringify(reason)) ) ) ).then(results => @@ -72,7 +72,7 @@ export class IngApi { } comment(ingId: number, data: { replyTo?: number; parentCommentId?: number; content: string }) { - return fetch(`${globalContext.config.cnblogsOpenApiUrl}/api/statuses/${ingId}/comments`, { + return fetch(`${globalCtx.config.cnblogsOpenApiUrl}/api/statuses/${ingId}/comments`, { method: 'POST', headers: [['Content-Type', 'application/json']], body: JSON.stringify(data), @@ -82,7 +82,7 @@ export class IngApi { return resp.ok }) .catch(reason => { - AlertService.warning(`发表评论失败, ${reason}`) + AlertService.err(`发表评论失败, ${reason}`) return false }) } diff --git a/src/services/ings-list-webview-provider.ts b/src/services/ings-list-webview-provider.ts index 632c4050..228e1b43 100644 --- a/src/services/ings-list-webview-provider.ts +++ b/src/services/ings-list-webview-provider.ts @@ -1,4 +1,4 @@ -import { globalContext } from 'src/services/global-state' +import { globalCtx } from 'src/services/global-ctx' import { CancellationToken, commands, @@ -20,7 +20,7 @@ import { CommentIngCommandHandler } from '@/commands/ing/comment-ing' export class IngsListWebviewProvider implements WebviewViewProvider { private static _instance?: IngsListWebviewProvider - readonly viewId = `${globalContext.extensionName}.ings-list-webview` + readonly viewId = `${globalCtx.extName}.ings-list-webview` private readonly _baseTitle = '闪存' private _view?: WebviewView @@ -35,7 +35,8 @@ export class IngsListWebviewProvider implements WebviewViewProvider { get observer(): IngWebviewMessageObserver { if (!this._view) throw Error('Cannot access the observer until the webviewView initialized!') - return (this._observer ??= new IngWebviewMessageObserver(this)) + this._observer ??= new IngWebviewMessageObserver(this) + return this._observer } get pageIndex() { @@ -51,7 +52,8 @@ export class IngsListWebviewProvider implements WebviewViewProvider { } get show() { - return (this._show ??= this._view ? this._view.show.bind(this._view) : undefined) + this._show ??= this._view ? this._view.show.bind(this._view) : undefined + return this._show } static get instance(): IngsListWebviewProvider | undefined { @@ -59,17 +61,18 @@ export class IngsListWebviewProvider implements WebviewViewProvider { } private get assetsUri() { - return globalContext.assetsUri + return globalCtx.assetsUri } private get ingApi() { - return (this._ingApi ??= new IngApi()) + this._ingApi ??= new IngApi() + return this._ingApi } static ensureRegistered() { if (!this._instance) { this._instance = new IngsListWebviewProvider() - globalContext.extensionContext.subscriptions.push( + globalCtx.extCtx.subscriptions.push( window.registerWebviewViewProvider(this._instance.viewId, this._instance) ) } @@ -156,22 +159,14 @@ export class IngsListWebviewProvider implements WebviewViewProvider { private async setIsRefreshing(value: boolean) { await commands - .executeCommand( - 'setContext', - `${globalContext.extensionName}.ingsList.isRefreshing`, - value ? true : undefined - ) + .executeCommand('setContext', `${globalCtx.extName}.ingsList.isRefreshing`, value ? true : undefined) .then(undefined, () => undefined) this._isRefreshing = value } private async setPageIndex(value: number) { await commands - .executeCommand( - 'setContext', - `${globalContext.extensionName}.ingsList.pageIndex`, - value > 0 ? value : undefined - ) + .executeCommand('setContext', `${globalCtx.extName}.ingsList.pageIndex`, value > 0 ? value : undefined) .then(undefined, () => undefined) this._pageIndex = value } diff --git a/src/services/mkd-img-extractor.service.ts b/src/services/mkd-img-extractor.service.ts new file mode 100644 index 00000000..c2f3700b --- /dev/null +++ b/src/services/mkd-img-extractor.service.ts @@ -0,0 +1,244 @@ +import path from 'path' +import { isString } from 'lodash-es' +import fs from 'fs' +import { Uri, workspace } from 'vscode' +import { imageService } from './image.service' +import { isErrorResponse } from '@/models/error-response' +import { promisify } from 'util' +import { Readable } from 'stream' +import { tmpdir } from 'os' + +export const enum DataType { + dataUrl, + url, +} + +export interface ImageInfo { + startOffset: number + data: string + dataType: DataType + prefix: string + postfix: string +} + +// Data URL reference see in: +// https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URLs +// Related RFC: +// https://datatracker.ietf.org/doc/html/rfc2397 + +const imgTagDataUrlImgPat = /()/g +const imgTagUrlImgPat = /()/gi +const mkdDataUrlImgPat = /(!\[.*?\]\()(data:image\/.*?,[a-zA-Z0-9+/]*?=?=?)(\))/g +const mkdUrlImgPat = /(!\[.*?\]\()(.*?\.(?:png|jpg|jpeg|webp|svg|gif))(\))/gi + +const cnblogsDomainRegExp = /\.cnblogs\.com\//gi + +export const enum ImageSrc { + web, + dataUrl, + fs, + any, +} + +export const newImageSrcFilter = (type: ImageSrc) => { + const isWebImage = (imgInfo: ImageInfo) => imgInfo.dataType === DataType.url && /https?:\/\//.test(imgInfo.data) + const isFsImage = (imgInfo: ImageInfo) => imgInfo.dataType === DataType.url && !isWebImage(imgInfo) + const isDataUrlImage = (imgInfo: ImageInfo) => imgInfo.dataType === DataType.dataUrl + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const isAnyImage = (_: ImageInfo) => true + + switch (type) { + case ImageSrc.web: + return isWebImage + case ImageSrc.fs: + return isFsImage + case ImageSrc.dataUrl: + return isDataUrlImage + case ImageSrc.any: + return isAnyImage + } +} + +enum ExtractorSt { + pending, + extracting, + extracted, +} + +export class MkdImgExtractor { + private _imageSrc = ImageSrc.any + private _status = ExtractorSt.pending + private _errors: [imageLink: string, msg: string][] = [] + private _images: ImageInfo[] | null | undefined = null + private readonly _workspaceDirs: string[] | undefined + + constructor( + private readonly markdown: string, + private readonly targetFileUri: Uri, + public onProgress?: (index: number, images: ImageInfo[]) => void + ) { + this._workspaceDirs = workspace.workspaceFolders?.map(({ uri: { fsPath } }) => fsPath) + } + + get imageSrc() { + return this._imageSrc + } + + set imageSrc(v) { + this._imageSrc = v + } + + get status() { + return this._status + } + + get errors() { + return this._errors + } + + async extract(): Promise<[src: ImageInfo, dst: ImageInfo | null][]> { + this._status = ExtractorSt.extracting + + const srcInfoArr = this.findImages() + let count = 0 + + const result: ReturnType extends Promise ? U : never = [] + + for (const srcInfo of srcInfoArr) { + if (this.onProgress) this.onProgress(count++, srcInfoArr) + + // reuse resolved link + const resolvedLink = result.find(([src, dst]) => dst != null && src.data === srcInfo.data)?.[1]?.data + + const streamOrLink = resolvedLink ?? (await this.resolveImgInfo(srcInfo)) + + const dstInfo = await (async () => { + if (streamOrLink === undefined) return null + try { + const newLink = isString(streamOrLink) ? streamOrLink : await imageService.upload(streamOrLink) + + return { + ...srcInfo, + data: newLink, + } + } catch (e) { + const errMsg = `上传图片失败, ${isErrorResponse(e) ? e.errors.join(',') : JSON.stringify(e)}` + this._errors.push([srcInfo.data, errMsg]) + return null + } + })() + + result.push([srcInfo, dstInfo]) + } + + this._status = ExtractorSt.extracted + + return result + } + + findImages(): ImageInfo[] { + const acc = () => { + const imgTagUrlImgMatchGroups = Array.from(this.markdown.matchAll(imgTagUrlImgPat)) + const mkdUrlImgMatchGroups = Array.from(this.markdown.matchAll(mkdUrlImgPat)) + const urlImgInfo = imgTagUrlImgMatchGroups.concat(mkdUrlImgMatchGroups).map(mg => ({ + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + startOffset: mg.index!, + dataType: DataType.url, + data: mg[2], + prefix: mg[1], + postfix: mg[3], + })) + + const imgTagDataUrlImgMatchGroups = Array.from(this.markdown.matchAll(imgTagDataUrlImgPat)) + const mkdDataUrlImgMatchGroups = Array.from(this.markdown.matchAll(mkdDataUrlImgPat)) + const dataUrlImgInfo = imgTagDataUrlImgMatchGroups.concat(mkdDataUrlImgMatchGroups).map(mg => ({ + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + startOffset: mg.index!, + dataType: DataType.dataUrl, + data: mg[2], + prefix: mg[1], + postfix: mg[3], + })) + + const acc = urlImgInfo.concat(dataUrlImgInfo) + + // TODO: better filter design needed + // remove cnblogs img link + return acc.filter(x => !cnblogsDomainRegExp.test(x.data)) + } + + this._images ??= acc() + + // apply settings + return this._images.filter(x => newImageSrcFilter(this._imageSrc)(x)) + } + + private async resolveWebImg(url: string) { + try { + return await imageService.download(url) + } catch (e) { + // eslint-disable-next-line @typescript-eslint/restrict-template-expressions + this._errors.push([url, `无法下载网络图片: ${e}`]) + return + } + } + + private async resolveFsImg(imgPath: string) { + const checkReadAccess = (filePath: string) => + promisify(fs.access)(filePath).then( + () => true, + () => false + ) + + let iPath: string | undefined | null = imgPath + let iDir = 0 + let searchingDirs: string[] | undefined | null + let isEncodedPath = false + + while (iPath != null) { + if (await checkReadAccess(iPath)) return fs.createReadStream(iPath) + + if (!isEncodedPath) { + iPath = decodeURIComponent(iPath) + isEncodedPath = true + continue + } + + searchingDirs ??= [path.dirname(this.targetFileUri.fsPath), ...(this._workspaceDirs ?? [])] + iPath = iDir >= 0 && searchingDirs.length > iDir ? path.resolve(searchingDirs[iDir], imgPath) : undefined + iDir++ + isEncodedPath = false + } + } + + private resolveDataUrlImg(dataUrl: string) { + // reference for this impl: + // https://stackoverflow.com/questions/6850276/how-to-convert-dataurl-to-file-object-in-javascript/7261048#7261048 + + const regex = /data:image\/(.*?);.*?,([a-zA-Z0-9+/]*=?=?)/g + + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const mg = Array.from(dataUrl.matchAll(regex)) + const buf = Buffer.from(mg[0][2], 'base64') + + const ext = mg[0][1] + const fileName = `${Date.now()}.${ext}` + const path = `${tmpdir()}/` + fileName + fs.writeFileSync(path, buf, 'utf8') + + return fs.createReadStream(path) + } + + private async resolveImgInfo(info: ImageInfo): Promise { + // for web img + // eslint-disable-next-line no-return-await + if (newImageSrcFilter(ImageSrc.web)(info)) return await this.resolveWebImg(info.data) + + // for fs img + // eslint-disable-next-line no-return-await + if (newImageSrcFilter(ImageSrc.fs)(info)) return await this.resolveFsImg(info.data) + + // for data url img + if (newImageSrcFilter(ImageSrc.dataUrl)(info)) return this.resolveDataUrlImg(info.data) + } +} diff --git a/src/services/oauth.api.ts b/src/services/oauth.api.ts index df47ae14..dd605428 100644 --- a/src/services/oauth.api.ts +++ b/src/services/oauth.api.ts @@ -1,45 +1,37 @@ /* eslint-disable @typescript-eslint/naming-convention */ -import { TokenInformation } from '@/models/token-information' -import { CnblogsAccountInformation } from '@/authentication/account-information' +import { TokenInfo } from '@/models/token-info' +import { AccountInfo } from '@/auth/account-info' import { convertObjectKeysToCamelCase } from '@/services/fetch-json-response-to-camel-case' -import { globalContext } from '@/services/global-state' +import { globalCtx } from '@/services/global-ctx' import fetch from '@/utils/fetch-client' import got from '@/utils/http-client' import { CancellationToken } from 'vscode' import { AbortController } from 'node-abort-controller' import { AuthorizationHeaderKey } from '@/utils/constants' -export type UserInformationSpec = Pick & { +export type UserInfoSpec = Pick & { readonly blog_id: string readonly account_id: string readonly picture: string } -export class OauthApi { - async fetchToken({ - codeVerifier, - authorizationCode, - cancellationToken, - }: { - codeVerifier: string - authorizationCode: string - cancellationToken?: CancellationToken - }): Promise { +export namespace Oauth { + export async function fetchToken(verifyCode: string, authCode: string, cancelToken?: CancellationToken) { const abortControl = new AbortController() - if (cancellationToken?.isCancellationRequested) abortControl.abort() - cancellationToken?.onCancellationRequested(() => abortControl.abort()) + if (cancelToken?.isCancellationRequested) abortControl.abort() + cancelToken?.onCancellationRequested(() => abortControl.abort()) - const url = globalContext.config.oauth.authority + globalContext.config.oauth.tokenEndpoint - const { clientId, clientSecret } = globalContext.config.oauth + const url = globalCtx.config.oauth.authority + globalCtx.config.oauth.tokenEndpoint + const { clientId, clientSecret } = globalCtx.config.oauth - const res = await got.post(url, { + const res = await got.post(url, { form: { - code: authorizationCode, - code_verifier: codeVerifier, + code: authCode, + code_verifier: verifyCode, grant_type: 'authorization_code', client_id: clientId, client_secret: clientSecret, - redirect_uri: globalContext.extensionUrl, + redirect_uri: globalCtx.extensionUrl, }, responseType: 'json', signal: abortControl.signal, @@ -47,6 +39,7 @@ export class OauthApi { [AuthorizationHeaderKey]: '', }, }) + if (res.statusCode === 200) return convertObjectKeysToCamelCase(res.body) throw Error( @@ -54,35 +47,33 @@ export class OauthApi { ) } - async fetchUserInformation( - token: string, - { cancellationToken }: { cancellationToken?: CancellationToken | null } = {} - ): Promise { - const { authority, userInfoEndpoint } = globalContext.config.oauth + export async function fetchUserInfo(token: string, cancelToken?: CancellationToken) { + const { authority, userInfoEndpoint } = globalCtx.config.oauth const abortController = new AbortController() - if (cancellationToken?.isCancellationRequested) abortController.abort() - const cancellationSubscribe = cancellationToken?.onCancellationRequested(() => abortController.abort()) + if (cancelToken?.isCancellationRequested) abortController.abort() + + const cancelSub = cancelToken?.onCancellationRequested(() => abortController.abort()) - const { body } = await got(`${authority}${userInfoEndpoint}`, { + const res = await got(`${authority}${userInfoEndpoint}`, { method: 'GET', // eslint-disable-next-line @typescript-eslint/naming-convention headers: { Authorization: `Bearer ${token}` }, signal: abortController.signal, responseType: 'json', }).finally(() => { - cancellationSubscribe?.dispose() + cancelSub?.dispose() }) - return body + return res.body } - async revoke(accessToken: string): Promise { - const { clientId, revocationEndpoint, authority } = globalContext.config.oauth + export async function revokeToken(token: string): Promise { + const { clientId, revocationEndpoint, authority } = globalCtx.config.oauth const body = new URLSearchParams([ ['client_id', clientId], - ['token', accessToken], + ['token', token], ['token_type_hint', 'access_token'], ]) const url = `${authority}${revocationEndpoint}` @@ -91,6 +82,7 @@ export class OauthApi { body: body, headers: [['Content-Type', 'application/x-www-form-urlencoded']], }) + return res.ok } } diff --git a/src/services/parse-webview-html.ts b/src/services/parse-webview-html.ts index 8070a096..8c1726e6 100644 --- a/src/services/parse-webview-html.ts +++ b/src/services/parse-webview-html.ts @@ -1,9 +1,10 @@ import vscode from 'vscode' -import { globalContext } from 'src/services/global-state' +import { globalCtx } from 'src/services/global-ctx' export type WebviewEntryName = 'ing' | 'post-configuration' -export const parseWebviewHtml = async (entry: WebviewEntryName, webview: vscode.Webview) => - (await vscode.workspace.fs.readFile(vscode.Uri.joinPath(globalContext.assetsUri, 'ui', entry, 'index.html'))) - .toString() - .replace(/@PWD/g, webview.asWebviewUri(globalContext.assetsUri).toString()) +export async function parseWebviewHtml(entry: WebviewEntryName, webview: vscode.Webview) { + const path = vscode.Uri.joinPath(globalCtx.assetsUri, 'ui', entry, 'index.html') + const file = await vscode.workspace.fs.readFile(path) + return file.toString().replace(/@PWD/g, webview.asWebviewUri(globalCtx.assetsUri).toString()) +} diff --git a/src/services/post-category.service.ts b/src/services/post-category.service.ts index 452b1c0a..aac70494 100644 --- a/src/services/post-category.service.ts +++ b/src/services/post-category.service.ts @@ -1,6 +1,6 @@ import fetch from '@/utils/fetch-client' import { PostCategories, PostCategory, PostCategoryAddDto } from '@/models/post-category' -import { globalContext } from './global-state' +import { globalCtx } from './global-ctx' import { URLSearchParams } from 'url' export class PostCategoryService { @@ -39,16 +39,17 @@ export class PostCategoryService { const parentId = typeof option === 'object' ? option.parentId ?? -1 : -1 const shouldForceRefresh = option === true || (typeof option === 'object' ? option.forceRefresh ?? false : false) - const map = (this._cache ??= new Map()) + this._cache ??= new Map() + const map = this._cache const cachedCategories = map.get(parentId) if (cachedCategories && !shouldForceRefresh) return cachedCategories const res = await fetch( - `${globalContext.config.apiBaseUrl}/api/v2/blog-category-types/1/categories?${new URLSearchParams([ + `${globalCtx.config.apiBaseUrl}/api/v2/blog-category-types/1/categories?${new URLSearchParams([ ['parent', parentId <= 0 ? '' : `${parentId}`], ]).toString()}` ) - if (!res.ok) throw Error(`Failed to fetch post categories\n${res.status}\n${await res.text()}`) + if (!res.ok) throw Error(`${res.status}\n${await res.text()}`) let { categories } = <{ parent?: PostCategory | null; categories: PostCategories }>await res.json() categories = categories.map(x => Object.assign(new PostCategory(), x)) @@ -58,7 +59,7 @@ export class PostCategoryService { async find(id: number) { const res = await fetch( - `${globalContext.config.apiBaseUrl}/api/v2/blog-category-types/1/categories?${new URLSearchParams([ + `${globalCtx.config.apiBaseUrl}/api/v2/blog-category-types/1/categories?${new URLSearchParams([ ['parent', id <= 0 ? '' : `${id}`], ]).toString()}` ) @@ -68,7 +69,7 @@ export class PostCategoryService { } async newCategory(categoryAddDto: PostCategoryAddDto) { - const res = await fetch(`${globalContext.config.apiBaseUrl}/api/category/blog/1`, { + const res = await fetch(`${globalCtx.config.apiBaseUrl}/api/category/blog/1`, { method: 'POST', body: JSON.stringify(categoryAddDto), headers: [['Content-Type', 'application/json']], @@ -77,7 +78,7 @@ export class PostCategoryService { } async updateCategory(category: PostCategory) { - const res = await fetch(`${globalContext.config.apiBaseUrl}/api/category/blog/${category.categoryId}`, { + const res = await fetch(`${globalCtx.config.apiBaseUrl}/api/category/blog/${category.categoryId}`, { method: 'PUT', body: JSON.stringify(category), headers: [['Content-Type', 'application/json']], @@ -88,7 +89,7 @@ export class PostCategoryService { async deleteCategory(categoryId: number) { if (categoryId <= 0) throw Error('Invalid param categoryId') - const res = await fetch(`${globalContext.config.apiBaseUrl}/api/category/blog/${categoryId}`, { + const res = await fetch(`${globalCtx.config.apiBaseUrl}/api/category/blog/${categoryId}`, { method: 'DELETE', headers: [['Content-Type', 'application/json']], }) diff --git a/src/services/post-configuration-panel.service.ts b/src/services/post-configuration-panel.service.ts index a486c415..c7cf4c7e 100644 --- a/src/services/post-configuration-panel.service.ts +++ b/src/services/post-configuration-panel.service.ts @@ -1,11 +1,11 @@ import { cloneDeep } from 'lodash-es' import vscode, { Uri } from 'vscode' import { Post } from '@/models/post' -import { globalContext } from './global-state' +import { globalCtx } from './global-ctx' import { postCategoryService } from './post-category.service' import { siteCategoryService } from './site-category.service' import { postTagService } from './post-tag.service' -import { postService } from './post.service' +import { PostService } from './post.service' import { isErrorResponse } from '@/models/error-response' import { webviewMessage } from '@/models/webview-message' import { WebviewCommonCommand, webviewCommands } from 'src/models/webview-commands' @@ -27,7 +27,7 @@ export namespace postConfigurationPanel { beforeUpdate?: (postToUpdate: Post, panel: vscode.WebviewPanel) => Promise } - const resourceRootUri = () => globalContext.assetsUri + const resourceRootUri = () => globalCtx.assetsUri const setHtml = async (webview: vscode.Webview): Promise => { webview.html = await parseWebviewHtml('post-configuration', webview) @@ -108,7 +108,7 @@ export namespace postConfigurationPanel { }) const { webview } = panel await setHtml(webview) - panel.iconPath = Uri.joinPath(globalContext.extensionContext.extensionUri, 'dist', 'assets', 'favicon.svg') + panel.iconPath = Uri.joinPath(globalCtx.extCtx.extensionUri, 'dist', 'assets', 'favicon.svg') panels.set(panelId, panel) return panel } @@ -174,18 +174,18 @@ export namespace postConfigurationPanel { return webview.onDidReceiveMessage(async message => { const { command } = (message ?? {}) as webviewMessage.Message switch (command) { - case webviewCommands.ExtensionCommands.savePost: + case webviewCommands.ExtensionCommands.uploadPost: try { if (!panel) return - const { post: postToUpdate } = message as webviewMessage.SavePostMessage + const { post: postToUpdate } = message as webviewMessage.UploadPostMessage if (beforeUpdate) { if (!(await beforeUpdate(postToUpdate, panel))) { panel.dispose() return } } - const postSavedModel = await postService.updatePost(postToUpdate) + const postSavedModel = await PostService.updatePost(postToUpdate) panel.dispose() successCallback(Object.assign({}, postToUpdate, postSavedModel)) } catch (err) { diff --git a/src/services/post-file-map.ts b/src/services/post-file-map.ts index 68e13017..1f0b12bb 100644 --- a/src/services/post-file-map.ts +++ b/src/services/post-file-map.ts @@ -1,6 +1,6 @@ import { postCategoriesDataProvider } from '@/tree-view-providers/post-categories-tree-data-provider' import { postsDataProvider } from '@/tree-view-providers/posts-data-provider' -import { globalContext } from './global-state' +import { globalCtx } from './global-ctx' const validatePostFileMap = (map: PostFileMap) => map[0] >= 0 && !!map[1] @@ -10,7 +10,7 @@ export class PostFileMapManager { static storageKey = 'postFileMaps' private static get maps(): PostFileMap[] { - return globalContext.storage.get(this.storageKey) ?? [] + return globalCtx.storage.get(this.storageKey) ?? [] } static updateOrCreateMany(maps: PostFileMap[]): Promise @@ -38,7 +38,7 @@ export class PostFileMapManager { if (exist) exist[1] = filePath else maps.push([postId, filePath]) - await globalContext.storage.update(this.storageKey, maps.filter(validatePostFileMap)) + await globalCtx.storage.update(this.storageKey, maps.filter(validatePostFileMap)) if (emitEvent) { postsDataProvider.fireTreeDataChangedEvent(postId) postCategoriesDataProvider.onPostUpdated({ refreshPosts: false, postIds: [postId] }) diff --git a/src/services/post-tag.service.ts b/src/services/post-tag.service.ts index 7d5c85c7..5225b54d 100644 --- a/src/services/post-tag.service.ts +++ b/src/services/post-tag.service.ts @@ -1,6 +1,6 @@ import got from '@/utils/http-client' import { PostTag } from '@/models/post-tag' -import { globalContext } from './global-state' +import { globalCtx } from './global-ctx' export class PostTagService { private static _instance: PostTagService @@ -23,7 +23,7 @@ export class PostTagService { url, method, body, - } = await got.get(`${globalContext.config.apiBaseUrl}/api/tags/list`, { responseType: 'json' }) + } = await got.get(`${globalCtx.config.apiBaseUrl}/api/tags/list`, { responseType: 'json' }) if (!isOk) throw Error(`Failed to ${method} ${url}`) return Array.isArray(body) diff --git a/src/services/post-title-sanitizer.service.ts b/src/services/post-title-sanitizer.service.ts index 010ec61a..6b6c7f23 100644 --- a/src/services/post-title-sanitizer.service.ts +++ b/src/services/post-title-sanitizer.service.ts @@ -1,7 +1,7 @@ import path from 'path' import sanitize from 'sanitize-filename' import { Post } from '@/models/post' -import { globalContext } from './global-state' +import { globalCtx } from './global-ctx' import { PostFileMapManager } from './post-file-map' type InvalidPostFileNameMap = [postId: number, invalidName: string | undefined | null] @@ -18,13 +18,13 @@ class InvalidPostTitleStore { store(map: InvalidPostFileNameMap): Thenable { const [postId, invalidName] = map const key = buildStorageKey(postId) - if (invalidName) return globalContext.storage.update(key, invalidName) - else return globalContext.storage.update(key, undefined) + if (invalidName) return globalCtx.storage.update(key, invalidName) + else return globalCtx.storage.update(key, undefined) } get(postId: number): string | undefined { const key = buildStorageKey(postId) - return globalContext.storage.get(key) + return globalCtx.storage.get(key) } } diff --git a/src/services/post.service.ts b/src/services/post.service.ts index 3a5f1443..aa8412d3 100644 --- a/src/services/post.service.ts +++ b/src/services/post.service.ts @@ -1,6 +1,6 @@ import fetch from '@/utils/fetch-client' import { Post } from '@/models/post' -import { globalContext } from './global-state' +import { globalCtx } from './global-ctx' import { PageModel } from '@/models/page-model' import { PostsListState } from '@/models/posts-list-state' import { PostEditDto } from '@/models/post-edit-dto' @@ -17,24 +17,12 @@ import iconv from 'iconv-lite' const defaultPageSize = 30 let newPostTemplate: PostEditDto | undefined -export class PostService { - private static _instance = new PostService() +export namespace PostService { + const getBaseUrl = () => globalCtx.config.apiBaseUrl - protected constructor() {} + export const getPostsListState = () => globalCtx.storage.get('postsListState') - protected get _baseUrl() { - return globalContext.config.apiBaseUrl - } - - static get instance() { - return this._instance - } - - get postsListState(): PostsListState | undefined { - return globalContext.storage.get('postsListState') - } - - async fetchPostsList({ + export async function fetchPostsList({ search = '', pageIndex = 1, pageSize = defaultPageSize, @@ -51,13 +39,14 @@ export class PostService { ['search', search], ['cid', categoryId != null && categoryId > 0 ? `${categoryId}` : ''], ]) - const response = await fetch(`${this._baseUrl}/api/posts/list?${s.toString()}`, { + const response = await fetch(`${getBaseUrl()}/api/posts/list?${s.toString()}`, { method: 'GET', }) - if (!response.ok) throw Error(`request failed, ${response.status}, ${await response.text()}`) + if (!response.ok) throw Error(`请求博文列表失败: ${response.status}, ${await response.text()}`) const obj = await response.json() const { zzkSearchResult } = obj + return Object.assign( new PageModel( obj.pageIndex, @@ -69,23 +58,26 @@ export class PostService { ) } - async fetchPostEditDto(postId: number, muteErrorNotification = false): Promise { - const response = await httpClient.get(`${this._baseUrl}/api/posts/${postId}`, { + export async function fetchPostEditDto( + postId: number, + muteErrorNotification = false + ): Promise { + const response = await httpClient.get(`${getBaseUrl()}/api/posts/${postId}`, { throwHttpErrors: false, responseType: 'buffer', }) try { throwIfNotOkGotResponse(response) - } catch (ex) { - const { statusCode, errors } = ex as IErrorResponse + } catch (e) { + const { statusCode, errors } = e as IErrorResponse if (!muteErrorNotification) { if (statusCode === 404) { - AlertService.error('博文不存在') + AlertService.err('博文不存在') const postFilePath = PostFileMapManager.getFilePath(postId) if (postFilePath) await PostFileMapManager.updateOrCreate(postId, '') } else { - AlertService.error(errors.join('\n')) + AlertService.err(errors.join('\n')) } } return undefined @@ -98,22 +90,22 @@ export class PostService { return blogPost ? new PostEditDto(Object.assign(new Post(), blogPost), myConfig) : undefined } - async deletePost(postId: number) { - const res = await fetch(`${this._baseUrl}/api/posts/${postId}`, { + export async function deletePost(postId: number) { + const res = await fetch(`${getBaseUrl()}/api/posts/${postId}`, { method: 'DELETE', }) if (!res.ok) throw Error(`删除博文失败!\n${res.status}\n${await res.text()}`) } - async deletePosts(postIds: number[]) { + export async function deletePosts(postIds: number[]) { const searchParams = new URLSearchParams(postIds.map<[string, string]>(id => ['postIds', `${id}`])) - const res = await fetch(`${this._baseUrl}/api/bulk-operation/post?${searchParams.toString()}`, { + const res = await fetch(`${getBaseUrl()}/api/bulk-operation/post?${searchParams.toString()}`, { method: 'DELETE', }) if (!res.ok) throw Error(`删除博文失败!\n${res.status}\n${await res.text()}`) } - async updatePost(post: Post): Promise { + export async function updatePost(post: Post): Promise { const { ok: isOk, url, @@ -121,12 +113,12 @@ export class PostService { body, statusCode, statusMessage, - } = await got.post(`${this._baseUrl}/api/posts`, { json: post, responseType: 'json' }) + } = await got.post(`${getBaseUrl()}/api/posts`, { json: post, responseType: 'json' }) if (!isOk) throw new Error(`Failed to ${method} ${url}, ${statusCode} - ${statusMessage}`) return PostUpdatedResponse.parse(body) } - async updatePostsListState(state: PostsListState | undefined | PageModel) { + export async function updatePostsListState(state: PostsListState | undefined | PageModel) { const finalState: PostsListState | undefined = state instanceof PageModel ? { @@ -140,11 +132,11 @@ export class PostService { pageCount: state.pageCount, } : state - await globalContext.storage.update('postsListState', finalState) + await globalCtx.storage.update('postsListState', finalState) } - async fetchPostEditTemplate(): Promise { - if (!newPostTemplate) newPostTemplate = await this.fetchPostEditDto(-1) + export async function fetchPostEditTemplate(): Promise { + if (!newPostTemplate) newPostTemplate = await fetchPostEditDto(-1) return newPostTemplate ? new PostEditDto( @@ -155,8 +147,6 @@ export class PostService { } } -export const postService = PostService.instance - interface PostListModel { categoryName: string pageIndex: number diff --git a/src/services/search-post-by-title.ts b/src/services/search-post-by-title.ts index c7389324..4d8260e7 100644 --- a/src/services/search-post-by-title.ts +++ b/src/services/search-post-by-title.ts @@ -1,6 +1,6 @@ import { QuickPickItem, window } from 'vscode' import { Post } from '@/models/post' -import { postService } from './post.service' +import { PostService } from './post.service' class PostPickItem implements QuickPickItem { label: string @@ -27,7 +27,7 @@ export const searchPostsByTitle = ({ postTitle = '', quickPickTitle = '按标题 const value = quickPick.value try { quickPick.busy = true - const paged = await postService.fetchPostsList({ search: value }) + const paged = await PostService.fetchPostsList({ search: value }) const posts = paged.items const pickItems = posts.map(p => new PostPickItem(p)) if (value === quickPick.value) quickPick.items = pickItems diff --git a/src/services/settings.service.ts b/src/services/settings.service.ts index b3a71bf7..733afa0d 100644 --- a/src/services/settings.service.ts +++ b/src/services/settings.service.ts @@ -1,7 +1,7 @@ import os, { homedir } from 'os' import fs from 'fs' import { ConfigurationTarget, Uri, workspace } from 'vscode' -import { ImageSrc, MarkdownImagesExtractor } from './images-extractor.service' +import { ImageSrc } from './mkd-img-extractor.service' import { isNumber } from 'lodash-es' import { untildify } from '@/utils/untildify' @@ -41,7 +41,10 @@ export class Settings { static get platformConfiguration() { const { platformPrefix, prefix } = this - return platformPrefix ? workspace.getConfiguration(`${prefix}.${platformPrefix}`) : null + + if (platformPrefix != null) return workspace.getConfiguration(`${prefix}.${platformPrefix}`) + + return null } static get workspaceUri(): Uri { @@ -74,11 +77,13 @@ export class Settings { } static get automaticallyExtractImagesType(): ImageSrc | null { - const cfg = this.configuration.get<'disable' | 'web' | 'local' | 'any'>('automaticallyExtractImages') ?? null + const cfg = + this.configuration.get<'disable' | 'web' | 'dataUrl' | 'fs' | 'any'>('automaticallyExtractImages') ?? null - if (cfg === 'local') return ImageSrc.local - if (cfg === 'any') return ImageSrc.any + if (cfg === 'fs') return ImageSrc.fs + if (cfg === 'dataUrl') return ImageSrc.dataUrl if (cfg === 'web') return ImageSrc.web + if (cfg === 'any') return ImageSrc.any return null // 'disable' case } @@ -88,6 +93,14 @@ export class Settings { return isNumber(size) ? size : 30 } + static get showConfirmMsgWhenUploadPost() { + return this.configuration.get('markdown.showConfirmMsgWhenUploadPost') ?? true + } + + static get showConfirmMsgWhenPullPost() { + return this.configuration.get('markdown.showConfirmMsgWhenPullPost') ?? true + } + static get isEnableMarkdownEnhancement() { return this.configuration.get('markdown.enableEnhancement') ?? true } @@ -113,8 +126,6 @@ export class Settings { } static async setChromiumPath(value: string) { - if (!value) return - await this.platformConfiguration?.update(this.chromiumPathKey, value, ConfigurationTarget.Global) } @@ -126,15 +137,14 @@ export class Settings { const oldKey = 'ing.enablePublishSelectionToIng' const isEnablePublishSelectionToIng = this.configuration.get(oldKey) if (isEnablePublishSelectionToIng === true) { - if ( - await this.configuration - .update('menus.context.editor', { 'ing:publish-selection': true }, ConfigurationTarget.Global) - .then( - () => true, - () => false - ) - ) - await this.configuration.update(oldKey, undefined, ConfigurationTarget.Global) + const isOk = await this.configuration + .update('menus.context.editor', { 'ing:publish-selection': true }, ConfigurationTarget.Global) + .then( + () => true, + () => false + ) + + if (isOk) await this.configuration.update(oldKey, undefined, ConfigurationTarget.Global) } } diff --git a/src/services/site-category.service.ts b/src/services/site-category.service.ts index 5ea31415..d100c795 100644 --- a/src/services/site-category.service.ts +++ b/src/services/site-category.service.ts @@ -1,6 +1,6 @@ import fetch from '@/utils/fetch-client' import { SiteCategories, SiteCategory } from '@/models/site-category' -import { globalContext } from './global-state' +import { globalCtx } from './global-ctx' export namespace siteCategoryService { let cached: SiteCategories | undefined @@ -8,7 +8,7 @@ export namespace siteCategoryService { export const fetchAll = async (forceRefresh = false): Promise => { if (cached && !forceRefresh) return cached - const response = await fetch(`${globalContext.config.apiBaseUrl}/api/category/site`) + const response = await fetch(`${globalCtx.config.apiBaseUrl}/api/category/site`) if (!response.ok) throw Error(`Failed to fetch post categories\n${response.status}\n${await response.text()}`) const categories = await response.json() diff --git a/src/services/webview.service.ts b/src/services/webview.service.ts deleted file mode 100644 index 41148a97..00000000 --- a/src/services/webview.service.ts +++ /dev/null @@ -1,14 +0,0 @@ -class WebviewService { - static _instance?: WebviewService - - private constructor() {} - - static get instance() { - this._instance ??= new WebviewService() - return this._instance - } -} - -const webviewService = WebviewService.instance - -export { webviewService } diff --git a/src/tree-view-providers/account-view-data-provider.ts b/src/tree-view-providers/account-view-data-provider.ts index 55d3a042..58ad00bd 100644 --- a/src/tree-view-providers/account-view-data-provider.ts +++ b/src/tree-view-providers/account-view-data-provider.ts @@ -1,4 +1,4 @@ -import { accountManager } from '@/authentication/account-manager' +import { accountManager } from '@/auth/account-manager' import { EventEmitter, ProviderResult, ThemeIcon, TreeDataProvider, TreeItem } from 'vscode' export class AccountViewDataProvider implements TreeDataProvider { @@ -24,7 +24,7 @@ export class AccountViewDataProvider implements TreeDataProvider { getChildren(element?: TreeItem): ProviderResult { if (!accountManager.isAuthorized || element) return [] - const u = accountManager.curUser + const u = accountManager.currentUser return [ { label: u.name, tooltip: '用户名', iconPath: new ThemeIcon('account') }, { diff --git a/src/tree-view-providers/blog-export-provider.ts b/src/tree-view-providers/blog-export-provider.ts index 4a1d7411..7b3d3f0e 100644 --- a/src/tree-view-providers/blog-export-provider.ts +++ b/src/tree-view-providers/blog-export-provider.ts @@ -12,7 +12,6 @@ import { ExportPostsEntryTreeItem, } from './models/blog-export/downloaded' import { Event, EventEmitter, ProviderResult, TreeDataProvider, TreeItem } from 'vscode' -import { ExportPostTreeItem } from './models/blog-export/post' import { AlertService } from '@/services/alert.service' import { BlogExportRecord } from '@/models/blog-export' @@ -24,7 +23,8 @@ export class BlogExportProvider implements TreeDataProvider private _downloadedExportEntry?: DownloadedExportsEntryTreeItem | null static get instance(): BlogExportProvider { - return (this._instance ??= new BlogExportProvider()) + this._instance ??= new BlogExportProvider() + return this._instance } static get optionalInstance(): BlogExportProvider | undefined | null { @@ -32,11 +32,13 @@ export class BlogExportProvider implements TreeDataProvider } get onDidChangeTreeData(): Event { - return (this._treeDataChangedSource ??= new EventEmitter()).event + this._treeDataChangedSource ??= new EventEmitter() + return this._treeDataChangedSource.event } get store(): BlogExportRecordsStore { - return (this._store ??= new BlogExportRecordsStore()) + this._store ??= new BlogExportRecordsStore() + return this._store } getTreeItem(element: BlogExportTreeItem): TreeItem | Thenable { @@ -59,7 +61,6 @@ export class BlogExportProvider implements TreeDataProvider element instanceof BlogExportRecordMetadata || element instanceof DownloadedExportMetadata || element instanceof DownloadedExportTreeItem || - element instanceof ExportPostTreeItem || element instanceof ExportPostsEntryTreeItem ) return element.parent @@ -90,7 +91,7 @@ export class BlogExportProvider implements TreeDataProvider */ async refreshRecords({ /** - * Tell if to raise a notify to the user when error response received during the refreshing process + * Tell if to raise notify to the user when error response received during the refreshing process */ notifyOnError = true, /** @@ -107,7 +108,9 @@ export class BlogExportProvider implements TreeDataProvider ? await this._store ?.refresh() .then(() => true) - .catch(e => (notifyOnError ? void AlertService.warning(`刷新博客备份失败记录, ${e}`) : undefined)) + .catch(e => { + if (notifyOnError) AlertService.err(`刷新博客备份记录失败: ${e.message}`) + }) : clearCache ? await this._store?.clearCache().then( () => true, @@ -129,7 +132,7 @@ export class BlogExportProvider implements TreeDataProvider store: { cached }, } = this // eslint-disable-next-line @typescript-eslint/no-floating-promises - if (cached == null) this.refreshRecords() + if (cached == null) void this.refreshRecords() const items: BlogExportRecord[] = cached?.items ?? [] return parseBlogExportRecords(this, items) } diff --git a/src/tree-view-providers/converters.ts b/src/tree-view-providers/converters.ts index 14d771ce..fa3e1e47 100644 --- a/src/tree-view-providers/converters.ts +++ b/src/tree-view-providers/converters.ts @@ -3,7 +3,7 @@ import { homedir } from 'os' import { MarkdownString, ThemeIcon, TreeItem, TreeItemCollapsibleState, Uri } from 'vscode' import { Post } from '@/models/post' import { PostCategory } from '@/models/post-category' -import { globalContext } from '@/services/global-state' +import { globalCtx } from '@/services/global-ctx' import { PostFileMapManager } from '@/services/post-file-map' import { Settings } from '@/services/settings.service' import { BaseTreeItemSource } from './models/base-tree-item-source' @@ -41,7 +41,7 @@ const postConverter: Converter = obj => { return Object.assign(new TreeItem(`${obj.title}`, TreeItemCollapsibleState.Collapsed), { tooltip: new MarkdownString(`[${url}](${url})` + descDatePublished + descLocalPath), command: { - command: `${globalContext.extensionName}.edit-post`, + command: `${globalCtx.extName}.edit-post`, arguments: [obj.id], title: '编辑博文', }, diff --git a/src/tree-view-providers/models/blog-export/downloaded.ts b/src/tree-view-providers/models/blog-export/downloaded.ts index e2133771..dee975d7 100644 --- a/src/tree-view-providers/models/blog-export/downloaded.ts +++ b/src/tree-view-providers/models/blog-export/downloaded.ts @@ -97,8 +97,10 @@ export class DownloadedExportsEntryTreeItem throw new Error('Not implemented') } - getChildrenAsync: () => Promise = async () => - (this._children ??= parseDownloadedExports(this, await DownloadedExportStore.instance.list())) + getChildrenAsync: () => Promise = async () => { + this._children ??= parseDownloadedExports(this, await DownloadedExportStore.instance.list()) + return this._children + } async refresh() { this._children = null @@ -107,7 +109,7 @@ export class DownloadedExportsEntryTreeItem toTreeItem(): TreeItem | Promise { return { - label: '已下载备份', + label: '已下载博客备份', iconPath: new ThemeIcon('archive'), collapsibleState: TreeItemCollapsibleState.Collapsed, contextValue: 'cnblogs-export-downloaded-entry', diff --git a/src/tree-view-providers/models/blog-export/record.ts b/src/tree-view-providers/models/blog-export/record.ts index a9e59442..13240d54 100644 --- a/src/tree-view-providers/models/blog-export/record.ts +++ b/src/tree-view-providers/models/blog-export/record.ts @@ -28,7 +28,8 @@ export class BlogExportRecordTreeItem extends BaseTreeItemSource implements Base } protected get blogExportApi() { - return (this._blogExportApi ??= new BlogExportApi()) + this._blogExportApi ??= new BlogExportApi() + return this._blogExportApi } toTreeItem(): Promise { diff --git a/src/tree-view-providers/models/post-metadata.ts b/src/tree-view-providers/models/post-metadata.ts index e1da1b71..bcfd06b6 100644 --- a/src/tree-view-providers/models/post-metadata.ts +++ b/src/tree-view-providers/models/post-metadata.ts @@ -7,7 +7,7 @@ import { TreeItem, TreeItemCollapsibleState, ThemeIcon } from 'vscode' import { AccessPermission, Post, formatAccessPermission } from '@/models/post' import { PostEditDto } from '@/models/post-edit-dto' import { postCategoryService } from '@/services/post-category.service' -import { postService } from '@/services/post.service' +import { PostService } from '@/services/post.service' import { BaseEntryTreeItem } from './base-entry-tree-item' import { BaseTreeItemSource } from './base-tree-item-source' import { PostTreeItem } from './post-tree-item' @@ -62,7 +62,7 @@ export abstract class PostMetadata extends BaseTreeItemSource { exclude?: RootPostMetadataType[] }): Promise { let parsedPost = post instanceof PostTreeItem ? post.post : post - const postEditDto = await postService.fetchPostEditDto(parsedPost.id) + const postEditDto = await PostService.fetchPostEditDto(parsedPost.id) parsedPost = postEditDto?.post || parsedPost return Promise.all( rootMetadataMap(parsedPost, postEditDto) @@ -124,7 +124,7 @@ export class PostCategoryMetadata extends PostMetadata { } static async parse(parent: Post, editDto?: PostEditDto): Promise { - editDto = editDto ? editDto : await postService.fetchPostEditDto(parent.id) + editDto = editDto ? editDto : await PostService.fetchPostEditDto(parent.id) if (editDto == null) return [] const { @@ -158,7 +158,7 @@ export class PostTagMetadata extends PostMetadata { } static async parse(parent: Post, editDto?: PostEditDto): Promise { - editDto = editDto ? editDto : await postService.fetchPostEditDto(parent.id) + editDto = editDto ? editDto : await PostService.fetchPostEditDto(parent.id) if (editDto == null) return [] const { diff --git a/src/tree-view-providers/post-categories-tree-data-provider.ts b/src/tree-view-providers/post-categories-tree-data-provider.ts index 79e3e3cc..8e2e7546 100644 --- a/src/tree-view-providers/post-categories-tree-data-provider.ts +++ b/src/tree-view-providers/post-categories-tree-data-provider.ts @@ -1,14 +1,15 @@ import { flattenDepth, take } from 'lodash-es' -import { commands, EventEmitter, MessageOptions, ProviderResult, TreeDataProvider, TreeItem, window } from 'vscode' +import { commands, EventEmitter, ProviderResult, TreeDataProvider, TreeItem } from 'vscode' import { PostCategories } from '@/models/post-category' -import { globalContext } from '@/services/global-state' +import { globalCtx } from '@/services/global-ctx' import { postCategoryService } from '@/services/post-category.service' -import { postService } from '@/services/post.service' +import { PostService } from '@/services/post.service' import { toTreeItem } from './converters' import { PostCategoriesListTreeItem } from './models/categories-list-tree-item' import { PostCategoryTreeItem } from './models/post-category-tree-item' import { PostEntryMetadata, PostMetadata, RootPostMetadataType } from './models/post-metadata' import { PostTreeItem } from './models/post-tree-item' +import { AlertService } from '@/services/alert.service' export class PostCategoriesTreeDataProvider implements TreeDataProvider { private static _instance: PostCategoriesTreeDataProvider @@ -19,7 +20,8 @@ export class PostCategoriesTreeDataProvider implements TreeDataProvider + (await PostService.fetchPostsList({ categoryId, pageSize: 100 })).items.map(x => Object.assign, Partial>>( new PostTreeItem(x, true), { @@ -134,10 +133,8 @@ export class PostCategoriesTreeDataProvider implements TreeDataProvidere).message}`) } finally { await this.setIsRefreshing(false) } diff --git a/src/tree-view-providers/posts-data-provider.ts b/src/tree-view-providers/posts-data-provider.ts index 3c86183e..0c9f25ad 100644 --- a/src/tree-view-providers/posts-data-provider.ts +++ b/src/tree-view-providers/posts-data-provider.ts @@ -3,7 +3,7 @@ import { refreshPostsList } from '@/commands/posts-list/refresh-posts-list' import { Post } from '@/models/post' import { PageModel } from '@/models/page-model' import { AlertService } from '@/services/alert.service' -import { postService } from '@/services/post.service' +import { PostService } from '@/services/post.service' import { Settings } from '@/services/settings.service' import { toTreeItem } from './converters' import { PostEntryMetadata, PostMetadata } from './models/post-metadata' @@ -23,7 +23,8 @@ export class PostsDataProvider implements TreeDataProvider { protected constructor() {} static get instance() { - return (this._instance ??= new PostsDataProvider()) + this._instance ??= new PostsDataProvider() + return this._instance } get onDidChangeTreeData() { @@ -47,9 +48,9 @@ export class PostsDataProvider implements TreeDataProvider { return PostMetadata.parseRoots({ post: parent }) } else if (parent instanceof PostEntryMetadata || parent instanceof PostSearchResultEntry) { return parent.getChildrenAsync() - } else { - return [] } + + return [] } getParent(el: PostsListTreeItem) { @@ -61,14 +62,17 @@ export class PostsDataProvider implements TreeDataProvider { } async loadPosts(): Promise | null> { - const { pageIndex } = postService.postsListState ?? {} + const { pageIndex } = PostService.getPostsListState() ?? {} const pageSize = Settings.postsListPageSize - this._pagedPosts = await postService.fetchPostsList({ pageIndex, pageSize }).catch(ex => { - if (ex instanceof Error) AlertService.error(ex.message) - else AlertService.error(`加载博文失败\n${JSON.stringify(ex)}`) + + this._pagedPosts = await PostService.fetchPostsList({ pageIndex, pageSize }).catch(e => { + if (e instanceof Error) AlertService.err(e.message) + else AlertService.err(`加载博文失败\n${JSON.stringify(e)}`) return undefined }) + this.fireTreeDataChangedEvent(undefined) + return this._pagedPosts ?? null } @@ -87,7 +91,7 @@ export class PostsDataProvider implements TreeDataProvider { async search({ key }: { key: string }): Promise { if (key.length <= 0) return - const { items, totalItemsCount, zzkSearchResult } = await postService.fetchPostsList({ search: key }) + const { items, totalItemsCount, zzkSearchResult } = await PostService.fetchPostsList({ search: key }) this._searchResultEntry = new PostSearchResultEntry(key, items, totalItemsCount, zzkSearchResult) this.fireTreeDataChangedEvent(undefined) @@ -100,6 +104,7 @@ export class PostsDataProvider implements TreeDataProvider { async refreshSearch(): Promise { const { _searchResultEntry } = this + if (_searchResultEntry) { const { searchKey } = _searchResultEntry this._searchResultEntry = null diff --git a/src/tree-view-providers/tree-view-registration.ts b/src/tree-view-providers/tree-view-registration.ts index 6e5f4a82..8168cc6a 100644 --- a/src/tree-view-providers/tree-view-registration.ts +++ b/src/tree-view-providers/tree-view-registration.ts @@ -1,4 +1,4 @@ -import { globalContext } from '@/services/global-state' +import { globalCtx } from '@/services/global-ctx' import vscode from 'vscode' import { accountViewDataProvider } from './account-view-data-provider' import { PostsListTreeItem, postsDataProvider } from './posts-data-provider' @@ -54,7 +54,7 @@ export const registerTreeViews = () => { const disposables: IDisposable[] = [] for (const [, item] of Object.entries(_views)) typeof item === 'function' ? undefined : disposables.push(item) - globalContext.extensionContext.subscriptions.push(...disposables) + globalCtx.extCtx.subscriptions.push(...disposables) return extensionViews } diff --git a/src/utils/get-clipboard-image.ts b/src/utils/get-clipboard-image.ts index aa32c50e..feb72e72 100644 --- a/src/utils/get-clipboard-image.ts +++ b/src/utils/get-clipboard-image.ts @@ -5,7 +5,7 @@ import path from 'path' import fs from 'fs' import os from 'os' import isWsl from 'is-wsl' -import { globalContext } from '@/services/global-state' +import { globalCtx } from '@/services/global-ctx' import { AlertService } from '@/services/alert.service' import { IClipboardImage } from '@/models/clipboard-image' import format from 'date-fns/format' @@ -30,7 +30,7 @@ const getCurrentPlatform = (): Platform => { const readClipboardScript = ( scriptName: 'mac.applescript' | 'linux.sh' | 'windows.ps1' | 'windows10.ps1' | 'wsl.sh' ) => { - const filePath = globalContext.extensionContext.asAbsolutePath(`dist/assets/scripts/clipboard/${scriptName}`) + const filePath = globalCtx.extCtx.asAbsolutePath(`dist/assets/scripts/clipboard/${scriptName}`) return fs.readFileSync(filePath).toString() } @@ -59,7 +59,7 @@ const platform2ScriptFilename: { const getClipboardImage = (): Promise => { const imagePath = path.join( - globalContext.extensionContext?.asAbsolutePath('./') ?? '', + globalCtx.extCtx?.asAbsolutePath('./') ?? '', `${format(new Date(), 'yyyyMMddHHmmss')}.png` ) return new Promise((resolve, reject): void => { @@ -94,7 +94,7 @@ const getClipboardImage = (): Promise => { execution.stdout.on('data', (data: Buffer) => { if (platform === 'linux') { if (data.toString().trim() === 'no xclip') { - AlertService.warning('xclip not found, Please install xclip first') + AlertService.warn('xclip not found, Please install xclip first') return reject(new Error('Please install xclip first')) } } diff --git a/src/utils/http-client.ts b/src/utils/http-client.ts index 7da043eb..4c406508 100644 --- a/src/utils/http-client.ts +++ b/src/utils/http-client.ts @@ -1,13 +1,17 @@ -import { accountManager } from '@/authentication/account-manager' +import { accountManager } from '@/auth/account-manager' import { AuthorizationHeaderKey } from '@/utils/constants' import got, { BeforeRequestHook } from 'got' import { isString } from 'lodash-es' const bearerTokenHook: BeforeRequestHook = async opt => { const { headers } = opt + const headerKeys = Object.keys(headers) + + const keyIndex = headerKeys.findIndex(x => x.toLowerCase() === AuthorizationHeaderKey.toLowerCase()) + + if (keyIndex < 0) { + const token = await accountManager.acquireToken() - if (Object.keys(headers).findIndex(x => x.toLowerCase() === AuthorizationHeaderKey.toLowerCase()) < 0) { - const token = await accountManager.acquireToken().catch((reason: unknown) => ({ reason })) if (isString(token)) headers[AuthorizationHeaderKey] = `Bearer ${token}` } } diff --git a/src/utils/input-post-settings.ts b/src/utils/input-post-settings.ts index 69f6db85..58ef8a17 100644 --- a/src/utils/input-post-settings.ts +++ b/src/utils/input-post-settings.ts @@ -102,7 +102,7 @@ export const inputPostSettings = ( try { categories = await postCategoryService.listCategories() } catch (err) { - AlertService.error(err instanceof Error ? err.message : JSON.stringify(err)) + AlertService.err(err instanceof Error ? err.message : JSON.stringify(err)) // 取消 throw InputFlowAction.cancel } diff --git a/src/utils/uri-handler.ts b/src/utils/uri-handler.ts index 90e87e9f..f9de5e5c 100644 --- a/src/utils/uri-handler.ts +++ b/src/utils/uri-handler.ts @@ -20,11 +20,13 @@ class ExtensionUriHandler implements UriHandler, Disposable { } private get uriEventEmitter() { - return (this._uriEventEmitter ??= new EventEmitter()) + this._uriEventEmitter ??= new EventEmitter() + return this._uriEventEmitter } get onUri() { - return (this._onUri ??= this.uriEventEmitter.event) + this._onUri ??= this.uriEventEmitter.event + return this._onUri } handleUri(uri: Uri): ProviderResult { diff --git a/ui/post-configuration/components/NestCategoriesSelect.tsx b/ui/post-configuration/components/NestCategoriesSelect.tsx index de8f2229..04cda6ed 100644 --- a/ui/post-configuration/components/NestCategoriesSelect.tsx +++ b/ui/post-configuration/components/NestCategoriesSelect.tsx @@ -121,8 +121,12 @@ export default class NestCategoriesSelect extends React.Component< let expandedSet = this.state.expanded - if (isExpanded) expandedSet?.delete(category.categoryId) - else (expandedSet ??= new Set()).add(category.categoryId) + if (isExpanded) { + expandedSet?.delete(category.categoryId) + } else { + expandedSet ??= new Set() + expandedSet.add(category.categoryId) + } this.setState({ expanded: expandedSet && expandedSet.size > 0 ? new Set(expandedSet) : null }) expandedSet?.clear() diff --git a/ui/post-configuration/components/PostForm.tsx b/ui/post-configuration/components/PostForm.tsx index 86857afc..09cf004a 100644 --- a/ui/post-configuration/components/PostForm.tsx +++ b/ui/post-configuration/components/PostForm.tsx @@ -147,9 +147,9 @@ export class PostForm extends React.Component { // eslint-disable-next-line @typescript-eslint/no-unsafe-call this.context.set({ disabled: true, status: 'submitting' }) vsCodeApi.getInstance().postMessage({ - command: webviewCommands.ExtensionCommands.savePost, + command: webviewCommands.ExtensionCommands.uploadPost, post: Object.assign({}, this.props.post, this.state), - } as webviewMessage.SavePostMessage) + } as webviewMessage.UploadPostMessage) } private onCancel() { diff --git a/ui/webpack.config.mjs b/ui/webpack.config.mjs index d05f61fb..4ff12f76 100644 --- a/ui/webpack.config.mjs +++ b/ui/webpack.config.mjs @@ -8,7 +8,7 @@ import tailwindConfig from './tailwind.config.js' import TsconfigPathsPlugin from 'tsconfig-paths-webpack-plugin' import TerserPlugin from 'terser-webpack-plugin' -const isDev = process.env.ASPNETCORE_ENVIRONMENT === 'Development' || process.env.NODE_ENV === 'development' +const isDevEnv = process.env.ASPNETCORE_ENVIRONMENT === 'Development' || process.env.NODE_ENV === 'development' rmSync('./dist/assets/ui/**', { force: true, recursive: true }) @@ -31,7 +31,7 @@ const buildEntry = () => { cpSync('./node_modules/@fluentui/font-icons-mdl2/fonts/', './dist/assets/fonts/', { recursive: true }) - if (isDev) console.log(entries) + if (isDevEnv) console.log(entries) return entries } @@ -49,8 +49,8 @@ const config = { extensions: ['.tsx', '.ts', 'less', '.css', '.js'], plugins: [new TsconfigPathsPlugin({ configFile: './ui/tsconfig.json' })], }, - devtool: isDev ? 'eval-source-map' : false, - mode: isDev ? 'development' : 'production', + devtool: isDevEnv ? 'eval-source-map' : false, + mode: isDevEnv ? 'development' : 'production', module: { rules: [ { @@ -61,7 +61,7 @@ const config = { loader: 'css-loader', options: { import: true, - sourceMap: isDev, + sourceMap: isDevEnv, url: false, }, }, @@ -114,7 +114,7 @@ const config = { }, ], optimization: { - minimize: !isDev, + minimize: !isDevEnv, minimizer: [ new TerserPlugin({ terserOptions: { diff --git a/webpack.config.mjs b/webpack.config.mjs index e8791fc5..3f56b22b 100644 --- a/webpack.config.mjs +++ b/webpack.config.mjs @@ -116,8 +116,8 @@ export default (env, { mode }) => { ], }), new webpack.DefinePlugin({ - CNBLOGS_CLIENTID: JSON.stringify(env.CLIENTID || 'vscode-cnb'), - CNBLOGS_CLIENTSECRET: JSON.stringify(env.CLIENTSECRET || ''), + CNBLOGS_CLIENTID: JSON.stringify(env.CLIENTID || 'UNSET'), + CNBLOGS_CLIENTSECRET: JSON.stringify(env.CLIENTSECRET || 'UNSET'), }), ], optimization: { From 6824102e6ac768888a7a6f5a50b39e1013266512 Mon Sep 17 00:00:00 2001 From: Thaumy Date: Wed, 19 Jul 2023 16:44:32 +0800 Subject: [PATCH 002/157] chore: reformat issue template --- .github/ISSUE_TEMPLATE/bug_report.md | 24 +++++++++++++-------- .github/ISSUE_TEMPLATE/feature-request.yaml | 8 +++---- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 26ee31cc..bbf164fa 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -4,28 +4,34 @@ about: Create a report to help us improve title: '' labels: '' assignees: '' - --- **问题描述** -简单的描述一下你遇到的问题. + +简单的描述一下你遇到的问题 **复现问题** + 复现问题的步骤: -1. 在某个地方 '...' -2. 进行了什么操作 '....' + +1. 在某个地方 ... +2. 进行了什么操作 ... 3. ... **期望的结果** -你期望的结果是什么. + +你期望的结果 **问题截图** -如果可能的话,提供下遇到问题时的截图以便排查. + +如果可能的话, 提供下遇到问题时的截图以便排查 **环境信息:** - - 操作系统: [e.g. iOS] - - vscode版本 [e.g. 1.63.2] - - vscode-cnb版本 [e.g. 0.0.13] + + - 操作系统: [e.g. macOS] + - VSCode版本 [e.g. 1.00.0] + - 博客园扩展版本 [e.g. 1.0.0] **任何其他有助于排查问题的信息** + 在这里填写任何其他有助于排查问题的信息 diff --git a/.github/ISSUE_TEMPLATE/feature-request.yaml b/.github/ISSUE_TEMPLATE/feature-request.yaml index 3c75ec73..fb246372 100644 --- a/.github/ISSUE_TEMPLATE/feature-request.yaml +++ b/.github/ISSUE_TEMPLATE/feature-request.yaml @@ -1,5 +1,5 @@ name: "新功能建议" -description: 给vscode-cnb提一个新功能建议 +description: 给博客园扩展提一个新功能建议 labels: - "feature" @@ -7,7 +7,7 @@ body: - type: dropdown id: affected-ui-area attributes: - label: ui上的哪部分与此新功能有关? + label: UI 上的哪个部分与此新功能有关? options: - 侧边栏控制台 - 侧边栏控制台随笔列表 @@ -18,8 +18,8 @@ body: - 侧边栏控制台随笔列表右键上下文菜单 - 侧边栏控制台分类列表右键上下文菜单 - 设置面板 - - markdown编辑器右键上下文菜单 - - markdown编辑器工具栏 + - Markdown 编辑器右键上下文菜单 + - Markdown 编辑器工具栏 - 侧边栏文件浏览右键上下文菜单 - 其他 multiple: true From b309c6ddf2f30c46352969bf4e19e4091fe49114 Mon Sep 17 00:00:00 2001 From: Thaumy Date: Wed, 19 Jul 2023 17:21:19 +0800 Subject: [PATCH 003/157] feat: add ui options to package.json --- package.json | 159 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 98 insertions(+), 61 deletions(-) diff --git a/package.json b/package.json index 9a3518ef..3faa7d4e 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ ], "icon": "dist/assets/logo.png", "engines": { - "vscode": "^1.70.0" + "vscode": "^1.80.0" }, "categories": [ "Other" @@ -419,7 +419,7 @@ { "title": "vscode-cnb", "properties": { - "cnblogsClientForVSCode.windows.workspace": { + "cnblogsClient.workspace.windows": { "order": 0, "default": "~/Documents/Cnblogs", "scope": "application", @@ -427,7 +427,7 @@ "editPresentation": "singlelineText", "markdownDescription": "Windows 上存放博文的文件夹, 默认为 `~/Documents/Cnblogs`" }, - "cnblogsClientForVSCode.macos.workspace": { + "cnblogsClient.workspace.macos": { "order": 1, "default": "~/Documents/Cnblogs", "scope": "application", @@ -435,7 +435,7 @@ "editPresentation": "singlelineText", "markdownDescription": "macOS 上存放博文的文件夹, 默认为 `~/Documents/Cnblogs`" }, - "cnblogsClientForVSCode.linux.workspace": { + "cnblogsClient.workspace.linux": { "order": 2, "default": "~/Documents/Cnblogs", "scope": "application", @@ -443,7 +443,7 @@ "editPresentation": "singlelineText", "markdownDescription": "Linux 上存放博文的文件夹, 默认为 `~/Documents/Cnblogs`" }, - "cnblogsClientForVSCode.windows.chromiumPath": { + "cnblogsClient.windows.chromiumPath": { "order": 3, "default": "C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe", "scope": "application", @@ -451,7 +451,7 @@ "editPresentation": "singlelineText", "markdownDescription": "Windows 上 Chromium 可执行文件路径, 用于进行 PDF 导出等操作" }, - "cnblogsClientForVSCode.macos.chromiumPath": { + "cnblogsClient.macos.chromiumPath": { "order": 4, "default": "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome", "scope": "application", @@ -459,21 +459,21 @@ "editPresentation": "singlelineText", "markdownDescription": "macOS 上 Chromium 可执行文件路径, 用于进行 PDF 导出等操作" }, - "cnblogsClientForVSCode.createLocalPostFileWithCategory": { + "cnblogsClient.createLocalPostFileWithCategory": { "order": 5, "default": true, "scope": "application", "type": "boolean", "markdownDescription": "创建本地博文时, 是否根据博文分类保存到对应的文件夹中" }, - "cnblogsClientForVSCode.automaticallyExtractImages": { + "cnblogsClient.autoExtractImages": { "order": 6, "default": "disable", "scope": "application", "enum": [ "disable", "local", - "dataurl", + "dataUrl", "web", "any" ], @@ -487,7 +487,7 @@ "editPresentation": "singlelineText", "markdownDescription": "提取图片, 配置上传到博客园时要自动提取上传到博客园的图片" }, - "cnblogsClientForVSCode.pageSize.postsList": { + "cnblogsClient.pageSize.postsList": { "order": 7, "default": 30, "scope": "application", @@ -507,21 +507,21 @@ 100 ] }, - "cnblogsClientForVSCode.markdown.enableEnhancement": { + "cnblogsClient.markdown.enableEnhancement": { "order": 8, "markdownDescription": "启用博客园 Markdown 语法扩展", "default": true, "type": "boolean", "scope": "application" }, - "cnblogsClientForVSCode.markdown.enableFenceQuote": { + "cnblogsClient.markdown.enableFenceQuote": { "order": 9, "type": "boolean", "scope": "application", "default": true, "markdownDescription": "博客园 Markdown 语法扩展: 三箭头(`<<<`)栅栏引用\n\n \n\n使用示例:\n\n```markdown\n\n<<<\n一段引用文字\n\n一段引用文字\n<<<\n\n```" }, - "cnblogsClientForVSCode.markdown.enableHighlightCodeLines": { + "cnblogsClient.markdown.enableHighlightCodeLines": { "order": 10, "type": "boolean", "scope": "application", @@ -529,7 +529,7 @@ "editPresentation": "singlelineText", "markdownDescription": "博客园 Markdown 语法扩展: 代码块指定行高亮\n\n \n\n使用示例:\n\n```markdown\n\n```typescript {1, 3-4}\nconsole.log(1)\nconsole.log(2)\nconsole.log(3)\nconsole.log(4)\nconsole.log(5)\n```\n\n```" }, - "cnblogsClientForVSCode.markdown.showConfirmMsgWhenUploadPost": { + "cnblogsClient.markdown.showConfirmMsgWhenUploadPost": { "order": 11, "type": "boolean", "scope": "application", @@ -537,7 +537,7 @@ "editPresentation": "singlelineText", "markdownDescription": "在上传博文时显示确认消息" }, - "cnblogsClientForVSCode.markdown.showConfirmMsgWhenPullPost": { + "cnblogsClient.markdown.showConfirmMsgWhenPullPost": { "order": 12, "type": "boolean", "scope": "application", @@ -545,7 +545,8 @@ "editPresentation": "singlelineText", "markdownDescription": "在拉取博文时显示确认消息" }, - "cnblogsClientForVSCode.menus.context.explorer": { + "cnblogsClient.menus.context.explorer": { + "order": 13, "type": "object", "additionalProperties": false, "default": { @@ -558,7 +559,6 @@ "copy-post-link": true }, "markdownDescription": "控制要在资源管理器右键菜单中显示的命令", - "order": 13, "properties": { "upload-post-file-to-cnblogs": { "description": "上传到博客园", @@ -604,7 +604,8 @@ } } }, - "cnblogsClientForVSCode.menus.context.editor": { + "cnblogsClient.menus.context.editor": { + "order": 14, "type": "object", "default": { "upload-post-file-to-cnblogs": true, @@ -621,66 +622,102 @@ }, "properties": { "upload-post-file-to-cnblogs": { + "order": 0, "description": "上传到博客园", - "type": "boolean", - "order": 0 + "type": "boolean" }, "pull-post-remote-updates": { + "order": 1, "description": "拉取博文", - "type": "boolean", - "order": 1 + "type": "boolean" }, "modify-post-settings": { + "order": 2, "description": "博文设置", - "type": "boolean", - "order": 2 + "type": "boolean" }, "show-post-to-local-file-info": { + "order": 3, "description": "博客园关联博文", - "type": "boolean", - "order": 3 + "type": "boolean" }, "open-post-in-blog-admin": { + "order": 4, "description": "在博客后台中编辑", "type": "boolean", - "default": true, - "order": 4 + "default": true }, "export-post-to-pdf": { + "order": 5, "description": "导出 PDF", - "type": "boolean", - "order": 5 + "type": "boolean" }, "copy-post-link": { + "order": 6, "description": "复制博文链接", - "type": "boolean", - "order": 6 + "type": "boolean" }, "upload-clipboard-image": { + "order": 7, "description": "上传剪贴板图片到博客园", - "type": "boolean", - "order": 7 + "type": "boolean" }, "upload-local-disk-image": { + "order": 8, "description": "上传本地图片到博客园", - "type": "boolean", - "order": 8 + "type": "boolean" }, "extract-images": { + "order": 9, "description": "提取图片", - "type": "boolean", - "order": 9 + "type": "boolean" }, "ing:publish-selection": { + "order": 10, "description": "将选中内容发到闪存", - "type": "boolean", - "order": 10 + "type": "boolean" } }, "scope": "application", "additionalProperties": false, - "markdownDescription": "控制要在编辑器右键菜单中显示的命令", - "order": 14 + "markdownDescription": "控制要在编辑器右键菜单中显示的命令" + }, + "cnblogsClient.ui.symbolicIngEmoji": { + "order": 15, + "type": "boolean", + "scope": "application", + "default": false, + "markdownDescription": "符号化闪存表情" + }, + "cnblogsClient.ui.disableIngAvatar": { + "order": 16, + "type": "boolean", + "scope": "application", + "default": false, + "markdownDescription": "禁用闪存头像" + }, + "cnblogsClient.ui.explorerTitleStyle": { + "order": 17, + "scope": "application", + "default": "normal", + "markdownDescription": "侧栏标题风格", + "enum": [ + "normal", + "short", + "short-english" + ], + "enumItemLabels": [ + "正常", + "精简", + "英文精简" + ] + }, + "cnblogsClient.ui.fakeExtIcon": { + "order": 18, + "type": "boolean", + "scope": "application", + "default": false, + "markdownDescription": "伪装扩展图标" } } } @@ -689,7 +726,7 @@ "explorer": [ { "id": "cnblogs-posts-list", - "name": "博客园 - 随笔列表", + "name": "随笔列表", "when": "vscode-cnb.isAuthorized && vscode-cnb.isTargetWorkspace" } ], @@ -708,7 +745,7 @@ }, { "id": "cnblogs-posts-list-another", - "name": "博客园 - 随笔列表", + "name": "随笔列表", "when": "vscode-cnb.isAuthorized", "visibility": "collapsed" }, @@ -1107,53 +1144,53 @@ }, { "command": "vscode-cnb.show-post-to-local-file-info", - "when": "resourceLangId == markdown && config.cnblogsClientForVSCode.menus.context.editor.show-post-to-local-file-info", + "when": "resourceLangId == markdown && config.cnblogsClient.menus.context.editor.show-post-to-local-file-info", "group": "cnblogs@1" }, { "command": "vscode-cnb.upload-post-file-to-cnblogs", - "when": "resourceLangId == markdown && config.cnblogsClientForVSCode.menus.context.editor.upload-post-file-to-cnblogs", + "when": "resourceLangId == markdown && config.cnblogsClient.menus.context.editor.upload-post-file-to-cnblogs", "group": "cnblogs@2" }, { "command": "vscode-cnb.pull-post-remote-updates", - "when": "resourceLangId == markdown && config.cnblogsClientForVSCode.menus.context.editor.pull-post-remote-updates", + "when": "resourceLangId == markdown && config.cnblogsClient.menus.context.editor.pull-post-remote-updates", "group": "cnblogs@3" }, { "command": "vscode-cnb.modify-post-settings", - "when": "resourceLangId == markdown && config.cnblogsClientForVSCode.menus.context.editor.modify-post-settings", + "when": "resourceLangId == markdown && config.cnblogsClient.menus.context.editor.modify-post-settings", "group": "cnblogs@4" }, { "command": "vscode-cnb.open-post-in-blog-admin", - "when": "resourceLangId == markdown && config.cnblogsClientForVSCode.menus.context.editor.open-post-in-blog-admin", + "when": "resourceLangId == markdown && config.cnblogsClient.menus.context.editor.open-post-in-blog-admin", "group": "cnblogs@5" }, { "command": "vscode-cnb.upload-clipboard-image", - "when": "resourceLangId == markdown && config.cnblogsClientForVSCode.menus.context.editor.upload-clipboard-image", + "when": "resourceLangId == markdown && config.cnblogsClient.menus.context.editor.upload-clipboard-image", "group": "cnblogs@6" }, { "command": "vscode-cnb.upload-local-disk-image", - "when": "resourceLangId == markdown && config.cnblogsClientForVSCode.menus.context.editor.upload-local-disk-image", + "when": "resourceLangId == markdown && config.cnblogsClient.menus.context.editor.upload-local-disk-image", "group": "cnblogs@7" }, { "command": "vscode-cnb.export-post-to-pdf", - "when": "resourceLangId == markdown && config.cnblogsClientForVSCode.menus.context.editor.export-post-to-pdf", + "when": "resourceLangId == markdown && config.cnblogsClient.menus.context.editor.export-post-to-pdf", "group": "cnblogs@8" }, { "command": "vscode-cnb.extract-images", - "when": "resourceLangId == markdown && config.cnblogsClientForVSCode.menus.context.editor.extract-images", + "when": "resourceLangId == markdown && config.cnblogsClient.menus.context.editor.extract-images", "group": "cnblogs@9" }, { "command": "vscode-cnb.ing.publish-selection", "group": "cnblogs@10", - "when": "config.cnblogsClientForVSCode.menus.context.editor.ing:publish-selection" + "when": "config.cnblogsClient.menus.context.editor.ing:publish-selection" } ], "editor/title": [ @@ -1176,37 +1213,37 @@ }, { "command": "vscode-cnb.upload-post-file-to-cnblogs", - "when": "resourceLangId == markdown && config.cnblogsClientForVSCode.menus.context.explorer.upload-post-file-to-cnblogs", + "when": "resourceLangId == markdown && config.cnblogsClient.menus.context.explorer.upload-post-file-to-cnblogs", "group": "cnblogs@2" }, { "command": "vscode-cnb.pull-post-remote-updates", - "when": "resourceLangId == markdown && config.cnblogsClientForVSCode.menus.context.explorer.pull-post-remote-updates", + "when": "resourceLangId == markdown && config.cnblogsClient.menus.context.explorer.pull-post-remote-updates", "group": "cnblogs@3" }, { "command": "vscode-cnb.modify-post-settings", - "when": "resourceLangId == markdown && config.cnblogsClientForVSCode.menus.context.explorer.modify-post-settings", + "when": "resourceLangId == markdown && config.cnblogsClient.menus.context.explorer.modify-post-settings", "group": "cnblogs@4" }, { "command": "vscode-cnb.show-post-to-local-file-info", - "when": "resourceLangId == markdown && config.cnblogsClientForVSCode.menus.context.explorer.show-post-to-local-file-info", + "when": "resourceLangId == markdown && config.cnblogsClient.menus.context.explorer.show-post-to-local-file-info", "group": "cnblogs@5" }, { "command": "vscode-cnb.open-post-in-blog-admin", - "when": "resourceLangId == markdown && config.cnblogsClientForVSCode.menus.context.explorer.open-post-in-blog-admin", + "when": "resourceLangId == markdown && config.cnblogsClient.menus.context.explorer.open-post-in-blog-admin", "group": "cnblogs@6" }, { "command": "vscode-cnb.export-post-to-pdf", - "when": "resourceLangId == markdown && config.cnblogsClientForVSCode.menus.context.explorer.export-post-to-pdf", + "when": "resourceLangId == markdown && config.cnblogsClient.menus.context.explorer.export-post-to-pdf", "group": "cnblogs@7" }, { "command": "vscode-cnb.copy-post-link", - "when": "resourceLangId == markdown && config.cnblogsClientForVSCode.menus.context.explorer.copy-post-link", + "when": "resourceLangId == markdown && config.cnblogsClient.menus.context.explorer.copy-post-link", "group": "cnblogs@8" } ] From 10cc66473032f7bebd3006fcf46ebc31f40e511d Mon Sep 17 00:00:00 2001 From: Thaumy Date: Thu, 20 Jul 2023 11:12:23 +0800 Subject: [PATCH 004/157] chore: update .gitignore --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 35d6eb0e..58eeb679 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,9 @@ out dist node_modules -.vscode-test/ +.vscode-test *.vsix .DS_Store .idea .vscode/api-key.txt +with-key-build.sh From dc8cf5bdd34e5c20c4e9eb40e7f81f0bb8d09408 Mon Sep 17 00:00:00 2001 From: Thaumy Date: Thu, 20 Jul 2023 12:21:56 +0800 Subject: [PATCH 005/157] refactor: simplify code --- src/commands/blog-export/create.ts | 9 +- src/commands/blog-export/delete.ts | 11 +- src/commands/blog-export/download.ts | 13 +- src/commands/blog-export/open-local.ts | 2 +- src/commands/ing/comment-ing.ts | 18 +-- src/commands/ing/publish-ing.ts | 4 +- .../upload-image/upload-clipboard-image.ts | 4 +- .../upload-image/upload-local-disk-image.ts | 4 +- src/services/blog-export-records.store.ts | 8 +- src/services/blog-export.api.ts | 84 ++++++------ src/services/downloaded-export.store.ts | 62 ++++----- src/services/image.service.ts | 29 +++-- src/services/ing.api.ts | 122 ++++++++++-------- src/services/ings-list-webview-provider.ts | 12 +- src/services/mkd-img-extractor.service.ts | 6 +- .../post-configuration-panel.service.ts | 4 +- src/services/post-tag.service.ts | 32 ++--- src/services/post-title-sanitizer.service.ts | 27 ++-- src/services/site-category.service.ts | 2 +- .../models/blog-export/downloaded.ts | 2 +- .../models/blog-export/record.ts | 13 +- 21 files changed, 216 insertions(+), 252 deletions(-) diff --git a/src/commands/blog-export/create.ts b/src/commands/blog-export/create.ts index 2905075d..0a42a5e6 100644 --- a/src/commands/blog-export/create.ts +++ b/src/commands/blog-export/create.ts @@ -7,18 +7,11 @@ import { MessageItem, window } from 'vscode' export class CreateBlogExportCommandHandler extends CommandHandler { static readonly commandName = 'vscode-cnb.blog-export.create' - private _blogExportApi?: BlogExportApi | null - - protected get blogExportApi() { - this._blogExportApi ??= new BlogExportApi() - return this._blogExportApi - } - async handle(): Promise { if (!(await this.confirm())) return if ( - (await this.blogExportApi.create().catch((e: unknown) => { + (await BlogExportApi.create().catch((e: unknown) => { AlertService.httpErr(typeof e === 'object' && e ? e : {}, { message: '创建博客备份失败' }) return false })) !== false diff --git a/src/commands/blog-export/delete.ts b/src/commands/blog-export/delete.ts index 2c4be4a5..76437f52 100644 --- a/src/commands/blog-export/delete.ts +++ b/src/commands/blog-export/delete.ts @@ -73,7 +73,7 @@ export class DeleteCommandHandler extends TreeViewCommandHandler true) .catch((e: unknown) => { AlertService.httpErr(typeof e === 'object' && e != null ? e : {}) @@ -96,9 +95,9 @@ export class DeleteCommandHandler extends TreeViewCommandHandler { static readonly commandName = 'vscode-cnb.blog-export.download' - private _exportApi?: BlogExportApi | null - constructor(public readonly input: unknown) { super() } - protected get exportApi() { - this._exportApi ??= new BlogExportApi() - return this._exportApi - } - parseInput(): BlogExportRecordTreeItem | null | undefined { return this.input instanceof BlogExportRecordTreeItem ? this.input : null } @@ -40,12 +33,11 @@ export class DownloadExportCommandHandler extends TreeViewCommandHandler promisify(fs.rm)(zipFilePath)) }) .then(() => { - DownloadedExportStore.instance - .add(nonZipFilePath, exportId) + DownloadedExportStore.add(nonZipFilePath, exportId) .then(() => treeItem.reportDownloadingProgress(null)) .then(() => blogExportProvider?.refreshItem(treeItem)) .then(() => blogExportProvider?.refreshDownloadedExports()) diff --git a/src/commands/blog-export/open-local.ts b/src/commands/blog-export/open-local.ts index 823cc7d3..4869b22d 100644 --- a/src/commands/blog-export/open-local.ts +++ b/src/commands/blog-export/open-local.ts @@ -62,7 +62,7 @@ export class OpenLocalExportCommandHandler extends CommandHandler { const exportRecord = await treeProvider?.store .list() .then(x => x.items.find(i => i.fileName === dbFileName && i.fileBytes === dbFileSize)) - await DownloadedExportStore.instance.add(dbFilePath, exportRecord?.id) + await DownloadedExportStore.add(dbFilePath, exportRecord?.id) if (exportRecord) await treeProvider?.refreshRecords({ force: false }) else await treeProvider?.refreshDownloadedExports() diff --git a/src/commands/ing/comment-ing.ts b/src/commands/ing/comment-ing.ts index ce9e2360..abad94ff 100644 --- a/src/commands/ing/comment-ing.ts +++ b/src/commands/ing/comment-ing.ts @@ -4,7 +4,6 @@ import { IngsListWebviewProvider } from '@/services/ings-list-webview-provider' import { ProgressLocation, window } from 'vscode' export class CommentIngCommandHandler extends CommandHandler { - private _ingApi?: IngApi private _content = '' constructor( @@ -16,11 +15,6 @@ export class CommentIngCommandHandler extends CommandHandler { super() } - private get ingApi() { - this._ingApi ??= new IngApi() - return this._ingApi - } - async handle(): Promise { if (!IngsListWebviewProvider.instance) return @@ -42,13 +36,11 @@ export class CommentIngCommandHandler extends CommandHandler { { location: ProgressLocation.Notification, title: '正在发表评论, 请稍后...' }, p => { p.report({ increment: 30 }) - return this.ingApi - .comment(this._ingId, { - replyTo: atUserId, - content: atContent + this._content, - parentCommentId: this._parentCommentId ?? 0, - }) - .then(hasCommented => (hasCommented ? this.onCommented() : undefined)) + return IngApi.comment(this._ingId, { + replyTo: atUserId, + content: atContent + this._content, + parentCommentId: this._parentCommentId ?? 0, + }).then(hasCommented => (hasCommented ? this.onCommented() : undefined)) } ) } diff --git a/src/commands/ing/publish-ing.ts b/src/commands/ing/publish-ing.ts index 5bab626e..51aafd59 100644 --- a/src/commands/ing/publish-ing.ts +++ b/src/commands/ing/publish-ing.ts @@ -86,12 +86,10 @@ export class PublishIngCommandHandler extends CommandHandler { } private async publish(model: IngPublishModel): Promise { - const api = new IngApi() - return this.onPublished( await window.withProgress({ location: ProgressLocation.Notification, title: '正在发闪, 请稍候...' }, p => { p.report({ increment: 30 }) - return api.publishIng(model).then(isPublished => { + return IngApi.publishIng(model).then(isPublished => { p.report({ increment: 70 }) return isPublished }) diff --git a/src/commands/upload-image/upload-clipboard-image.ts b/src/commands/upload-image/upload-clipboard-image.ts index 315f79cf..e3bea8fc 100644 --- a/src/commands/upload-image/upload-clipboard-image.ts +++ b/src/commands/upload-image/upload-clipboard-image.ts @@ -1,7 +1,7 @@ import fs from 'fs' import { ProgressLocation, Uri, window, workspace } from 'vscode' import { AlertService } from '@/services/alert.service' -import { imageService } from '@/services/image.service' +import { ImageService } from '@/services/image.service' import getClipboardImage from '@/utils/get-clipboard-image' const noImagePath = 'no image' @@ -16,7 +16,7 @@ export const uploadImageFromClipboard = async () => { try { return await window.withProgress({ title: '正在上传图片', location: ProgressLocation.Notification }, p => { p.report({ increment: 10 }) - return imageService.upload(fs.createReadStream(clipboardImage.imgPath)) + return ImageService.upload(fs.createReadStream(clipboardImage.imgPath)) }) } finally { if (!clipboardImage.shouldKeepAfterUploading) await workspace.fs.delete(Uri.file(clipboardImage.imgPath)) diff --git a/src/commands/upload-image/upload-local-disk-image.ts b/src/commands/upload-image/upload-local-disk-image.ts index ffcf2e2d..1556c621 100644 --- a/src/commands/upload-image/upload-local-disk-image.ts +++ b/src/commands/upload-image/upload-local-disk-image.ts @@ -1,5 +1,5 @@ import { ProgressLocation, window } from 'vscode' -import { imageService } from '@/services/image.service' +import { ImageService } from '@/services/image.service' import fs from 'fs' export const uploadLocalDiskImage = async () => { @@ -25,7 +25,7 @@ export const uploadLocalDiskImage = async () => { }) const readStream = fs.createReadStream(imageFilePath) try { - return await imageService.upload(readStream) + return await ImageService.upload(readStream) } finally { p.report({ increment: 100, diff --git a/src/services/blog-export-records.store.ts b/src/services/blog-export-records.store.ts index 25d5e3cc..e611e628 100644 --- a/src/services/blog-export-records.store.ts +++ b/src/services/blog-export-records.store.ts @@ -2,7 +2,6 @@ import { BlogExportRecordList } from '@/models/blog-export' import { BlogExportApi } from '@/services/blog-export.api' export class BlogExportRecordsStore { - private readonly _api = new BlogExportApi() private _cachedList?: Promise | null private _cached?: BlogExportRecordList | null @@ -24,7 +23,7 @@ export class BlogExportRecordsStore { this._cached = null } - list({ + async list({ pageIndex = 1, pageSize = 500, }: { @@ -32,6 +31,9 @@ export class BlogExportRecordsStore { pageSize?: number shouldRefresh?: boolean } = {}): Promise { - return (this._cachedList ??= this._api.list({ pageIndex, pageSize })).then(d => (this._cached = d)) + this._cachedList ??= BlogExportApi.list({ pageIndex, pageSize }) + this._cached = await this._cachedList + + return this._cached } } diff --git a/src/services/blog-export.api.ts b/src/services/blog-export.api.ts index 448aa9ab..c2850c16 100644 --- a/src/services/blog-export.api.ts +++ b/src/services/blog-export.api.ts @@ -5,53 +5,57 @@ import got from '@/utils/http-client' const basePath = `${globalCtx.config.apiBaseUrl}/api/blogExports` const downloadOrigin = 'https://export.cnblogs.com' -export class BlogExportApi { - list({ pageIndex, pageSize }: { pageIndex?: number; pageSize?: number }): Promise { - return got - .get(`${basePath}`, { - searchParams: new URLSearchParams({ pageIndex: `${pageIndex ?? ''}`, pageSize: `${pageSize ?? ''}` }), - responseType: 'json', - }) - .then(r => r.body) +export namespace BlogExportApi { + export async function list({ pageIndex, pageSize }: { pageIndex?: number; pageSize?: number }) { + const para = new URLSearchParams({ pageIndex: `${pageIndex ?? ''}`, pageSize: `${pageSize ?? ''}` }) + + const res = await got.get(`${basePath}`, { + searchParams: para, + responseType: 'json', + }) + + return res.body } - create(): Promise { - return got.post(`${basePath}`, { responseType: 'json' }).then(r => r.body) + export async function create() { + const res = await got.post(`${basePath}`, { responseType: 'json' }) + + return res.body } - delete(id: number): Promise { - return got.delete(`${basePath}/${id}`).then(() => undefined) + export async function del(id: number): Promise { + await got.delete(`${basePath}/${id}`).then(() => undefined) } - getById(id: number): Promise { - return got - .get(`${basePath}/${id}`, { - responseType: 'json', - timeout: { - request: 500, - }, - retry: { - limit: 0, - }, - }) - .then(x => x.body) + export async function getById(id: number): Promise { + const res = await got.get(`${basePath}/${id}`, { + responseType: 'json', + timeout: { + request: 500, + }, + retry: { + limit: 0, + }, + }) + + return res.body } - download(blogId: number, exportId: number) { - return got - .extend({ - hooks: { - beforeRedirect: [ - (opt, resp) => { - const location = resp.headers.location - if (location && location.includes('account.cnblogs.com')) throw new Error('未授权') - }, - ], - }, - }) - .stream.get(`${downloadOrigin}/blogs/${blogId}/exports/${exportId}`, { - throwHttpErrors: true, - followRedirect: true, - }) + export function download(blogId: number, exportId: number) { + const g = got.extend({ + hooks: { + beforeRedirect: [ + (opt, resp) => { + const location = resp.headers.location + if (location && location.includes('account.cnblogs.com')) throw new Error('未授权') + }, + ], + }, + }) + + return g.stream.get(`${downloadOrigin}/blogs/${blogId}/exports/${exportId}`, { + throwHttpErrors: true, + followRedirect: true, + }) } } diff --git a/src/services/downloaded-export.store.ts b/src/services/downloaded-export.store.ts index 7b06212c..555ce054 100644 --- a/src/services/downloaded-export.store.ts +++ b/src/services/downloaded-export.store.ts @@ -4,34 +4,31 @@ import { exists, existsSync } from 'fs' import { take } from 'lodash-es' import { promisify } from 'util' -export class DownloadedExportStore { - private static _instance: DownloadedExportStore +const listKey = 'downloadExports' +const metadataKey = 'downloadedExport-' - readonly listKey = 'downloadExports' - readonly metadataKey = 'downloadedExport-' +const updateList = (value?: DownloadedBlogExport[] | null) => globalCtx.storage.update(listKey, value) - private readonly _storage = globalCtx.storage +const updateExport = (id: number, value?: DownloadedBlogExport | null) => + globalCtx.storage.update(`${metadataKey}${id}`, value) - static get instance(): DownloadedExportStore { - this._instance ??= new DownloadedExportStore() - return this._instance - } - - async add(filePath: string, id?: number | null): Promise { +export namespace DownloadedExportStore { + export async function add(filePath: string, id?: number | null): Promise { const item: DownloadedBlogExport = { id, filePath } - const list = await this.list() + const list = await DownloadedExportStore.list() const oldIdx = list.findIndex(x => x.filePath === filePath) list.splice(oldIdx >= 0 ? oldIdx : 0, oldIdx >= 0 ? 1 : 0, item) return Promise.all([ - id != null && id > 0 ? this.updateExport(id, { id, filePath }) : Promise.resolve(), - this.updateList(take(list, 5000)), + id != null && id > 0 ? updateExport(id, { id, filePath }) : Promise.resolve(), + updateList(take(list, 5000)), ]).then(() => undefined) } - async list({ prune = true } = {}): Promise { - let items = this._storage.get(this.listKey) ?? [] + export async function list({ prune = true } = {}): Promise { + let items = globalCtx.storage.get(listKey) ?? [] + if (prune) { const prunedItems: DownloadedBlogExport[] = [] items = items.filter(x => { @@ -46,44 +43,41 @@ export class DownloadedExportStore { if (prunedItems.length > 0) { await Promise.all( - [this.updateList(items)].concat( - prunedItems.map(p => (p.id ? this.updateExport(p.id, undefined) : Promise.resolve())) + [updateList(items)].concat( + prunedItems.map(p => (p.id ? updateExport(p.id, undefined) : Promise.resolve())) ) ) } } - return Promise.resolve(this._storage.get(this.listKey) ?? []) + return Promise.resolve(globalCtx.storage.get(listKey) ?? []) } - async remove(downloaded: DownloadedBlogExport, { shouldRemoveExportRecordMap = true } = {}) { + export async function remove(downloaded: DownloadedBlogExport, { shouldRemoveExportRecordMap = true } = {}) { await Promise.all([ - this.updateList((await this.list()).filter(x => x.filePath !== downloaded.filePath)), + updateList((await list()).filter(x => x.filePath !== downloaded.filePath)), shouldRemoveExportRecordMap && downloaded.id != null && downloaded.id > 0 - ? this.updateExport(downloaded.id, undefined) + ? updateExport(downloaded.id, undefined) : Promise.resolve(), ]) } - async findById(id: number, { prune = true } = {}): Promise { - const key = `${this.metadataKey}${id}` - let item = this._storage.get(key) + export async function findById( + id: number, + { prune = true } = {} + ): Promise { + const key = `${metadataKey}${id}` + + let item = globalCtx.storage.get(key) + if (prune && item) { const isExist = await promisify(exists)(item.filePath) if (!isExist) { item = undefined - await this.updateExport(id, undefined) + await updateExport(id, undefined) } } return item } - - private updateList(value?: DownloadedBlogExport[] | null) { - return this._storage.update(this.listKey, value) - } - - private updateExport(id: number, value?: DownloadedBlogExport | null) { - return this._storage.update(`${this.metadataKey}${id}`, value) - } } diff --git a/src/services/image.service.ts b/src/services/image.service.ts index b32b7503..7ae7f424 100644 --- a/src/services/image.service.ts +++ b/src/services/image.service.ts @@ -4,10 +4,15 @@ import { isString, merge, pick } from 'lodash-es' import httpClient from '@/utils/http-client' import path from 'path' -class ImageService { - async upload( - file: T - ) { +export namespace ImageService { + export async function upload< + T extends Readable & { + name?: string + fileName?: string + filename?: string + path?: string | Buffer + } + >(file: T) { // eslint-disable-next-line @typescript-eslint/naming-convention const { name, fileName, filename, path: _path } = file const finalName = path.basename(isString(_path) ? _path : fileName || filename || name || 'image.png') @@ -19,11 +24,11 @@ class ImageService { const fd = new (await import('form-data')).default() fd.append('image', file, { filename: finalName, contentType: mimeType }) - const response = await httpClient.post(`${globalCtx.config.apiBaseUrl}/api/posts/body/images`, { + const res = await httpClient.post(`${globalCtx.config.apiBaseUrl}/api/posts/body/images`, { body: fd, }) - return response.body + return res.body } /** @@ -33,17 +38,15 @@ class ImageService { * @param name The name that expected applied to the downloaded image * @returns The {@link Readable} stream */ - async download(url: string, name?: string): Promise { - const response = await httpClient.get(url, { responseType: 'buffer' }) - const contentType = response.headers['content-type'] ?? 'image/png' + export async function download(url: string, name?: string): Promise { + const res = await httpClient.get(url, { responseType: 'buffer' }) + const contentType = res.headers['content-type'] ?? 'image/png' name = !name ? 'image' : name const mime = await import('mime') - return merge(Readable.from(response.body), { - ...pick(response, 'httpVersion', 'headers'), + return merge(Readable.from(res.body), { + ...pick(res, 'httpVersion', 'headers'), path: `${name}.${mime.extension(contentType) ?? 'png'}`, }) } } - -export const imageService = new ImageService() diff --git a/src/services/ing.api.ts b/src/services/ing.api.ts index d1caa667..269e1b7d 100644 --- a/src/services/ing.api.ts +++ b/src/services/ing.api.ts @@ -3,23 +3,24 @@ import { AlertService } from '@/services/alert.service' import { globalCtx } from '@/services/global-ctx' import fetch from '@/utils/fetch-client' import { URLSearchParams } from 'url' -import { isArray, isNumber, isObject } from 'lodash-es' +import { isArray, isObject } from 'lodash-es' -export class IngApi { - async publishIng(ing: IngPublishModel): Promise { - const resp = await fetch(`${globalCtx.config.cnblogsOpenApiUrl}/api/statuses`, { +export namespace IngApi { + export async function publishIng(ing: IngPublishModel): Promise { + const res = await fetch(`${globalCtx.config.cnblogsOpenApiUrl}/api/statuses`, { method: 'POST', body: JSON.stringify(ing), headers: [['Content-Type', 'application/json']], }).catch(reason => void AlertService.warn(JSON.stringify(reason))) - if (!resp || !resp.ok) - AlertService.err(`闪存发布失败, ${resp?.statusText ?? ''} ${JSON.stringify((await resp?.text()) ?? '')}`) - return resp != null && resp.ok + if (!res || !res.ok) + AlertService.err(`闪存发布失败, ${res?.statusText ?? ''} ${JSON.stringify((await res?.text()) ?? '')}`) + + return res != null && res.ok } - async list({ pageIndex = 1, pageSize = 30, type = IngType.all } = {}): Promise { - const resp = await fetch( + export async function list({ pageIndex = 1, pageSize = 30, type = IngType.all } = {}) { + const res = await fetch( `${globalCtx.config.cnblogsOpenApiUrl}/api/statuses/@${type}?${new URLSearchParams({ pageIndex: `${pageIndex}`, pageSize: `${pageSize}`, @@ -28,62 +29,71 @@ export class IngApi { method: 'GET', headers: [['Content-Type', 'application/json']], } - ).catch(reason => void AlertService.warn(JSON.stringify(reason))) - if (!resp || !resp.ok) { - AlertService.err( - `获取闪存列表失败, ${resp?.statusText ?? ''} ${JSON.stringify((await resp?.text()) ?? '')}` - ) - return null + ).catch(e => void AlertService.warn(JSON.stringify(e))) + + if (!res || !res.ok) { + AlertService.err(`获取闪存列表失败, ${res?.statusText ?? ''} ${JSON.stringify((await res?.text()) ?? '')}`) + return [] } - return resp - .json() - .then(x => (isArray(x) ? (x.every(isObject) ? x.map(Ing.parse) : null) : null)) - .then(x => { - if (x == null) throw Error('获取闪存列表失败, 无法读取响应') - return x - }) - .catch(reason => { - AlertService.err(JSON.stringify(reason)) - return null - }) + const arr = await res.json() + + try { + if (isArray(arr) && arr.every(isObject)) return arr.map(Ing.parse) + AlertService.err('获取闪存列表失败, 无法读取响应') + } catch (e) { + AlertService.err(JSON.stringify(e)) + } + + return [] } - listComments(ingIds: number | number[]): Promise> { - const arr = isNumber(ingIds) ? [ingIds] : ingIds - return Promise.all( - arr.map(id => - fetch(`${globalCtx.config.cnblogsOpenApiUrl}/api/statuses/${id}/comments`, { - method: 'GET', - headers: [['Content-Type', 'application/json']], - }).then( - resp => - resp?.json().then(obj => [id, obj as IngComment[] | null | undefined] as const) ?? - Promise.resolve(undefined), - reason => void AlertService.warn(JSON.stringify(reason)) - ) + export async function listComments(...ingIds: number[]) { + const tasks = ingIds.map(id => + fetch(`${globalCtx.config.cnblogsOpenApiUrl}/api/statuses/${id}/comments`, { + method: 'GET', + headers: [['Content-Type', 'application/json']], + }).then( + resp => + resp?.json().then(obj => [id, obj as IngComment[] | null | undefined] as const) ?? + Promise.resolve(undefined), + reason => void AlertService.warn(JSON.stringify(reason)) ) - ).then(results => - results.reduce>((p, v) => { - if (v) p[v[0]] = (v[1] ?? []).map(IngComment.parse) - return p - }, {}) ) + + const results = await Promise.all(tasks) + + return results.reduce>((p, v) => { + if (v) p[v[0]] = (v[1] ?? []).map(IngComment.parse) + return p + }, {}) } - comment(ingId: number, data: { replyTo?: number; parentCommentId?: number; content: string }) { - return fetch(`${globalCtx.config.cnblogsOpenApiUrl}/api/statuses/${ingId}/comments`, { - method: 'POST', - headers: [['Content-Type', 'application/json']], - body: JSON.stringify(data), - }) - .then(async resp => { - if (!resp.ok) throw Error(await resp.text()) - return resp.ok + export async function comment( + ingId: number, + data: { + replyTo?: number + parentCommentId?: number + content: string + } + ) { + try { + const res = await fetch(`${globalCtx.config.cnblogsOpenApiUrl}/api/statuses/${ingId}/comments`, { + method: 'POST', + headers: [['Content-Type', 'application/json']], + body: JSON.stringify(data), }) - .catch(reason => { - AlertService.err(`发表评论失败, ${reason}`) + + if (!res.ok) { + AlertService.err(`发表评论失败, ${await res.text()}`) return false - }) + } + } catch (e) { + // eslint-disable-next-line @typescript-eslint/restrict-template-expressions + AlertService.err(`发表评论失败, ${e}`) + return false + } + + return true } } diff --git a/src/services/ings-list-webview-provider.ts b/src/services/ings-list-webview-provider.ts index 228e1b43..b317a23e 100644 --- a/src/services/ings-list-webview-provider.ts +++ b/src/services/ings-list-webview-provider.ts @@ -25,7 +25,6 @@ export class IngsListWebviewProvider implements WebviewViewProvider { private readonly _baseTitle = '闪存' private _view?: WebviewView private _observer?: IngWebviewMessageObserver - private _ingApi?: IngApi private _pageIndex = 1 private _isRefreshing = false private _ingType = IngType.all @@ -64,11 +63,6 @@ export class IngsListWebviewProvider implements WebviewViewProvider { return globalCtx.assetsUri } - private get ingApi() { - this._ingApi ??= new IngApi() - return this._ingApi - } - static ensureRegistered() { if (!this._instance) { this._instance = new IngsListWebviewProvider() @@ -116,12 +110,12 @@ export class IngsListWebviewProvider implements WebviewViewProvider { command: webviewCommands.ingCommands.UiCommands.setAppState, } as IngWebviewUiCommand>) .then(undefined, () => undefined) - const ings = await this.ingApi.list({ + const ings = await IngApi.list({ type: ingType, pageIndex, pageSize: 30, }) - const comments = await this.ingApi.listComments(ings?.map(x => x.id) ?? []) + const comments = await IngApi.listComments(...ings.map(x => x.id)) await this._view.webview .postMessage({ command: webviewCommands.ingCommands.UiCommands.setAppState, @@ -144,7 +138,7 @@ export class IngsListWebviewProvider implements WebviewViewProvider { async updateComments(ingIds: number[]) { if (!this._view || !this._view.visible) return - const comments = await this.ingApi.listComments(ingIds) + const comments = await IngApi.listComments(...ingIds) await this._view.webview.postMessage({ command: webviewCommands.ingCommands.UiCommands.setAppState, payload: { diff --git a/src/services/mkd-img-extractor.service.ts b/src/services/mkd-img-extractor.service.ts index c2f3700b..05a2b5a9 100644 --- a/src/services/mkd-img-extractor.service.ts +++ b/src/services/mkd-img-extractor.service.ts @@ -2,7 +2,7 @@ import path from 'path' import { isString } from 'lodash-es' import fs from 'fs' import { Uri, workspace } from 'vscode' -import { imageService } from './image.service' +import { ImageService } from './image.service' import { isErrorResponse } from '@/models/error-response' import { promisify } from 'util' import { Readable } from 'stream' @@ -115,7 +115,7 @@ export class MkdImgExtractor { const dstInfo = await (async () => { if (streamOrLink === undefined) return null try { - const newLink = isString(streamOrLink) ? streamOrLink : await imageService.upload(streamOrLink) + const newLink = isString(streamOrLink) ? streamOrLink : await ImageService.upload(streamOrLink) return { ...srcInfo, @@ -175,7 +175,7 @@ export class MkdImgExtractor { private async resolveWebImg(url: string) { try { - return await imageService.download(url) + return await ImageService.download(url) } catch (e) { // eslint-disable-next-line @typescript-eslint/restrict-template-expressions this._errors.push([url, `无法下载网络图片: ${e}`]) diff --git a/src/services/post-configuration-panel.service.ts b/src/services/post-configuration-panel.service.ts index c7cf4c7e..42f060e7 100644 --- a/src/services/post-configuration-panel.service.ts +++ b/src/services/post-configuration-panel.service.ts @@ -4,7 +4,7 @@ import { Post } from '@/models/post' import { globalCtx } from './global-ctx' import { postCategoryService } from './post-category.service' import { siteCategoryService } from './site-category.service' -import { postTagService } from './post-tag.service' +import { PostTagService } from './post-tag.service' import { PostService } from './post.service' import { isErrorResponse } from '@/models/error-response' import { webviewMessage } from '@/models/webview-message' @@ -62,7 +62,7 @@ export namespace postConfigurationPanel { activeTheme: vscode.window.activeColorTheme.kind, personalCategories: cloneDeep(await postCategoryService.listCategories()), siteCategories: cloneDeep(await siteCategoryService.fetchAll()), - tags: cloneDeep(await postTagService.fetchTags()), + tags: cloneDeep(await PostTagService.fetchTags()), breadcrumbs, fileName: localFileUri ? path.basename(localFileUri.fsPath, path.extname(localFileUri?.fsPath)) diff --git a/src/services/post-tag.service.ts b/src/services/post-tag.service.ts index 5225b54d..6c46e856 100644 --- a/src/services/post-tag.service.ts +++ b/src/services/post-tag.service.ts @@ -2,21 +2,11 @@ import got from '@/utils/http-client' import { PostTag } from '@/models/post-tag' import { globalCtx } from './global-ctx' -export class PostTagService { - private static _instance: PostTagService +let cachedTags: PostTag[] | null = null - private _cachedTags?: PostTag[] - - private constructor() {} - - static get instance() { - if (!this._instance) this._instance = new PostTagService() - - return this._instance - } - - async fetchTags(forceRefresh = false): Promise { - if (this._cachedTags && !forceRefresh) return this._cachedTags +export namespace PostTagService { + export async function fetchTags(forceRefresh = false): Promise { + if (cachedTags && !forceRefresh) return cachedTags const { ok: isOk, @@ -24,12 +14,16 @@ export class PostTagService { method, body, } = await got.get(`${globalCtx.config.apiBaseUrl}/api/tags/list`, { responseType: 'json' }) + if (!isOk) throw Error(`Failed to ${method} ${url}`) - return Array.isArray(body) - ? body.map((x: PostTag) => Object.assign(new PostTag(), x)).filter(({ name: tagName }) => tagName) - : [] + if (Array.isArray(body)) { + cachedTags = body + .map((x: PostTag) => Object.assign(new PostTag(), x)) + .filter(({ name: tagName }) => tagName) + return cachedTags + } + + return [] } } - -export const postTagService = PostTagService.instance diff --git a/src/services/post-title-sanitizer.service.ts b/src/services/post-title-sanitizer.service.ts index 6b6c7f23..6a7693f5 100644 --- a/src/services/post-title-sanitizer.service.ts +++ b/src/services/post-title-sanitizer.service.ts @@ -1,5 +1,5 @@ import path from 'path' -import sanitize from 'sanitize-filename' +import sanitizeFilename from 'sanitize-filename' import { Post } from '@/models/post' import { globalCtx } from './global-ctx' import { PostFileMapManager } from './post-file-map' @@ -14,43 +14,42 @@ interface SanitizeResult { isSanitized: boolean } -class InvalidPostTitleStore { - store(map: InvalidPostFileNameMap): Thenable { +export namespace InvalidPostTitleStore { + export function store(map: InvalidPostFileNameMap): Thenable { const [postId, invalidName] = map const key = buildStorageKey(postId) if (invalidName) return globalCtx.storage.update(key, invalidName) else return globalCtx.storage.update(key, undefined) } - get(postId: number): string | undefined { + export function get(postId: number): string | undefined { const key = buildStorageKey(postId) return globalCtx.storage.get(key) } } -const invalidPostTitleStore = new InvalidPostTitleStore() - -class PostTitleSanitizer { - static async unSanitize(post: Post): Promise { +export namespace PostTitleSanitizer { + export async function unSanitize(post: Post): Promise { const { id: postId } = post const localFilePath = PostFileMapManager.getFilePath(postId) const { title: postTitle } = post if (!localFilePath) return postTitle const localFilename = path.basename(localFilePath, path.extname(localFilePath)) - const { text: sanitizedTitle } = await this.sanitize(post) + const { text: sanitizedTitle } = await sanitize(post) if (sanitizedTitle === localFilename) return postTitle // the blogger have already changed the filename after post opened in the vscode, // so this changed filename should be the expected post title now - await invalidPostTitleStore.store([postId, undefined]) + await InvalidPostTitleStore.store([postId, undefined]) return localFilename } - static async sanitize(post: Post): Promise { - const sanitizedTitle = sanitize(post.title) + export async function sanitize(post: Post): Promise { + const sanitizedTitle = sanitizeFilename(post.title) const isSanitized = sanitizedTitle !== post.title - if (isSanitized) await invalidPostTitleStore.store([post.id, post.title]) + + if (isSanitized) await InvalidPostTitleStore.store([post.id, post.title]) return { text: sanitizedTitle, @@ -58,5 +57,3 @@ class PostTitleSanitizer { } } } - -export { PostTitleSanitizer } diff --git a/src/services/site-category.service.ts b/src/services/site-category.service.ts index d100c795..c053bf62 100644 --- a/src/services/site-category.service.ts +++ b/src/services/site-category.service.ts @@ -3,7 +3,7 @@ import { SiteCategories, SiteCategory } from '@/models/site-category' import { globalCtx } from './global-ctx' export namespace siteCategoryService { - let cached: SiteCategories | undefined + let cached: SiteCategories | null = null export const fetchAll = async (forceRefresh = false): Promise => { if (cached && !forceRefresh) return cached diff --git a/src/tree-view-providers/models/blog-export/downloaded.ts b/src/tree-view-providers/models/blog-export/downloaded.ts index dee975d7..7707a3d8 100644 --- a/src/tree-view-providers/models/blog-export/downloaded.ts +++ b/src/tree-view-providers/models/blog-export/downloaded.ts @@ -98,7 +98,7 @@ export class DownloadedExportsEntryTreeItem } getChildrenAsync: () => Promise = async () => { - this._children ??= parseDownloadedExports(this, await DownloadedExportStore.instance.list()) + this._children ??= parseDownloadedExports(this, await DownloadedExportStore.list()) return this._children } diff --git a/src/tree-view-providers/models/blog-export/record.ts b/src/tree-view-providers/models/blog-export/record.ts index 13240d54..40ea70d3 100644 --- a/src/tree-view-providers/models/blog-export/record.ts +++ b/src/tree-view-providers/models/blog-export/record.ts @@ -15,7 +15,7 @@ import { BlogExportApi } from '@/services/blog-export.api' export class BlogExportRecordTreeItem extends BaseTreeItemSource implements BaseEntryTreeItem { static readonly contextValue = 'cnblogs-export-record' - private _blogExportApi?: BlogExportApi | null + private _downloadingProgress?: { percentage?: number transferred?: number @@ -27,11 +27,6 @@ export class BlogExportRecordTreeItem extends BaseTreeItemSource implements Base super() } - protected get blogExportApi() { - this._blogExportApi ??= new BlogExportApi() - return this._blogExportApi - } - toTreeItem(): Promise { const { record: { fileName, status }, @@ -60,11 +55,9 @@ export class BlogExportRecordTreeItem extends BaseTreeItemSource implements Base } private pollingStatus() { - const { blogExportApi } = this const timeoutId = setTimeout(() => { clearTimeout(timeoutId) - blogExportApi - .getById(this.record.id) + BlogExportApi.getById(this.record.id) .then(record => { this.record = record }) @@ -82,7 +75,7 @@ export class BlogExportRecordTreeItem extends BaseTreeItemSource implements Base } = this const formattedFileSize = filesize(fileBytes) const dateTimeFormat = 'yyyy MM-dd HH:mm' - const localExport = await DownloadedExportStore.instance.findById(id) + const localExport = await DownloadedExportStore.findById(id) const items = [ new BlogExportRecordMetadata( this, From fb4d7cab7ef9153122cf96f50009cc388749807b Mon Sep 17 00:00:00 2001 From: Thaumy Date: Thu, 20 Jul 2023 16:21:54 +0800 Subject: [PATCH 006/157] refactor: simplify code --- __mocks__/vscode.ts | 6 +- src/auth/account-manager.ts | 9 +- src/auth/auth-provider.ts | 6 +- src/commands/blog-export/create.ts | 6 +- src/commands/blog-export/delete.ts | 6 +- src/commands/blog-export/download.ts | 11 ++- src/commands/blog-export/edit.ts | 6 +- src/commands/blog-export/index.ts | 49 ++++------ src/commands/blog-export/open-local.ts | 11 ++- src/commands/blog-export/refresh.ts | 11 +-- src/commands/blog-export/view-post.ts | 6 +- .../{command-handler.ts => cmd-handler.ts} | 8 +- src/commands/cmd-register.ts | 96 ++++++++++++++++++ src/commands/commands-registration.ts | 98 ------------------- src/commands/extract-images.ts | 8 +- src/commands/ing/comment-ing.ts | 4 +- src/commands/ing/goto-ings-list-page.ts | 8 +- src/commands/ing/ings-list-cmd-register.ts | 23 +++++ .../ing/ings-list-commands-registration.ts | 26 ----- src/commands/ing/open-ing-in-browser.ts | 9 +- src/commands/ing/publish-ing.ts | 24 ++--- src/commands/ing/refresh-ings-list.ts | 4 +- src/commands/ing/select-ing-type.ts | 4 +- src/commands/open-my-account-settings.ts | 3 +- src/commands/open-my-blog-console.ts | 4 + .../open-my-blog-management-background.ts | 4 - src/commands/open-my-blog.ts | 3 +- src/commands/open-my-home-page.ts | 3 +- src/commands/open-post-in-blog-admin.ts | 5 +- src/commands/open-workspace.ts | 12 +-- src/commands/pdf/export-pdf.command.ts | 10 +- ...ndler.ts => base-tree-view-cmd-handler.ts} | 12 +-- .../delete-selected-categories.ts | 9 +- .../post-category/new-post-category.ts | 7 +- .../post-category/update-post-category.ts | 6 +- src/commands/posts-list/copy-link.ts | 4 +- .../delete-post-to-local-file-map.ts | 7 +- src/commands/posts-list/delete-post.ts | 8 +- .../posts-list/modify-post-settings.ts | 4 +- src/commands/posts-list/open-post-file.ts | 5 +- .../posts-list/open-post-in-vscode.ts | 2 +- src/commands/posts-list/refresh-posts-list.ts | 15 ++- src/commands/posts-list/rename-post.ts | 5 +- src/commands/posts-list/upload-post.ts | 8 +- src/commands/pull-post-remote-updates.ts | 14 +-- src/commands/reveal-local-post-file-in-os.ts | 5 +- src/commands/reveal-workspace-in-os.ts | 3 +- src/commands/show-local-file-to-post-info.ts | 4 +- .../upload-image/upload-image-utils.ts | 3 +- src/commands/upload-image/upload-image.ts | 2 +- src/commands/view-post-online.ts | 5 +- src/extension.ts | 14 +-- src/models/post-cfg.ts | 6 ++ src/models/post-configuration.ts | 6 -- .../{webview-commands.ts => webview-cmd.ts} | 30 +++--- .../{webview-message.ts => webview-msg.ts} | 6 +- src/services/alert.service.ts | 19 ++-- src/services/blog-export-records.store.ts | 4 +- src/services/check-workspace.ts | 7 +- ...response-to-camel-case.ts => converter.ts} | 0 src/services/ings-list-webview-provider.ts | 62 ++++++------ src/services/oauth.api.ts | 6 +- src/services/parse-webview-html.ts | 2 +- src/services/post-category.service.ts | 4 +- ...l.service.ts => post-cfg-panel.service.ts} | 54 +++++----- src/services/posts-list-view.ts | 4 +- src/test/suite/extension.test.ts | 4 +- .../account-view-data-provider.ts | 6 +- .../blog-export-provider.ts | 2 +- .../models/blog-export/post.ts | 4 +- .../post-categories-tree-data-provider.ts | 7 +- .../posts-data-provider.ts | 2 +- .../tree-view-registration.ts | 30 +++--- src/utils/cmd.ts | 9 ++ src/utils/constants.ts | 1 - src/utils/http-client.ts | 6 +- src/utils/msg.ts | 0 src/utils/reveal-active-file.ts | 5 +- src/utils/tree-view.ts | 5 + src/utils/uri-handler.ts | 6 +- ui/global.d.ts | 8 +- ui/ing/App.tsx | 14 +-- ui/ing/IngItem.tsx | 12 +-- ui/{post-configuration => post-cfg}/App.tsx | 18 ++-- .../components/AccessPermissionSelector.tsx | 0 .../components/CategoriesSelect.tsx | 0 .../components/CommonOptions.tsx | 0 .../components/ErrorResponse.tsx | 6 +- .../components/InputSummary.tsx | 12 +-- .../components/NestCategoriesSelect.tsx | 2 +- .../components/PasswordInput.tsx | 0 .../components/PostEntryNameInput.tsx | 0 .../components/PostForm.tsx | 24 +++-- .../components/PostFormContext.ts | 0 .../components/PostFormContextProvider.tsx | 0 .../components/PostTitleInput.tsx | 0 .../components/SiteCategoriesSelector.tsx | 0 .../SiteHomeContributionOptionsSelector.tsx | 0 .../components/TagsInput.tsx | 0 .../index.html | 4 +- .../index.less | 0 ui/{post-configuration => post-cfg}/index.tsx | 0 .../models/site-home-contribution-options.ts | 0 .../services/personal-categories-store.ts | 14 +-- .../services/site-categories-store.ts | 0 .../services/tags-store.ts | 0 ui/share/vscode-api.ts | 8 +- 107 files changed, 519 insertions(+), 525 deletions(-) rename src/commands/{command-handler.ts => cmd-handler.ts} (69%) create mode 100644 src/commands/cmd-register.ts delete mode 100644 src/commands/commands-registration.ts create mode 100644 src/commands/ing/ings-list-cmd-register.ts delete mode 100644 src/commands/ing/ings-list-commands-registration.ts create mode 100644 src/commands/open-my-blog-console.ts delete mode 100644 src/commands/open-my-blog-management-background.ts rename src/commands/post-category/{base-tree-view-command-handler.ts => base-tree-view-cmd-handler.ts} (74%) create mode 100644 src/models/post-cfg.ts delete mode 100644 src/models/post-configuration.ts rename src/models/{webview-commands.ts => webview-cmd.ts} (61%) rename src/models/{webview-message.ts => webview-msg.ts} (87%) rename src/services/{fetch-json-response-to-camel-case.ts => converter.ts} (100%) rename src/services/{post-configuration-panel.service.ts => post-cfg-panel.service.ts} (81%) create mode 100644 src/utils/cmd.ts delete mode 100644 src/utils/constants.ts create mode 100644 src/utils/msg.ts create mode 100644 src/utils/tree-view.ts rename ui/{post-configuration => post-cfg}/App.tsx (87%) rename ui/{post-configuration => post-cfg}/components/AccessPermissionSelector.tsx (100%) rename ui/{post-configuration => post-cfg}/components/CategoriesSelect.tsx (100%) rename ui/{post-configuration => post-cfg}/components/CommonOptions.tsx (100%) rename ui/{post-configuration => post-cfg}/components/ErrorResponse.tsx (89%) rename ui/{post-configuration => post-cfg}/components/InputSummary.tsx (94%) rename ui/{post-configuration => post-cfg}/components/NestCategoriesSelect.tsx (98%) rename ui/{post-configuration => post-cfg}/components/PasswordInput.tsx (100%) rename ui/{post-configuration => post-cfg}/components/PostEntryNameInput.tsx (100%) rename ui/{post-configuration => post-cfg}/components/PostForm.tsx (89%) rename ui/{post-configuration => post-cfg}/components/PostFormContext.ts (100%) rename ui/{post-configuration => post-cfg}/components/PostFormContextProvider.tsx (100%) rename ui/{post-configuration => post-cfg}/components/PostTitleInput.tsx (100%) rename ui/{post-configuration => post-cfg}/components/SiteCategoriesSelector.tsx (100%) rename ui/{post-configuration => post-cfg}/components/SiteHomeContributionOptionsSelector.tsx (100%) rename ui/{post-configuration => post-cfg}/components/TagsInput.tsx (100%) rename ui/{post-configuration => post-cfg}/index.html (74%) rename ui/{post-configuration => post-cfg}/index.less (100%) rename ui/{post-configuration => post-cfg}/index.tsx (100%) rename ui/{post-configuration => post-cfg}/models/site-home-contribution-options.ts (100%) rename ui/{post-configuration => post-cfg}/services/personal-categories-store.ts (77%) rename ui/{post-configuration => post-cfg}/services/site-categories-store.ts (100%) rename ui/{post-configuration => post-cfg}/services/tags-store.ts (100%) diff --git a/__mocks__/vscode.ts b/__mocks__/vscode.ts index 372fd4e0..b02ec649 100644 --- a/__mocks__/vscode.ts +++ b/__mocks__/vscode.ts @@ -65,9 +65,9 @@ const debug = { } const commands = { - executeCommand: jest.fn(), - registerCommand: jest.fn(), - registerTextEditorCommand: jest.fn(), + execCmd: jest.fn(), + regCmd: jest.fn(), + regTextEditorCmd: jest.fn(), } // eslint-disable-next-line @typescript-eslint/no-empty-function diff --git a/src/auth/account-manager.ts b/src/auth/account-manager.ts index 83d88173..5829ba86 100644 --- a/src/auth/account-manager.ts +++ b/src/auth/account-manager.ts @@ -9,6 +9,7 @@ import { AuthProvider } from '@/auth/auth-provider' import { AuthSession } from '@/auth/auth-session' import { BlogExportProvider } from '@/tree-view-providers/blog-export-provider' import { AlertService } from '@/services/alert.service' +import { execCmd } from '@/utils/cmd' const isAuthorizedStorageKey = 'isAuthorized' @@ -87,14 +88,10 @@ class AccountManager extends vscode.Disposable { async updateAuthStatus() { await this.ensureSession({ createIfNone: false }) - await vscode.commands.executeCommand( - 'setContext', - `${globalCtx.extName}.${isAuthorizedStorageKey}`, - this.isAuthorized - ) + await execCmd('setContext', `${globalCtx.extName}.${isAuthorizedStorageKey}`, this.isAuthorized) if (this.isAuthorized) { - await vscode.commands.executeCommand('setContext', `${globalCtx.extName}.user`, { + await execCmd('setContext', `${globalCtx.extName}.user`, { name: this.currentUser.name, avatar: this.currentUser.avatar, }) diff --git a/src/auth/auth-provider.ts b/src/auth/auth-provider.ts index 12180076..44461c30 100644 --- a/src/auth/auth-provider.ts +++ b/src/auth/auth-provider.ts @@ -17,7 +17,7 @@ import { import { globalCtx } from '@/services/global-ctx' import RandomString from 'randomstring' import { Oauth } from '@/services/oauth.api' -import extensionUriHandler from '@/utils/uri-handler' +import { extUriHandler } from '@/utils/uri-handler' import { AccountInfo } from '@/auth/account-info' import { TokenInfo } from '@/models/token-info' import { Optional } from 'utility-types' @@ -108,9 +108,9 @@ export class AuthProvider implements AuthenticationProvider, Disposable { reject(`${isTimeout ? '由于超时, ' : ''}登录操作已取消`) }), cancelTokenSrc, - extensionUriHandler + extUriHandler ) - extensionUriHandler.onUri(uri => { + extUriHandler.onUri(uri => { if (cancelTokenSrc.token.isCancellationRequested) return const authorizationCode = this.parseOauthCallbackUri(uri) diff --git a/src/commands/blog-export/create.ts b/src/commands/blog-export/create.ts index 0a42a5e6..cb71ef00 100644 --- a/src/commands/blog-export/create.ts +++ b/src/commands/blog-export/create.ts @@ -1,10 +1,10 @@ -import { CommandHandler } from '@/commands/command-handler' +import { CmdHandler } from '@/commands/cmd-handler' import { AlertService } from '@/services/alert.service' import { BlogExportApi } from '@/services/blog-export.api' import { BlogExportProvider } from '@/tree-view-providers/blog-export-provider' import { MessageItem, window } from 'vscode' -export class CreateBlogExportCommandHandler extends CommandHandler { +export class CreateBlogExportCmdHandler extends CmdHandler { static readonly commandName = 'vscode-cnb.blog-export.create' async handle(): Promise { @@ -21,7 +21,7 @@ export class CreateBlogExportCommandHandler extends CommandHandler { private async confirm(): Promise { const items: MessageItem[] = [{ title: '确定', isCloseAffordance: false }] - const result = await window.showInformationMessage( + const result = await AlertService.info( '确定要创建备份吗?', { modal: true, detail: '一天可以创建一次备份' }, ...items diff --git a/src/commands/blog-export/delete.ts b/src/commands/blog-export/delete.ts index 76437f52..66d7a5de 100644 --- a/src/commands/blog-export/delete.ts +++ b/src/commands/blog-export/delete.ts @@ -1,4 +1,4 @@ -import { TreeViewCommandHandler } from '@/commands/command-handler' +import { TreeViewCmdHandler } from '@/commands/cmd-handler' import { DownloadedBlogExport } from '@/models/blog-export' import { AlertService } from '@/services/alert.service' import { BlogExportApi } from '@/services/blog-export.api' @@ -10,7 +10,7 @@ import path from 'path' import { promisify } from 'util' import { MessageItem, window } from 'vscode' -export class DeleteCommandHandler extends TreeViewCommandHandler { +export class DeleteCmdHandler extends TreeViewCmdHandler { static readonly commandName = 'vscode-cnb.blog-export.delete' constructor(private readonly _input: unknown) { @@ -35,7 +35,7 @@ export class DeleteCommandHandler extends TreeViewCommandHandler { const options: (MessageItem & { - result: ReturnType extends Thenable ? R : never + result: ReturnType extends Thenable ? R : never })[] = [ { title: '确定' + (hasLocalFile ? '(保留本地文件)' : ''), result: { shouldDeleteLocal: false } }, ...(hasLocalFile ? [{ title: '确定(同时删除本地文件)', result: { shouldDeleteLocal: true } }] : []), diff --git a/src/commands/blog-export/download.ts b/src/commands/blog-export/download.ts index 4e643a3d..edb54bee 100644 --- a/src/commands/blog-export/download.ts +++ b/src/commands/blog-export/download.ts @@ -1,4 +1,4 @@ -import { TreeViewCommandHandler } from '@/commands/command-handler' +import { TreeViewCmdHandler } from '@/commands/cmd-handler' import { AlertService } from '@/services/alert.service' import { BlogExportApi } from '@/services/blog-export.api' import { DownloadedExportStore } from '@/services/downloaded-export.store' @@ -6,14 +6,15 @@ import { globalCtx } from '@/services/global-ctx' import { Settings } from '@/services/settings.service' import { BlogExportProvider } from '@/tree-view-providers/blog-export-provider' import { BlogExportRecordTreeItem } from '@/tree-view-providers/models/blog-export' -import { extensionViews } from '@/tree-view-providers/tree-view-registration' +import { extViews } from '@/tree-view-providers/tree-view-registration' import fs from 'fs' import { Progress } from 'got' import path from 'path' import { promisify } from 'util' import { commands } from 'vscode' +import { execCmd } from '@/utils/cmd' -export class DownloadExportCommandHandler extends TreeViewCommandHandler { +export class DownloadExportCmdHandler extends TreeViewCmdHandler { static readonly commandName = 'vscode-cnb.blog-export.download' constructor(public readonly input: unknown) { @@ -40,7 +41,7 @@ export class DownloadExportCommandHandler extends TreeViewCommandHandler { +export class EditExportPostCmdHandler extends TreeViewCmdHandler { static readonly commandName = 'vscode-cnb.blog-export.edit' constructor(public readonly input: unknown) { @@ -21,7 +21,7 @@ export class EditExportPostCommandHandler extends TreeViewCommandHandler { const target = this.parseInput() - if (!target) return AlertService.warn('不支持的参数输入') + if (!target) return void AlertService.warn('不支持的参数输入') const { post: { title, isMarkdown, id: postId }, diff --git a/src/commands/blog-export/index.ts b/src/commands/blog-export/index.ts index 1bce5495..a0f89fe0 100644 --- a/src/commands/blog-export/index.ts +++ b/src/commands/blog-export/index.ts @@ -1,34 +1,23 @@ -import { RefreshExportRecordsCommandHandler } from './refresh' +import { RefreshExportRecordsCmdHandler } from './refresh' import { globalCtx } from '@/services/global-ctx' -import { commands, Disposable } from 'vscode' -import { OpenLocalExportCommandHandler } from '@/commands/blog-export/open-local' -import { EditExportPostCommandHandler } from '@/commands/blog-export/edit' -import { CreateBlogExportCommandHandler } from '@/commands/blog-export/create' -import { DownloadExportCommandHandler } from '@/commands/blog-export/download' -import { ViewPostCommandHandler } from '@/commands/blog-export/view-post' -import { DeleteCommandHandler } from '@/commands/blog-export/delete' +import { OpenLocalExportCmdHandler } from '@/commands/blog-export/open-local' +import { EditExportPostCmdHandler } from '@/commands/blog-export/edit' +import { CreateBlogExportCmdHandler } from '@/commands/blog-export/create' +import { DownloadExportCmdHandler } from '@/commands/blog-export/download' +import { ViewPostCmdHandler } from '@/commands/blog-export/view-post' +import { DeleteCmdHandler } from '@/commands/blog-export/delete' +import { regCmd } from '@/utils/cmd' -export function registerCommandsForBlogExport(disposables: Disposable[]) { +export function regBlogExportCmds() { const { extName } = globalCtx - disposables.push( - commands.registerCommand(`${extName}.blog-export.refresh-records`, () => - new RefreshExportRecordsCommandHandler().handle() - ), - commands.registerCommand(OpenLocalExportCommandHandler.commandName, () => - new OpenLocalExportCommandHandler().handle() - ), - commands.registerCommand(EditExportPostCommandHandler.commandName, input => - new EditExportPostCommandHandler(input).handle() - ), - commands.registerCommand(CreateBlogExportCommandHandler.commandName, () => - new CreateBlogExportCommandHandler().handle() - ), - commands.registerCommand(DownloadExportCommandHandler.commandName, input => - new DownloadExportCommandHandler(input).handle() - ), - commands.registerCommand(ViewPostCommandHandler.commandName, input => - new ViewPostCommandHandler(input).handle() - ), - commands.registerCommand(DeleteCommandHandler.commandName, input => new DeleteCommandHandler(input).handle()) - ) + + return [ + regCmd(`${extName}.blog-export.refresh-records`, () => new RefreshExportRecordsCmdHandler().handle()), + regCmd(OpenLocalExportCmdHandler.commandName, () => new OpenLocalExportCmdHandler().handle()), + regCmd(EditExportPostCmdHandler.commandName, input => new EditExportPostCmdHandler(input).handle()), + regCmd(CreateBlogExportCmdHandler.commandName, () => new CreateBlogExportCmdHandler().handle()), + regCmd(DownloadExportCmdHandler.commandName, input => new DownloadExportCmdHandler(input).handle()), + regCmd(ViewPostCmdHandler.commandName, input => new ViewPostCmdHandler(input).handle()), + regCmd(DeleteCmdHandler.commandName, input => new DeleteCmdHandler(input).handle()), + ] } diff --git a/src/commands/blog-export/open-local.ts b/src/commands/blog-export/open-local.ts index 4869b22d..ed46ea9e 100644 --- a/src/commands/blog-export/open-local.ts +++ b/src/commands/blog-export/open-local.ts @@ -1,4 +1,4 @@ -import { CommandHandler } from '@/commands/command-handler' +import { CmdHandler } from '@/commands/cmd-handler' import { window } from 'vscode' import path from 'path' import fs from 'fs' @@ -9,7 +9,7 @@ import { BlogExportProvider } from '@/tree-view-providers/blog-export-provider' const defaultOptions = { confirmUnzip: true } -export class OpenLocalExportCommandHandler extends CommandHandler { +export class OpenLocalExportCmdHandler extends CmdHandler { static readonly commandName = `vscode-cnb.blog-export.open-local-export` async handle(opts: Partial = defaultOptions): Promise { @@ -28,7 +28,8 @@ export class OpenLocalExportCommandHandler extends CommandHandler { })) ?? [] if (fileUri == null) return const filePath = fileUri.fsPath - if (filePath.endsWith('.zip') && !filePath.endsWith('.db.zip')) return AlertService.warn('不支持的博客备份文件') + if (filePath.endsWith('.zip') && !filePath.endsWith('.db.zip')) + return void AlertService.warn('不支持的博客备份文件') const fileName = path.basename(filePath.replace(/\.db(\.zip)?$/, '')) const dirname = path.dirname(filePath) @@ -36,7 +37,7 @@ export class OpenLocalExportCommandHandler extends CommandHandler { isConfirmedToUnzip = filePath.endsWith('.db.zip') // if (!confirmUnzip && fileUri.fsPath.endsWith('db.zip')) { // const options: (MessageItem & { confirmed: boolean })[] = [{ title: '确定', confirmed: true }]; - // const selected = await window.showInformationMessage( + // const selected = await AlertService.info( // '浏览博客备份需要解决, 确定要解压吗?', // { modal: true }, // ...options @@ -55,7 +56,7 @@ export class OpenLocalExportCommandHandler extends CommandHandler { const dbFileName = path.basename(dbFilePath) const isExist = await promisify(fs.exists)(dbFilePath) - if (!isExist) return AlertService.warn('文件不存在') + if (!isExist) return void AlertService.warn('文件不存在') const treeProvider = BlogExportProvider.optionalInstance const dbFileSize = (await promisify(fs.stat)(dbFilePath)).size diff --git a/src/commands/blog-export/refresh.ts b/src/commands/blog-export/refresh.ts index ab41a7de..08e85ab9 100644 --- a/src/commands/blog-export/refresh.ts +++ b/src/commands/blog-export/refresh.ts @@ -1,9 +1,10 @@ -import { CommandHandler } from '@/commands/command-handler' +import { CmdHandler } from '@/commands/cmd-handler' +import { execCmd } from '@/utils/cmd' import { globalCtx } from '@/services/global-ctx' import { BlogExportProvider } from '@/tree-view-providers/blog-export-provider' import { commands } from 'vscode' -export class RefreshExportRecordsCommandHandler extends CommandHandler { +export class RefreshExportRecordsCmdHandler extends CmdHandler { async handle(): Promise { await this.setIsRefreshing(true) @@ -13,10 +14,6 @@ export class RefreshExportRecordsCommandHandler extends CommandHandler { } private setIsRefreshing(value: boolean) { - return commands.executeCommand( - 'setContext', - `${globalCtx.extName}.blog-export.records.isRefreshing`, - value || undefined - ) + return execCmd('setContext', `${globalCtx.extName}.blog-export.records.isRefreshing`, value || undefined) } } diff --git a/src/commands/blog-export/view-post.ts b/src/commands/blog-export/view-post.ts index 6b4e2cac..008a7a5a 100644 --- a/src/commands/blog-export/view-post.ts +++ b/src/commands/blog-export/view-post.ts @@ -1,11 +1,11 @@ -import { TreeViewCommandHandler } from '@/commands/command-handler' +import { TreeViewCmdHandler } from '@/commands/cmd-handler' import { DownloadedBlogExport } from '@/models/blog-export' import { ExportPost } from '@/models/blog-export/export-post' import { ExportPostTreeItem } from '@/tree-view-providers/models/blog-export/post' import { URLSearchParams } from 'url' import { languages, TextDocumentContentProvider, Uri, window, workspace } from 'vscode' -export class ViewPostCommandHandler extends TreeViewCommandHandler { +export class ViewPostCmdHandler extends TreeViewCmdHandler { static readonly commandName = 'vscode-cnb.blog-export.view-post' static readonly schema = 'vscode-cnb.blog-export.post' @@ -30,7 +30,7 @@ export class ViewPostCommandHandler extends TreeViewCommandHandler { if (document.uri.scheme === schema && !document.isClosed) { diff --git a/src/commands/command-handler.ts b/src/commands/cmd-handler.ts similarity index 69% rename from src/commands/command-handler.ts rename to src/commands/cmd-handler.ts index 6fe04811..926a9187 100644 --- a/src/commands/command-handler.ts +++ b/src/commands/cmd-handler.ts @@ -1,16 +1,14 @@ -export abstract class CommandHandler { +export abstract class CmdHandler { abstract handle(): Promise | void } -export abstract class TreeViewCommandHandler extends CommandHandler { +export abstract class TreeViewCmdHandler extends CmdHandler { readonly input: unknown abstract parseInput(): TData | null | undefined } -export abstract class MultiSelectableTreeViewCommandHandler - implements TreeViewCommandHandler -{ +export abstract class MultiSelectableTreeViewCmdHandler implements TreeViewCmdHandler { private _selections: TData[] | null = null constructor(public readonly input: TArgument) {} diff --git a/src/commands/cmd-register.ts b/src/commands/cmd-register.ts new file mode 100644 index 00000000..5fd9fd7d --- /dev/null +++ b/src/commands/cmd-register.ts @@ -0,0 +1,96 @@ +import { openMyAccountSettings } from './open-my-account-settings' +import { openMyWebBlogConsole } from './open-my-blog-console' +import { openMyHomePage } from './open-my-home-page' +import { login, logout } from './login' +import { openMyBlog } from './open-my-blog' +import { globalCtx } from '@/services/global-ctx' +import { + gotoNextPostsList, + gotoPreviousPostsList, + refreshPostsList, + seekPostsList, +} from './posts-list/refresh-posts-list' +import { uploadPostFileToCnblogs, uploadPostToCnblogs } from './posts-list/upload-post' +import { createLocalDraft } from './posts-list/create-local-draft' +import { deleteSelectedPosts } from './posts-list/delete-post' +import { modifyPostSettings } from './posts-list/modify-post-settings' +import { uploadImage } from './upload-image/upload-image' +import { revealLocalPostFileInOs } from './reveal-local-post-file-in-os' +import { showLocalFileToPostInfo } from './show-local-file-to-post-info' +import { newPostCategory } from './post-category/new-post-category' +import { refreshPostCategoriesList } from './post-category/refresh-post-categories-list' +import { handleUpdatePostCategory } from './post-category/update-post-category' +import { openPostInVscode } from './posts-list/open-post-in-vscode' +import { deletePostToLocalFileMap } from './posts-list/delete-post-to-local-file-map' +import { renamePost } from './posts-list/rename-post' +import { openPostInBlogAdmin } from './open-post-in-blog-admin' +import { openWorkspace } from './open-workspace' +import { setWorkspace } from './set-workspace' +import { revealWorkspaceInOs } from './reveal-workspace-in-os' +import { viewPostOnline } from './view-post-online' +import { pullPostRemoteUpdates } from './pull-post-remote-updates' +import { extractImages } from './extract-images' +import { clearPostsSearchResults, refreshPostsSearchResults, searchPosts } from './posts-list/search' +import { handleDeletePostCategories } from './post-category/delete-selected-categories' +import { PublishIngCmdHandler } from '@/commands/ing/publish-ing' +import { regIngListCmds } from 'src/commands/ing/ings-list-cmd-register' +import { CopyPostLinkCmdHandler } from '@/commands/posts-list/copy-link' +import { regBlogExportCmds } from '@/commands/blog-export' +import { regCmd } from '@/utils/cmd' + +export function setupExtCmd() { + const ctx = globalCtx.extCtx + const appName = globalCtx.extName + + // TODO: simplify register + const disposables = [ + regCmd(`${appName}.login`, login), + regCmd(`${appName}.open-my-blog`, openMyBlog), + regCmd(`${appName}.open-my-home-page`, openMyHomePage), + regCmd(`${appName}.open-my-blog-console`, openMyWebBlogConsole), + regCmd(`${appName}.open-my-account-settings`, openMyAccountSettings), + regCmd(`${appName}.logout`, logout), + regCmd(`${appName}.refresh-posts-list`, refreshPostsList), + regCmd(`${appName}.previous-posts-list`, gotoPreviousPostsList), + regCmd(`${appName}.seek-posts-list`, seekPostsList), + regCmd(`${appName}.next-posts-list`, gotoNextPostsList), + regCmd(`${appName}.edit-post`, openPostInVscode), + regCmd(`${appName}.upload-post`, uploadPostToCnblogs), + regCmd(`${appName}.modify-post-settings`, modifyPostSettings), + regCmd(`${appName}.delete-post`, deleteSelectedPosts), + regCmd(`${appName}.create-local-draft`, createLocalDraft), + regCmd(`${appName}.upload-post-file-to-cnblogs`, uploadPostFileToCnblogs), + regCmd(`${appName}.pull-post-remote-updates`, pullPostRemoteUpdates), + regCmd(`${appName}.upload-clipboard-image`, () => uploadImage(true, 'clipboard')), + regCmd(`${appName}.upload-local-disk-image`, () => uploadImage(true, 'local')), + regCmd(`${appName}.upload-image`, () => uploadImage(true)), + regCmd(`${appName}.reveal-local-post-file-in-os`, revealLocalPostFileInOs), + regCmd(`${appName}.show-post-to-local-file-info`, showLocalFileToPostInfo), + regCmd(`${appName}.new-post-category`, newPostCategory), + regCmd(`${appName}.delete-selected-post-categories`, handleDeletePostCategories), + regCmd(`${appName}.refresh-post-categories-list`, refreshPostCategoriesList), + regCmd(`${appName}.update-post-category`, handleUpdatePostCategory), + regCmd(`${appName}.delete-post-to-local-file-map`, deletePostToLocalFileMap), + regCmd(`${appName}.rename-post`, renamePost), + regCmd(`${appName}.open-post-in-blog-admin`, openPostInBlogAdmin), + regCmd(`${appName}.open-workspace`, openWorkspace), + regCmd(`${appName}.set-workspace`, setWorkspace), + regCmd(`${appName}.reveal-workspace-in-os`, revealWorkspaceInOs), + regCmd(`${appName}.view-post-online`, viewPostOnline), + regCmd(`${appName}.export-post-to-pdf`, (input: unknown) => + import('./pdf/export-pdf.command').then(m => m.exportPostToPdf(input)) + ), + regCmd(`${appName}.extract-images`, extractImages), + regCmd(`${appName}.search-posts`, searchPosts), + regCmd(`${appName}.clear-posts-search-results`, clearPostsSearchResults), + regCmd(`${appName}.refresh-posts-search-results`, refreshPostsSearchResults), + regCmd(`${appName}.copy-post-link`, input => new CopyPostLinkCmdHandler(input).handle()), + regCmd(`${appName}.ing.publish`, () => new PublishIngCmdHandler('input').handle()), + regCmd(`${appName}.ing.publish-selection`, () => new PublishIngCmdHandler('selection').handle()), + + ...regIngListCmds(), + ...regBlogExportCmds(), + ] + + ctx?.subscriptions.push(...disposables) +} diff --git a/src/commands/commands-registration.ts b/src/commands/commands-registration.ts deleted file mode 100644 index d28b2fe8..00000000 --- a/src/commands/commands-registration.ts +++ /dev/null @@ -1,98 +0,0 @@ -import { commands } from 'vscode' -import { openMyAccountSettings } from './open-my-account-settings' -import { openMyWebBlogConsole } from './open-my-blog-management-background' -import { openMyHomePage } from './open-my-home-page' -import { login, logout } from './login' -import { openMyBlog } from './open-my-blog' -import { globalCtx } from '@/services/global-ctx' -import { - gotoNextPostsList, - gotoPreviousPostsList, - refreshPostsList, - seekPostsList, -} from './posts-list/refresh-posts-list' -import { uploadPostFileToCnblogs, uploadPostToCnblogs } from './posts-list/upload-post' -import { createLocalDraft } from './posts-list/create-local-draft' -import { deleteSelectedPosts } from './posts-list/delete-post' -import { modifyPostSettings } from './posts-list/modify-post-settings' -import { uploadImage } from './upload-image/upload-image' -import { revealLocalPostFileInOs } from './reveal-local-post-file-in-os' -import { showLocalFileToPostInfo } from './show-local-file-to-post-info' -import { newPostCategory } from './post-category/new-post-category' -import { refreshPostCategoriesList } from './post-category/refresh-post-categories-list' -import { handleUpdatePostCategory } from './post-category/update-post-category' -import { openPostInVscode } from './posts-list/open-post-in-vscode' -import { deletePostToLocalFileMap } from './posts-list/delete-post-to-local-file-map' -import { renamePost } from './posts-list/rename-post' -import { openPostInBlogAdmin } from './open-post-in-blog-admin' -import { openWorkspace } from './open-workspace' -import { setWorkspace } from './set-workspace' -import { revealWorkspaceInOs } from './reveal-workspace-in-os' -import { viewPostOnline } from './view-post-online' -import { pullPostRemoteUpdates } from './pull-post-remote-updates' -import { extractImages } from './extract-images' -import { clearPostsSearchResults, refreshPostsSearchResults, searchPosts } from './posts-list/search' -import { handleDeletePostCategories } from './post-category/delete-selected-categories' -import { PublishIngCommandHandler } from '@/commands/ing/publish-ing' -import { registerCommandsForIngsList } from 'src/commands/ing/ings-list-commands-registration' -import { CopyPostLinkCommandHandler } from '@/commands/posts-list/copy-link' -import { registerCommandsForBlogExport } from '@/commands/blog-export' - -export const registerCommands = () => { - const context = globalCtx.extCtx - const appName = globalCtx.extName - - // TODO: simplify register - const disposables = [ - commands.registerCommand(`${appName}.login`, login), - commands.registerCommand(`${appName}.open-my-blog`, openMyBlog), - commands.registerCommand(`${appName}.open-my-home-page`, openMyHomePage), - commands.registerCommand(`${appName}.open-my-blog-management-background`, openMyWebBlogConsole), - commands.registerCommand(`${appName}.open-my-account-settings`, openMyAccountSettings), - commands.registerCommand(`${appName}.logout`, logout), - commands.registerCommand(`${appName}.refresh-posts-list`, refreshPostsList), - commands.registerCommand(`${appName}.previous-posts-list`, gotoPreviousPostsList), - commands.registerCommand(`${appName}.seek-posts-list`, seekPostsList), - commands.registerCommand(`${appName}.next-posts-list`, gotoNextPostsList), - commands.registerCommand(`${appName}.edit-post`, openPostInVscode), - commands.registerCommand(`${appName}.upload-post`, uploadPostToCnblogs), - commands.registerCommand(`${appName}.modify-post-settings`, modifyPostSettings), - commands.registerCommand(`${appName}.delete-post`, deleteSelectedPosts), - commands.registerCommand(`${appName}.create-local-draft`, createLocalDraft), - commands.registerCommand(`${appName}.upload-post-file-to-cnblogs`, uploadPostFileToCnblogs), - commands.registerCommand(`${appName}.pull-post-remote-updates`, pullPostRemoteUpdates), - commands.registerCommand(`${appName}.upload-clipboard-image`, () => uploadImage(true, 'clipboard')), - commands.registerCommand(`${appName}.upload-local-disk-image`, () => uploadImage(true, 'local')), - commands.registerCommand(`${appName}.upload-image`, () => uploadImage(true)), - commands.registerCommand(`${appName}.reveal-local-post-file-in-os`, revealLocalPostFileInOs), - commands.registerCommand(`${appName}.show-post-to-local-file-info`, showLocalFileToPostInfo), - commands.registerCommand(`${appName}.new-post-category`, newPostCategory), - commands.registerCommand(`${appName}.delete-selected-post-categories`, handleDeletePostCategories), - commands.registerCommand(`${appName}.refresh-post-categories-list`, refreshPostCategoriesList), - commands.registerCommand(`${appName}.update-post-category`, handleUpdatePostCategory), - commands.registerCommand(`${appName}.delete-post-to-local-file-map`, deletePostToLocalFileMap), - commands.registerCommand(`${appName}.rename-post`, renamePost), - commands.registerCommand(`${appName}.open-post-in-blog-admin`, openPostInBlogAdmin), - commands.registerCommand(`${appName}.open-workspace`, openWorkspace), - commands.registerCommand(`${appName}.set-workspace`, setWorkspace), - commands.registerCommand(`${appName}.reveal-workspace-in-os`, revealWorkspaceInOs), - commands.registerCommand(`${appName}.view-post-online`, viewPostOnline), - commands.registerCommand(`${appName}.export-post-to-pdf`, (input: unknown) => - import('./pdf/export-pdf.command').then(m => m.exportPostToPdf(input)) - ), - commands.registerCommand(`${appName}.extract-images`, extractImages), - commands.registerCommand(`${appName}.search-posts`, searchPosts), - commands.registerCommand(`${appName}.clear-posts-search-results`, clearPostsSearchResults), - commands.registerCommand(`${appName}.refresh-posts-search-results`, refreshPostsSearchResults), - commands.registerCommand(`${appName}.copy-post-link`, input => new CopyPostLinkCommandHandler(input).handle()), - commands.registerCommand(`${appName}.ing.publish`, () => new PublishIngCommandHandler('input').handle()), - commands.registerCommand(`${appName}.ing.publish-selection`, () => - new PublishIngCommandHandler('selection').handle() - ), - ] - - registerCommandsForIngsList(disposables) - registerCommandsForBlogExport(disposables) - - context?.subscriptions.push(...disposables) -} diff --git a/src/commands/extract-images.ts b/src/commands/extract-images.ts index 48f68280..6c1066e8 100644 --- a/src/commands/extract-images.ts +++ b/src/commands/extract-images.ts @@ -1,5 +1,6 @@ import { MessageItem, MessageOptions, ProgressLocation, Range, Uri, window, workspace, WorkspaceEdit } from 'vscode' import { ImageInfo, ImageSrc, MkdImgExtractor, newImageSrcFilter } from '@/services/mkd-img-extractor.service' +import { AlertService } from '@/services/alert.service' type ExtractOption = MessageItem & Partial<{ imageSrc: ImageSrc }> @@ -16,8 +17,7 @@ export async function extractImages(arg: unknown, inputImageSrc?: ImageSrc) { const extractor = new MkdImgExtractor(markdown, arg) const images = extractor.findImages() - if (images.length <= 0) - void (!inputImageSrc != null ? window.showWarningMessage('没有找到可以提取的图片') : undefined) + if (images.length <= 0) void (!inputImageSrc != null ? AlertService.warn('没有找到可以提取的图片') : undefined) const getExtractOption = () => { const webImgCount = images.filter(newImageSrcFilter(ImageSrc.web)).length @@ -36,7 +36,7 @@ export async function extractImages(arg: unknown, inputImageSrc?: ImageSrc) { return Promise.resolve(displayOptions.find(ent => ent.imageSrc === inputImageSrc)) // if src is not specified: - return window.showInformationMessage( + return AlertService.info( '要提取哪些图片? 此操作会替换源文件中的图片链接!', { modal: true, @@ -113,6 +113,6 @@ export async function extractImages(arg: unknown, inputImageSrc?: ImageSrc) { const info = failedImages .map(info => [info.data, extractor.errors.find(([link]) => link === info.data)?.[1] ?? ''].join(',')) .join('\n') - window.showErrorMessage(`${failedImages.length} 张图片提取失败: ${info}`).then(undefined, console.warn) + AlertService.err(`${failedImages.length} 张图片提取失败: ${info}`).then(undefined, console.warn) } } diff --git a/src/commands/ing/comment-ing.ts b/src/commands/ing/comment-ing.ts index abad94ff..f0c9a90c 100644 --- a/src/commands/ing/comment-ing.ts +++ b/src/commands/ing/comment-ing.ts @@ -1,9 +1,9 @@ -import { CommandHandler } from '@/commands/command-handler' +import { CmdHandler } from '@/commands/cmd-handler' import { IngApi } from '@/services/ing.api' import { IngsListWebviewProvider } from '@/services/ings-list-webview-provider' import { ProgressLocation, window } from 'vscode' -export class CommentIngCommandHandler extends CommandHandler { +export class CommentIngCmdHandler extends CmdHandler { private _content = '' constructor( diff --git a/src/commands/ing/goto-ings-list-page.ts b/src/commands/ing/goto-ings-list-page.ts index b19e6dd4..d7e47261 100644 --- a/src/commands/ing/goto-ings-list-page.ts +++ b/src/commands/ing/goto-ings-list-page.ts @@ -1,7 +1,7 @@ -import { CommandHandler } from 'src/commands/command-handler' +import { CmdHandler } from '@/commands/cmd-handler' import { IngsListWebviewProvider } from 'src/services/ings-list-webview-provider' -export class GotoIngsListNextPage extends CommandHandler { +export class GotoIngsListNextPage extends CmdHandler { handle(): Promise { const provider = IngsListWebviewProvider.ensureRegistered() const { pageIndex } = provider @@ -9,7 +9,7 @@ export class GotoIngsListNextPage extends CommandHandler { } } -export class GotoIngsListPreviousPage extends CommandHandler { +export class GotoIngsListPreviousPage extends CmdHandler { handle(): Promise { const provider = IngsListWebviewProvider.ensureRegistered() const { pageIndex } = provider @@ -18,7 +18,7 @@ export class GotoIngsListPreviousPage extends CommandHandler { } } -export class GotoIngsListFirstPage extends CommandHandler { +export class GotoIngsListFirstPage extends CmdHandler { handle(): Promise { return IngsListWebviewProvider.ensureRegistered().refreshIngsList({ pageIndex: 1 }) } diff --git a/src/commands/ing/ings-list-cmd-register.ts b/src/commands/ing/ings-list-cmd-register.ts new file mode 100644 index 00000000..892e9a79 --- /dev/null +++ b/src/commands/ing/ings-list-cmd-register.ts @@ -0,0 +1,23 @@ +import { RefreshIngsList } from 'src/commands/ing/refresh-ings-list' +import { globalCtx } from 'src/services/global-ctx' +import { + GotoIngsListFirstPage, + GotoIngsListNextPage, + GotoIngsListPreviousPage, +} from 'src/commands/ing/goto-ings-list-page' +import { SelectIngType } from '@/commands/ing/select-ing-type' +import { OpenIngInBrowser } from '@/commands/ing/open-ing-in-browser' +import { regCmd } from '@/utils/cmd' + +export const regIngListCmds = () => { + const appName = globalCtx.extName + + return [ + regCmd(`${appName}.ings-list.refresh`, () => new RefreshIngsList().handle()), + regCmd(`${appName}.ings-list.next`, () => new GotoIngsListNextPage().handle()), + regCmd(`${appName}.ings-list.previous`, () => new GotoIngsListPreviousPage().handle()), + regCmd(`${appName}.ings-list.first`, () => new GotoIngsListFirstPage().handle()), + regCmd(`${appName}.ings-list.select-type`, () => new SelectIngType().handle()), + regCmd(`${appName}.ings-list.open-in-browser`, () => new OpenIngInBrowser().handle()), + ] +} diff --git a/src/commands/ing/ings-list-commands-registration.ts b/src/commands/ing/ings-list-commands-registration.ts deleted file mode 100644 index 8beb4056..00000000 --- a/src/commands/ing/ings-list-commands-registration.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { commands } from 'vscode' -import { RefreshIngsList } from 'src/commands/ing/refresh-ings-list' -import { globalCtx } from 'src/services/global-ctx' -import { IDisposable } from '@fluentui/react' -import { - GotoIngsListFirstPage, - GotoIngsListNextPage, - GotoIngsListPreviousPage, -} from 'src/commands/ing/goto-ings-list-page' -import { SelectIngType } from '@/commands/ing/select-ing-type' -import { OpenIngInBrowser } from '@/commands/ing/open-ing-in-browser' - -export const registerCommandsForIngsList = (disposables: IDisposable[]) => { - const appName = globalCtx.extName - - disposables.push( - ...[ - commands.registerCommand(`${appName}.ings-list.refresh`, () => new RefreshIngsList().handle()), - commands.registerCommand(`${appName}.ings-list.next`, () => new GotoIngsListNextPage().handle()), - commands.registerCommand(`${appName}.ings-list.previous`, () => new GotoIngsListPreviousPage().handle()), - commands.registerCommand(`${appName}.ings-list.first`, () => new GotoIngsListFirstPage().handle()), - commands.registerCommand(`${appName}.ings-list.select-type`, () => new SelectIngType().handle()), - commands.registerCommand(`${appName}.ings-list.open-in-browser`, () => new OpenIngInBrowser().handle()), - ] - ) -} diff --git a/src/commands/ing/open-ing-in-browser.ts b/src/commands/ing/open-ing-in-browser.ts index c0107a28..fdc68b7c 100644 --- a/src/commands/ing/open-ing-in-browser.ts +++ b/src/commands/ing/open-ing-in-browser.ts @@ -1,9 +1,10 @@ -import { CommandHandler } from '@/commands/command-handler' +import { CmdHandler } from '@/commands/cmd-handler' +import { execCmd } from '@/utils/cmd' import { globalCtx } from '@/services/global-ctx' -import { commands, Uri } from 'vscode' +import { Uri } from 'vscode' -export class OpenIngInBrowser extends CommandHandler { +export class OpenIngInBrowser extends CmdHandler { async handle(): Promise { - await commands.executeCommand('vscode.open', Uri.parse(globalCtx.config.ingSite)) + await execCmd('vscode.open', Uri.parse(globalCtx.config.ingSite)) } } diff --git a/src/commands/ing/publish-ing.ts b/src/commands/ing/publish-ing.ts index 51aafd59..955ecd49 100644 --- a/src/commands/ing/publish-ing.ts +++ b/src/commands/ing/publish-ing.ts @@ -1,13 +1,14 @@ -import { CommandHandler } from '@/commands/command-handler' +import { CmdHandler } from '@/commands/cmd-handler' +import { execCmd } from '@/utils/cmd' import { IngPublishModel, IngType } from '@/models/ing' import { AlertService } from '@/services/alert.service' import { globalCtx } from '@/services/global-ctx' import { IngApi } from '@/services/ing.api' import { IngsListWebviewProvider } from '@/services/ings-list-webview-provider' import { InputStep, MultiStepInput, QuickPickParameters } from '@/services/multi-step-input' -import { commands, MessageOptions, ProgressLocation, QuickPickItem, Uri, window } from 'vscode' +import { MessageOptions, ProgressLocation, QuickPickItem, Uri, window } from 'vscode' -export class PublishIngCommandHandler extends CommandHandler { +export class PublishIngCmdHandler extends CmdHandler { readonly maxLength = 0 readonly operation = '发布闪存' readonly editingText = '编辑闪存' @@ -133,7 +134,7 @@ export class PublishIngCommandHandler extends CommandHandler { ['编辑访问权限', async () => (await this.acquireInputContent(this.inputStep.access)) !== false], ['编辑标签', async () => (await this.acquireInputContent(this.inputStep.tags)) !== false], ] as const - const selected = await window.showInformationMessage( + const selected = await AlertService.info( '确定要发布闪存吗?', { modal: true, @@ -159,27 +160,22 @@ export class PublishIngCommandHandler extends CommandHandler { } const options = [ - [ - '打开闪存', - (): Thenable => commands.executeCommand('vscode.open', Uri.parse(globalCtx.config.ingSite)), - ], + ['打开闪存', (): Thenable => execCmd('vscode.open', Uri.parse(globalCtx.config.ingSite))], [ '我的闪存', - (): Thenable => - commands.executeCommand('vscode.open', Uri.parse(globalCtx.config.ingSite + '/#my')), + (): Thenable => execCmd('vscode.open', Uri.parse(globalCtx.config.ingSite + '/#my')), ], [ '新回应', (): Thenable => - commands.executeCommand('vscode.open', Uri.parse(globalCtx.config.ingSite + '/#recentcomment')), + execCmd('vscode.open', Uri.parse(globalCtx.config.ingSite + '/#recentcomment')), ], [ '提到我', - (): Thenable => - commands.executeCommand('vscode.open', Uri.parse(globalCtx.config.ingSite + '/#mention')), + (): Thenable => execCmd('vscode.open', Uri.parse(globalCtx.config.ingSite + '/#mention')), ], ] as const - const option = await window.showInformationMessage( + const option = await AlertService.info( '闪存已发布, 快去看看吧', { modal: false }, ...options.map(v => ({ title: v[0], id: v[0] })) diff --git a/src/commands/ing/refresh-ings-list.ts b/src/commands/ing/refresh-ings-list.ts index a38505db..711710fc 100644 --- a/src/commands/ing/refresh-ings-list.ts +++ b/src/commands/ing/refresh-ings-list.ts @@ -1,7 +1,7 @@ -import { CommandHandler } from 'src/commands/command-handler' +import { CmdHandler } from '@/commands/cmd-handler' import { IngsListWebviewProvider } from 'src/services/ings-list-webview-provider' -export class RefreshIngsList extends CommandHandler { +export class RefreshIngsList extends CmdHandler { handle(): Promise { return IngsListWebviewProvider.ensureRegistered().refreshIngsList() } diff --git a/src/commands/ing/select-ing-type.ts b/src/commands/ing/select-ing-type.ts index 63cc6733..1b1ac4df 100644 --- a/src/commands/ing/select-ing-type.ts +++ b/src/commands/ing/select-ing-type.ts @@ -1,10 +1,10 @@ -import { CommandHandler } from '@/commands/command-handler' +import { CmdHandler } from '@/commands/cmd-handler' import { IngType, IngTypesMetadata } from '@/models/ing' import { IngsListWebviewProvider } from '@/services/ings-list-webview-provider' import { IDisposable } from '@fluentui/react' import { QuickPickItem, window } from 'vscode' -export class SelectIngType extends CommandHandler { +export class SelectIngType extends CmdHandler { handle(): Promise { const { ingType: curIngType } = IngsListWebviewProvider.ensureRegistered() const options: (QuickPickItem & { ingType: IngType })[] = IngTypesMetadata.map( diff --git a/src/commands/open-my-account-settings.ts b/src/commands/open-my-account-settings.ts index 9730f91e..059194d0 100644 --- a/src/commands/open-my-account-settings.ts +++ b/src/commands/open-my-account-settings.ts @@ -1,4 +1,5 @@ import vscode from 'vscode' +import { execCmd } from '@/utils/cmd' export const openMyAccountSettings = () => - vscode.commands.executeCommand('vscode.open', vscode.Uri.parse('https://account.cnblogs.com/settings/account')) + execCmd('vscode.open', vscode.Uri.parse('https://account.cnblogs.com/settings/account')) diff --git a/src/commands/open-my-blog-console.ts b/src/commands/open-my-blog-console.ts new file mode 100644 index 00000000..c14e9d88 --- /dev/null +++ b/src/commands/open-my-blog-console.ts @@ -0,0 +1,4 @@ +import vscode from 'vscode' + +export const openMyWebBlogConsole = () => execCmd('vscode.open', vscode.Uri.parse('https://i.cnblogs.com')) +import { execCmd } from '@/utils/cmd' diff --git a/src/commands/open-my-blog-management-background.ts b/src/commands/open-my-blog-management-background.ts deleted file mode 100644 index a210554b..00000000 --- a/src/commands/open-my-blog-management-background.ts +++ /dev/null @@ -1,4 +0,0 @@ -import vscode from 'vscode' - -export const openMyWebBlogConsole = () => - vscode.commands.executeCommand('vscode.open', vscode.Uri.parse('https://i.cnblogs.com')) diff --git a/src/commands/open-my-blog.ts b/src/commands/open-my-blog.ts index a7f4a00b..93dc2c74 100644 --- a/src/commands/open-my-blog.ts +++ b/src/commands/open-my-blog.ts @@ -1,7 +1,8 @@ import { accountManager } from '@/auth/account-manager' import vscode from 'vscode' +import { execCmd } from '@/utils/cmd' export const openMyBlog = () => { const userBlogUrl = accountManager.currentUser?.website - if (userBlogUrl) return vscode.commands.executeCommand('vscode.open', vscode.Uri.parse(userBlogUrl)) + if (userBlogUrl) return execCmd('vscode.open', vscode.Uri.parse(userBlogUrl)) } diff --git a/src/commands/open-my-home-page.ts b/src/commands/open-my-home-page.ts index feae1216..2d4664aa 100644 --- a/src/commands/open-my-home-page.ts +++ b/src/commands/open-my-home-page.ts @@ -1,4 +1,5 @@ import { accountManager } from '@/auth/account-manager' +import { execCmd } from '@/utils/cmd' import vscode from 'vscode' export const openMyHomePage = () => { @@ -6,5 +7,5 @@ export const openMyHomePage = () => { if (!accountId || accountId <= 0) return const userHomePageUrl = `https://home.cnblogs.com/u/${accountId}` - if (userHomePageUrl) void vscode.commands.executeCommand('vscode.open', vscode.Uri.parse(userHomePageUrl)) + if (userHomePageUrl) void execCmd('vscode.open', vscode.Uri.parse(userHomePageUrl)) } diff --git a/src/commands/open-post-in-blog-admin.ts b/src/commands/open-post-in-blog-admin.ts index 593ec30e..32f3dba0 100644 --- a/src/commands/open-post-in-blog-admin.ts +++ b/src/commands/open-post-in-blog-admin.ts @@ -1,4 +1,5 @@ -import { commands, Uri } from 'vscode' +import { Uri } from 'vscode' +import { execCmd } from '@/utils/cmd' import { Post } from '@/models/post' import { PostFileMapManager } from '@/services/post-file-map' import { PostTreeItem } from '@/tree-view-providers/models/post-tree-item' @@ -9,5 +10,5 @@ export const openPostInBlogAdmin = (item: Post | PostTreeItem | Uri) => { item = item instanceof PostTreeItem ? item.post : item const postId = item instanceof Post ? item.id : PostFileMapManager.getPostId(item.fsPath) ?? -1 - void commands.executeCommand('vscode.open', Uri.parse(`https://i.cnblogs.com/posts/edit;postId=${postId}`)) + void execCmd('vscode.open', Uri.parse(`https://i.cnblogs.com/posts/edit;postId=${postId}`)) } diff --git a/src/commands/open-workspace.ts b/src/commands/open-workspace.ts index e7fd9562..0104111d 100644 --- a/src/commands/open-workspace.ts +++ b/src/commands/open-workspace.ts @@ -1,18 +1,16 @@ -import { commands, MessageOptions, window } from 'vscode' +import { MessageOptions } from 'vscode' import { Settings } from '@/services/settings.service' +import { execCmd } from '@/utils/cmd' +import { AlertService } from '@/services/alert.service' export const openWorkspace = async () => { const uri = Settings.workspaceUri const { fsPath } = uri const options = ['在当前窗口中打开', '在新窗口中打开'] - const input = await window.showInformationMessage( - `即将打开 ${fsPath}`, - { modal: true } as MessageOptions, - ...options - ) + const input = await AlertService.info(`即将打开 ${fsPath}`, { modal: true } as MessageOptions, ...options) if (!input) return const shouldOpenInNewWindow = input === options[1] - await commands.executeCommand('vscode.openFolder', uri, shouldOpenInNewWindow) + await execCmd('vscode.openFolder', uri, shouldOpenInNewWindow) } diff --git a/src/commands/pdf/export-pdf.command.ts b/src/commands/pdf/export-pdf.command.ts index f4c12c7f..e2180db2 100644 --- a/src/commands/pdf/export-pdf.command.ts +++ b/src/commands/pdf/export-pdf.command.ts @@ -6,7 +6,7 @@ import { MessageOptions, Progress, ProgressLocation, Uri, window, workspace } fr import { Post } from '@/models/post' import { PostFileMapManager } from '@/services/post-file-map' import { PostService } from '@/services/post.service' -import { extensionViews } from '@/tree-view-providers/tree-view-registration' +import { extViews } from '@/tree-view-providers/tree-view-registration' import { chromiumPathProvider } from '@/utils/chromium-path-provider' import { Settings } from '@/services/settings.service' import { accountManager } from '@/auth/account-manager' @@ -114,7 +114,7 @@ const retrieveChromiumPath = async (): Promise => { if (!path) { const { Options: options } = chromiumPathProvider - const input = await window.showWarningMessage( + const input = await AlertService.warn( '未找到Chromium可执行文件', { modal: true, @@ -140,7 +140,7 @@ const inputTargetFolder = async (): Promise => const handlePostInput = (post: Post | PostTreeItem): Promise => { const posts: Post[] = [post instanceof PostTreeItem ? post.post : post] - extensionViews.visiblePostsList()?.selection.map(item => { + extViews.visiblePostsList()?.selection.map(item => { item = item instanceof PostTreeItem ? item.post : item if (item instanceof Post && !posts.includes(item)) posts.push(item) }) @@ -175,7 +175,7 @@ const mapToPostEditDto = async (posts: Post[]) => const reportErrors = (errors: string[] | undefined) => { if (errors && errors.length > 0) { - void window.showErrorMessage('导出 PDF 时遇到错误', { + void AlertService.err('导出 PDF 时遇到错误', { modal: true, detail: errors.join('\n'), } as MessageOptions) @@ -192,7 +192,7 @@ const exportPostToPdf = async (input: Post | PostTreeItem | Uri | unknown): Prom currentUser: { blogApp }, } = accountManager - if (!blogApp) return AlertService.warn('无法获取到博客地址, 请检查登录状态') + if (!blogApp) return void AlertService.warn('无法获取到博客地址, 请检查登录状态') reportErrors( await window.withProgress( diff --git a/src/commands/post-category/base-tree-view-command-handler.ts b/src/commands/post-category/base-tree-view-cmd-handler.ts similarity index 74% rename from src/commands/post-category/base-tree-view-command-handler.ts rename to src/commands/post-category/base-tree-view-cmd-handler.ts index 5c1da191..d649d3c0 100644 --- a/src/commands/post-category/base-tree-view-command-handler.ts +++ b/src/commands/post-category/base-tree-view-cmd-handler.ts @@ -1,11 +1,11 @@ import { PostCategory } from '@/models/post-category' import { PostCategoriesListTreeItem } from '@/tree-view-providers/models/categories-list-tree-item' import { PostCategoryTreeItem } from '@/tree-view-providers/models/post-category-tree-item' -import { extensionViews } from '@/tree-view-providers/tree-view-registration' -import { MultiSelectableTreeViewCommandHandler, TreeViewCommandHandler } from '../command-handler' +import { extViews } from '@/tree-view-providers/tree-view-registration' +import { MultiSelectableTreeViewCmdHandler, TreeViewCmdHandler } from '../cmd-handler' -export abstract class BasePostCategoryTreeViewCommandHandler implements TreeViewCommandHandler { - protected readonly view = extensionViews.postCategoriesList +export abstract class BasePostCategoryTreeViewCmdHandler implements TreeViewCmdHandler { + protected readonly view = extViews.postCategoriesList constructor(public readonly input: unknown) {} @@ -23,12 +23,12 @@ export abstract class BasePostCategoryTreeViewCommandHandler implements TreeView abstract handle(): void | Promise } -export abstract class BaseMultiSelectablePostCategoryTreeViewCommandHandler extends MultiSelectableTreeViewCommandHandler< +export abstract class BaseMultiSelectablePostCategoryTreeViewCmdHandler extends MultiSelectableTreeViewCmdHandler< PostCategoriesListTreeItem, PostCategory > { protected get view() { - return extensionViews.postCategoriesList + return extViews.postCategoriesList } protected parseSelections() { diff --git a/src/commands/post-category/delete-selected-categories.ts b/src/commands/post-category/delete-selected-categories.ts index b49761b9..9f08622a 100644 --- a/src/commands/post-category/delete-selected-categories.ts +++ b/src/commands/post-category/delete-selected-categories.ts @@ -2,10 +2,11 @@ import { MessageOptions, ProgressLocation, window } from 'vscode' import { PostCategory } from '@/models/post-category' import { postCategoryService } from '@/services/post-category.service' import { PostCategoriesListTreeItem } from '@/tree-view-providers/models/categories-list-tree-item' -import { BaseMultiSelectablePostCategoryTreeViewCommandHandler } from './base-tree-view-command-handler' +import { BaseMultiSelectablePostCategoryTreeViewCmdHandler } from './base-tree-view-cmd-handler' import { refreshPostCategoriesList } from './refresh-post-categories-list' +import { AlertService } from '@/services/alert.service' -export class DeletePostCategoriesHandler extends BaseMultiSelectablePostCategoryTreeViewCommandHandler { +export class DeletePostCategoriesHandler extends BaseMultiSelectablePostCategoryTreeViewCmdHandler { constructor(input: PostCategoriesListTreeItem) { super(input) } @@ -44,7 +45,7 @@ export class DeletePostCategoriesHandler extends BaseMultiSelectablePostCategory p.report({ increment: 100 }) if (errs.length > 0) { - await window.showErrorMessage('删除博文分类时发生了一些错误', { + await AlertService.err('删除博文分类时发生了一些错误', { detail: errs .map( err => @@ -62,7 +63,7 @@ export class DeletePostCategoriesHandler extends BaseMultiSelectablePostCategory private async confirm() { const options = ['确定'] - const clicked = await window.showWarningMessage( + const clicked = await AlertService.warn( '确定要删除这些博文分类吗', { detail: `${this.selections.map(x => `📂${x.title}`).join(', ')} 将被永久删除! 请谨慎操作!`, diff --git a/src/commands/post-category/new-post-category.ts b/src/commands/post-category/new-post-category.ts index 37127907..2a9c923b 100644 --- a/src/commands/post-category/new-post-category.ts +++ b/src/commands/post-category/new-post-category.ts @@ -1,8 +1,9 @@ import { MessageOptions, ProgressLocation, window } from 'vscode' import { postCategoryService } from '@/services/post-category.service' -import { extensionViews } from '@/tree-view-providers/tree-view-registration' +import { extViews } from '@/tree-view-providers/tree-view-registration' import { inputPostCategory } from './input-post-category' import { refreshPostCategoriesList } from './refresh-post-categories-list' +import { AlertService } from '@/services/alert.service' export const newPostCategory = async () => { const input = await inputPostCategory({ @@ -26,9 +27,9 @@ export const newPostCategory = async () => { }) refreshPostCategoriesList() const newCategory = (await postCategoryService.listCategories()).find(x => x.title === input.title) - if (newCategory) await extensionViews.postCategoriesList.reveal(newCategory) + if (newCategory) await extViews.postCategoriesList.reveal(newCategory) } catch (err) { - void window.showErrorMessage('新建博文分类时遇到了错误', { + void AlertService.err('新建博文分类时遇到了错误', { modal: true, detail: `服务器反回了错误\n${err instanceof Error ? err.message : JSON.stringify(err)}`, } as MessageOptions) diff --git a/src/commands/post-category/update-post-category.ts b/src/commands/post-category/update-post-category.ts index 62e653bb..9d655170 100644 --- a/src/commands/post-category/update-post-category.ts +++ b/src/commands/post-category/update-post-category.ts @@ -5,9 +5,9 @@ import { postCategoryService } from '@/services/post-category.service' import { inputPostCategory } from './input-post-category' import { refreshPostCategoriesList } from './refresh-post-categories-list' import { Settings } from '@/services/settings.service' -import { BasePostCategoryTreeViewCommandHandler } from './base-tree-view-command-handler' +import { BasePostCategoryTreeViewCmdHandler } from './base-tree-view-cmd-handler' -class UpdatePostCategoryTreeViewCommandHandler extends BasePostCategoryTreeViewCommandHandler { +class UpdatePostCategoryTreeViewCmdHandler extends BasePostCategoryTreeViewCmdHandler { async handle(): Promise { const category = this.parseInput() if (category == null) return @@ -60,4 +60,4 @@ class UpdatePostCategoryTreeViewCommandHandler extends BasePostCategoryTreeViewC } } -export const handleUpdatePostCategory = (arg: unknown) => new UpdatePostCategoryTreeViewCommandHandler(arg).handle() +export const handleUpdatePostCategory = (arg: unknown) => new UpdatePostCategoryTreeViewCmdHandler(arg).handle() diff --git a/src/commands/posts-list/copy-link.ts b/src/commands/posts-list/copy-link.ts index 28fb51f2..5502d346 100644 --- a/src/commands/posts-list/copy-link.ts +++ b/src/commands/posts-list/copy-link.ts @@ -1,4 +1,4 @@ -import { TreeViewCommandHandler } from '@/commands/command-handler' +import { TreeViewCmdHandler } from '@/commands/cmd-handler' import { Post } from '@/models/post' import { AlertService } from '@/services/alert.service' import { PostFileMapManager } from '@/services/post-file-map' @@ -12,7 +12,7 @@ interface CopyStrategy { provideContent: (post: Post) => Thenable } -export class CopyPostLinkCommandHandler extends TreeViewCommandHandler> { +export class CopyPostLinkCmdHandler extends TreeViewCmdHandler> { private readonly _strategies: { [key in LinkFormat]: CopyStrategy } = { raw: { name: '复制链接', diff --git a/src/commands/posts-list/delete-post-to-local-file-map.ts b/src/commands/posts-list/delete-post-to-local-file-map.ts index 8ffdbef0..0f2b861e 100644 --- a/src/commands/posts-list/delete-post-to-local-file-map.ts +++ b/src/commands/posts-list/delete-post-to-local-file-map.ts @@ -3,11 +3,12 @@ import { Post } from '@/models/post' import { PostFileMap, PostFileMapManager } from '@/services/post-file-map' import { revealPostsListItem } from '@/services/posts-list-view' import { PostTreeItem } from '@/tree-view-providers/models/post-tree-item' -import { extensionViews } from '@/tree-view-providers/tree-view-registration' +import { extViews } from '@/tree-view-providers/tree-view-registration' +import { AlertService } from '@/services/alert.service' const confirm = async (posts: Post[]): Promise => { const options = ['确定'] - const input = await window.showInformationMessage( + const input = await AlertService.info( '确定要取消这些博文与本地文件的关联吗?', { detail: posts.map(x => x.title).join(', '), @@ -20,7 +21,7 @@ const confirm = async (posts: Post[]): Promise => { export const deletePostToLocalFileMap = async (post: Post | PostTreeItem) => { post = post instanceof PostTreeItem ? post.post : post - const view = extensionViews.postsList + const view = extViews.postsList let selectedPosts = view.selection .map(x => (x instanceof Post ? x : x instanceof PostTreeItem ? x.post : null)) .filter((x): x is Post => x != null) diff --git a/src/commands/posts-list/delete-post.ts b/src/commands/posts-list/delete-post.ts index 0536dd30..cd204ab7 100644 --- a/src/commands/posts-list/delete-post.ts +++ b/src/commands/posts-list/delete-post.ts @@ -4,7 +4,7 @@ import { AlertService } from '@/services/alert.service' import { PostService } from '@/services/post.service' import { PostFileMap, PostFileMapManager } from '@/services/post-file-map' import { postsDataProvider } from '@/tree-view-providers/posts-data-provider' -import { extensionViews } from '@/tree-view-providers/tree-view-registration' +import { extViews } from '@/tree-view-providers/tree-view-registration' import { refreshPostsList } from './refresh-posts-list' import { PostTreeItem } from '@/tree-view-providers/models/post-tree-item' import { postCategoriesDataProvider } from '@/tree-view-providers/post-categories-tree-data-provider' @@ -18,7 +18,7 @@ const confirmDelete = async ( if (!selectedPosts || selectedPosts.length <= 0) return result const items = ['确定(保留本地文件)', '确定(同时删除本地文件)'] - const clicked = await window.showWarningMessage( + const clicked = await AlertService.warn( '确定要删除吗?', { detail: `确认后将会删除 ${selectedPosts.map(x => x.title).join(', ')} 这${selectedPosts.length}篇博文吗?`, @@ -45,7 +45,7 @@ export const deleteSelectedPosts = async (arg: unknown) => { else return const selectedPosts: Post[] = post ? [post] : [] - extensionViews.visiblePostsList()?.selection.map(item => { + extViews.visiblePostsList()?.selection.map(item => { const post = item instanceof PostTreeItem ? item.post : item if (post instanceof Post && !selectedPosts.includes(post)) { postsDataProvider.pagedPosts?.items.find(item => item === post) @@ -91,7 +91,7 @@ export const deleteSelectedPosts = async (arg: unknown) => { postIds: selectedPosts.map(({ id }) => id), }) } catch (err) { - void window.showErrorMessage('删除博文失败', { + void AlertService.err('删除博文失败', { detail: `服务器返回了错误, ${err instanceof Error ? err.message : JSON.stringify(err)}`, } as MessageOptions) } finally { diff --git a/src/commands/posts-list/modify-post-settings.ts b/src/commands/posts-list/modify-post-settings.ts index cd1002f7..eaa0b653 100644 --- a/src/commands/posts-list/modify-post-settings.ts +++ b/src/commands/posts-list/modify-post-settings.ts @@ -4,7 +4,7 @@ import { AlertService } from '@/services/alert.service' import { PostService } from '@/services/post.service' import { PostFileMapManager } from '@/services/post-file-map' import { revealPostsListItem } from '@/services/posts-list-view' -import { postConfigurationPanel } from '@/services/post-configuration-panel.service' +import { PostCfgPanel } from '@/services/post-cfg-panel.service' import fs from 'fs' import { LocalDraft } from '@/services/local-draft.service' import { saveFilePendingChanges } from '@/utils/save-file-pending-changes' @@ -34,7 +34,7 @@ export const modifyPostSettings = async (input: Post | PostTreeItem | Uri) => { const postEditDto = editDto.post const localFilePath = PostFileMapManager.getFilePath(postId) - await postConfigurationPanel.open({ + await PostCfgPanel.open({ panelTitle: '', breadcrumbs: ['更新博文设置', editDto.post.title], post: postEditDto, diff --git a/src/commands/posts-list/open-post-file.ts b/src/commands/posts-list/open-post-file.ts index 596490c6..a11cac37 100644 --- a/src/commands/posts-list/open-post-file.ts +++ b/src/commands/posts-list/open-post-file.ts @@ -1,4 +1,5 @@ -import { commands, TextDocumentShowOptions, Uri } from 'vscode' +import { TextDocumentShowOptions, Uri } from 'vscode' +import { execCmd } from '@/utils/cmd' import { Post } from '@/models/post' import { LocalDraft } from '@/services/local-draft.service' import { PostFileMapManager } from '@/services/post-file-map' @@ -11,7 +12,7 @@ export const openPostFile = async (post: LocalDraft | Post | string, options?: T if (!filePath) return - await commands.executeCommand( + await execCmd( 'vscode.open', Uri.file(filePath), Object.assign({ preview: false } as TextDocumentShowOptions, options ?? {}) diff --git a/src/commands/posts-list/open-post-in-vscode.ts b/src/commands/posts-list/open-post-in-vscode.ts index 6c5d12b4..efa8c1b9 100644 --- a/src/commands/posts-list/open-post-in-vscode.ts +++ b/src/commands/posts-list/open-post-in-vscode.ts @@ -68,7 +68,7 @@ export const openPostInVscode = async (postId: number, forceUpdateLocalPostFile '保留本地文件(这会新建另一个文件名中包含博文id的文件)', '覆盖本地文件(会导致本地文件中内容丢失)', ] - const selectedOption = await window.showInformationMessage( + const selectedOption = await AlertService.info( `无法新建博文与本地文件的关联, 文件名冲突`, { detail: `本地已存在名为"${path.basename(fileUri.fsPath)}"的文件`, modal: true } as MessageOptions, ...conflictOptions diff --git a/src/commands/posts-list/refresh-posts-list.ts b/src/commands/posts-list/refresh-posts-list.ts index 23462f83..5216cff2 100644 --- a/src/commands/posts-list/refresh-posts-list.ts +++ b/src/commands/posts-list/refresh-posts-list.ts @@ -4,7 +4,8 @@ import vscode, { window } from 'vscode' import { postsDataProvider } from '@/tree-view-providers/posts-data-provider' import { AlertService } from '@/services/alert.service' import { PostsListState } from '@/models/posts-list-state' -import { extensionViews } from '@/tree-view-providers/tree-view-registration' +import { extViews } from '@/tree-view-providers/tree-view-registration' +import { execCmd } from '@/utils/cmd' let refreshTask: Promise | null = null @@ -79,17 +80,15 @@ export const seekPostsList = async () => { let isRefreshing = false const setRefreshing = async (value = false) => { const extName = globalCtx.extName - await vscode.commands - .executeCommand('setContext', `${extName}.posts-list.refreshing`, value) - .then(undefined, () => false) + await execCmd('setContext', `${extName}.posts-list.refreshing`, value).then(undefined, () => false) isRefreshing = value } const setPostListContext = async (pageCount: number, hasPrevious: boolean, hasNext: boolean) => { const extName = globalCtx.extName - await vscode.commands.executeCommand('setContext', `${extName}.posts-list.hasPrevious`, hasPrevious) - await vscode.commands.executeCommand('setContext', `${extName}.posts-list.hasNext`, hasNext) - await vscode.commands.executeCommand('setContext', `${extName}.posts-list.pageCount`, pageCount) + await execCmd('setContext', `${extName}.posts-list.hasPrevious`, hasPrevious) + await execCmd('setContext', `${extName}.posts-list.hasNext`, hasNext) + await execCmd('setContext', `${extName}.posts-list.pageCount`, pageCount) } const alertRefreshing = () => { @@ -125,7 +124,7 @@ const updatePostsListViewTitle = () => { if (!state) return const { pageIndex, pageCount } = state - const views = [extensionViews.postsList, extensionViews.anotherPostsList] + const views = [extViews.postsList, extViews.anotherPostsList] for (const view of views) { let title = view.title ?? '' const idx = title.indexOf('(') diff --git a/src/commands/posts-list/rename-post.ts b/src/commands/posts-list/rename-post.ts index ec0d4d0b..0c752ad3 100644 --- a/src/commands/posts-list/rename-post.ts +++ b/src/commands/posts-list/rename-post.ts @@ -7,6 +7,7 @@ import { PostFileMapManager } from '@/services/post-file-map' import { postsDataProvider } from '@/tree-view-providers/posts-data-provider' import { revealPostsListItem } from '@/services/posts-list-view' import { PostTreeItem } from '@/tree-view-providers/models/post-tree-item' +import { AlertService } from '@/services/alert.service' const renameLinkedFile = async (post: Post): Promise => { const filePath = PostFileMapManager.getFilePath(post.id) @@ -16,7 +17,7 @@ const renameLinkedFile = async (post: Post): Promise => { const fileUri = Uri.file(filePath) const options = ['是'] - const input = await window.showInformationMessage( + const input = await AlertService.info( '重命名博文成功, 发现与博文关联的本地文件, 是否要重名本地文件', { modal: true, @@ -69,7 +70,7 @@ export const renamePost = async (arg: Post | PostTreeItem) => { postsDataProvider.fireTreeDataChangedEvent(post) hasUpdated = true } catch (err) { - void window.showErrorMessage('更新博文失败', { + void AlertService.err('更新博文失败', { modal: true, detail: err instanceof Error ? err.message : '服务器返回异常', } as MessageOptions) diff --git a/src/commands/posts-list/upload-post.ts b/src/commands/posts-list/upload-post.ts index ab95bd59..751af008 100644 --- a/src/commands/posts-list/upload-post.ts +++ b/src/commands/posts-list/upload-post.ts @@ -11,7 +11,7 @@ import { searchPostsByTitle } from '@/services/search-post-by-title' import * as path from 'path' import { refreshPostsList } from './refresh-posts-list' import { PostEditDto } from '@/models/post-edit-dto' -import { postConfigurationPanel } from '@/services/post-configuration-panel.service' +import { PostCfgPanel } from '@/services/post-cfg-panel.service' import { saveFilePendingChanges } from '@/utils/save-file-pending-changes' import { extractImages } from '../extract-images' import { Settings } from '@/services/settings.service' @@ -44,7 +44,7 @@ export const uploadPostFileToCnblogs = async (fileUri: Uri | undefined) => { await uploadPostToCnblogs(await PostService.fetchPostEditDto(postId)) } else { const options = [`新建博文`, `关联已有博文`] - const selected = await window.showInformationMessage( + const selected = await AlertService.info( '本地文件尚未关联到博客园博文', { modal: true, @@ -94,7 +94,7 @@ export const saveLocalDraftToCnblogs = async (localDraft: LocalDraft) => { post.title = localDraft.fileNameWithoutExt post.isMarkdown = true post.categoryIds ??= [] - void postConfigurationPanel.open({ + void PostCfgPanel.open({ panelTitle: '', localFileUri: localDraft.filePathUri, breadcrumbs: ['新建博文', '博文设置', post.title], @@ -148,7 +148,7 @@ export const uploadPostToCnblogs = async (input: Post | PostTreeItem | PostEditD if (!validatePost(post)) return false if (Settings.showConfirmMsgWhenUploadPost) { - const answer = await vscode.window.showWarningMessage( + const answer = await AlertService.warn( '确认上传吗?', { modal: true, diff --git a/src/commands/pull-post-remote-updates.ts b/src/commands/pull-post-remote-updates.ts index 18b48517..0f1b5543 100644 --- a/src/commands/pull-post-remote-updates.ts +++ b/src/commands/pull-post-remote-updates.ts @@ -11,14 +11,14 @@ import { PostTreeItem } from '@/tree-view-providers/models/post-tree-item' import { Settings } from '@/services/settings.service' const pullPostRemoteUpdates = async (input: Post | PostTreeItem | Uri | undefined | null): Promise => { - const ctxs: CommandContext[] = [] + const ctxs: CmdCtx[] = [] let uri: Uri | undefined input = input instanceof PostTreeItem ? input.post : input if (parsePostInput(input) && input.id > 0) await handlePostInput(input, ctxs) else if ((uri = parseUriInput(input))) await handleUriInput(uri, ctxs) if (Settings.showConfirmMsgWhenPullPost) { - const answer = await window.showWarningMessage( + const answer = await AlertService.warn( '确认要拉取远程博文吗?', { modal: true, @@ -39,11 +39,11 @@ const pullPostRemoteUpdates = async (input: Post | PostTreeItem | Uri | undefine export { pullPostRemoteUpdates } type InputType = Post | Uri | undefined | null -type CommandContext = { postId: number; fileUri: Uri } +type CmdCtx = { postId: number; fileUri: Uri } const parsePostInput = (input: InputType): input is Post => input instanceof Post -const handlePostInput = async (post: Post, contexts: CommandContext[]) => { +const handlePostInput = async (post: Post, contexts: CmdCtx[]) => { const { id: postId } = post let filePath = PostFileMapManager.getFilePath(postId) if (filePath && !fs.existsSync(filePath)) { @@ -68,7 +68,7 @@ const parseUriInput = (input: InputType): Uri | undefined => { if (document && !document.isUntitled) return document.uri } -const handleUriInput = (fileUri: Uri, contexts: CommandContext[]): Promise => { +const handleUriInput = (fileUri: Uri, contexts: CmdCtx[]): Promise => { const postId = PostFileMapManager.getPostId(fileUri.fsPath) if (!postId) return Promise.resolve().then(() => AlertService.fileNotLinkedToPost(fileUri)) @@ -76,7 +76,7 @@ const handleUriInput = (fileUri: Uri, contexts: CommandContext[]): Promise return Promise.resolve() } -const update = async (contexts: CommandContext[]) => { +const update = async (contexts: CmdCtx[]) => { for (const ctx of contexts) { const { fileUri, postId } = ctx const { post } = (await PostService.fetchPostEditDto(postId)) ?? {} @@ -88,4 +88,4 @@ const update = async (contexts: CommandContext[]) => { } } -const resolveFileNames = (ctxs: CommandContext[]) => `"${ctxs.map(x => path.basename(x.fileUri.fsPath)).join('", ')}"` +const resolveFileNames = (ctxs: CmdCtx[]) => `"${ctxs.map(x => path.basename(x.fileUri.fsPath)).join('", ')}"` diff --git a/src/commands/reveal-local-post-file-in-os.ts b/src/commands/reveal-local-post-file-in-os.ts index 00d300f8..e031ae48 100644 --- a/src/commands/reveal-local-post-file-in-os.ts +++ b/src/commands/reveal-local-post-file-in-os.ts @@ -1,4 +1,5 @@ -import { commands, Uri } from 'vscode' +import { Uri } from 'vscode' +import { execCmd } from '@/utils/cmd' import { Post } from '@/models/post' import { PostFileMapManager } from '@/services/post-file-map' @@ -8,5 +9,5 @@ export const revealLocalPostFileInOs = (post: Post) => { const postFilePath = PostFileMapManager.getFilePath(post.id) if (!postFilePath) return - return commands.executeCommand('revealFileInOS', Uri.file(postFilePath)) + return execCmd('revealFileInOS', Uri.file(postFilePath)) } diff --git a/src/commands/reveal-workspace-in-os.ts b/src/commands/reveal-workspace-in-os.ts index 909bf647..a9e696a6 100644 --- a/src/commands/reveal-workspace-in-os.ts +++ b/src/commands/reveal-workspace-in-os.ts @@ -1,4 +1,5 @@ import { commands } from 'vscode' +import { execCmd } from '@/utils/cmd' import { Settings } from '@/services/settings.service' -export const revealWorkspaceInOs = () => commands.executeCommand('revealFileInOS', Settings.workspaceUri) +export const revealWorkspaceInOs = () => execCmd('revealFileInOS', Settings.workspaceUri) diff --git a/src/commands/show-local-file-to-post-info.ts b/src/commands/show-local-file-to-post-info.ts index bad8d357..fe83db27 100644 --- a/src/commands/show-local-file-to-post-info.ts +++ b/src/commands/show-local-file-to-post-info.ts @@ -22,7 +22,7 @@ export const showLocalFileToPostInfo = async (input: Uri | number): Promise 0 ? `博文标签: ${post.tags?.join(', ')}\n` : '' const options = ['在线查看博文', '取消关联'] const postUrl = post.url.startsWith('//') ? `https:${post.url}` : post.url - const selected = await window.showInformationMessage( + const selected = await AlertService.info( `关联博文 - ${post.title}(Id: ${post.id})`, { modal: true, diff --git a/src/commands/upload-image/upload-image-utils.ts b/src/commands/upload-image/upload-image-utils.ts index 262e1339..644bec04 100644 --- a/src/commands/upload-image/upload-image-utils.ts +++ b/src/commands/upload-image/upload-image-utils.ts @@ -1,5 +1,6 @@ import { env, MessageOptions, SnippetString, window } from 'vscode' import { formatImageLink } from '@/utils/format-image-link' +import { AlertService } from '@/services/alert.service' /** * 显示上传成功对话框, 支持复制不同格式的图片链接 @@ -9,7 +10,7 @@ import { formatImageLink } from '@/utils/format-image-link' */ export const showUploadSuccessModel = async (imgLink: string): Promise => { const copyOptions = ['复制链接', '复制链接(markdown)', '复制链接(html)'] - const option = await window.showInformationMessage( + const option = await AlertService.info( '上传图片成功', { modal: true, diff --git a/src/commands/upload-image/upload-image.ts b/src/commands/upload-image/upload-image.ts index 78a912ed..f434690c 100644 --- a/src/commands/upload-image/upload-image.ts +++ b/src/commands/upload-image/upload-image.ts @@ -7,7 +7,7 @@ import { uploadLocalDiskImage } from './upload-local-disk-image' export const uploadImage = async (autoInsertToActiveEditor = true, from?: 'local' | 'clipboard') => { const options = ['本地图片文件', '剪贴板图片'] const selected = !from - ? await window.showInformationMessage( + ? await AlertService.info( '上传图片到博客园', { modal: true, diff --git a/src/commands/view-post-online.ts b/src/commands/view-post-online.ts index 81b2b003..a42b667a 100644 --- a/src/commands/view-post-online.ts +++ b/src/commands/view-post-online.ts @@ -1,4 +1,5 @@ -import { commands, Uri, window } from 'vscode' +import { Uri, window } from 'vscode' +import { execCmd } from '@/utils/cmd' import { Post } from '@/models/post' import { PostService } from '@/services/post.service' import { PostFileMapManager } from '@/services/post-file-map' @@ -15,5 +16,5 @@ export const viewPostOnline = async (input?: Post | PostTreeItem | Uri) => { if (!post) return - await commands.executeCommand('vscode.open', Uri.parse(post.url)) + await execCmd('vscode.open', Uri.parse(post.url)) } diff --git a/src/extension.ts b/src/extension.ts index 9104c943..7d3b75fb 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -1,5 +1,5 @@ -import { registerTreeViews } from '@/tree-view-providers/tree-view-registration' -import { registerCommands } from '@/commands/commands-registration' +import { setupExtTreeView } from '@/tree-view-providers/tree-view-registration' +import { setupExtCmd } from '@/commands/cmd-register' import { globalCtx } from '@/services/global-ctx' // The module 'vscode' contains the VS Code extensibility API // Import the module and reference it with the alias vscode in your code below @@ -9,20 +9,20 @@ import { observeConfigurationChange, observeWorkspaceFolderAndFileChange as observeWorkspaceFolderChange, } from '@/services/check-workspace' -import extensionUriHandler from '@/utils/uri-handler' +import { extUriHandler } from '@/utils/uri-handler' import { IngsListWebviewProvider } from 'src/services/ings-list-webview-provider' import { extendMarkdownIt } from '@/markdown/extend-markdownIt' import { Settings } from '@/services/settings.service' // this method is called when your extension is activated -// your extension is activated the very first time the command is executed +// your extension is activated the very first time the commands is executed export function activate(context: vscode.ExtensionContext) { globalCtx.extCtx = context context.subscriptions.push(accountManager) - registerCommands() - registerTreeViews() + setupExtCmd() + setupExtTreeView() const timeoutId = setTimeout(() => { IngsListWebviewProvider.ensureRegistered() @@ -34,7 +34,7 @@ export function activate(context: vscode.ExtensionContext) { Settings.migrateEnablePublishSelectionToIng().catch(console.warn) - vscode.window.registerUriHandler(extensionUriHandler) + vscode.window.registerUriHandler(extUriHandler) return { extendMarkdownIt } } diff --git a/src/models/post-cfg.ts b/src/models/post-cfg.ts new file mode 100644 index 00000000..7ba043e8 --- /dev/null +++ b/src/models/post-cfg.ts @@ -0,0 +1,6 @@ +import { Post } from './post' + +type PostCfg = Partial> & + Required<{ [P in keyof Post as Post[P] extends boolean ? P : never]: Post[P] }> + +export { PostCfg } diff --git a/src/models/post-configuration.ts b/src/models/post-configuration.ts deleted file mode 100644 index ee243b29..00000000 --- a/src/models/post-configuration.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { Post } from './post' - -type PostConfiguration = Partial> & - Required<{ [P in keyof Post as Post[P] extends boolean ? P : never]: Post[P] }> - -export { PostConfiguration } diff --git a/src/models/webview-commands.ts b/src/models/webview-cmd.ts similarity index 61% rename from src/models/webview-commands.ts rename to src/models/webview-cmd.ts index 2d8ec259..03435f27 100644 --- a/src/models/webview-commands.ts +++ b/src/models/webview-cmd.ts @@ -1,8 +1,8 @@ import { PostCategories } from '@/models/post-category' -export namespace webviewCommands { - export enum UiCommands { - editPostConfiguration = 'editPostConfiguration', +export namespace WebviewCmd { + export enum UiCmd { + editPostCfg = 'editPostCfg', showErrorResponse = 'showErrorResponse', updateBreadcrumbs = 'updateBreadcrumbs', updateImageUploadStatus = 'updateImageUploadStatus', @@ -11,7 +11,7 @@ export namespace webviewCommands { updateChildCategories = 'updateChildCategories', } - export enum ExtensionCommands { + export enum ExtCmd { uploadPost = 'uploadPost', disposePanel = 'disposePanel', uploadImage = 'uploadImage', @@ -28,18 +28,18 @@ export namespace webviewCommands { value: PostCategories } - export namespace ingCommands { - export enum UiCommands { + export namespace IngCmd { + export enum UiCmd { setAppState = 'setAppState', updateTheme = 'updateTheme', } - export enum ExtensionCommands { + export enum ExtCmd { refreshIngsList = 'refreshIngsList', comment = 'comment', } - export type CommentCommandPayload = { + export type CommentCmdPayload = { ingId: number atUser?: { id: number; displayName: string } parentCommentId?: number @@ -48,17 +48,17 @@ export namespace webviewCommands { } } -export interface WebviewCommonCommand { +export interface WebviewCommonCmd { payload: T command: unknown } -export interface IngWebviewUiCommand = Record> - extends WebviewCommonCommand { - command: webviewCommands.ingCommands.UiCommands +export interface IngWebviewUiCmd = Record> + extends WebviewCommonCmd { + command: WebviewCmd.IngCmd.UiCmd } -export interface IngWebviewHostCommand = Record> - extends WebviewCommonCommand { - command: webviewCommands.ingCommands.ExtensionCommands +export interface IngWebviewHostCmd = Record> + extends WebviewCommonCmd { + command: WebviewCmd.IngCmd.ExtCmd } diff --git a/src/models/webview-message.ts b/src/models/webview-msg.ts similarity index 87% rename from src/models/webview-message.ts rename to src/models/webview-msg.ts index b0613233..365f8ca0 100644 --- a/src/models/webview-message.ts +++ b/src/models/webview-msg.ts @@ -1,5 +1,5 @@ import { Post } from './post' -import { webviewCommands } from './webview-commands' +import { WebviewCmd } from './webview-cmd' import { ColorThemeKind } from 'vscode' import { PostCategories } from './post-category' import { SiteCategories } from './site-category' @@ -9,10 +9,10 @@ import { ImageUploadStatus } from './image-upload-status' export namespace webviewMessage { export interface Message { - command: webviewCommands.UiCommands | webviewCommands.ExtensionCommands + command: WebviewCmd.UiCmd | WebviewCmd.ExtCmd } - export interface EditPostConfigurationMessage extends Message { + export interface EditPostCfgMessage extends Message { post: Post activeTheme: ColorThemeKind personalCategories: PostCategories diff --git a/src/services/alert.service.ts b/src/services/alert.service.ts index 107002ba..8d057d65 100644 --- a/src/services/alert.service.ts +++ b/src/services/alert.service.ts @@ -2,19 +2,14 @@ import type { HTTPError } from 'got' import { isArray } from 'lodash-es' import path from 'path' import vscode, { Uri } from 'vscode' +import { window } from 'vscode' export namespace AlertService { - export function err(message: string) { - void vscode.window.showErrorMessage(message) - } + export const err = window.showErrorMessage - export function info(message: string) { - vscode.window.showInformationMessage(message).then(undefined, undefined) - } + export const info = window.showInformationMessage - export function warn(message: string) { - vscode.window.showWarningMessage(message).then(undefined, undefined) - } + export const warn = window.showWarningMessage export function httpErr(httpError: Partial, { message = '' } = {}) { const body = httpError.response?.body as @@ -27,7 +22,7 @@ export namespace AlertService { else if (httpError.message) parsedError = httpError.message else parsedError = '未知网络错误' - AlertService.warn((message ? message + (parsedError ? ', ' : '') : '') + parsedError) + void AlertService.warn((message ? message + (parsedError ? ', ' : '') : '') + parsedError) } /** @@ -38,12 +33,12 @@ export namespace AlertService { export function fileNotLinkedToPost(file: string | Uri, { trimExt = true } = {}) { file = file instanceof Uri ? file.fsPath : file file = trimExt ? path.basename(file, path.extname(file)) : file - AlertService.warn(`本地文件"${file}"未关联博客园博文`) + void AlertService.warn(`本地文件"${file}"未关联博客园博文`) } export async function alertUnAuth({ onLoginActionHook }: { onLoginActionHook?: () => unknown } = {}) { const options = ['立即登录'] - const input = await vscode.window.showWarningMessage( + const input = await AlertService.warn( '登录状态已过期, 请重新登录', { modal: true } as vscode.MessageOptions, ...options diff --git a/src/services/blog-export-records.store.ts b/src/services/blog-export-records.store.ts index e611e628..b924213e 100644 --- a/src/services/blog-export-records.store.ts +++ b/src/services/blog-export-records.store.ts @@ -2,8 +2,8 @@ import { BlogExportRecordList } from '@/models/blog-export' import { BlogExportApi } from '@/services/blog-export.api' export class BlogExportRecordsStore { - private _cachedList?: Promise | null - private _cached?: BlogExportRecordList | null + private _cachedList: Promise | null = null + private _cached: BlogExportRecordList | null = null get cached() { return this._cached diff --git a/src/services/check-workspace.ts b/src/services/check-workspace.ts index bad99d6c..b25ad770 100644 --- a/src/services/check-workspace.ts +++ b/src/services/check-workspace.ts @@ -1,9 +1,10 @@ import os from 'os' -import { commands, workspace } from 'vscode' +import { workspace } from 'vscode' import { refreshPostCategoriesList } from '@/commands/post-category/refresh-post-categories-list' import { refreshPostsList } from '@/commands/posts-list/refresh-posts-list' import { globalCtx } from './global-ctx' import { PostFileMapManager } from './post-file-map' +import { execCmd } from '@/utils/cmd' import { Settings } from './settings.service' const diskSymbolRegex = /^(\S{1,5}:)(.*)/ @@ -20,7 +21,7 @@ export const isTargetWorkspace = (): boolean => { targetFolder = targetFolder.replace(diskSymbolRegex, replacer) } const isTarget = !!currentFolder && currentFolder === targetFolder - void commands.executeCommand('setContext', `${globalCtx.extName}.isTargetWorkspace`, isTarget) + void execCmd('setContext', `${globalCtx.extName}.isTargetWorkspace`, isTarget) return isTarget } @@ -36,7 +37,7 @@ export const observeConfigurationChange = () => { refreshPostsList({ queue: true }).catch(() => undefined) if (ev.affectsConfiguration(`${Settings.prefix}.markdown`)) - commands.executeCommand('markdown.preview.refresh').then(undefined, () => undefined) + execCmd('markdown.preview.refresh').then(undefined, () => undefined) }) ) isTargetWorkspace() diff --git a/src/services/fetch-json-response-to-camel-case.ts b/src/services/converter.ts similarity index 100% rename from src/services/fetch-json-response-to-camel-case.ts rename to src/services/converter.ts diff --git a/src/services/ings-list-webview-provider.ts b/src/services/ings-list-webview-provider.ts index b317a23e..0fc12c49 100644 --- a/src/services/ings-list-webview-provider.ts +++ b/src/services/ings-list-webview-provider.ts @@ -1,7 +1,6 @@ import { globalCtx } from 'src/services/global-ctx' import { CancellationToken, - commands, Disposable, Webview, WebviewView, @@ -10,25 +9,26 @@ import { window, } from 'vscode' import { parseWebviewHtml } from 'src/services/parse-webview-html' -import { IngWebviewHostCommand, IngWebviewUiCommand, webviewCommands } from 'src/models/webview-commands' +import { IngWebviewHostCmd, IngWebviewUiCmd, WebviewCmd } from 'src/models/webview-cmd' import { IngApi } from 'src/services/ing.api' import { IngAppState } from 'src/models/ing-view' import { IngType, IngTypesMetadata } from 'src/models/ing' import { isNumber } from 'lodash-es' -import { CommentIngCommandHandler } from '@/commands/ing/comment-ing' +import { CommentIngCmdHandler } from '@/commands/ing/comment-ing' +import { execCmd } from '@/utils/cmd' export class IngsListWebviewProvider implements WebviewViewProvider { - private static _instance?: IngsListWebviewProvider + private static _instance: IngsListWebviewProvider | null = null readonly viewId = `${globalCtx.extName}.ings-list-webview` private readonly _baseTitle = '闪存' - private _view?: WebviewView - private _observer?: IngWebviewMessageObserver + private _view: WebviewView | null = null + private _observer: IngWebviewMessageObserver | null = null private _pageIndex = 1 private _isRefreshing = false private _ingType = IngType.all - private _show?: WebviewView['show'] + private _show: WebviewView['show'] | null = null private constructor() {} @@ -51,11 +51,12 @@ export class IngsListWebviewProvider implements WebviewViewProvider { } get show() { - this._show ??= this._view ? this._view.show.bind(this._view) : undefined + this._show ??= this._view ? this._view.show.bind(this._view) : null return this._show } - static get instance(): IngsListWebviewProvider | undefined { + static get instance() { + this._instance ??= new IngsListWebviewProvider() return this._instance } @@ -79,20 +80,22 @@ export class IngsListWebviewProvider implements WebviewViewProvider { if (this._view && this._view === webviewView) return this._view = webviewView + webviewView.webview.options = { enableScripts: true, localResourceRoots: [this.assetsUri], } + const disposables: Disposable[] = [] webviewView.webview.onDidReceiveMessage(this.observer.observer, disposables) webviewView.webview.html = await this.provideHtml(webviewView.webview) window.onDidChangeActiveColorTheme( - () => webviewView.webview.postMessage(webviewCommands.UiCommands.updateTheme), + () => webviewView.webview.postMessage(WebviewCmd.UiCmd.updateTheme), disposables ) webviewView.onDidDispose(() => { disposables.forEach(d => void d.dispose()) - this._view = undefined + this._view = null this.setIsRefreshing(false).catch(() => undefined) }, disposables) } @@ -107,8 +110,8 @@ export class IngsListWebviewProvider implements WebviewViewProvider { await this._view.webview .postMessage({ payload: { isRefreshing: true }, - command: webviewCommands.ingCommands.UiCommands.setAppState, - } as IngWebviewUiCommand>) + command: WebviewCmd.IngCmd.UiCmd.setAppState, + } as IngWebviewUiCmd>) .then(undefined, () => undefined) const ings = await IngApi.list({ type: ingType, @@ -118,13 +121,13 @@ export class IngsListWebviewProvider implements WebviewViewProvider { const comments = await IngApi.listComments(...ings.map(x => x.id)) await this._view.webview .postMessage({ - command: webviewCommands.ingCommands.UiCommands.setAppState, + command: WebviewCmd.IngCmd.UiCmd.setAppState, payload: { ings, isRefreshing: false, comments, }, - } as IngWebviewUiCommand>) + } as IngWebviewUiCmd>) .then(undefined, () => undefined) } else { this.show() @@ -140,11 +143,11 @@ export class IngsListWebviewProvider implements WebviewViewProvider { if (!this._view || !this._view.visible) return const comments = await IngApi.listComments(...ingIds) await this._view.webview.postMessage({ - command: webviewCommands.ingCommands.UiCommands.setAppState, + command: WebviewCmd.IngCmd.UiCmd.setAppState, payload: { comments, }, - } as IngWebviewUiCommand>) + } as IngWebviewUiCmd>) } private provideHtml(webview: Webview) { @@ -152,16 +155,18 @@ export class IngsListWebviewProvider implements WebviewViewProvider { } private async setIsRefreshing(value: boolean) { - await commands - .executeCommand('setContext', `${globalCtx.extName}.ingsList.isRefreshing`, value ? true : undefined) - .then(undefined, () => undefined) + await execCmd('setContext', `${globalCtx.extName}.ingsList.isRefreshing`, value ? true : undefined).then( + undefined, + () => undefined + ) this._isRefreshing = value } private async setPageIndex(value: number) { - await commands - .executeCommand('setContext', `${globalCtx.extName}.ingsList.pageIndex`, value > 0 ? value : undefined) - .then(undefined, () => undefined) + await execCmd('setContext', `${globalCtx.extName}.ingsList.pageIndex`, value > 0 ? value : undefined).then( + undefined, + () => undefined + ) this._pageIndex = value } @@ -181,9 +186,9 @@ export class IngsListWebviewProvider implements WebviewViewProvider { class IngWebviewMessageObserver { constructor(private _provider: IngsListWebviewProvider) {} - observer = ({ command, payload }: IngWebviewHostCommand) => { + observer = ({ command, payload }: IngWebviewHostCmd) => { switch (command) { - case webviewCommands.ingCommands.ExtensionCommands.refreshIngsList: { + case WebviewCmd.IngCmd.ExtCmd.refreshIngsList: { const { ingType, pageIndex } = payload return this._provider.refreshIngsList({ ingType: @@ -193,10 +198,9 @@ class IngWebviewMessageObserver { pageIndex: isNumber(pageIndex) ? pageIndex : undefined, }) } - case webviewCommands.ingCommands.ExtensionCommands.comment: { - const { atUser, ingId, ingContent, parentCommentId } = - payload as webviewCommands.ingCommands.CommentCommandPayload - return new CommentIngCommandHandler(ingId, ingContent, parentCommentId, atUser).handle() + case WebviewCmd.IngCmd.ExtCmd.comment: { + const { atUser, ingId, ingContent, parentCommentId } = payload as WebviewCmd.IngCmd.CommentCmdPayload + return new CommentIngCmdHandler(ingId, ingContent, parentCommentId, atUser).handle() } } } diff --git a/src/services/oauth.api.ts b/src/services/oauth.api.ts index dd605428..5e5fb59b 100644 --- a/src/services/oauth.api.ts +++ b/src/services/oauth.api.ts @@ -1,13 +1,12 @@ /* eslint-disable @typescript-eslint/naming-convention */ import { TokenInfo } from '@/models/token-info' import { AccountInfo } from '@/auth/account-info' -import { convertObjectKeysToCamelCase } from '@/services/fetch-json-response-to-camel-case' +import { convertObjectKeysToCamelCase } from '@/services/converter' import { globalCtx } from '@/services/global-ctx' import fetch from '@/utils/fetch-client' import got from '@/utils/http-client' import { CancellationToken } from 'vscode' import { AbortController } from 'node-abort-controller' -import { AuthorizationHeaderKey } from '@/utils/constants' export type UserInfoSpec = Pick & { readonly blog_id: string @@ -16,6 +15,7 @@ export type UserInfoSpec = Pick & { } export namespace Oauth { + export const AuthHeaderKey = 'Authorization' export async function fetchToken(verifyCode: string, authCode: string, cancelToken?: CancellationToken) { const abortControl = new AbortController() if (cancelToken?.isCancellationRequested) abortControl.abort() @@ -36,7 +36,7 @@ export namespace Oauth { responseType: 'json', signal: abortControl.signal, headers: { - [AuthorizationHeaderKey]: '', + [AuthHeaderKey]: '', }, }) diff --git a/src/services/parse-webview-html.ts b/src/services/parse-webview-html.ts index 8c1726e6..229ed5f5 100644 --- a/src/services/parse-webview-html.ts +++ b/src/services/parse-webview-html.ts @@ -1,7 +1,7 @@ import vscode from 'vscode' import { globalCtx } from 'src/services/global-ctx' -export type WebviewEntryName = 'ing' | 'post-configuration' +export type WebviewEntryName = 'ing' | 'post-cfg' export async function parseWebviewHtml(entry: WebviewEntryName, webview: vscode.Webview) { const path = vscode.Uri.joinPath(globalCtx.assetsUri, 'ui', entry, 'index.html') diff --git a/src/services/post-category.service.ts b/src/services/post-category.service.ts index aac70494..2f67e1cd 100644 --- a/src/services/post-category.service.ts +++ b/src/services/post-category.service.ts @@ -4,14 +4,14 @@ import { globalCtx } from './global-ctx' import { URLSearchParams } from 'url' export class PostCategoryService { - private static _instance: PostCategoryService + private static _instance: PostCategoryService | null = null private _cache?: Map private constructor() {} static get instance(): PostCategoryService { - if (!this._instance) this._instance = new PostCategoryService() + this._instance ??= new PostCategoryService() return this._instance } diff --git a/src/services/post-configuration-panel.service.ts b/src/services/post-cfg-panel.service.ts similarity index 81% rename from src/services/post-configuration-panel.service.ts rename to src/services/post-cfg-panel.service.ts index 42f060e7..60313402 100644 --- a/src/services/post-configuration-panel.service.ts +++ b/src/services/post-cfg-panel.service.ts @@ -7,8 +7,8 @@ import { siteCategoryService } from './site-category.service' import { PostTagService } from './post-tag.service' import { PostService } from './post.service' import { isErrorResponse } from '@/models/error-response' -import { webviewMessage } from '@/models/webview-message' -import { WebviewCommonCommand, webviewCommands } from 'src/models/webview-commands' +import { webviewMessage } from '@/models/webview-msg' +import { WebviewCommonCmd, WebviewCmd } from 'src/models/webview-cmd' import { uploadImage } from '@/commands/upload-image/upload-image' import { ImageUploadStatusId } from '@/models/image-upload-status' import { openPostFile } from '@/commands/posts-list/open-post-file' @@ -17,8 +17,8 @@ import path from 'path' const panels: Map = new Map() -export namespace postConfigurationPanel { - interface PostConfigurationPanelOpenOption { +export namespace PostCfgPanel { + interface PostCfgPanelOpenOption { post: Post panelTitle?: string localFileUri?: Uri @@ -30,12 +30,12 @@ export namespace postConfigurationPanel { const resourceRootUri = () => globalCtx.assetsUri const setHtml = async (webview: vscode.Webview): Promise => { - webview.html = await parseWebviewHtml('post-configuration', webview) + webview.html = await parseWebviewHtml('post-cfg', webview) } export const buildPanelId = (postId: number, postTitle: string): string => `${postId}-${postTitle}` export const findPanelById = (panelId: string) => panels.get(panelId) - export const open = async (option: PostConfigurationPanelOpenOption) => { + export const open = async (option: PostCfgPanelOpenOption) => { const { post, breadcrumbs, localFileUri } = option const panelTitle = option.panelTitle ? option.panelTitle : `博文设置 - ${post.title}` await openPostFile(post, { @@ -51,13 +51,13 @@ export namespace postConfigurationPanel { disposables.push( webview.onDidReceiveMessage(async ({ command }: webviewMessage.Message) => { - if (command === webviewCommands.ExtensionCommands.refreshPost) { + if (command === WebviewCmd.ExtCmd.refreshPost) { await webview.postMessage({ - command: webviewCommands.UiCommands.setFluentIconBaseUrl, + command: WebviewCmd.UiCmd.setFluentIconBaseUrl, baseUrl: webview.asWebviewUri(Uri.joinPath(resourceRootUri(), 'fonts')).toString() + '/', } as webviewMessage.SetFluentIconBaseUrlMessage) await webview.postMessage({ - command: webviewCommands.UiCommands.editPostConfiguration, + command: WebviewCmd.UiCmd.editPostCfg, post: cloneDeep(post), activeTheme: vscode.window.activeColorTheme.kind, personalCategories: cloneDeep(await postCategoryService.listCategories()), @@ -67,7 +67,7 @@ export namespace postConfigurationPanel { fileName: localFileUri ? path.basename(localFileUri.fsPath, path.extname(localFileUri?.fsPath)) : '', - } as webviewMessage.EditPostConfigurationMessage) + } as webviewMessage.EditPostCfgMessage) } }), observeWebviewMessages(panel, option), @@ -78,7 +78,7 @@ export namespace postConfigurationPanel { const tryRevealPanel = ( panelId: string | undefined, - options: PostConfigurationPanelOpenOption + options: PostCfgPanelOpenOption ): vscode.WebviewPanel | undefined => { if (!panelId) return @@ -89,7 +89,7 @@ export namespace postConfigurationPanel { const { breadcrumbs } = options const { webview } = panel void webview.postMessage({ - command: webviewCommands.UiCommands.updateBreadcrumbs, + command: WebviewCmd.UiCmd.updateBreadcrumbs, breadcrumbs, } as webviewMessage.UpdateBreadcrumbsMessage) panel.reveal() @@ -113,14 +113,14 @@ export namespace postConfigurationPanel { return panel } - const onUploadImageCommand = async ( + const onUploadImageCmd = async ( panel: vscode.WebviewPanel | undefined, message: webviewMessage.UploadImageMessage ) => { if (panel) { const { webview } = panel await webview.postMessage({ - command: webviewCommands.UiCommands.updateImageUploadStatus, + command: WebviewCmd.UiCmd.updateImageUploadStatus, status: { id: ImageUploadStatusId.uploading, }, @@ -129,7 +129,7 @@ export namespace postConfigurationPanel { try { const imageUrl = await uploadImage(false) await webview.postMessage({ - command: webviewCommands.UiCommands.updateImageUploadStatus, + command: WebviewCmd.UiCmd.updateImageUploadStatus, status: { imageUrl, id: ImageUploadStatusId.uploaded, @@ -139,7 +139,7 @@ export namespace postConfigurationPanel { } catch (err) { if (isErrorResponse(err)) { await webview.postMessage({ - command: webviewCommands.UiCommands.updateImageUploadStatus, + command: WebviewCmd.UiCmd.updateImageUploadStatus, status: { id: ImageUploadStatusId.failed, errors: err.errors, @@ -157,7 +157,7 @@ export namespace postConfigurationPanel { const { webview } = panel return vscode.window.onDidChangeActiveColorTheme(async theme => { await webview.postMessage({ - command: webviewCommands.UiCommands.updateTheme, + command: WebviewCmd.UiCmd.updateTheme, colorThemeKind: theme.kind, } as webviewMessage.ChangeThemeMessage) }) @@ -165,7 +165,7 @@ export namespace postConfigurationPanel { const observeWebviewMessages = ( panel: vscode.WebviewPanel | undefined, - options: PostConfigurationPanelOpenOption + options: PostCfgPanelOpenOption ): vscode.Disposable | undefined => { if (!panel) return @@ -174,7 +174,7 @@ export namespace postConfigurationPanel { return webview.onDidReceiveMessage(async message => { const { command } = (message ?? {}) as webviewMessage.Message switch (command) { - case webviewCommands.ExtensionCommands.uploadPost: + case WebviewCmd.ExtCmd.uploadPost: try { if (!panel) return @@ -191,7 +191,7 @@ export namespace postConfigurationPanel { } catch (err) { if (isErrorResponse(err)) { await webview.postMessage({ - command: webviewCommands.UiCommands.showErrorResponse, + command: WebviewCmd.UiCmd.showErrorResponse, errorResponse: err, } as webviewMessage.ShowErrorResponseMessage) } else { @@ -199,24 +199,24 @@ export namespace postConfigurationPanel { } } break - case webviewCommands.ExtensionCommands.disposePanel: + case WebviewCmd.ExtCmd.disposePanel: panel?.dispose() break - case webviewCommands.ExtensionCommands.uploadImage: - await onUploadImageCommand(panel, message) + case WebviewCmd.ExtCmd.uploadImage: + await onUploadImageCmd(panel, message) break - case webviewCommands.ExtensionCommands.getChildCategories: + case WebviewCmd.ExtCmd.getChildCategories: { - const { payload } = message as WebviewCommonCommand + const { payload } = message as WebviewCommonCmd await webview.postMessage({ - command: webviewCommands.UiCommands.updateChildCategories, + command: WebviewCmd.UiCmd.updateChildCategories, payload: { value: await postCategoryService .listCategories({ parentId: payload.parentId }) .catch(() => []), parentId: payload.parentId, }, - } as WebviewCommonCommand) + } as WebviewCommonCmd) } break } diff --git a/src/services/posts-list-view.ts b/src/services/posts-list-view.ts index 51c22350..ad9635f3 100644 --- a/src/services/posts-list-view.ts +++ b/src/services/posts-list-view.ts @@ -1,5 +1,5 @@ import { Post } from '@/models/post' -import { extensionViews } from '@/tree-view-providers/tree-view-registration' +import { extViews } from '@/tree-view-providers/tree-view-registration' export const revealPostsListItem = async ( post: Post, @@ -7,6 +7,6 @@ export const revealPostsListItem = async ( ) => { if (!post) return - const view = extensionViews.visiblePostsList() + const view = extViews.visiblePostsList() await view?.reveal(post, options) } diff --git a/src/test/suite/extension.test.ts b/src/test/suite/extension.test.ts index 0dab3fd8..2bdec69c 100644 --- a/src/test/suite/extension.test.ts +++ b/src/test/suite/extension.test.ts @@ -1,12 +1,12 @@ +import { AlertService } from '@/services/alert.service' import assert from 'assert' // You can import and use all API from the 'vscode' module // as well as import your extension to test it -import vscode from 'vscode' // import * as myExtension from '../../extension'; suite('Extension Test Suite', () => { - vscode.window.showInformationMessage('Start all tests.') + AlertService.info('Start all tests.') test('Sample test', () => { assert.strictEqual(-1, [1, 2, 3].indexOf(5)) diff --git a/src/tree-view-providers/account-view-data-provider.ts b/src/tree-view-providers/account-view-data-provider.ts index 58ad00bd..661341b7 100644 --- a/src/tree-view-providers/account-view-data-provider.ts +++ b/src/tree-view-providers/account-view-data-provider.ts @@ -2,13 +2,13 @@ import { accountManager } from '@/auth/account-manager' import { EventEmitter, ProviderResult, ThemeIcon, TreeDataProvider, TreeItem } from 'vscode' export class AccountViewDataProvider implements TreeDataProvider { - private static _instance?: AccountViewDataProvider + private static _instance: AccountViewDataProvider | null = null protected _onDidChangeTreeData = new EventEmitter() protected constructor() {} static get instance() { - if (!this._instance) this._instance = new AccountViewDataProvider() + this._instance ??= new AccountViewDataProvider() return this._instance } @@ -42,7 +42,7 @@ export class AccountViewDataProvider implements TreeDataProvider { tooltip: '博客后台', command: { title: '打开博客后台', - command: 'vscode-cnb.open-my-blog-management-background', + command: 'vscode-cnb.open-my-blog-console', tooltip: '浏览器中打开我的博客后台', }, iconPath: new ThemeIcon('console'), diff --git a/src/tree-view-providers/blog-export-provider.ts b/src/tree-view-providers/blog-export-provider.ts index 7b3d3f0e..78a42339 100644 --- a/src/tree-view-providers/blog-export-provider.ts +++ b/src/tree-view-providers/blog-export-provider.ts @@ -16,7 +16,7 @@ import { AlertService } from '@/services/alert.service' import { BlogExportRecord } from '@/models/blog-export' export class BlogExportProvider implements TreeDataProvider { - private static _instance?: BlogExportProvider | null + private static _instance: BlogExportProvider | null = null private _treeDataChangedSource?: EventEmitter | null private _store?: BlogExportRecordsStore | null diff --git a/src/tree-view-providers/models/blog-export/post.ts b/src/tree-view-providers/models/blog-export/post.ts index 419f1ebe..f3b37799 100644 --- a/src/tree-view-providers/models/blog-export/post.ts +++ b/src/tree-view-providers/models/blog-export/post.ts @@ -1,4 +1,4 @@ -import { ViewPostCommandHandler } from '@/commands/blog-export/view-post' +import { ViewPostCmdHandler } from '@/commands/blog-export/view-post' import type { ExportPost } from '@/models/blog-export/export-post' import { Settings } from '@/services/settings.service' import { BaseTreeItemSource } from '@/tree-view-providers/models/base-tree-item-source' @@ -24,7 +24,7 @@ export class ExportPostTreeItem extends BaseTreeItemSource { collapsibleState: TreeItemCollapsibleState.None, command: { title: '查看博文', - command: ViewPostCommandHandler.commandName, + command: ViewPostCmdHandler.commandName, arguments: [this], }, resourceUri: Uri.joinPath(Settings.workspaceUri, title + (isMarkdown ? '.md' : '.html')), diff --git a/src/tree-view-providers/post-categories-tree-data-provider.ts b/src/tree-view-providers/post-categories-tree-data-provider.ts index 8e2e7546..e82d2c65 100644 --- a/src/tree-view-providers/post-categories-tree-data-provider.ts +++ b/src/tree-view-providers/post-categories-tree-data-provider.ts @@ -1,5 +1,5 @@ import { flattenDepth, take } from 'lodash-es' -import { commands, EventEmitter, ProviderResult, TreeDataProvider, TreeItem } from 'vscode' +import { EventEmitter, ProviderResult, TreeDataProvider, TreeItem } from 'vscode' import { PostCategories } from '@/models/post-category' import { globalCtx } from '@/services/global-ctx' import { postCategoryService } from '@/services/post-category.service' @@ -10,9 +10,10 @@ import { PostCategoryTreeItem } from './models/post-category-tree-item' import { PostEntryMetadata, PostMetadata, RootPostMetadataType } from './models/post-metadata' import { PostTreeItem } from './models/post-tree-item' import { AlertService } from '@/services/alert.service' +import { execCmd } from '@/utils/cmd' export class PostCategoriesTreeDataProvider implements TreeDataProvider { - private static _instance: PostCategoriesTreeDataProvider + private static _instance: PostCategoriesTreeDataProvider | null = null private _treeDataChanged = new EventEmitter() private _isRefreshing = false private _roots: PostCategoryTreeItem[] | null = null @@ -50,7 +51,7 @@ export class PostCategoriesTreeDataProvider implements TreeDataProvider { - private static _instance?: PostsDataProvider + private static _instance: PostsDataProvider | null = null protected _pagedPosts?: PageModel protected _onDidChangeTreeData = new EventEmitter() diff --git a/src/tree-view-providers/tree-view-registration.ts b/src/tree-view-providers/tree-view-registration.ts index 8168cc6a..ab0c656f 100644 --- a/src/tree-view-providers/tree-view-registration.ts +++ b/src/tree-view-providers/tree-view-registration.ts @@ -7,6 +7,7 @@ import { PostCategoriesListTreeItem } from './models/categories-list-tree-item' import { IDisposable } from '@fluentui/react' import { BlogExportTreeItem } from '@/tree-view-providers/models/blog-export' import { BlogExportProvider } from '@/tree-view-providers/blog-export-provider' +import { regTreeView } from '@/utils/tree-view' const _views: { postsList?: vscode.TreeView @@ -23,29 +24,26 @@ const _views: { } let _hasRegistered = false -export const registerTreeViews = () => { - if (_hasRegistered) return extensionViews +export function setupExtTreeView() { + if (_hasRegistered) return extViews - _views.account = vscode.window.createTreeView('cnblogs-account', { + _views.account = regTreeView('cnblogs-account', { treeDataProvider: accountViewDataProvider, canSelectMany: false, }) - _views.postsList = vscode.window.createTreeView('cnblogs-posts-list', { + _views.postsList = regTreeView('cnblogs-posts-list', { treeDataProvider: postsDataProvider, canSelectMany: true, }) - _views.anotherPostsList = vscode.window.createTreeView('cnblogs-posts-list-another', { + _views.anotherPostsList = regTreeView('cnblogs-posts-list-another', { treeDataProvider: postsDataProvider, canSelectMany: true, }) - _views.postCategoriesList = vscode.window.createTreeView( - 'cnblogs-post-categories-list', - { - treeDataProvider: postCategoriesDataProvider, - canSelectMany: true, - } - ) - _views.blogExport = vscode.window.createTreeView('vscode-cnb.blog-export', { + _views.postCategoriesList = regTreeView('cnblogs-post-categories-list', { + treeDataProvider: postCategoriesDataProvider, + canSelectMany: true, + }) + _views.blogExport = regTreeView('vscode-cnb.blog-export', { canSelectMany: false, treeDataProvider: BlogExportProvider.instance, }) @@ -56,10 +54,10 @@ export const registerTreeViews = () => { globalCtx.extCtx.subscriptions.push(...disposables) - return extensionViews + return extViews } -class ExtensionViews implements Required { +class ExtViews implements Required { postsLists = _views.postsLists visiblePostsList = _views.visiblePostsList @@ -92,4 +90,4 @@ class ExtensionViews implements Required { } } -export const extensionViews = new ExtensionViews() +export const extViews = new ExtViews() diff --git a/src/utils/cmd.ts b/src/utils/cmd.ts new file mode 100644 index 00000000..e2bffe75 --- /dev/null +++ b/src/utils/cmd.ts @@ -0,0 +1,9 @@ +import { commands } from 'vscode' + +export function regCmd(cmd: string, f: (...args: any[]) => any) { + return commands.registerCommand(cmd, f) +} + +export function execCmd(cmd: string, ...rest: any[]) { + return commands.executeCommand(cmd, rest) +} diff --git a/src/utils/constants.ts b/src/utils/constants.ts deleted file mode 100644 index d03bafb7..00000000 --- a/src/utils/constants.ts +++ /dev/null @@ -1 +0,0 @@ -export const AuthorizationHeaderKey = 'Authorization' diff --git a/src/utils/http-client.ts b/src/utils/http-client.ts index 4c406508..a43343dc 100644 --- a/src/utils/http-client.ts +++ b/src/utils/http-client.ts @@ -1,18 +1,18 @@ import { accountManager } from '@/auth/account-manager' -import { AuthorizationHeaderKey } from '@/utils/constants' import got, { BeforeRequestHook } from 'got' import { isString } from 'lodash-es' +import { Oauth } from '@/services/oauth.api' const bearerTokenHook: BeforeRequestHook = async opt => { const { headers } = opt const headerKeys = Object.keys(headers) - const keyIndex = headerKeys.findIndex(x => x.toLowerCase() === AuthorizationHeaderKey.toLowerCase()) + const keyIndex = headerKeys.findIndex(x => x.toLowerCase() === Oauth.AuthHeaderKey.toLowerCase()) if (keyIndex < 0) { const token = await accountManager.acquireToken() - if (isString(token)) headers[AuthorizationHeaderKey] = `Bearer ${token}` + if (isString(token)) headers[Oauth.AuthHeaderKey] = `Bearer ${token}` } } diff --git a/src/utils/msg.ts b/src/utils/msg.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/utils/reveal-active-file.ts b/src/utils/reveal-active-file.ts index 01dda303..e8772543 100644 --- a/src/utils/reveal-active-file.ts +++ b/src/utils/reveal-active-file.ts @@ -1,4 +1,3 @@ -import { commands } from 'vscode' +import { execCmd } from '@/utils/cmd' -export const revealActiveFileInExplorer = () => - commands.executeCommand('workbench.files.action.showActiveFileInExplorer') +export const revealActiveFileInExplorer = () => execCmd('workbench.files.action.showActiveFileInExplorer') diff --git a/src/utils/tree-view.ts b/src/utils/tree-view.ts new file mode 100644 index 00000000..b65bd915 --- /dev/null +++ b/src/utils/tree-view.ts @@ -0,0 +1,5 @@ +import vscode, { TreeViewOptions } from 'vscode' + +export function regTreeView(id: string, opt: TreeViewOptions) { + return vscode.window.createTreeView(id, opt) +} diff --git a/src/utils/uri-handler.ts b/src/utils/uri-handler.ts index f9de5e5c..a635cbbb 100644 --- a/src/utils/uri-handler.ts +++ b/src/utils/uri-handler.ts @@ -1,7 +1,7 @@ import { Disposable, EventEmitter, ProviderResult, Uri, UriHandler, Event } from 'vscode' import { openPostInVscode } from '@/commands/posts-list/open-post-in-vscode' -class ExtensionUriHandler implements UriHandler, Disposable { +class ExtUriHandler implements UriHandler, Disposable { private _uriEventEmitter?: EventEmitter private readonly _disposable: Disposable private _onUri?: Event @@ -38,6 +38,4 @@ class ExtensionUriHandler implements UriHandler, Disposable { } } -const extensionUriHandler = new ExtensionUriHandler() - -export default extensionUriHandler +export const extUriHandler = new ExtUriHandler() diff --git a/ui/global.d.ts b/ui/global.d.ts index e3eb8b27..0d884e6a 100644 --- a/ui/global.d.ts +++ b/ui/global.d.ts @@ -1,13 +1,13 @@ -type WebviewCommonCommand = import('@models/webview-commands').WebviewCommonCommand +type WebviewCommonCmd = import('@models/webview-cmd').WebviewCommonCmd declare interface VsCodeApi { - postMessage = WebviewCommonCommand<{}>>(message: Object | T): any + postMessage = WebviewCommonCmd<{}>>(message: Object | T): any } declare interface Window { - addEventListener>( + addEventListener>( type: 'message', - callback: (event: { data: TCommand }) => unknown + callback: (event: { data: TCmd }) => unknown ): void } diff --git a/ui/ing/App.tsx b/ui/ing/App.tsx index 010b1304..fde339d5 100644 --- a/ui/ing/App.tsx +++ b/ui/ing/App.tsx @@ -1,7 +1,7 @@ import React, { Component, ReactNode } from 'react' -import { IngWebviewUiCommand, webviewCommands } from '@models/webview-commands' +import { IngWebviewUiCmd, WebviewCmd } from '@models/webview-cmd' import { IngList } from 'ing/IngList' -import { vsCodeApi } from 'share/vscode-api' +import { getVsCodeApiSingleton } from 'share/vscode-api' import { IngAppState } from '@models/ing-view' import { Ing, IngComment } from '@models/ing' import { activeThemeProvider } from 'share/active-theme-provider' @@ -47,9 +47,9 @@ export class App extends Component { } private observeMessages() { - window.addEventListener('message', ({ data: { command, payload } }: { data: IngWebviewUiCommand }) => { + window.addEventListener('message', ({ data: { command, payload } }: { data: IngWebviewUiCmd }) => { switch (command) { - case webviewCommands.ingCommands.UiCommands.setAppState: { + case WebviewCmd.IngCmd.UiCmd.setAppState: { const { ings, isRefreshing, comments } = payload as Partial this.setState({ ings: ings?.map(Ing.parse) ?? this.state.ings, @@ -67,7 +67,7 @@ export class App extends Component { }) break } - case webviewCommands.ingCommands.UiCommands.updateTheme: + case WebviewCmd.IngCmd.UiCmd.updateTheme: this.setState({ theme: activeThemeProvider.activeTheme() }) break } @@ -75,8 +75,8 @@ export class App extends Component { } private refresh() { - vsCodeApi.getInstance().postMessage({ - command: webviewCommands.ingCommands.ExtensionCommands.refreshIngsList, + getVsCodeApiSingleton().postMessage({ + command: WebviewCmd.IngCmd.ExtCmd.refreshIngsList, payload: {}, }) } diff --git a/ui/ing/IngItem.tsx b/ui/ing/IngItem.tsx index 2984873b..a1639f97 100644 --- a/ui/ing/IngItem.tsx +++ b/ui/ing/IngItem.tsx @@ -5,8 +5,8 @@ import { take } from 'lodash-es' import { ActivityItem, IPersonaProps, Link, Text } from '@fluentui/react' import { format, formatDistanceStrict } from 'date-fns' import { zhCN } from 'date-fns/locale' -import { vsCodeApi } from 'share/vscode-api' -import { IngWebviewHostCommand, webviewCommands } from '@models/webview-commands' +import { getVsCodeApiSingleton } from 'share/vscode-api' +import { IngWebviewHostCmd, WebviewCmd } from '@models/webview-cmd' interface IngItemProps { ing: Ing @@ -197,11 +197,11 @@ class IngItem extends Component { } } - private comment(payload: webviewCommands.ingCommands.CommentCommandPayload) { - vsCodeApi.getInstance().postMessage({ - command: webviewCommands.ingCommands.ExtensionCommands.comment, + private comment(payload: WebviewCmd.IngCmd.CommentCmdPayload) { + getVsCodeApiSingleton().postMessage({ + command: WebviewCmd.IngCmd.ExtCmd.comment, payload, - } as IngWebviewHostCommand) + } as IngWebviewHostCmd) } } diff --git a/ui/post-configuration/App.tsx b/ui/post-cfg/App.tsx similarity index 87% rename from ui/post-configuration/App.tsx rename to ui/post-cfg/App.tsx index 7d106eec..38a41562 100644 --- a/ui/post-configuration/App.tsx +++ b/ui/post-cfg/App.tsx @@ -6,12 +6,12 @@ import { Post } from '@models/post' import { personalCategoriesStore } from './services/personal-categories-store' import { siteCategoriesStore } from './services/site-categories-store' import { tagsStore } from './services/tags-store' -import { webviewMessage } from '@models/webview-message' -import { webviewCommands } from '@models/webview-commands' +import { webviewMessage } from '@models/webview-msg' +import { WebviewCmd } from '@models/webview-cmd' import { PostFormContextProvider } from './components/PostFormContextProvider' import { activeThemeProvider } from 'share/active-theme-provider' import { darkTheme, lightTheme } from 'share/theme' -import { vsCodeApi } from 'share/vscode-api' +import { getVsCodeApiSingleton } from 'share/vscode-api' interface AppState { post?: Post @@ -28,7 +28,7 @@ class App extends Component { super(props) this.state = { theme: activeThemeProvider.activeTheme(), fileName: '', useNestCategoriesSelect: false } this.observerMessages() - vsCodeApi.getInstance().postMessage({ command: webviewCommands.ExtensionCommands.refreshPost }) + getVsCodeApiSingleton().postMessage({ command: WebviewCmd.ExtCmd.refreshPost }) } render() { @@ -87,9 +87,9 @@ class App extends Component { // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment const message = ev.data as any - if (command === webviewCommands.UiCommands.editPostConfiguration) { + if (command === WebviewCmd.UiCmd.editPostCfg) { const { post, activeTheme, personalCategories, siteCategories, tags, breadcrumbs, fileName } = - message as webviewMessage.EditPostConfigurationMessage + message as webviewMessage.EditPostCfgMessage personalCategoriesStore.set(personalCategories) siteCategoriesStore.set(siteCategories) tagsStore.set(tags) @@ -101,13 +101,13 @@ class App extends Component { fileName, useNestCategoriesSelect: personalCategories.some(c => c.childCount > 0), }) - } else if (command === webviewCommands.UiCommands.updateBreadcrumbs) { + } else if (command === WebviewCmd.UiCmd.updateBreadcrumbs) { const { breadcrumbs } = message as webviewMessage.UpdateBreadcrumbsMessage this.setState({ breadcrumbs }) - } else if (command === webviewCommands.UiCommands.setFluentIconBaseUrl) { + } else if (command === WebviewCmd.UiCmd.setFluentIconBaseUrl) { const { baseUrl } = message as webviewMessage.SetFluentIconBaseUrlMessage initializeIcons(baseUrl) - } else if (command === webviewCommands.UiCommands.updateTheme) { + } else if (command === WebviewCmd.UiCmd.updateTheme) { this.setState({ theme: activeThemeProvider.activeTheme() }) } }) diff --git a/ui/post-configuration/components/AccessPermissionSelector.tsx b/ui/post-cfg/components/AccessPermissionSelector.tsx similarity index 100% rename from ui/post-configuration/components/AccessPermissionSelector.tsx rename to ui/post-cfg/components/AccessPermissionSelector.tsx diff --git a/ui/post-configuration/components/CategoriesSelect.tsx b/ui/post-cfg/components/CategoriesSelect.tsx similarity index 100% rename from ui/post-configuration/components/CategoriesSelect.tsx rename to ui/post-cfg/components/CategoriesSelect.tsx diff --git a/ui/post-configuration/components/CommonOptions.tsx b/ui/post-cfg/components/CommonOptions.tsx similarity index 100% rename from ui/post-configuration/components/CommonOptions.tsx rename to ui/post-cfg/components/CommonOptions.tsx diff --git a/ui/post-configuration/components/ErrorResponse.tsx b/ui/post-cfg/components/ErrorResponse.tsx similarity index 89% rename from ui/post-configuration/components/ErrorResponse.tsx rename to ui/post-cfg/components/ErrorResponse.tsx index 3b0dddaf..fd48877d 100644 --- a/ui/post-configuration/components/ErrorResponse.tsx +++ b/ui/post-cfg/components/ErrorResponse.tsx @@ -1,6 +1,6 @@ import { MessageBar, MessageBarType } from '@fluentui/react' -import { webviewCommands } from '@models/webview-commands' -import { webviewMessage } from '@models/webview-message' +import { WebviewCmd } from '@models/webview-cmd' +import { webviewMessage } from '@models/webview-msg' import React from 'react' import { Optional } from 'utility-types' import { PostFormContext } from './PostFormContext' @@ -26,7 +26,7 @@ export class ErrorResponse extends React.Component - if (command === webviewCommands.UiCommands.showErrorResponse) { + if (command === WebviewCmd.UiCmd.showErrorResponse) { this.setState({ errors: errorResponse.errors ?? [] }, () => this.reveal()) this.context.set({ disabled: false, status: '' }) } diff --git a/ui/post-configuration/components/InputSummary.tsx b/ui/post-cfg/components/InputSummary.tsx similarity index 94% rename from ui/post-configuration/components/InputSummary.tsx rename to ui/post-cfg/components/InputSummary.tsx index b832e739..9848ff9c 100644 --- a/ui/post-configuration/components/InputSummary.tsx +++ b/ui/post-cfg/components/InputSummary.tsx @@ -1,9 +1,9 @@ import { ActionButton, Label, MessageBar, MessageBarType, Stack, TextField, Text } from '@fluentui/react' import { ImageUploadStatusId } from '@models/image-upload-status' -import { webviewCommands } from '@models/webview-commands' -import { webviewMessage } from '@models/webview-message' +import { WebviewCmd } from '@models/webview-cmd' +import { webviewMessage } from '@models/webview-msg' import React from 'react' -import { vsCodeApi } from 'share/vscode-api' +import { getVsCodeApiSingleton } from 'share/vscode-api' export interface IInputSummaryProps { summary?: string @@ -105,7 +105,7 @@ export class InputSummary extends React.Component void + onConfirm?: (postCfg: PostCfg) => void onTitleChange?: (title: string) => void } -export interface IPostFormState extends PostConfiguration {} +export interface IPostFormState extends PostCfg {} export class PostForm extends React.Component { static contextType?: React.Context | undefined = PostFormContext @@ -146,15 +146,13 @@ export class PostForm extends React.Component { private onConfirm() { // eslint-disable-next-line @typescript-eslint/no-unsafe-call this.context.set({ disabled: true, status: 'submitting' }) - vsCodeApi.getInstance().postMessage({ - command: webviewCommands.ExtensionCommands.uploadPost, + getVsCodeApiSingleton().postMessage({ + command: WebviewCmd.ExtCmd.uploadPost, post: Object.assign({}, this.props.post, this.state), } as webviewMessage.UploadPostMessage) } private onCancel() { - vsCodeApi - .getInstance() - .postMessage({ command: webviewCommands.ExtensionCommands.disposePanel } as webviewMessage.Message) + getVsCodeApiSingleton().postMessage({ command: WebviewCmd.ExtCmd.disposePanel } as webviewMessage.Message) } } diff --git a/ui/post-configuration/components/PostFormContext.ts b/ui/post-cfg/components/PostFormContext.ts similarity index 100% rename from ui/post-configuration/components/PostFormContext.ts rename to ui/post-cfg/components/PostFormContext.ts diff --git a/ui/post-configuration/components/PostFormContextProvider.tsx b/ui/post-cfg/components/PostFormContextProvider.tsx similarity index 100% rename from ui/post-configuration/components/PostFormContextProvider.tsx rename to ui/post-cfg/components/PostFormContextProvider.tsx diff --git a/ui/post-configuration/components/PostTitleInput.tsx b/ui/post-cfg/components/PostTitleInput.tsx similarity index 100% rename from ui/post-configuration/components/PostTitleInput.tsx rename to ui/post-cfg/components/PostTitleInput.tsx diff --git a/ui/post-configuration/components/SiteCategoriesSelector.tsx b/ui/post-cfg/components/SiteCategoriesSelector.tsx similarity index 100% rename from ui/post-configuration/components/SiteCategoriesSelector.tsx rename to ui/post-cfg/components/SiteCategoriesSelector.tsx diff --git a/ui/post-configuration/components/SiteHomeContributionOptionsSelector.tsx b/ui/post-cfg/components/SiteHomeContributionOptionsSelector.tsx similarity index 100% rename from ui/post-configuration/components/SiteHomeContributionOptionsSelector.tsx rename to ui/post-cfg/components/SiteHomeContributionOptionsSelector.tsx diff --git a/ui/post-configuration/components/TagsInput.tsx b/ui/post-cfg/components/TagsInput.tsx similarity index 100% rename from ui/post-configuration/components/TagsInput.tsx rename to ui/post-cfg/components/TagsInput.tsx diff --git a/ui/post-configuration/index.html b/ui/post-cfg/index.html similarity index 74% rename from ui/post-configuration/index.html rename to ui/post-cfg/index.html index 1de9b6d3..a2b40c84 100644 --- a/ui/post-configuration/index.html +++ b/ui/post-cfg/index.html @@ -8,13 +8,13 @@ + href="@PWD/ui/post-cfg/index.css">
+ src="@PWD/ui/post-cfg/index.js"> diff --git a/ui/post-configuration/index.less b/ui/post-cfg/index.less similarity index 100% rename from ui/post-configuration/index.less rename to ui/post-cfg/index.less diff --git a/ui/post-configuration/index.tsx b/ui/post-cfg/index.tsx similarity index 100% rename from ui/post-configuration/index.tsx rename to ui/post-cfg/index.tsx diff --git a/ui/post-configuration/models/site-home-contribution-options.ts b/ui/post-cfg/models/site-home-contribution-options.ts similarity index 100% rename from ui/post-configuration/models/site-home-contribution-options.ts rename to ui/post-cfg/models/site-home-contribution-options.ts diff --git a/ui/post-configuration/services/personal-categories-store.ts b/ui/post-cfg/services/personal-categories-store.ts similarity index 77% rename from ui/post-configuration/services/personal-categories-store.ts rename to ui/post-cfg/services/personal-categories-store.ts index 337c218f..c22cf8d0 100644 --- a/ui/post-configuration/services/personal-categories-store.ts +++ b/ui/post-cfg/services/personal-categories-store.ts @@ -1,6 +1,6 @@ import { PostCategories } from '@/models/post-category' -import { WebviewCommonCommand, webviewCommands } from '@models/webview-commands' -import { vsCodeApi } from 'share/vscode-api' +import { WebviewCommonCmd, WebviewCmd } from '@models/webview-cmd' +import { getVsCodeApiSingleton } from 'share/vscode-api' let children: Map let pendingChildrenQuery: Map> | undefined | null @@ -12,7 +12,7 @@ export namespace personalCategoriesStore { export const getByParent = async (parent: number): Promise => { children ??= new Map() let result = children.get(parent) - const vscode = vsCodeApi.getInstance() + const vscode = getVsCodeApiSingleton() if (!result) { let promise = pendingChildrenQuery?.get(parent) @@ -28,7 +28,7 @@ export namespace personalCategoriesStore { const onUpdate = ({ data: message, }: { - data: WebviewCommonCommand + data: WebviewCommonCmd }) => { console.log('onUpdate', message) if (message.payload.parentId === parent) { @@ -40,14 +40,14 @@ export namespace personalCategoriesStore { } } - window.addEventListener>( + window.addEventListener>( 'message', onUpdate ) }).finally(() => pendingChildrenQuery?.delete(parent)) - vscode.postMessage>({ - command: webviewCommands.ExtensionCommands.getChildCategories, + vscode.postMessage>({ + command: WebviewCmd.ExtCmd.getChildCategories, payload: { parentId: parent }, }) } diff --git a/ui/post-configuration/services/site-categories-store.ts b/ui/post-cfg/services/site-categories-store.ts similarity index 100% rename from ui/post-configuration/services/site-categories-store.ts rename to ui/post-cfg/services/site-categories-store.ts diff --git a/ui/post-configuration/services/tags-store.ts b/ui/post-cfg/services/tags-store.ts similarity index 100% rename from ui/post-configuration/services/tags-store.ts rename to ui/post-cfg/services/tags-store.ts diff --git a/ui/share/vscode-api.ts b/ui/share/vscode-api.ts index 4dcc36eb..b3e37305 100644 --- a/ui/share/vscode-api.ts +++ b/ui/share/vscode-api.ts @@ -1,4 +1,6 @@ -export namespace vsCodeApi { - let instance: VsCodeApi | undefined - export const getInstance = () => (instance ??= acquireVsCodeApi()) +let instance: VsCodeApi | undefined + +export function getVsCodeApiSingleton() { + instance ??= acquireVsCodeApi() + return instance } From 1556f9ada9072a0759da12cdd29d94eeae92d6f5 Mon Sep 17 00:00:00 2001 From: Thaumy Date: Thu, 20 Jul 2023 17:49:45 +0800 Subject: [PATCH 007/157] style: optimize imports --- .prettierrc.js | 1 + download-iconfont.mjs | 4 +- package-lock.json | 30 ++++++++++- package.json | 1 + src/auth/account-manager.ts | 20 +++---- src/auth/auth-provider.ts | 14 ++--- src/commands/blog-export/create.ts | 10 ++-- src/commands/blog-export/delete.ts | 4 +- src/commands/blog-export/download.ts | 6 +-- src/commands/blog-export/edit.ts | 4 +- src/commands/blog-export/index.ts | 10 ++-- src/commands/blog-export/open-local.ts | 17 +++--- src/commands/blog-export/refresh.ts | 2 +- src/commands/cmd-register.ts | 52 +++++++++---------- src/commands/extract-images.ts | 10 ++-- src/commands/ing/ings-list-cmd-register.ts | 10 ++-- src/commands/ing/open-ing-in-browser.ts | 2 +- src/commands/ing/publish-ing.ts | 10 ++-- src/commands/open-my-account-settings.ts | 2 +- src/commands/open-my-blog-console.ts | 2 +- src/commands/open-my-blog.ts | 2 +- src/commands/open-post-in-blog-admin.ts | 4 +- src/commands/open-workspace.ts | 6 +-- src/commands/pdf/export-pdf.command.ts | 28 +++++----- src/commands/pdf/post-pdf-template-builder.ts | 8 +-- .../delete-selected-categories.ts | 8 +-- .../post-category/input-post-category.ts | 2 +- .../post-category/new-post-category.ts | 6 +-- .../post-category/update-post-category.ts | 8 +-- src/commands/posts-list/copy-link.ts | 4 +- src/commands/posts-list/create-local-draft.ts | 4 +- .../delete-post-to-local-file-map.ts | 6 +-- src/commands/posts-list/delete-post.ts | 16 +++--- .../posts-list/modify-post-settings.ts | 28 +++++----- src/commands/posts-list/open-post-file.ts | 4 +- .../posts-list/open-post-in-vscode.ts | 20 +++---- src/commands/posts-list/refresh-posts-list.ts | 10 ++-- src/commands/posts-list/rename-post.ts | 16 +++--- src/commands/posts-list/search.ts | 2 +- src/commands/posts-list/upload-post.ts | 42 +++++++-------- src/commands/pull-post-remote-updates.ts | 18 +++---- src/commands/reveal-local-post-file-in-os.ts | 4 +- src/commands/reveal-workspace-in-os.ts | 4 +- src/commands/set-workspace.ts | 6 +-- src/commands/show-local-file-to-post-info.ts | 18 +++---- .../upload-image/upload-clipboard-image.ts | 8 +-- .../upload-image/upload-image-utils.ts | 6 +-- src/commands/upload-image/upload-image.ts | 7 ++- .../upload-image/upload-local-disk-image.ts | 2 +- src/commands/view-post-online.ts | 6 +-- src/extension.ts | 8 +-- src/markdown/extend-markdownIt.ts | 2 +- src/models/ing-view.ts | 2 +- src/models/webview-msg.ts | 10 ++-- src/services/alert.service.ts | 15 ++---- src/services/blog-export-post.store.ts | 2 +- src/services/blog-settings.service.ts | 2 +- src/services/check-workspace.ts | 6 +-- src/services/global-ctx.ts | 2 +- src/services/image.service.ts | 6 +-- src/services/ing.api.ts | 22 ++++---- src/services/ings-list-webview-provider.ts | 16 +++--- src/services/local-draft.service.ts | 2 +- src/services/mkd-img-extractor.service.ts | 12 ++--- src/services/oauth.api.ts | 4 +- src/services/parse-webview-html.ts | 2 +- src/services/post-category.service.ts | 4 +- src/services/post-cfg-panel.service.ts | 20 +++---- src/services/post-tag.service.ts | 2 +- src/services/post-title-sanitizer.service.ts | 2 +- src/services/post.service.ts | 23 ++++---- src/services/search-post-by-title.ts | 2 +- src/services/settings.service.ts | 6 +-- src/services/site-category.service.ts | 2 +- src/test/suite/extension.test.ts | 4 +- src/test/suite/index.ts | 4 +- .../blog-export-provider.ts | 10 ++-- src/tree-view-providers/converters.ts | 6 +-- .../models/blog-export/index.ts | 10 ++-- .../models/blog-export/parser.ts | 6 +-- .../models/blog-export/record.ts | 16 +++--- .../models/post-category-tree-item.ts | 2 +- .../models/post-metadata.ts | 12 ++--- .../models/post-search-result-entry.ts | 2 +- .../models/post-tree-item.ts | 2 +- .../post-categories-tree-data-provider.ts | 10 ++-- .../posts-data-provider.ts | 10 ++-- .../tree-view-registration.ts | 12 ++--- src/utils/chromium-path-provider.ts | 6 +-- src/utils/cmd.ts | 8 +-- src/utils/get-clipboard-image.ts | 14 ++--- src/utils/http-client.ts | 4 +- src/utils/input-post-settings.ts | 6 +-- src/utils/msg.ts | 0 src/utils/save-file-pending-changes.ts | 2 +- src/utils/throw-if-not-ok-response.ts | 4 +- src/utils/tree-view.ts | 6 +-- src/utils/uri-handler.ts | 2 +- ui/ing/App.tsx | 14 ++--- ui/ing/IngItem.tsx | 8 +-- ui/ing/IngList.tsx | 4 +- ui/ing/index.tsx | 2 +- ui/post-cfg/App.tsx | 16 +++--- ui/post-cfg/components/InputSummary.tsx | 2 +- ui/post-cfg/components/PostForm.tsx | 28 +++++----- .../components/PostFormContextProvider.tsx | 2 +- .../SiteHomeContributionOptionsSelector.tsx | 6 +-- ui/post-cfg/components/TagsInput.tsx | 4 +- ui/post-cfg/index.tsx | 4 +- .../services/personal-categories-store.ts | 2 +- ui/webpack.config.mjs | 6 +-- webpack.config.mjs | 2 +- 112 files changed, 479 insertions(+), 467 deletions(-) delete mode 100644 src/utils/msg.ts diff --git a/.prettierrc.js b/.prettierrc.js index 767c7f06..f370214b 100644 --- a/.prettierrc.js +++ b/.prettierrc.js @@ -2,4 +2,5 @@ module.exports = { ...require('@cnblogs/prettier-config'), tabWidth: 4, semi: false, + organizeImportsSkipDestructiveCodeActions: true, } diff --git a/download-iconfont.mjs b/download-iconfont.mjs index 6013c5a5..53839c95 100644 --- a/download-iconfont.mjs +++ b/download-iconfont.mjs @@ -1,7 +1,7 @@ /* eslint-disable no-console */ -import fetch from 'node-fetch' -import fs from 'fs' import AdmZip from 'adm-zip' +import fs from 'fs' +import fetch from 'node-fetch' const url = 'https://www.iconfont.cn/api/project/download.zip?spm=a313x.7781069.1998910419.d7543c303&pid=2996691&ctoken=ndNRCUzYy381Rxk59b1LjTrg' const cookie = diff --git a/package-lock.json b/package-lock.json index b4739722..d94d0ddb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -79,6 +79,7 @@ "postcss-loader": "^6.2.1", "postcss-preset-env": "^7.4.3", "prettier": "^2.8.8", + "prettier-plugin-organize-imports": "^3.2.3", "style-loader": "^3.3.1", "tailwindcss": "^3.0.23", "terser-webpack-plugin": "^5.3.7", @@ -92,7 +93,7 @@ "webpack-cli": "^5.0.1" }, "engines": { - "vscode": "^1.70.0" + "vscode": "^1.80.0" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -12137,6 +12138,26 @@ "node": ">=6.0.0" } }, + "node_modules/prettier-plugin-organize-imports": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/prettier-plugin-organize-imports/-/prettier-plugin-organize-imports-3.2.3.tgz", + "integrity": "sha512-KFvk8C/zGyvUaE3RvxN2MhCLwzV6OBbFSkwZ2OamCrs9ZY4i5L77jQ/w4UmUr+lqX8qbaqVq6bZZkApn+IgJSg==", + "dev": true, + "peerDependencies": { + "@volar/vue-language-plugin-pug": "^1.0.4", + "@volar/vue-typescript": "^1.0.4", + "prettier": ">=2.0", + "typescript": ">=2.9" + }, + "peerDependenciesMeta": { + "@volar/vue-language-plugin-pug": { + "optional": true + }, + "@volar/vue-typescript": { + "optional": true + } + } + }, "node_modules/pretty-format": { "version": "29.4.3", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.4.3.tgz", @@ -23143,6 +23164,13 @@ "fast-diff": "^1.1.2" } }, + "prettier-plugin-organize-imports": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/prettier-plugin-organize-imports/-/prettier-plugin-organize-imports-3.2.3.tgz", + "integrity": "sha512-KFvk8C/zGyvUaE3RvxN2MhCLwzV6OBbFSkwZ2OamCrs9ZY4i5L77jQ/w4UmUr+lqX8qbaqVq6bZZkApn+IgJSg==", + "dev": true, + "requires": {} + }, "pretty-format": { "version": "29.4.3", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.4.3.tgz", diff --git a/package.json b/package.json index 3faa7d4e..e7888a5a 100644 --- a/package.json +++ b/package.json @@ -1361,6 +1361,7 @@ "postcss-loader": "^6.2.1", "postcss-preset-env": "^7.4.3", "prettier": "^2.8.8", + "prettier-plugin-organize-imports": "^3.2.3", "style-loader": "^3.3.1", "tailwindcss": "^3.0.23", "terser-webpack-plugin": "^5.3.7", diff --git a/src/auth/account-manager.ts b/src/auth/account-manager.ts index 5829ba86..772df47b 100644 --- a/src/auth/account-manager.ts +++ b/src/auth/account-manager.ts @@ -1,15 +1,15 @@ -import { AccountInfo } from './account-info' -import { globalCtx } from '@/services/global-ctx' -import vscode, { authentication, AuthenticationGetSessionOptions, Disposable } from 'vscode' -import { accountViewDataProvider } from '@/tree-view-providers/account-view-data-provider' -import { postsDataProvider } from '@/tree-view-providers/posts-data-provider' -import { postCategoriesDataProvider } from '@/tree-view-providers/post-categories-tree-data-provider' -import { Oauth } from '@/services/oauth.api' import { AuthProvider } from '@/auth/auth-provider' import { AuthSession } from '@/auth/auth-session' +import { Alert } from '@/services/alert.service' +import { globalCtx } from '@/services/global-ctx' +import { Oauth } from '@/services/oauth.api' +import { accountViewDataProvider } from '@/tree-view-providers/account-view-data-provider' import { BlogExportProvider } from '@/tree-view-providers/blog-export-provider' -import { AlertService } from '@/services/alert.service' +import { postCategoriesDataProvider } from '@/tree-view-providers/post-categories-tree-data-provider' +import { postsDataProvider } from '@/tree-view-providers/posts-data-provider' import { execCmd } from '@/utils/cmd' +import vscode, { authentication, AuthenticationGetSessionOptions, Disposable } from 'vscode' +import { AccountInfo } from './account-info' const isAuthorizedStorageKey = 'isAuthorized' @@ -81,7 +81,7 @@ class AccountManager extends vscode.Disposable { await AuthProvider.instance.removeSession(session.id) await Oauth.revokeToken(session.accessToken) } catch (e: any) { - AlertService.err(`登出发生错误: ${e}`) + void Alert.err(`登出发生错误: ${e}`) } } @@ -102,7 +102,7 @@ class AccountManager extends vscode.Disposable { const session = await authentication.getSession(AuthProvider.instance.providerId, [], opt).then( session => (session ? AuthSession.from(session) : null), e => { - AlertService.err(`创建/获取 Session 失败: ${e}`) + void Alert.err(`创建/获取 Session 失败: ${e}`) } ) diff --git a/src/auth/auth-provider.ts b/src/auth/auth-provider.ts index 44461c30..3c836668 100644 --- a/src/auth/auth-provider.ts +++ b/src/auth/auth-provider.ts @@ -1,6 +1,13 @@ +import { AccountInfo } from '@/auth/account-info' import { AuthSession } from '@/auth/auth-session' +import { TokenInfo } from '@/models/token-info' import { genVerifyChallengePair } from '@/services/code-challenge.service' +import { globalCtx } from '@/services/global-ctx' +import { Oauth } from '@/services/oauth.api' +import { extUriHandler } from '@/utils/uri-handler' import { isArray, isUndefined } from 'lodash-es' +import RandomString from 'randomstring' +import { Optional } from 'utility-types' import { authentication, AuthenticationProvider, @@ -14,13 +21,6 @@ import { Uri, window, } from 'vscode' -import { globalCtx } from '@/services/global-ctx' -import RandomString from 'randomstring' -import { Oauth } from '@/services/oauth.api' -import { extUriHandler } from '@/utils/uri-handler' -import { AccountInfo } from '@/auth/account-info' -import { TokenInfo } from '@/models/token-info' -import { Optional } from 'utility-types' export class AuthProvider implements AuthenticationProvider, Disposable { static readonly providerId = 'cnblogs' diff --git a/src/commands/blog-export/create.ts b/src/commands/blog-export/create.ts index cb71ef00..4bde0275 100644 --- a/src/commands/blog-export/create.ts +++ b/src/commands/blog-export/create.ts @@ -1,5 +1,5 @@ import { CmdHandler } from '@/commands/cmd-handler' -import { AlertService } from '@/services/alert.service' +import { Alert } from '@/services/alert.service' import { BlogExportApi } from '@/services/blog-export.api' import { BlogExportProvider } from '@/tree-view-providers/blog-export-provider' import { MessageItem, window } from 'vscode' @@ -12,7 +12,7 @@ export class CreateBlogExportCmdHandler extends CmdHandler { if ( (await BlogExportApi.create().catch((e: unknown) => { - AlertService.httpErr(typeof e === 'object' && e ? e : {}, { message: '创建博客备份失败' }) + void Alert.httpErr(typeof e === 'object' && e ? e : {}, { message: '创建博客备份失败' }) return false })) !== false ) @@ -21,11 +21,7 @@ export class CreateBlogExportCmdHandler extends CmdHandler { private async confirm(): Promise { const items: MessageItem[] = [{ title: '确定', isCloseAffordance: false }] - const result = await AlertService.info( - '确定要创建备份吗?', - { modal: true, detail: '一天可以创建一次备份' }, - ...items - ) + const result = await Alert.info('确定要创建备份吗?', { modal: true, detail: '一天可以创建一次备份' }, ...items) return result != null } } diff --git a/src/commands/blog-export/delete.ts b/src/commands/blog-export/delete.ts index 66d7a5de..e41279d3 100644 --- a/src/commands/blog-export/delete.ts +++ b/src/commands/blog-export/delete.ts @@ -1,6 +1,6 @@ import { TreeViewCmdHandler } from '@/commands/cmd-handler' import { DownloadedBlogExport } from '@/models/blog-export' -import { AlertService } from '@/services/alert.service' +import { Alert } from '@/services/alert.service' import { BlogExportApi } from '@/services/blog-export.api' import { DownloadedExportStore } from '@/services/downloaded-export.store' import { BlogExportProvider } from '@/tree-view-providers/blog-export-provider' @@ -86,7 +86,7 @@ export class DeleteCmdHandler extends TreeViewCmdHandler true) .catch((e: unknown) => { - AlertService.httpErr(typeof e === 'object' && e != null ? e : {}) + void Alert.httpErr(typeof e === 'object' && e != null ? e : {}) return false }) if (hasDeleted) if (downloaded) await this.removeDownloadedBlogExport(downloaded, { shouldDeleteLocal }) diff --git a/src/commands/blog-export/download.ts b/src/commands/blog-export/download.ts index edb54bee..6695a233 100644 --- a/src/commands/blog-export/download.ts +++ b/src/commands/blog-export/download.ts @@ -1,5 +1,5 @@ import { TreeViewCmdHandler } from '@/commands/cmd-handler' -import { AlertService } from '@/services/alert.service' +import { Alert } from '@/services/alert.service' import { BlogExportApi } from '@/services/blog-export.api' import { DownloadedExportStore } from '@/services/downloaded-export.store' import { globalCtx } from '@/services/global-ctx' @@ -7,12 +7,12 @@ import { Settings } from '@/services/settings.service' import { BlogExportProvider } from '@/tree-view-providers/blog-export-provider' import { BlogExportRecordTreeItem } from '@/tree-view-providers/models/blog-export' import { extViews } from '@/tree-view-providers/tree-view-registration' +import { execCmd } from '@/utils/cmd' import fs from 'fs' import { Progress } from 'got' import path from 'path' import { promisify } from 'util' import { commands } from 'vscode' -import { execCmd } from '@/utils/cmd' export class DownloadExportCmdHandler extends TreeViewCmdHandler { static readonly commandName = 'vscode-cnb.blog-export.download' @@ -47,7 +47,7 @@ export class DownloadExportCmdHandler extends TreeViewCmdHandler { - if (msg) AlertService.warn(msg) + if (msg) void Alert.warn(msg) if (!isFileExist) fs.rmSync(zipFilePath) blogExportProvider?.refreshItem(treeItem) this.setIsDownloading(false).then(undefined, console.warn) diff --git a/src/commands/blog-export/edit.ts b/src/commands/blog-export/edit.ts index d65f8c19..23c12389 100644 --- a/src/commands/blog-export/edit.ts +++ b/src/commands/blog-export/edit.ts @@ -1,6 +1,6 @@ import { TreeViewCmdHandler } from '@/commands/cmd-handler' import { openPostFile } from '@/commands/posts-list/open-post-file' -import { AlertService } from '@/services/alert.service' +import { Alert } from '@/services/alert.service' import { Settings } from '@/services/settings.service' import { ExportPostTreeItem } from '@/tree-view-providers/models/blog-export/post' import fs from 'fs' @@ -21,7 +21,7 @@ export class EditExportPostCmdHandler extends TreeViewCmdHandler { const target = this.parseInput() - if (!target) return void AlertService.warn('不支持的参数输入') + if (!target) return void Alert.warn('不支持的参数输入') const { post: { title, isMarkdown, id: postId }, diff --git a/src/commands/blog-export/index.ts b/src/commands/blog-export/index.ts index a0f89fe0..52c92ff4 100644 --- a/src/commands/blog-export/index.ts +++ b/src/commands/blog-export/index.ts @@ -1,12 +1,12 @@ -import { RefreshExportRecordsCmdHandler } from './refresh' -import { globalCtx } from '@/services/global-ctx' -import { OpenLocalExportCmdHandler } from '@/commands/blog-export/open-local' -import { EditExportPostCmdHandler } from '@/commands/blog-export/edit' import { CreateBlogExportCmdHandler } from '@/commands/blog-export/create' +import { DeleteCmdHandler } from '@/commands/blog-export/delete' import { DownloadExportCmdHandler } from '@/commands/blog-export/download' +import { EditExportPostCmdHandler } from '@/commands/blog-export/edit' +import { OpenLocalExportCmdHandler } from '@/commands/blog-export/open-local' import { ViewPostCmdHandler } from '@/commands/blog-export/view-post' -import { DeleteCmdHandler } from '@/commands/blog-export/delete' +import { globalCtx } from '@/services/global-ctx' import { regCmd } from '@/utils/cmd' +import { RefreshExportRecordsCmdHandler } from './refresh' export function regBlogExportCmds() { const { extName } = globalCtx diff --git a/src/commands/blog-export/open-local.ts b/src/commands/blog-export/open-local.ts index ed46ea9e..fa02974b 100644 --- a/src/commands/blog-export/open-local.ts +++ b/src/commands/blog-export/open-local.ts @@ -1,11 +1,11 @@ import { CmdHandler } from '@/commands/cmd-handler' -import { window } from 'vscode' -import path from 'path' -import fs from 'fs' -import { promisify } from 'util' -import { AlertService } from '@/services/alert.service' +import { Alert } from '@/services/alert.service' import { DownloadedExportStore } from '@/services/downloaded-export.store' import { BlogExportProvider } from '@/tree-view-providers/blog-export-provider' +import fs from 'fs' +import path from 'path' +import { promisify } from 'util' +import { window } from 'vscode' const defaultOptions = { confirmUnzip: true } @@ -28,8 +28,7 @@ export class OpenLocalExportCmdHandler extends CmdHandler { })) ?? [] if (fileUri == null) return const filePath = fileUri.fsPath - if (filePath.endsWith('.zip') && !filePath.endsWith('.db.zip')) - return void AlertService.warn('不支持的博客备份文件') + if (filePath.endsWith('.zip') && !filePath.endsWith('.db.zip')) return void Alert.warn('不支持的博客备份文件') const fileName = path.basename(filePath.replace(/\.db(\.zip)?$/, '')) const dirname = path.dirname(filePath) @@ -37,7 +36,7 @@ export class OpenLocalExportCmdHandler extends CmdHandler { isConfirmedToUnzip = filePath.endsWith('.db.zip') // if (!confirmUnzip && fileUri.fsPath.endsWith('db.zip')) { // const options: (MessageItem & { confirmed: boolean })[] = [{ title: '确定', confirmed: true }]; - // const selected = await AlertService.info( + // const selected = await Alert.info( // '浏览博客备份需要解决, 确定要解压吗?', // { modal: true }, // ...options @@ -56,7 +55,7 @@ export class OpenLocalExportCmdHandler extends CmdHandler { const dbFileName = path.basename(dbFilePath) const isExist = await promisify(fs.exists)(dbFilePath) - if (!isExist) return void AlertService.warn('文件不存在') + if (!isExist) return void Alert.warn('文件不存在') const treeProvider = BlogExportProvider.optionalInstance const dbFileSize = (await promisify(fs.stat)(dbFilePath)).size diff --git a/src/commands/blog-export/refresh.ts b/src/commands/blog-export/refresh.ts index 08e85ab9..4759dded 100644 --- a/src/commands/blog-export/refresh.ts +++ b/src/commands/blog-export/refresh.ts @@ -1,7 +1,7 @@ import { CmdHandler } from '@/commands/cmd-handler' -import { execCmd } from '@/utils/cmd' import { globalCtx } from '@/services/global-ctx' import { BlogExportProvider } from '@/tree-view-providers/blog-export-provider' +import { execCmd } from '@/utils/cmd' import { commands } from 'vscode' export class RefreshExportRecordsCmdHandler extends CmdHandler { diff --git a/src/commands/cmd-register.ts b/src/commands/cmd-register.ts index 5fd9fd7d..21522e24 100644 --- a/src/commands/cmd-register.ts +++ b/src/commands/cmd-register.ts @@ -1,42 +1,42 @@ +import { regBlogExportCmds } from '@/commands/blog-export' +import { PublishIngCmdHandler } from '@/commands/ing/publish-ing' +import { CopyPostLinkCmdHandler } from '@/commands/posts-list/copy-link' +import { globalCtx } from '@/services/global-ctx' +import { regCmd } from '@/utils/cmd' +import { regIngListCmds } from 'src/commands/ing/ings-list-cmd-register' +import { extractImages } from './extract-images' +import { login, logout } from './login' import { openMyAccountSettings } from './open-my-account-settings' +import { openMyBlog } from './open-my-blog' import { openMyWebBlogConsole } from './open-my-blog-console' import { openMyHomePage } from './open-my-home-page' -import { login, logout } from './login' -import { openMyBlog } from './open-my-blog' -import { globalCtx } from '@/services/global-ctx' +import { openPostInBlogAdmin } from './open-post-in-blog-admin' +import { openWorkspace } from './open-workspace' +import { handleDeletePostCategories } from './post-category/delete-selected-categories' +import { newPostCategory } from './post-category/new-post-category' +import { refreshPostCategoriesList } from './post-category/refresh-post-categories-list' +import { handleUpdatePostCategory } from './post-category/update-post-category' +import { createLocalDraft } from './posts-list/create-local-draft' +import { deleteSelectedPosts } from './posts-list/delete-post' +import { deletePostToLocalFileMap } from './posts-list/delete-post-to-local-file-map' +import { modifyPostSettings } from './posts-list/modify-post-settings' +import { openPostInVscode } from './posts-list/open-post-in-vscode' import { gotoNextPostsList, gotoPreviousPostsList, refreshPostsList, seekPostsList, } from './posts-list/refresh-posts-list' +import { renamePost } from './posts-list/rename-post' +import { clearPostsSearchResults, refreshPostsSearchResults, searchPosts } from './posts-list/search' import { uploadPostFileToCnblogs, uploadPostToCnblogs } from './posts-list/upload-post' -import { createLocalDraft } from './posts-list/create-local-draft' -import { deleteSelectedPosts } from './posts-list/delete-post' -import { modifyPostSettings } from './posts-list/modify-post-settings' -import { uploadImage } from './upload-image/upload-image' +import { pullPostRemoteUpdates } from './pull-post-remote-updates' import { revealLocalPostFileInOs } from './reveal-local-post-file-in-os' -import { showLocalFileToPostInfo } from './show-local-file-to-post-info' -import { newPostCategory } from './post-category/new-post-category' -import { refreshPostCategoriesList } from './post-category/refresh-post-categories-list' -import { handleUpdatePostCategory } from './post-category/update-post-category' -import { openPostInVscode } from './posts-list/open-post-in-vscode' -import { deletePostToLocalFileMap } from './posts-list/delete-post-to-local-file-map' -import { renamePost } from './posts-list/rename-post' -import { openPostInBlogAdmin } from './open-post-in-blog-admin' -import { openWorkspace } from './open-workspace' -import { setWorkspace } from './set-workspace' import { revealWorkspaceInOs } from './reveal-workspace-in-os' +import { setWorkspace } from './set-workspace' +import { showLocalFileToPostInfo } from './show-local-file-to-post-info' +import { uploadImage } from './upload-image/upload-image' import { viewPostOnline } from './view-post-online' -import { pullPostRemoteUpdates } from './pull-post-remote-updates' -import { extractImages } from './extract-images' -import { clearPostsSearchResults, refreshPostsSearchResults, searchPosts } from './posts-list/search' -import { handleDeletePostCategories } from './post-category/delete-selected-categories' -import { PublishIngCmdHandler } from '@/commands/ing/publish-ing' -import { regIngListCmds } from 'src/commands/ing/ings-list-cmd-register' -import { CopyPostLinkCmdHandler } from '@/commands/posts-list/copy-link' -import { regBlogExportCmds } from '@/commands/blog-export' -import { regCmd } from '@/utils/cmd' export function setupExtCmd() { const ctx = globalCtx.extCtx diff --git a/src/commands/extract-images.ts b/src/commands/extract-images.ts index 6c1066e8..35d41d42 100644 --- a/src/commands/extract-images.ts +++ b/src/commands/extract-images.ts @@ -1,6 +1,6 @@ -import { MessageItem, MessageOptions, ProgressLocation, Range, Uri, window, workspace, WorkspaceEdit } from 'vscode' +import { Alert } from '@/services/alert.service' import { ImageInfo, ImageSrc, MkdImgExtractor, newImageSrcFilter } from '@/services/mkd-img-extractor.service' -import { AlertService } from '@/services/alert.service' +import { MessageItem, MessageOptions, ProgressLocation, Range, Uri, window, workspace, WorkspaceEdit } from 'vscode' type ExtractOption = MessageItem & Partial<{ imageSrc: ImageSrc }> @@ -17,7 +17,7 @@ export async function extractImages(arg: unknown, inputImageSrc?: ImageSrc) { const extractor = new MkdImgExtractor(markdown, arg) const images = extractor.findImages() - if (images.length <= 0) void (!inputImageSrc != null ? AlertService.warn('没有找到可以提取的图片') : undefined) + if (images.length <= 0) void (!inputImageSrc != null ? Alert.warn('没有找到可以提取的图片') : undefined) const getExtractOption = () => { const webImgCount = images.filter(newImageSrcFilter(ImageSrc.web)).length @@ -36,7 +36,7 @@ export async function extractImages(arg: unknown, inputImageSrc?: ImageSrc) { return Promise.resolve(displayOptions.find(ent => ent.imageSrc === inputImageSrc)) // if src is not specified: - return AlertService.info( + return Alert.info( '要提取哪些图片? 此操作会替换源文件中的图片链接!', { modal: true, @@ -113,6 +113,6 @@ export async function extractImages(arg: unknown, inputImageSrc?: ImageSrc) { const info = failedImages .map(info => [info.data, extractor.errors.find(([link]) => link === info.data)?.[1] ?? ''].join(',')) .join('\n') - AlertService.err(`${failedImages.length} 张图片提取失败: ${info}`).then(undefined, console.warn) + void Alert.err(`${failedImages.length} 张图片提取失败: ${info}`).then(undefined, console.warn) } } diff --git a/src/commands/ing/ings-list-cmd-register.ts b/src/commands/ing/ings-list-cmd-register.ts index 892e9a79..7a655af3 100644 --- a/src/commands/ing/ings-list-cmd-register.ts +++ b/src/commands/ing/ings-list-cmd-register.ts @@ -1,13 +1,13 @@ -import { RefreshIngsList } from 'src/commands/ing/refresh-ings-list' -import { globalCtx } from 'src/services/global-ctx' +import { OpenIngInBrowser } from '@/commands/ing/open-ing-in-browser' +import { SelectIngType } from '@/commands/ing/select-ing-type' +import { regCmd } from '@/utils/cmd' import { GotoIngsListFirstPage, GotoIngsListNextPage, GotoIngsListPreviousPage, } from 'src/commands/ing/goto-ings-list-page' -import { SelectIngType } from '@/commands/ing/select-ing-type' -import { OpenIngInBrowser } from '@/commands/ing/open-ing-in-browser' -import { regCmd } from '@/utils/cmd' +import { RefreshIngsList } from 'src/commands/ing/refresh-ings-list' +import { globalCtx } from 'src/services/global-ctx' export const regIngListCmds = () => { const appName = globalCtx.extName diff --git a/src/commands/ing/open-ing-in-browser.ts b/src/commands/ing/open-ing-in-browser.ts index fdc68b7c..e1756b3c 100644 --- a/src/commands/ing/open-ing-in-browser.ts +++ b/src/commands/ing/open-ing-in-browser.ts @@ -1,6 +1,6 @@ import { CmdHandler } from '@/commands/cmd-handler' -import { execCmd } from '@/utils/cmd' import { globalCtx } from '@/services/global-ctx' +import { execCmd } from '@/utils/cmd' import { Uri } from 'vscode' export class OpenIngInBrowser extends CmdHandler { diff --git a/src/commands/ing/publish-ing.ts b/src/commands/ing/publish-ing.ts index 955ecd49..16967f1c 100644 --- a/src/commands/ing/publish-ing.ts +++ b/src/commands/ing/publish-ing.ts @@ -1,11 +1,11 @@ import { CmdHandler } from '@/commands/cmd-handler' -import { execCmd } from '@/utils/cmd' import { IngPublishModel, IngType } from '@/models/ing' -import { AlertService } from '@/services/alert.service' +import { Alert } from '@/services/alert.service' import { globalCtx } from '@/services/global-ctx' import { IngApi } from '@/services/ing.api' import { IngsListWebviewProvider } from '@/services/ings-list-webview-provider' import { InputStep, MultiStepInput, QuickPickParameters } from '@/services/multi-step-input' +import { execCmd } from '@/utils/cmd' import { MessageOptions, ProgressLocation, QuickPickItem, Uri, window } from 'vscode' export class PublishIngCmdHandler extends CmdHandler { @@ -134,7 +134,7 @@ export class PublishIngCmdHandler extends CmdHandler { ['编辑访问权限', async () => (await this.acquireInputContent(this.inputStep.access)) !== false], ['编辑标签', async () => (await this.acquireInputContent(this.inputStep.tags)) !== false], ] as const - const selected = await AlertService.info( + const selected = await Alert.info( '确定要发布闪存吗?', { modal: true, @@ -146,7 +146,7 @@ export class PublishIngCmdHandler extends CmdHandler { } private warnNoSelection() { - AlertService.warn(`无法${this.operation}, 当前没有选中的内容`) + void Alert.warn(`无法${this.operation}, 当前没有选中的内容`) } private async onPublished(isPublished: boolean): Promise { @@ -175,7 +175,7 @@ export class PublishIngCmdHandler extends CmdHandler { (): Thenable => execCmd('vscode.open', Uri.parse(globalCtx.config.ingSite + '/#mention')), ], ] as const - const option = await AlertService.info( + const option = await Alert.info( '闪存已发布, 快去看看吧', { modal: false }, ...options.map(v => ({ title: v[0], id: v[0] })) diff --git a/src/commands/open-my-account-settings.ts b/src/commands/open-my-account-settings.ts index 059194d0..7f2c5d00 100644 --- a/src/commands/open-my-account-settings.ts +++ b/src/commands/open-my-account-settings.ts @@ -1,5 +1,5 @@ -import vscode from 'vscode' import { execCmd } from '@/utils/cmd' +import vscode from 'vscode' export const openMyAccountSettings = () => execCmd('vscode.open', vscode.Uri.parse('https://account.cnblogs.com/settings/account')) diff --git a/src/commands/open-my-blog-console.ts b/src/commands/open-my-blog-console.ts index c14e9d88..03d18959 100644 --- a/src/commands/open-my-blog-console.ts +++ b/src/commands/open-my-blog-console.ts @@ -1,4 +1,4 @@ +import { execCmd } from '@/utils/cmd' import vscode from 'vscode' export const openMyWebBlogConsole = () => execCmd('vscode.open', vscode.Uri.parse('https://i.cnblogs.com')) -import { execCmd } from '@/utils/cmd' diff --git a/src/commands/open-my-blog.ts b/src/commands/open-my-blog.ts index 93dc2c74..d78b3a00 100644 --- a/src/commands/open-my-blog.ts +++ b/src/commands/open-my-blog.ts @@ -1,6 +1,6 @@ import { accountManager } from '@/auth/account-manager' -import vscode from 'vscode' import { execCmd } from '@/utils/cmd' +import vscode from 'vscode' export const openMyBlog = () => { const userBlogUrl = accountManager.currentUser?.website diff --git a/src/commands/open-post-in-blog-admin.ts b/src/commands/open-post-in-blog-admin.ts index 32f3dba0..36475a74 100644 --- a/src/commands/open-post-in-blog-admin.ts +++ b/src/commands/open-post-in-blog-admin.ts @@ -1,8 +1,8 @@ -import { Uri } from 'vscode' -import { execCmd } from '@/utils/cmd' import { Post } from '@/models/post' import { PostFileMapManager } from '@/services/post-file-map' import { PostTreeItem } from '@/tree-view-providers/models/post-tree-item' +import { execCmd } from '@/utils/cmd' +import { Uri } from 'vscode' export const openPostInBlogAdmin = (item: Post | PostTreeItem | Uri) => { if (!item) return diff --git a/src/commands/open-workspace.ts b/src/commands/open-workspace.ts index 0104111d..2257c2cf 100644 --- a/src/commands/open-workspace.ts +++ b/src/commands/open-workspace.ts @@ -1,13 +1,13 @@ -import { MessageOptions } from 'vscode' +import { Alert } from '@/services/alert.service' import { Settings } from '@/services/settings.service' import { execCmd } from '@/utils/cmd' -import { AlertService } from '@/services/alert.service' +import { MessageOptions } from 'vscode' export const openWorkspace = async () => { const uri = Settings.workspaceUri const { fsPath } = uri const options = ['在当前窗口中打开', '在新窗口中打开'] - const input = await AlertService.info(`即将打开 ${fsPath}`, { modal: true } as MessageOptions, ...options) + const input = await Alert.info(`即将打开 ${fsPath}`, { modal: true } as MessageOptions, ...options) if (!input) return const shouldOpenInNewWindow = input === options[1] diff --git a/src/commands/pdf/export-pdf.command.ts b/src/commands/pdf/export-pdf.command.ts index e2180db2..46b48200 100644 --- a/src/commands/pdf/export-pdf.command.ts +++ b/src/commands/pdf/export-pdf.command.ts @@ -1,19 +1,19 @@ -import type puppeteer from 'puppeteer-core' -import fs from 'fs' -import path from 'path' -import os from 'os' -import { MessageOptions, Progress, ProgressLocation, Uri, window, workspace } from 'vscode' +import { accountManager } from '@/auth/account-manager' +import { postPdfTemplateBuilder } from '@/commands/pdf/post-pdf-template-builder' import { Post } from '@/models/post' +import { PostEditDto } from '@/models/post-edit-dto' +import { Alert } from '@/services/alert.service' import { PostFileMapManager } from '@/services/post-file-map' import { PostService } from '@/services/post.service' -import { extViews } from '@/tree-view-providers/tree-view-registration' -import { chromiumPathProvider } from '@/utils/chromium-path-provider' import { Settings } from '@/services/settings.service' -import { accountManager } from '@/auth/account-manager' -import { AlertService } from '@/services/alert.service' import { PostTreeItem } from '@/tree-view-providers/models/post-tree-item' -import { PostEditDto } from '@/models/post-edit-dto' -import { postPdfTemplateBuilder } from '@/commands/pdf/post-pdf-template-builder' +import { extViews } from '@/tree-view-providers/tree-view-registration' +import { chromiumPathProvider } from '@/utils/chromium-path-provider' +import fs from 'fs' +import os from 'os' +import path from 'path' +import type puppeteer from 'puppeteer-core' +import { MessageOptions, Progress, ProgressLocation, Uri, window, workspace } from 'vscode' const launchBrowser = async ( chromiumPath: string @@ -114,7 +114,7 @@ const retrieveChromiumPath = async (): Promise => { if (!path) { const { Options: options } = chromiumPathProvider - const input = await AlertService.warn( + const input = await Alert.warn( '未找到Chromium可执行文件', { modal: true, @@ -175,7 +175,7 @@ const mapToPostEditDto = async (posts: Post[]) => const reportErrors = (errors: string[] | undefined) => { if (errors && errors.length > 0) { - void AlertService.err('导出 PDF 时遇到错误', { + void Alert.err('导出 PDF 时遇到错误', { modal: true, detail: errors.join('\n'), } as MessageOptions) @@ -192,7 +192,7 @@ const exportPostToPdf = async (input: Post | PostTreeItem | Uri | unknown): Prom currentUser: { blogApp }, } = accountManager - if (!blogApp) return void AlertService.warn('无法获取到博客地址, 请检查登录状态') + if (!blogApp) return void Alert.warn('无法获取到博客地址, 请检查登录状态') reportErrors( await window.withProgress( diff --git a/src/commands/pdf/post-pdf-template-builder.ts b/src/commands/pdf/post-pdf-template-builder.ts index 62e7647f..ac7dbec1 100644 --- a/src/commands/pdf/post-pdf-template-builder.ts +++ b/src/commands/pdf/post-pdf-template-builder.ts @@ -1,11 +1,11 @@ +import { accountManager } from '@/auth/account-manager' import { Post } from '@/models/post' -import { PostFileMapManager } from '@/services/post-file-map' -import fs from 'fs' +import { PostCategory } from '@/models/post-category' import { BlogSettingsService } from '@/services/blog-settings.service' -import { accountManager } from '@/auth/account-manager' import { postCategoryService } from '@/services/post-category.service' -import { PostCategory } from '@/models/post-category' +import { PostFileMapManager } from '@/services/post-file-map' import { markdownItFactory } from '@cnblogs/markdown-it-presets' +import fs from 'fs' export namespace postPdfTemplateBuilder { export const HighlightedMessage = 'markdown-highlight-finished' diff --git a/src/commands/post-category/delete-selected-categories.ts b/src/commands/post-category/delete-selected-categories.ts index 9f08622a..f0239cf3 100644 --- a/src/commands/post-category/delete-selected-categories.ts +++ b/src/commands/post-category/delete-selected-categories.ts @@ -1,10 +1,10 @@ -import { MessageOptions, ProgressLocation, window } from 'vscode' import { PostCategory } from '@/models/post-category' +import { Alert } from '@/services/alert.service' import { postCategoryService } from '@/services/post-category.service' import { PostCategoriesListTreeItem } from '@/tree-view-providers/models/categories-list-tree-item' +import { MessageOptions, ProgressLocation, window } from 'vscode' import { BaseMultiSelectablePostCategoryTreeViewCmdHandler } from './base-tree-view-cmd-handler' import { refreshPostCategoriesList } from './refresh-post-categories-list' -import { AlertService } from '@/services/alert.service' export class DeletePostCategoriesHandler extends BaseMultiSelectablePostCategoryTreeViewCmdHandler { constructor(input: PostCategoriesListTreeItem) { @@ -45,7 +45,7 @@ export class DeletePostCategoriesHandler extends BaseMultiSelectablePostCategory p.report({ increment: 100 }) if (errs.length > 0) { - await AlertService.err('删除博文分类时发生了一些错误', { + await Alert.err('删除博文分类时发生了一些错误', { detail: errs .map( err => @@ -63,7 +63,7 @@ export class DeletePostCategoriesHandler extends BaseMultiSelectablePostCategory private async confirm() { const options = ['确定'] - const clicked = await AlertService.warn( + const clicked = await Alert.warn( '确定要删除这些博文分类吗', { detail: `${this.selections.map(x => `📂${x.title}`).join(', ')} 将被永久删除! 请谨慎操作!`, diff --git a/src/commands/post-category/input-post-category.ts b/src/commands/post-category/input-post-category.ts index 2dd10471..54a0fe22 100644 --- a/src/commands/post-category/input-post-category.ts +++ b/src/commands/post-category/input-post-category.ts @@ -1,6 +1,6 @@ -import { QuickPickItem } from 'vscode' import { PostCategory, PostCategoryAddDto } from '@/models/post-category' import { InputStep, MultiStepInput } from '@/services/multi-step-input' +import { QuickPickItem } from 'vscode' class InputOption { title = '编辑分类' diff --git a/src/commands/post-category/new-post-category.ts b/src/commands/post-category/new-post-category.ts index 2a9c923b..6171d05d 100644 --- a/src/commands/post-category/new-post-category.ts +++ b/src/commands/post-category/new-post-category.ts @@ -1,9 +1,9 @@ -import { MessageOptions, ProgressLocation, window } from 'vscode' +import { Alert } from '@/services/alert.service' import { postCategoryService } from '@/services/post-category.service' import { extViews } from '@/tree-view-providers/tree-view-registration' +import { MessageOptions, ProgressLocation, window } from 'vscode' import { inputPostCategory } from './input-post-category' import { refreshPostCategoriesList } from './refresh-post-categories-list' -import { AlertService } from '@/services/alert.service' export const newPostCategory = async () => { const input = await inputPostCategory({ @@ -29,7 +29,7 @@ export const newPostCategory = async () => { const newCategory = (await postCategoryService.listCategories()).find(x => x.title === input.title) if (newCategory) await extViews.postCategoriesList.reveal(newCategory) } catch (err) { - void AlertService.err('新建博文分类时遇到了错误', { + void Alert.err('新建博文分类时遇到了错误', { modal: true, detail: `服务器反回了错误\n${err instanceof Error ? err.message : JSON.stringify(err)}`, } as MessageOptions) diff --git a/src/commands/post-category/update-post-category.ts b/src/commands/post-category/update-post-category.ts index 9d655170..297bd522 100644 --- a/src/commands/post-category/update-post-category.ts +++ b/src/commands/post-category/update-post-category.ts @@ -1,11 +1,11 @@ -import fs from 'fs' -import { MessageOptions, ProgressLocation, window, Uri, workspace } from 'vscode' import { PostCategory } from '@/models/post-category' import { postCategoryService } from '@/services/post-category.service' -import { inputPostCategory } from './input-post-category' -import { refreshPostCategoriesList } from './refresh-post-categories-list' import { Settings } from '@/services/settings.service' +import fs from 'fs' +import { MessageOptions, ProgressLocation, Uri, window, workspace } from 'vscode' import { BasePostCategoryTreeViewCmdHandler } from './base-tree-view-cmd-handler' +import { inputPostCategory } from './input-post-category' +import { refreshPostCategoriesList } from './refresh-post-categories-list' class UpdatePostCategoryTreeViewCmdHandler extends BasePostCategoryTreeViewCmdHandler { async handle(): Promise { diff --git a/src/commands/posts-list/copy-link.ts b/src/commands/posts-list/copy-link.ts index 5502d346..e02333e2 100644 --- a/src/commands/posts-list/copy-link.ts +++ b/src/commands/posts-list/copy-link.ts @@ -1,6 +1,6 @@ import { TreeViewCmdHandler } from '@/commands/cmd-handler' import { Post } from '@/models/post' -import { AlertService } from '@/services/alert.service' +import { Alert } from '@/services/alert.service' import { PostFileMapManager } from '@/services/post-file-map' import { PostService } from '@/services/post.service' import { PostTreeItem } from '@/tree-view-providers/models/post-tree-item' @@ -53,7 +53,7 @@ export class CopyPostLinkCmdHandler extends TreeViewCmdHandler void AlertService.fileNotLinkedToPost(input)) + ? Promise.resolve(undefined).then(() => void Alert.fileNotLinkedToPost(input)) : PostService.fetchPostEditDto(postId).then(v => v?.post) } diff --git a/src/commands/posts-list/create-local-draft.ts b/src/commands/posts-list/create-local-draft.ts index 5c959555..90714c01 100644 --- a/src/commands/posts-list/create-local-draft.ts +++ b/src/commands/posts-list/create-local-draft.ts @@ -1,8 +1,8 @@ +import { Settings } from '@/services/settings.service' +import { revealActiveFileInExplorer } from '@/utils/reveal-active-file' import { homedir } from 'os' import path from 'path' import { Uri, window, workspace } from 'vscode' -import { Settings } from '@/services/settings.service' -import { revealActiveFileInExplorer } from '@/utils/reveal-active-file' import { openPostFile } from './open-post-file' export const createLocalDraft = async () => { diff --git a/src/commands/posts-list/delete-post-to-local-file-map.ts b/src/commands/posts-list/delete-post-to-local-file-map.ts index 0f2b861e..e02e536a 100644 --- a/src/commands/posts-list/delete-post-to-local-file-map.ts +++ b/src/commands/posts-list/delete-post-to-local-file-map.ts @@ -1,14 +1,14 @@ -import { MessageOptions, window } from 'vscode' import { Post } from '@/models/post' +import { Alert } from '@/services/alert.service' import { PostFileMap, PostFileMapManager } from '@/services/post-file-map' import { revealPostsListItem } from '@/services/posts-list-view' import { PostTreeItem } from '@/tree-view-providers/models/post-tree-item' import { extViews } from '@/tree-view-providers/tree-view-registration' -import { AlertService } from '@/services/alert.service' +import { MessageOptions, window } from 'vscode' const confirm = async (posts: Post[]): Promise => { const options = ['确定'] - const input = await AlertService.info( + const input = await Alert.info( '确定要取消这些博文与本地文件的关联吗?', { detail: posts.map(x => x.title).join(', '), diff --git a/src/commands/posts-list/delete-post.ts b/src/commands/posts-list/delete-post.ts index cd204ab7..4a609bce 100644 --- a/src/commands/posts-list/delete-post.ts +++ b/src/commands/posts-list/delete-post.ts @@ -1,13 +1,13 @@ -import { MessageOptions, ProgressLocation, Uri, window, workspace } from 'vscode' import { Post } from '@/models/post' -import { AlertService } from '@/services/alert.service' -import { PostService } from '@/services/post.service' +import { Alert } from '@/services/alert.service' import { PostFileMap, PostFileMapManager } from '@/services/post-file-map' +import { PostService } from '@/services/post.service' +import { PostTreeItem } from '@/tree-view-providers/models/post-tree-item' +import { postCategoriesDataProvider } from '@/tree-view-providers/post-categories-tree-data-provider' import { postsDataProvider } from '@/tree-view-providers/posts-data-provider' import { extViews } from '@/tree-view-providers/tree-view-registration' +import { MessageOptions, ProgressLocation, Uri, window, workspace } from 'vscode' import { refreshPostsList } from './refresh-posts-list' -import { PostTreeItem } from '@/tree-view-providers/models/post-tree-item' -import { postCategoriesDataProvider } from '@/tree-view-providers/post-categories-tree-data-provider' let isDeleting = false @@ -18,7 +18,7 @@ const confirmDelete = async ( if (!selectedPosts || selectedPosts.length <= 0) return result const items = ['确定(保留本地文件)', '确定(同时删除本地文件)'] - const clicked = await AlertService.warn( + const clicked = await Alert.warn( '确定要删除吗?', { detail: `确认后将会删除 ${selectedPosts.map(x => x.title).join(', ')} 这${selectedPosts.length}篇博文吗?`, @@ -55,7 +55,7 @@ export const deleteSelectedPosts = async (arg: unknown) => { if (selectedPosts.length <= 0) return if (isDeleting) { - AlertService.warn('休息会儿再点吧~') + void Alert.warn('休息会儿再点吧~') return } @@ -91,7 +91,7 @@ export const deleteSelectedPosts = async (arg: unknown) => { postIds: selectedPosts.map(({ id }) => id), }) } catch (err) { - void AlertService.err('删除博文失败', { + void Alert.err('删除博文失败', { detail: `服务器返回了错误, ${err instanceof Error ? err.message : JSON.stringify(err)}`, } as MessageOptions) } finally { diff --git a/src/commands/posts-list/modify-post-settings.ts b/src/commands/posts-list/modify-post-settings.ts index eaa0b653..c83f35ce 100644 --- a/src/commands/posts-list/modify-post-settings.ts +++ b/src/commands/posts-list/modify-post-settings.ts @@ -1,28 +1,29 @@ -import { Uri } from 'vscode' import { Post } from '@/models/post' -import { AlertService } from '@/services/alert.service' -import { PostService } from '@/services/post.service' +import { Alert } from '@/services/alert.service' +import { LocalDraft } from '@/services/local-draft.service' +import { PostCfgPanel } from '@/services/post-cfg-panel.service' import { PostFileMapManager } from '@/services/post-file-map' +import { PostService } from '@/services/post.service' import { revealPostsListItem } from '@/services/posts-list-view' -import { PostCfgPanel } from '@/services/post-cfg-panel.service' -import fs from 'fs' -import { LocalDraft } from '@/services/local-draft.service' -import { saveFilePendingChanges } from '@/utils/save-file-pending-changes' -import { postsDataProvider } from '@/tree-view-providers/posts-data-provider' import { PostTreeItem } from '@/tree-view-providers/models/post-tree-item' import { postCategoriesDataProvider } from '@/tree-view-providers/post-categories-tree-data-provider' +import { postsDataProvider } from '@/tree-view-providers/posts-data-provider' +import { saveFilePendingChanges } from '@/utils/save-file-pending-changes' +import fs from 'fs' +import { Uri } from 'vscode' export const modifyPostSettings = async (input: Post | PostTreeItem | Uri) => { let post: Post | undefined - let postId = -1 + let postId: number input = input instanceof PostTreeItem ? input.post : input if (input instanceof Post) { post = input postId = input.id - } else if (input instanceof Uri) { + } else { + // input is Uri postId = PostFileMapManager.getPostId(input.fsPath) ?? -1 - if (postId < 0) return AlertService.fileNotLinkedToPost(input) + if (postId < 0) return void Alert.fileNotLinkedToPost(input) } if (!(postId >= 0)) return @@ -40,15 +41,14 @@ export const modifyPostSettings = async (input: Post | PostTreeItem | Uri) => { post: postEditDto, localFileUri: localFilePath ? Uri.file(localFilePath) : undefined, successCallback: ({ id }) => { - AlertService.info('博文已更新') + void Alert.info('博文已更新') postsDataProvider.fireTreeDataChangedEvent(id) postCategoriesDataProvider.onPostUpdated({ refreshPosts: false, postIds: [id] }) }, beforeUpdate: async post => { if (localFilePath && fs.existsSync(localFilePath)) { await saveFilePendingChanges(localFilePath) - const content = await new LocalDraft(localFilePath).readAllText() - post.postBody = content + post.postBody = await new LocalDraft(localFilePath).readAllText() } return true }, diff --git a/src/commands/posts-list/open-post-file.ts b/src/commands/posts-list/open-post-file.ts index a11cac37..40af1378 100644 --- a/src/commands/posts-list/open-post-file.ts +++ b/src/commands/posts-list/open-post-file.ts @@ -1,8 +1,8 @@ -import { TextDocumentShowOptions, Uri } from 'vscode' -import { execCmd } from '@/utils/cmd' import { Post } from '@/models/post' import { LocalDraft } from '@/services/local-draft.service' import { PostFileMapManager } from '@/services/post-file-map' +import { execCmd } from '@/utils/cmd' +import { TextDocumentShowOptions, Uri } from 'vscode' export const openPostFile = async (post: LocalDraft | Post | string, options?: TextDocumentShowOptions) => { let filePath = '' diff --git a/src/commands/posts-list/open-post-in-vscode.ts b/src/commands/posts-list/open-post-in-vscode.ts index efa8c1b9..97ec93f5 100644 --- a/src/commands/posts-list/open-post-in-vscode.ts +++ b/src/commands/posts-list/open-post-in-vscode.ts @@ -1,15 +1,15 @@ -import fs from 'fs' -import path from 'path' -import { FileSystemError, MessageOptions, Uri, window, workspace } from 'vscode' import { Post } from '@/models/post' -import { AlertService } from '@/services/alert.service' -import { PostService } from '@/services/post.service' +import { Alert } from '@/services/alert.service' +import { postCategoryService } from '@/services/post-category.service' import { PostFileMapManager } from '@/services/post-file-map' -import { Settings } from '@/services/settings.service' -import { openPostFile } from './open-post-file' import { PostTitleSanitizer } from '@/services/post-title-sanitizer.service' -import { postCategoryService } from '@/services/post-category.service' +import { PostService } from '@/services/post.service' +import { Settings } from '@/services/settings.service' +import fs from 'fs' +import path from 'path' import sanitizeFileName from 'sanitize-filename' +import { FileSystemError, MessageOptions, Uri, window, workspace } from 'vscode' +import { openPostFile } from './open-post-file' const buildLocalPostFileUri = async (post: Post, includePostId = false): Promise => { const workspaceUri = Settings.workspaceUri @@ -68,7 +68,7 @@ export const openPostInVscode = async (postId: number, forceUpdateLocalPostFile '保留本地文件(这会新建另一个文件名中包含博文id的文件)', '覆盖本地文件(会导致本地文件中内容丢失)', ] - const selectedOption = await AlertService.info( + const selectedOption = await Alert.info( `无法新建博文与本地文件的关联, 文件名冲突`, { detail: `本地已存在名为"${path.basename(fileUri.fsPath)}"的文件`, modal: true } as MessageOptions, ...conflictOptions @@ -97,7 +97,7 @@ const createDirectoryIfNotExist = async (uri: Uri) => { } catch (err) { if (err instanceof FileSystemError) await workspace.fs.createDirectory(uri) - AlertService.err('Create workspace directory failed') + void Alert.err('Create workspace directory failed') console.error(err) } } diff --git a/src/commands/posts-list/refresh-posts-list.ts b/src/commands/posts-list/refresh-posts-list.ts index 5216cff2..afb1adf1 100644 --- a/src/commands/posts-list/refresh-posts-list.ts +++ b/src/commands/posts-list/refresh-posts-list.ts @@ -1,11 +1,11 @@ +import { PostsListState } from '@/models/posts-list-state' +import { Alert } from '@/services/alert.service' import { globalCtx } from '@/services/global-ctx' import { PostService } from '@/services/post.service' -import vscode, { window } from 'vscode' import { postsDataProvider } from '@/tree-view-providers/posts-data-provider' -import { AlertService } from '@/services/alert.service' -import { PostsListState } from '@/models/posts-list-state' import { extViews } from '@/tree-view-providers/tree-view-registration' import { execCmd } from '@/utils/cmd' +import { window } from 'vscode' let refreshTask: Promise | null = null @@ -33,7 +33,7 @@ export const refreshPostsList = async ({ queue = false } = {}): Promise ) .then(pagedPosts => { if (pagedPosts == null) { - return Promise.resolve(false).finally(() => AlertService.err('刷新博文列表失败')) + return Promise.resolve(false).finally(() => void Alert.err('刷新博文列表失败')) } else { return PostService.updatePostsListState(pagedPosts) .then(() => updatePostsListViewTitle()) @@ -92,7 +92,7 @@ const setPostListContext = async (pageCount: number, hasPrevious: boolean, hasNe } const alertRefreshing = () => { - AlertService.info('正在刷新, 请勿重复操作') + void Alert.info('正在刷新, 请勿重复操作') } const gotoPage = async (pageIndex: (currentIndex: number) => number) => { diff --git a/src/commands/posts-list/rename-post.ts b/src/commands/posts-list/rename-post.ts index 0c752ad3..886a351f 100644 --- a/src/commands/posts-list/rename-post.ts +++ b/src/commands/posts-list/rename-post.ts @@ -1,13 +1,13 @@ -import { escapeRegExp } from 'lodash-es' -import path from 'path' -import { MessageOptions, ProgressLocation, Uri, window, workspace } from 'vscode' import { Post } from '@/models/post' -import { PostService } from '@/services/post.service' +import { Alert } from '@/services/alert.service' import { PostFileMapManager } from '@/services/post-file-map' -import { postsDataProvider } from '@/tree-view-providers/posts-data-provider' +import { PostService } from '@/services/post.service' import { revealPostsListItem } from '@/services/posts-list-view' import { PostTreeItem } from '@/tree-view-providers/models/post-tree-item' -import { AlertService } from '@/services/alert.service' +import { postsDataProvider } from '@/tree-view-providers/posts-data-provider' +import { escapeRegExp } from 'lodash-es' +import path from 'path' +import { MessageOptions, ProgressLocation, Uri, window, workspace } from 'vscode' const renameLinkedFile = async (post: Post): Promise => { const filePath = PostFileMapManager.getFilePath(post.id) @@ -17,7 +17,7 @@ const renameLinkedFile = async (post: Post): Promise => { const fileUri = Uri.file(filePath) const options = ['是'] - const input = await AlertService.info( + const input = await Alert.info( '重命名博文成功, 发现与博文关联的本地文件, 是否要重名本地文件', { modal: true, @@ -70,7 +70,7 @@ export const renamePost = async (arg: Post | PostTreeItem) => { postsDataProvider.fireTreeDataChangedEvent(post) hasUpdated = true } catch (err) { - void AlertService.err('更新博文失败', { + void Alert.err('更新博文失败', { modal: true, detail: err instanceof Error ? err.message : '服务器返回异常', } as MessageOptions) diff --git a/src/commands/posts-list/search.ts b/src/commands/posts-list/search.ts index 4492f99f..5101c376 100644 --- a/src/commands/posts-list/search.ts +++ b/src/commands/posts-list/search.ts @@ -1,5 +1,5 @@ -import { window } from 'vscode' import { postsDataProvider } from '@/tree-view-providers/posts-data-provider' +import { window } from 'vscode' export const searchPosts = async () => { const searchKey = await window.showInputBox({ diff --git a/src/commands/posts-list/upload-post.ts b/src/commands/posts-list/upload-post.ts index 751af008..bfbe7c11 100644 --- a/src/commands/posts-list/upload-post.ts +++ b/src/commands/posts-list/upload-post.ts @@ -1,21 +1,21 @@ -import vscode, { Uri, workspace, window, ProgressLocation, MessageOptions } from 'vscode' import { Post } from '@/models/post' +import { PostEditDto } from '@/models/post-edit-dto' +import { Alert } from '@/services/alert.service' import { LocalDraft } from '@/services/local-draft.service' -import { AlertService } from '@/services/alert.service' -import { PostService } from '@/services/post.service' +import { PostCfgPanel } from '@/services/post-cfg-panel.service' import { PostFileMapManager } from '@/services/post-file-map' -import { postsDataProvider } from '@/tree-view-providers/posts-data-provider' -import { openPostInVscode } from './open-post-in-vscode' -import { openPostFile } from './open-post-file' +import { PostService } from '@/services/post.service' import { searchPostsByTitle } from '@/services/search-post-by-title' -import * as path from 'path' -import { refreshPostsList } from './refresh-posts-list' -import { PostEditDto } from '@/models/post-edit-dto' -import { PostCfgPanel } from '@/services/post-cfg-panel.service' -import { saveFilePendingChanges } from '@/utils/save-file-pending-changes' -import { extractImages } from '../extract-images' import { Settings } from '@/services/settings.service' import { PostTreeItem } from '@/tree-view-providers/models/post-tree-item' +import { postsDataProvider } from '@/tree-view-providers/posts-data-provider' +import { saveFilePendingChanges } from '@/utils/save-file-pending-changes' +import * as path from 'path' +import { MessageOptions, ProgressLocation, Uri, window, workspace } from 'vscode' +import { extractImages } from '../extract-images' +import { openPostFile } from './open-post-file' +import { openPostInVscode } from './open-post-in-vscode' +import { refreshPostsList } from './refresh-posts-list' const parseFileUri = async (fileUri: Uri | undefined): Promise => { if (fileUri && fileUri.scheme !== 'file') { @@ -44,7 +44,7 @@ export const uploadPostFileToCnblogs = async (fileUri: Uri | undefined) => { await uploadPostToCnblogs(await PostService.fetchPostEditDto(postId)) } else { const options = [`新建博文`, `关联已有博文`] - const selected = await AlertService.info( + const selected = await Alert.info( '本地文件尚未关联到博客园博文', { modal: true, @@ -84,7 +84,7 @@ export const saveLocalDraftToCnblogs = async (localDraft: LocalDraft) => { // check format if (!['.md'].some(x => localDraft.fileExt === x)) { - AlertService.warn('不受支持的文件格式! 只支持markdown格式') + void Alert.warn('不受支持的文件格式! 只支持markdown格式') return } const editDto = await PostService.fetchPostEditTemplate() @@ -106,13 +106,13 @@ export const saveLocalDraftToCnblogs = async (localDraft: LocalDraft) => { await PostFileMapManager.updateOrCreate(savedPost.id, localDraft.filePath) await openPostFile(localDraft) postsDataProvider.fireTreeDataChangedEvent(undefined) - AlertService.info('博文已创建') + void Alert.info('博文已创建') }, beforeUpdate: async (postToSave, panel) => { await saveFilePendingChanges(localDraft.filePath) // 本地文件已经被删除了 if (!localDraft.exist && panel) { - AlertService.warn('本地文件已删除, 无法新建博文') + void Alert.warn('本地文件已删除, 无法新建博文') return false } if (Settings.automaticallyExtractImagesType) @@ -136,7 +136,7 @@ export const uploadPostToCnblogs = async (input: Post | PostTreeItem | PostEditD const { id: postId } = post const localFilePath = PostFileMapManager.getFilePath(postId) - if (!localFilePath) return AlertService.warn('本地无该博文的编辑记录') + if (!localFilePath) return Alert.warn('本地无该博文的编辑记录') if (Settings.automaticallyExtractImagesType) await extractImages(Uri.file(localFilePath), Settings.automaticallyExtractImagesType).catch(console.warn) @@ -148,7 +148,7 @@ export const uploadPostToCnblogs = async (input: Post | PostTreeItem | PostEditD if (!validatePost(post)) return false if (Settings.showConfirmMsgWhenUploadPost) { - const answer = await AlertService.warn( + const answer = await Alert.warn( '确认上传吗?', { modal: true, @@ -177,11 +177,11 @@ export const uploadPostToCnblogs = async (input: Post | PostTreeItem | PostEditD hasSaved = true progress.report({ increment: 100 }) - AlertService.info('上传成功') + void Alert.info('上传成功') await refreshPostsList() } catch (err) { progress.report({ increment: 100 }) - AlertService.err(`上传失败\n${err instanceof Error ? err.message : JSON.stringify(err)}`) + void Alert.err(`上传失败\n${err instanceof Error ? err.message : JSON.stringify(err)}`) console.error(err) } return hasSaved @@ -191,7 +191,7 @@ export const uploadPostToCnblogs = async (input: Post | PostTreeItem | PostEditD const validatePost = (post: Post): boolean => { if (!post.postBody) { - AlertService.warn('文件内容为空!') + void Alert.warn('文件内容为空!') return false } diff --git a/src/commands/pull-post-remote-updates.ts b/src/commands/pull-post-remote-updates.ts index 0f1b5543..fb300aee 100644 --- a/src/commands/pull-post-remote-updates.ts +++ b/src/commands/pull-post-remote-updates.ts @@ -1,14 +1,14 @@ -import { MessageOptions, Uri, window, workspace } from 'vscode' import { Post } from '@/models/post' +import { Alert } from '@/services/alert.service' import { PostFileMapManager } from '@/services/post-file-map' -import { openPostInVscode } from './posts-list/open-post-in-vscode' -import fs from 'fs' import { PostService } from '@/services/post.service' -import { AlertService } from '@/services/alert.service' -import path from 'path' import { revealPostsListItem } from '@/services/posts-list-view' -import { PostTreeItem } from '@/tree-view-providers/models/post-tree-item' import { Settings } from '@/services/settings.service' +import { PostTreeItem } from '@/tree-view-providers/models/post-tree-item' +import fs from 'fs' +import path from 'path' +import { MessageOptions, Uri, window, workspace } from 'vscode' +import { openPostInVscode } from './posts-list/open-post-in-vscode' const pullPostRemoteUpdates = async (input: Post | PostTreeItem | Uri | undefined | null): Promise => { const ctxs: CmdCtx[] = [] @@ -18,7 +18,7 @@ const pullPostRemoteUpdates = async (input: Post | PostTreeItem | Uri | undefine else if ((uri = parseUriInput(input))) await handleUriInput(uri, ctxs) if (Settings.showConfirmMsgWhenPullPost) { - const answer = await AlertService.warn( + const answer = await Alert.warn( '确认要拉取远程博文吗?', { modal: true, @@ -33,7 +33,7 @@ const pullPostRemoteUpdates = async (input: Post | PostTreeItem | Uri | undefine await update(ctxs) - AlertService.info(`本地文件${resolveFileNames(ctxs)}已更新`) + void Alert.info(`本地文件${resolveFileNames(ctxs)}已更新`) } export { pullPostRemoteUpdates } @@ -70,7 +70,7 @@ const parseUriInput = (input: InputType): Uri | undefined => { const handleUriInput = (fileUri: Uri, contexts: CmdCtx[]): Promise => { const postId = PostFileMapManager.getPostId(fileUri.fsPath) - if (!postId) return Promise.resolve().then(() => AlertService.fileNotLinkedToPost(fileUri)) + if (!postId) return Promise.resolve().then(() => void Alert.fileNotLinkedToPost(fileUri)) contexts.push({ postId, fileUri }) return Promise.resolve() diff --git a/src/commands/reveal-local-post-file-in-os.ts b/src/commands/reveal-local-post-file-in-os.ts index e031ae48..0dbecbf8 100644 --- a/src/commands/reveal-local-post-file-in-os.ts +++ b/src/commands/reveal-local-post-file-in-os.ts @@ -1,7 +1,7 @@ -import { Uri } from 'vscode' -import { execCmd } from '@/utils/cmd' import { Post } from '@/models/post' import { PostFileMapManager } from '@/services/post-file-map' +import { execCmd } from '@/utils/cmd' +import { Uri } from 'vscode' export const revealLocalPostFileInOs = (post: Post) => { if (!post) return diff --git a/src/commands/reveal-workspace-in-os.ts b/src/commands/reveal-workspace-in-os.ts index a9e696a6..73701847 100644 --- a/src/commands/reveal-workspace-in-os.ts +++ b/src/commands/reveal-workspace-in-os.ts @@ -1,5 +1,5 @@ -import { commands } from 'vscode' -import { execCmd } from '@/utils/cmd' import { Settings } from '@/services/settings.service' +import { execCmd } from '@/utils/cmd' +import { commands } from 'vscode' export const revealWorkspaceInOs = () => execCmd('revealFileInOS', Settings.workspaceUri) diff --git a/src/commands/set-workspace.ts b/src/commands/set-workspace.ts index 56898e36..88549c7e 100644 --- a/src/commands/set-workspace.ts +++ b/src/commands/set-workspace.ts @@ -1,6 +1,6 @@ -import { window } from 'vscode' -import { AlertService } from '@/services/alert.service' +import { Alert } from '@/services/alert.service' import { Settings } from '@/services/settings.service' +import { window } from 'vscode' export const setWorkspace = async () => { const input = ((await window.showOpenDialog({ @@ -14,5 +14,5 @@ export const setWorkspace = async () => { if (!input) return await Settings.setWorkspaceUri(input) - AlertService.info(`工作空间成功修改为: "${Settings.workspaceUri.fsPath}"`) + void Alert.info(`工作空间成功修改为: "${Settings.workspaceUri.fsPath}"`) } diff --git a/src/commands/show-local-file-to-post-info.ts b/src/commands/show-local-file-to-post-info.ts index fe83db27..8a8e5f96 100644 --- a/src/commands/show-local-file-to-post-info.ts +++ b/src/commands/show-local-file-to-post-info.ts @@ -1,12 +1,12 @@ -import path from 'path' -import { MessageOptions, Uri, window } from 'vscode' -import { AlertService } from '@/services/alert.service' -import { PostService } from '@/services/post.service' +import { Alert } from '@/services/alert.service' import { postCategoryService } from '@/services/post-category.service' import { PostFileMapManager } from '@/services/post-file-map' +import { PostService } from '@/services/post.service' import { searchPostsByTitle } from '@/services/search-post-by-title' -import { viewPostOnline } from './view-post-online' import format from 'date-fns/format' +import path from 'path' +import { MessageOptions, Uri, window } from 'vscode' +import { viewPostOnline } from './view-post-online' /** * 本地文件所关联的博文信息 @@ -22,7 +22,7 @@ export const showLocalFileToPostInfo = async (input: Uri | number): Promise 0 ? `博文标签: ${post.tags?.join(', ')}\n` : '' const options = ['在线查看博文', '取消关联'] const postUrl = post.url.startsWith('//') ? `https:${post.url}` : post.url - const selected = await AlertService.info( + const selected = await Alert.info( `关联博文 - ${post.title}(Id: ${post.id})`, { modal: true, @@ -75,6 +75,6 @@ export const showLocalFileToPostInfo = async (input: Uri | number): Promise { const clipboardImage = await getClipboardImage() if (clipboardImage.imgPath === noImagePath) { - AlertService.warn('剪贴板中没有找到图片') + void Alert.warn('剪贴板中没有找到图片') return } diff --git a/src/commands/upload-image/upload-image-utils.ts b/src/commands/upload-image/upload-image-utils.ts index 644bec04..ebbf106f 100644 --- a/src/commands/upload-image/upload-image-utils.ts +++ b/src/commands/upload-image/upload-image-utils.ts @@ -1,6 +1,6 @@ -import { env, MessageOptions, SnippetString, window } from 'vscode' +import { Alert } from '@/services/alert.service' import { formatImageLink } from '@/utils/format-image-link' -import { AlertService } from '@/services/alert.service' +import { env, MessageOptions, SnippetString, window } from 'vscode' /** * 显示上传成功对话框, 支持复制不同格式的图片链接 @@ -10,7 +10,7 @@ import { AlertService } from '@/services/alert.service' */ export const showUploadSuccessModel = async (imgLink: string): Promise => { const copyOptions = ['复制链接', '复制链接(markdown)', '复制链接(html)'] - const option = await AlertService.info( + const option = await Alert.info( '上传图片成功', { modal: true, diff --git a/src/commands/upload-image/upload-image.ts b/src/commands/upload-image/upload-image.ts index f434690c..4024ea40 100644 --- a/src/commands/upload-image/upload-image.ts +++ b/src/commands/upload-image/upload-image.ts @@ -1,5 +1,4 @@ -import { AlertService } from '@/services/alert.service' -import { window } from 'vscode' +import { Alert } from '@/services/alert.service' import { uploadImageFromClipboard } from './upload-clipboard-image' import { insertImageLinkToActiveEditor, showUploadSuccessModel } from './upload-image-utils' import { uploadLocalDiskImage } from './upload-local-disk-image' @@ -7,7 +6,7 @@ import { uploadLocalDiskImage } from './upload-local-disk-image' export const uploadImage = async (autoInsertToActiveEditor = true, from?: 'local' | 'clipboard') => { const options = ['本地图片文件', '剪贴板图片'] const selected = !from - ? await AlertService.info( + ? await Alert.info( '上传图片到博客园', { modal: true, @@ -19,7 +18,7 @@ export const uploadImage = async (autoInsertToActiveEditor = true, from?: 'local let imageUrl: string | undefined const caughtFailedUpload = (e: unknown) => - void AlertService.httpErr(typeof e === 'object' && e != null ? e : {}, { message: '上传图片失败' }) + void Alert.httpErr(typeof e === 'object' && e != null ? e : {}, { message: '上传图片失败' }) switch (selected) { case 'local': case options[0]: diff --git a/src/commands/upload-image/upload-local-disk-image.ts b/src/commands/upload-image/upload-local-disk-image.ts index 1556c621..00880809 100644 --- a/src/commands/upload-image/upload-local-disk-image.ts +++ b/src/commands/upload-image/upload-local-disk-image.ts @@ -1,6 +1,6 @@ -import { ProgressLocation, window } from 'vscode' import { ImageService } from '@/services/image.service' import fs from 'fs' +import { ProgressLocation, window } from 'vscode' export const uploadLocalDiskImage = async () => { const imageFileUri = ((await window.showOpenDialog({ diff --git a/src/commands/view-post-online.ts b/src/commands/view-post-online.ts index a42b667a..7fb20bc9 100644 --- a/src/commands/view-post-online.ts +++ b/src/commands/view-post-online.ts @@ -1,9 +1,9 @@ -import { Uri, window } from 'vscode' -import { execCmd } from '@/utils/cmd' import { Post } from '@/models/post' -import { PostService } from '@/services/post.service' import { PostFileMapManager } from '@/services/post-file-map' +import { PostService } from '@/services/post.service' import { PostTreeItem } from '@/tree-view-providers/models/post-tree-item' +import { execCmd } from '@/utils/cmd' +import { Uri, window } from 'vscode' export const viewPostOnline = async (input?: Post | PostTreeItem | Uri) => { let post: Post | undefined = input instanceof Post ? input : input instanceof PostTreeItem ? input.post : undefined diff --git a/src/extension.ts b/src/extension.ts index 7d3b75fb..eaa1313b 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -1,18 +1,18 @@ -import { setupExtTreeView } from '@/tree-view-providers/tree-view-registration' import { setupExtCmd } from '@/commands/cmd-register' import { globalCtx } from '@/services/global-ctx' +import { setupExtTreeView } from '@/tree-view-providers/tree-view-registration' // The module 'vscode' contains the VS Code extensibility API // Import the module and reference it with the alias vscode in your code below -import vscode from 'vscode' import { accountManager } from '@/auth/account-manager' +import { extendMarkdownIt } from '@/markdown/extend-markdownIt' import { observeConfigurationChange, observeWorkspaceFolderAndFileChange as observeWorkspaceFolderChange, } from '@/services/check-workspace' +import { Settings } from '@/services/settings.service' import { extUriHandler } from '@/utils/uri-handler' import { IngsListWebviewProvider } from 'src/services/ings-list-webview-provider' -import { extendMarkdownIt } from '@/markdown/extend-markdownIt' -import { Settings } from '@/services/settings.service' +import vscode from 'vscode' // this method is called when your extension is activated // your extension is activated the very first time the commands is executed diff --git a/src/markdown/extend-markdownIt.ts b/src/markdown/extend-markdownIt.ts index c777c53d..7184616b 100644 --- a/src/markdown/extend-markdownIt.ts +++ b/src/markdown/extend-markdownIt.ts @@ -1,6 +1,6 @@ import { Settings } from '@/services/settings.service' -import { HighlightCodeLinesPlugin, MultilineBlockquotePlugin } from '@cnblogs/markdown-it-presets' import type { MarkdownIt } from '@cnblogs/markdown-it-presets' +import { HighlightCodeLinesPlugin, MultilineBlockquotePlugin } from '@cnblogs/markdown-it-presets' export const extendMarkdownIt = (md: MarkdownIt) => md diff --git a/src/models/ing-view.ts b/src/models/ing-view.ts index 1b878e6c..fa3af854 100644 --- a/src/models/ing-view.ts +++ b/src/models/ing-view.ts @@ -1,5 +1,5 @@ -import { Ing, IngComment } from './ing' import { PartialTheme, Theme } from '@fluentui/react' +import { Ing, IngComment } from './ing' export interface IngAppState { ings?: Ing[] diff --git a/src/models/webview-msg.ts b/src/models/webview-msg.ts index 365f8ca0..931f0d41 100644 --- a/src/models/webview-msg.ts +++ b/src/models/webview-msg.ts @@ -1,11 +1,11 @@ -import { Post } from './post' -import { WebviewCmd } from './webview-cmd' import { ColorThemeKind } from 'vscode' -import { PostCategories } from './post-category' -import { SiteCategories } from './site-category' -import { PostTags } from './post-tag' import { IErrorResponse as ErrorResponse } from './error-response' import { ImageUploadStatus } from './image-upload-status' +import { Post } from './post' +import { PostCategories } from './post-category' +import { PostTags } from './post-tag' +import { SiteCategories } from './site-category' +import { WebviewCmd } from './webview-cmd' export namespace webviewMessage { export interface Message { diff --git a/src/services/alert.service.ts b/src/services/alert.service.ts index 8d057d65..05f03c50 100644 --- a/src/services/alert.service.ts +++ b/src/services/alert.service.ts @@ -1,10 +1,9 @@ import type { HTTPError } from 'got' import { isArray } from 'lodash-es' import path from 'path' -import vscode, { Uri } from 'vscode' -import { window } from 'vscode' +import { MessageOptions, Uri, window } from 'vscode' -export namespace AlertService { +export namespace Alert { export const err = window.showErrorMessage export const info = window.showInformationMessage @@ -22,7 +21,7 @@ export namespace AlertService { else if (httpError.message) parsedError = httpError.message else parsedError = '未知网络错误' - void AlertService.warn((message ? message + (parsedError ? ', ' : '') : '') + parsedError) + void Alert.warn((message ? message + (parsedError ? ', ' : '') : '') + parsedError) } /** @@ -33,16 +32,12 @@ export namespace AlertService { export function fileNotLinkedToPost(file: string | Uri, { trimExt = true } = {}) { file = file instanceof Uri ? file.fsPath : file file = trimExt ? path.basename(file, path.extname(file)) : file - void AlertService.warn(`本地文件"${file}"未关联博客园博文`) + void Alert.warn(`本地文件"${file}"未关联博客园博文`) } export async function alertUnAuth({ onLoginActionHook }: { onLoginActionHook?: () => unknown } = {}) { const options = ['立即登录'] - const input = await AlertService.warn( - '登录状态已过期, 请重新登录', - { modal: true } as vscode.MessageOptions, - ...options - ) + const input = await Alert.warn('登录状态已过期, 请重新登录', { modal: true } as MessageOptions, ...options) if (input === options[0]) onLoginActionHook?.() } } diff --git a/src/services/blog-export-post.store.ts b/src/services/blog-export-post.store.ts index 7921283a..a7467fe5 100644 --- a/src/services/blog-export-post.store.ts +++ b/src/services/blog-export-post.store.ts @@ -1,8 +1,8 @@ import { DownloadedBlogExport } from '@/models/blog-export' import { ExportPost, ExportPostModel } from '@/models/blog-export/export-post' import { DataTypes, Op, Sequelize } from 'sequelize' -import { Disposable } from 'vscode' import sqlite3 from 'sqlite3' +import { Disposable } from 'vscode' export class ExportPostStore implements Disposable { private _sequelize?: null | Sequelize diff --git a/src/services/blog-settings.service.ts b/src/services/blog-settings.service.ts index f97f73be..4bd12c4e 100644 --- a/src/services/blog-settings.service.ts +++ b/src/services/blog-settings.service.ts @@ -1,5 +1,5 @@ -import fetch from '@/utils/fetch-client' import { BlogSettings, BlogSiteDto, BlogSiteExtendDto } from '@/models/blog-settings' +import fetch from '@/utils/fetch-client' import { globalCtx } from './global-ctx' let settingCache: BlogSettings | null = null diff --git a/src/services/check-workspace.ts b/src/services/check-workspace.ts index b25ad770..ce5624f3 100644 --- a/src/services/check-workspace.ts +++ b/src/services/check-workspace.ts @@ -1,10 +1,10 @@ -import os from 'os' -import { workspace } from 'vscode' import { refreshPostCategoriesList } from '@/commands/post-category/refresh-post-categories-list' import { refreshPostsList } from '@/commands/posts-list/refresh-posts-list' +import { execCmd } from '@/utils/cmd' +import os from 'os' +import { workspace } from 'vscode' import { globalCtx } from './global-ctx' import { PostFileMapManager } from './post-file-map' -import { execCmd } from '@/utils/cmd' import { Settings } from './settings.service' const diskSymbolRegex = /^(\S{1,5}:)(.*)/ diff --git a/src/services/global-ctx.ts b/src/services/global-ctx.ts index 928aaafc..035c83e5 100644 --- a/src/services/global-ctx.ts +++ b/src/services/global-ctx.ts @@ -1,6 +1,6 @@ -import { env, ExtensionContext, Uri } from 'vscode' import { defaultConfig, devConfig, IExtensionConfig, isDevEnv } from '@/models/config' import path from 'path' +import { env, ExtensionContext, Uri } from 'vscode' class GlobalCtx { private _extensionContext?: ExtensionContext diff --git a/src/services/image.service.ts b/src/services/image.service.ts index 7ae7f424..ae7e1fdf 100644 --- a/src/services/image.service.ts +++ b/src/services/image.service.ts @@ -1,8 +1,8 @@ -import { globalCtx } from './global-ctx' -import { Readable } from 'stream' -import { isString, merge, pick } from 'lodash-es' import httpClient from '@/utils/http-client' +import { isString, merge, pick } from 'lodash-es' import path from 'path' +import { Readable } from 'stream' +import { globalCtx } from './global-ctx' export namespace ImageService { export async function upload< diff --git a/src/services/ing.api.ts b/src/services/ing.api.ts index 269e1b7d..4284b812 100644 --- a/src/services/ing.api.ts +++ b/src/services/ing.api.ts @@ -1,9 +1,9 @@ import { Ing, IngComment, IngPublishModel, IngType } from '@/models/ing' -import { AlertService } from '@/services/alert.service' +import { Alert } from '@/services/alert.service' import { globalCtx } from '@/services/global-ctx' import fetch from '@/utils/fetch-client' -import { URLSearchParams } from 'url' import { isArray, isObject } from 'lodash-es' +import { URLSearchParams } from 'url' export namespace IngApi { export async function publishIng(ing: IngPublishModel): Promise { @@ -11,10 +11,10 @@ export namespace IngApi { method: 'POST', body: JSON.stringify(ing), headers: [['Content-Type', 'application/json']], - }).catch(reason => void AlertService.warn(JSON.stringify(reason))) + }).catch(reason => void Alert.warn(JSON.stringify(reason))) if (!res || !res.ok) - AlertService.err(`闪存发布失败, ${res?.statusText ?? ''} ${JSON.stringify((await res?.text()) ?? '')}`) + void Alert.err(`闪存发布失败, ${res?.statusText ?? ''} ${JSON.stringify((await res?.text()) ?? '')}`) return res != null && res.ok } @@ -29,10 +29,10 @@ export namespace IngApi { method: 'GET', headers: [['Content-Type', 'application/json']], } - ).catch(e => void AlertService.warn(JSON.stringify(e))) + ).catch(e => void Alert.warn(JSON.stringify(e))) if (!res || !res.ok) { - AlertService.err(`获取闪存列表失败, ${res?.statusText ?? ''} ${JSON.stringify((await res?.text()) ?? '')}`) + void Alert.err(`获取闪存列表失败, ${res?.statusText ?? ''} ${JSON.stringify((await res?.text()) ?? '')}`) return [] } @@ -40,9 +40,9 @@ export namespace IngApi { try { if (isArray(arr) && arr.every(isObject)) return arr.map(Ing.parse) - AlertService.err('获取闪存列表失败, 无法读取响应') + void Alert.err('获取闪存列表失败, 无法读取响应') } catch (e) { - AlertService.err(JSON.stringify(e)) + void Alert.err(JSON.stringify(e)) } return [] @@ -57,7 +57,7 @@ export namespace IngApi { resp => resp?.json().then(obj => [id, obj as IngComment[] | null | undefined] as const) ?? Promise.resolve(undefined), - reason => void AlertService.warn(JSON.stringify(reason)) + reason => void Alert.warn(JSON.stringify(reason)) ) ) @@ -85,12 +85,12 @@ export namespace IngApi { }) if (!res.ok) { - AlertService.err(`发表评论失败, ${await res.text()}`) + void Alert.err(`发表评论失败, ${await res.text()}`) return false } } catch (e) { // eslint-disable-next-line @typescript-eslint/restrict-template-expressions - AlertService.err(`发表评论失败, ${e}`) + void Alert.err(`发表评论失败, ${e}`) return false } diff --git a/src/services/ings-list-webview-provider.ts b/src/services/ings-list-webview-provider.ts index 0fc12c49..f08cb9e9 100644 --- a/src/services/ings-list-webview-provider.ts +++ b/src/services/ings-list-webview-provider.ts @@ -1,4 +1,12 @@ +import { CommentIngCmdHandler } from '@/commands/ing/comment-ing' +import { execCmd } from '@/utils/cmd' +import { isNumber } from 'lodash-es' +import { IngType, IngTypesMetadata } from 'src/models/ing' +import { IngAppState } from 'src/models/ing-view' +import { IngWebviewHostCmd, IngWebviewUiCmd, WebviewCmd } from 'src/models/webview-cmd' import { globalCtx } from 'src/services/global-ctx' +import { IngApi } from 'src/services/ing.api' +import { parseWebviewHtml } from 'src/services/parse-webview-html' import { CancellationToken, Disposable, @@ -8,14 +16,6 @@ import { WebviewViewResolveContext, window, } from 'vscode' -import { parseWebviewHtml } from 'src/services/parse-webview-html' -import { IngWebviewHostCmd, IngWebviewUiCmd, WebviewCmd } from 'src/models/webview-cmd' -import { IngApi } from 'src/services/ing.api' -import { IngAppState } from 'src/models/ing-view' -import { IngType, IngTypesMetadata } from 'src/models/ing' -import { isNumber } from 'lodash-es' -import { CommentIngCmdHandler } from '@/commands/ing/comment-ing' -import { execCmd } from '@/utils/cmd' export class IngsListWebviewProvider implements WebviewViewProvider { private static _instance: IngsListWebviewProvider | null = null diff --git a/src/services/local-draft.service.ts b/src/services/local-draft.service.ts index c723d2cb..ee462a9d 100644 --- a/src/services/local-draft.service.ts +++ b/src/services/local-draft.service.ts @@ -1,5 +1,5 @@ -import path from 'path' import fs from 'fs' +import path from 'path' import { Uri, workspace } from 'vscode' export class LocalDraft { diff --git a/src/services/mkd-img-extractor.service.ts b/src/services/mkd-img-extractor.service.ts index 05a2b5a9..1b90d095 100644 --- a/src/services/mkd-img-extractor.service.ts +++ b/src/services/mkd-img-extractor.service.ts @@ -1,12 +1,12 @@ -import path from 'path' -import { isString } from 'lodash-es' +import { isErrorResponse } from '@/models/error-response' import fs from 'fs' +import { isString } from 'lodash-es' +import { tmpdir } from 'os' +import path from 'path' +import { Readable } from 'stream' +import { promisify } from 'util' import { Uri, workspace } from 'vscode' import { ImageService } from './image.service' -import { isErrorResponse } from '@/models/error-response' -import { promisify } from 'util' -import { Readable } from 'stream' -import { tmpdir } from 'os' export const enum DataType { dataUrl, diff --git a/src/services/oauth.api.ts b/src/services/oauth.api.ts index 5e5fb59b..6c5ad147 100644 --- a/src/services/oauth.api.ts +++ b/src/services/oauth.api.ts @@ -1,12 +1,12 @@ /* eslint-disable @typescript-eslint/naming-convention */ -import { TokenInfo } from '@/models/token-info' import { AccountInfo } from '@/auth/account-info' +import { TokenInfo } from '@/models/token-info' import { convertObjectKeysToCamelCase } from '@/services/converter' import { globalCtx } from '@/services/global-ctx' import fetch from '@/utils/fetch-client' import got from '@/utils/http-client' -import { CancellationToken } from 'vscode' import { AbortController } from 'node-abort-controller' +import { CancellationToken } from 'vscode' export type UserInfoSpec = Pick & { readonly blog_id: string diff --git a/src/services/parse-webview-html.ts b/src/services/parse-webview-html.ts index 229ed5f5..7012e709 100644 --- a/src/services/parse-webview-html.ts +++ b/src/services/parse-webview-html.ts @@ -1,5 +1,5 @@ -import vscode from 'vscode' import { globalCtx } from 'src/services/global-ctx' +import vscode from 'vscode' export type WebviewEntryName = 'ing' | 'post-cfg' diff --git a/src/services/post-category.service.ts b/src/services/post-category.service.ts index 2f67e1cd..c8f89fcd 100644 --- a/src/services/post-category.service.ts +++ b/src/services/post-category.service.ts @@ -1,7 +1,7 @@ -import fetch from '@/utils/fetch-client' import { PostCategories, PostCategory, PostCategoryAddDto } from '@/models/post-category' -import { globalCtx } from './global-ctx' +import fetch from '@/utils/fetch-client' import { URLSearchParams } from 'url' +import { globalCtx } from './global-ctx' export class PostCategoryService { private static _instance: PostCategoryService | null = null diff --git a/src/services/post-cfg-panel.service.ts b/src/services/post-cfg-panel.service.ts index 60313402..679b59b7 100644 --- a/src/services/post-cfg-panel.service.ts +++ b/src/services/post-cfg-panel.service.ts @@ -1,19 +1,19 @@ +import { openPostFile } from '@/commands/posts-list/open-post-file' +import { uploadImage } from '@/commands/upload-image/upload-image' +import { isErrorResponse } from '@/models/error-response' +import { ImageUploadStatusId } from '@/models/image-upload-status' +import { Post } from '@/models/post' +import { webviewMessage } from '@/models/webview-msg' import { cloneDeep } from 'lodash-es' +import path from 'path' +import { WebviewCmd, WebviewCommonCmd } from 'src/models/webview-cmd' +import { parseWebviewHtml } from 'src/services/parse-webview-html' import vscode, { Uri } from 'vscode' -import { Post } from '@/models/post' import { globalCtx } from './global-ctx' import { postCategoryService } from './post-category.service' -import { siteCategoryService } from './site-category.service' import { PostTagService } from './post-tag.service' import { PostService } from './post.service' -import { isErrorResponse } from '@/models/error-response' -import { webviewMessage } from '@/models/webview-msg' -import { WebviewCommonCmd, WebviewCmd } from 'src/models/webview-cmd' -import { uploadImage } from '@/commands/upload-image/upload-image' -import { ImageUploadStatusId } from '@/models/image-upload-status' -import { openPostFile } from '@/commands/posts-list/open-post-file' -import { parseWebviewHtml } from 'src/services/parse-webview-html' -import path from 'path' +import { siteCategoryService } from './site-category.service' const panels: Map = new Map() diff --git a/src/services/post-tag.service.ts b/src/services/post-tag.service.ts index 6c46e856..23835dcb 100644 --- a/src/services/post-tag.service.ts +++ b/src/services/post-tag.service.ts @@ -1,5 +1,5 @@ -import got from '@/utils/http-client' import { PostTag } from '@/models/post-tag' +import got from '@/utils/http-client' import { globalCtx } from './global-ctx' let cachedTags: PostTag[] | null = null diff --git a/src/services/post-title-sanitizer.service.ts b/src/services/post-title-sanitizer.service.ts index 6a7693f5..52375c24 100644 --- a/src/services/post-title-sanitizer.service.ts +++ b/src/services/post-title-sanitizer.service.ts @@ -1,6 +1,6 @@ +import { Post } from '@/models/post' import path from 'path' import sanitizeFilename from 'sanitize-filename' -import { Post } from '@/models/post' import { globalCtx } from './global-ctx' import { PostFileMapManager } from './post-file-map' diff --git a/src/services/post.service.ts b/src/services/post.service.ts index aa8412d3..43fc1396 100644 --- a/src/services/post.service.ts +++ b/src/services/post.service.ts @@ -1,18 +1,17 @@ -import fetch from '@/utils/fetch-client' -import { Post } from '@/models/post' -import { globalCtx } from './global-ctx' +import { IErrorResponse } from '@/models/error-response' import { PageModel } from '@/models/page-model' -import { PostsListState } from '@/models/posts-list-state' +import { Post } from '@/models/post' import { PostEditDto } from '@/models/post-edit-dto' import { PostUpdatedResponse } from '@/models/post-updated-response' -import { throwIfNotOkGotResponse } from '@/utils/throw-if-not-ok-response' -import { IErrorResponse } from '@/models/error-response' -import { AlertService } from './alert.service' -import { PostFileMapManager } from './post-file-map' +import { PostsListState } from '@/models/posts-list-state' import { ZzkSearchResult } from '@/models/zzk-search-result' -import got from '@/utils/http-client' -import httpClient from '@/utils/http-client' +import fetch from '@/utils/fetch-client' +import { default as got, default as httpClient } from '@/utils/http-client' +import { throwIfNotOkGotResponse } from '@/utils/throw-if-not-ok-response' import iconv from 'iconv-lite' +import { Alert } from './alert.service' +import { globalCtx } from './global-ctx' +import { PostFileMapManager } from './post-file-map' const defaultPageSize = 30 let newPostTemplate: PostEditDto | undefined @@ -73,11 +72,11 @@ export namespace PostService { const { statusCode, errors } = e as IErrorResponse if (!muteErrorNotification) { if (statusCode === 404) { - AlertService.err('博文不存在') + void Alert.err('博文不存在') const postFilePath = PostFileMapManager.getFilePath(postId) if (postFilePath) await PostFileMapManager.updateOrCreate(postId, '') } else { - AlertService.err(errors.join('\n')) + void Alert.err(errors.join('\n')) } } return undefined diff --git a/src/services/search-post-by-title.ts b/src/services/search-post-by-title.ts index 4d8260e7..0aad9dd4 100644 --- a/src/services/search-post-by-title.ts +++ b/src/services/search-post-by-title.ts @@ -1,5 +1,5 @@ -import { QuickPickItem, window } from 'vscode' import { Post } from '@/models/post' +import { QuickPickItem, window } from 'vscode' import { PostService } from './post.service' class PostPickItem implements QuickPickItem { diff --git a/src/services/settings.service.ts b/src/services/settings.service.ts index 733afa0d..d97e93e1 100644 --- a/src/services/settings.service.ts +++ b/src/services/settings.service.ts @@ -1,9 +1,9 @@ -import os, { homedir } from 'os' +import { untildify } from '@/utils/untildify' import fs from 'fs' +import { isNumber } from 'lodash-es' +import os, { homedir } from 'os' import { ConfigurationTarget, Uri, workspace } from 'vscode' import { ImageSrc } from './mkd-img-extractor.service' -import { isNumber } from 'lodash-es' -import { untildify } from '@/utils/untildify' export class Settings { static readonly postsListPageSizeKey = 'pageSize.postsList' diff --git a/src/services/site-category.service.ts b/src/services/site-category.service.ts index c053bf62..ce975d7d 100644 --- a/src/services/site-category.service.ts +++ b/src/services/site-category.service.ts @@ -1,5 +1,5 @@ -import fetch from '@/utils/fetch-client' import { SiteCategories, SiteCategory } from '@/models/site-category' +import fetch from '@/utils/fetch-client' import { globalCtx } from './global-ctx' export namespace siteCategoryService { diff --git a/src/test/suite/extension.test.ts b/src/test/suite/extension.test.ts index 2bdec69c..89de4d8c 100644 --- a/src/test/suite/extension.test.ts +++ b/src/test/suite/extension.test.ts @@ -1,4 +1,4 @@ -import { AlertService } from '@/services/alert.service' +import { Alert } from '@/services/alert.service' import assert from 'assert' // You can import and use all API from the 'vscode' module @@ -6,7 +6,7 @@ import assert from 'assert' // import * as myExtension from '../../extension'; suite('Extension Test Suite', () => { - AlertService.info('Start all tests.') + void Alert.info('Start all tests.') test('Sample test', () => { assert.strictEqual(-1, [1, 2, 3].indexOf(5)) diff --git a/src/test/suite/index.ts b/src/test/suite/index.ts index 6947a966..3b69a023 100644 --- a/src/test/suite/index.ts +++ b/src/test/suite/index.ts @@ -1,6 +1,6 @@ -import path from 'path' -import Mocha from 'mocha' import glob from 'glob' +import Mocha from 'mocha' +import path from 'path' export function run(): Promise { // Create the mocha test diff --git a/src/tree-view-providers/blog-export-provider.ts b/src/tree-view-providers/blog-export-provider.ts index 78a42339..400042fc 100644 --- a/src/tree-view-providers/blog-export-provider.ts +++ b/src/tree-view-providers/blog-export-provider.ts @@ -1,7 +1,10 @@ +import { BlogExportRecord } from '@/models/blog-export' +import { Alert } from '@/services/alert.service' import { BlogExportRecordsStore } from '@/services/blog-export-records.store' +import { Event, EventEmitter, ProviderResult, TreeDataProvider, TreeItem } from 'vscode' import { - BlogExportRecordTreeItem, BlogExportRecordMetadata, + BlogExportRecordTreeItem, BlogExportTreeItem, parseBlogExportRecords, } from './models/blog-export' @@ -11,9 +14,6 @@ import { DownloadedExportTreeItem, ExportPostsEntryTreeItem, } from './models/blog-export/downloaded' -import { Event, EventEmitter, ProviderResult, TreeDataProvider, TreeItem } from 'vscode' -import { AlertService } from '@/services/alert.service' -import { BlogExportRecord } from '@/models/blog-export' export class BlogExportProvider implements TreeDataProvider { private static _instance: BlogExportProvider | null = null @@ -109,7 +109,7 @@ export class BlogExportProvider implements TreeDataProvider ?.refresh() .then(() => true) .catch(e => { - if (notifyOnError) AlertService.err(`刷新博客备份记录失败: ${e.message}`) + if (notifyOnError) void Alert.err(`刷新博客备份记录失败: ${e.message}`) }) : clearCache ? await this._store?.clearCache().then( diff --git a/src/tree-view-providers/converters.ts b/src/tree-view-providers/converters.ts index fa3e1e47..73df604d 100644 --- a/src/tree-view-providers/converters.ts +++ b/src/tree-view-providers/converters.ts @@ -1,11 +1,11 @@ -import format from 'date-fns/format' -import { homedir } from 'os' -import { MarkdownString, ThemeIcon, TreeItem, TreeItemCollapsibleState, Uri } from 'vscode' import { Post } from '@/models/post' import { PostCategory } from '@/models/post-category' import { globalCtx } from '@/services/global-ctx' import { PostFileMapManager } from '@/services/post-file-map' import { Settings } from '@/services/settings.service' +import format from 'date-fns/format' +import { homedir } from 'os' +import { MarkdownString, ThemeIcon, TreeItem, TreeItemCollapsibleState, Uri } from 'vscode' import { BaseTreeItemSource } from './models/base-tree-item-source' const contextValues = { diff --git a/src/tree-view-providers/models/blog-export/index.ts b/src/tree-view-providers/models/blog-export/index.ts index 79f55d76..c0a234b6 100644 --- a/src/tree-view-providers/models/blog-export/index.ts +++ b/src/tree-view-providers/models/blog-export/index.ts @@ -3,12 +3,14 @@ import { DownloadedExportsEntryTreeItem, DownloadedExportTreeItem, } from '@/tree-view-providers/models/blog-export/downloaded' -import { BlogExportRecordMetadata } from '@/tree-view-providers/models/blog-export/record-metadata' import { BlogExportRecordTreeItem } from '@/tree-view-providers/models/blog-export/record' +import { BlogExportRecordMetadata } from '@/tree-view-providers/models/blog-export/record-metadata' -export * from './record-metadata' -export * from './record' +export * from '../post-tree-item' export * from './downloaded' +export { parseBlogExportRecords, parseStatusIcon } from './parser' +export * from './record' +export * from './record-metadata' export type BlogExportTreeItem = | BlogExportRecordMetadata @@ -16,5 +18,3 @@ export type BlogExportTreeItem = | DownloadedExportTreeItem | DownloadedExportChildTreeItem | DownloadedExportsEntryTreeItem -export { parseBlogExportRecords, parseStatusIcon } from './parser' -export * from '../post-tree-item' diff --git a/src/tree-view-providers/models/blog-export/parser.ts b/src/tree-view-providers/models/blog-export/parser.ts index 91d88de7..6f28413f 100644 --- a/src/tree-view-providers/models/blog-export/parser.ts +++ b/src/tree-view-providers/models/blog-export/parser.ts @@ -1,11 +1,11 @@ import { BlogExportRecord, BlogExportStatus, DownloadedBlogExport } from '@/models/blog-export' -import { BlogExportRecordTreeItem } from './record' -import { ThemeColor, ThemeIcon } from 'vscode' +import { BlogExportProvider } from '@/tree-view-providers/blog-export-provider' import { DownloadedExportsEntryTreeItem, DownloadedExportTreeItem, } from '@/tree-view-providers/models/blog-export/downloaded' -import { BlogExportProvider } from '@/tree-view-providers/blog-export-provider' +import { ThemeColor, ThemeIcon } from 'vscode' +import { BlogExportRecordTreeItem } from './record' export function parseStatusIcon(status: BlogExportStatus) { switch (status) { diff --git a/src/tree-view-providers/models/blog-export/record.ts b/src/tree-view-providers/models/blog-export/record.ts index 40ea70d3..72734d9e 100644 --- a/src/tree-view-providers/models/blog-export/record.ts +++ b/src/tree-view-providers/models/blog-export/record.ts @@ -1,17 +1,17 @@ import { BlogExportRecord, BlogExportStatus, blogExportStatusNameMap } from '@/models/blog-export' +import { BlogExportApi } from '@/services/blog-export.api' +import { DownloadedExportStore } from '@/services/downloaded-export.store' +import { BlogExportProvider } from '@/tree-view-providers/blog-export-provider' import { BaseEntryTreeItem } from '@/tree-view-providers/models/base-entry-tree-item' import { BaseTreeItemSource } from '@/tree-view-providers/models/base-tree-item-source' -import { BlogExportRecordMetadata } from './record-metadata' -import { parseStatusIcon } from './parser' -import { TreeItem, TreeItemCollapsibleState, ThemeIcon } from 'vscode' +import { BlogExportTreeItem, DownloadedExportTreeItem } from '@/tree-view-providers/models/blog-export' import format from 'date-fns/format' import parseISO from 'date-fns/parseISO' -import { DownloadedExportStore } from '@/services/downloaded-export.store' -import { BlogExportTreeItem, DownloadedExportTreeItem } from '@/tree-view-providers/models/blog-export' -import os from 'os' import { escapeRegExp } from 'lodash-es' -import { BlogExportProvider } from '@/tree-view-providers/blog-export-provider' -import { BlogExportApi } from '@/services/blog-export.api' +import os from 'os' +import { ThemeIcon, TreeItem, TreeItemCollapsibleState } from 'vscode' +import { parseStatusIcon } from './parser' +import { BlogExportRecordMetadata } from './record-metadata' export class BlogExportRecordTreeItem extends BaseTreeItemSource implements BaseEntryTreeItem { static readonly contextValue = 'cnblogs-export-record' diff --git a/src/tree-view-providers/models/post-category-tree-item.ts b/src/tree-view-providers/models/post-category-tree-item.ts index a0010e4d..3791f112 100644 --- a/src/tree-view-providers/models/post-category-tree-item.ts +++ b/src/tree-view-providers/models/post-category-tree-item.ts @@ -1,5 +1,5 @@ -import { TreeItem } from 'vscode' import { PostCategory } from '@/models/post-category' +import { TreeItem } from 'vscode' import { toTreeItem } from '../converters' import { BaseTreeItemSource } from './base-tree-item-source' import { PostTreeItem } from './post-tree-item' diff --git a/src/tree-view-providers/models/post-metadata.ts b/src/tree-view-providers/models/post-metadata.ts index bcfd06b6..f76a7b42 100644 --- a/src/tree-view-providers/models/post-metadata.ts +++ b/src/tree-view-providers/models/post-metadata.ts @@ -1,17 +1,17 @@ +import { AccessPermission, formatAccessPermission, Post } from '@/models/post' +import { PostCategory } from '@/models/post-category' +import { PostEditDto } from '@/models/post-edit-dto' +import { postCategoryService } from '@/services/post-category.service' +import { PostService } from '@/services/post.service' import differenceInSeconds from 'date-fns/differenceInSeconds' import differenceInYears from 'date-fns/differenceInYears' import format from 'date-fns/format' import formatDistanceStrict from 'date-fns/formatDistanceStrict' import zhCN from 'date-fns/locale/zh-CN' -import { TreeItem, TreeItemCollapsibleState, ThemeIcon } from 'vscode' -import { AccessPermission, Post, formatAccessPermission } from '@/models/post' -import { PostEditDto } from '@/models/post-edit-dto' -import { postCategoryService } from '@/services/post-category.service' -import { PostService } from '@/services/post.service' +import { ThemeIcon, TreeItem, TreeItemCollapsibleState } from 'vscode' import { BaseEntryTreeItem } from './base-entry-tree-item' import { BaseTreeItemSource } from './base-tree-item-source' import { PostTreeItem } from './post-tree-item' -import { PostCategory } from '@/models/post-category' export enum RootPostMetadataType { categoryEntry = 'categoryEntry', diff --git a/src/tree-view-providers/models/post-search-result-entry.ts b/src/tree-view-providers/models/post-search-result-entry.ts index 69a6e081..1d027297 100644 --- a/src/tree-view-providers/models/post-search-result-entry.ts +++ b/src/tree-view-providers/models/post-search-result-entry.ts @@ -1,6 +1,6 @@ -import { ThemeIcon, TreeItem, TreeItemCollapsibleState } from 'vscode' import { Post } from '@/models/post' import { ZzkSearchResult } from '@/models/zzk-search-result' +import { ThemeIcon, TreeItem, TreeItemCollapsibleState } from 'vscode' import { BaseEntryTreeItem } from './base-entry-tree-item' import { BaseTreeItemSource } from './base-tree-item-source' import { PostTreeItem } from './post-tree-item' diff --git a/src/tree-view-providers/models/post-tree-item.ts b/src/tree-view-providers/models/post-tree-item.ts index 76848158..bade85d0 100644 --- a/src/tree-view-providers/models/post-tree-item.ts +++ b/src/tree-view-providers/models/post-tree-item.ts @@ -1,5 +1,5 @@ -import { TreeItem, TreeItemCollapsibleState } from 'vscode' import { Post } from '@/models/post' +import { TreeItem, TreeItemCollapsibleState } from 'vscode' import { toTreeItem } from '../converters' import { BaseTreeItemSource } from './base-tree-item-source' diff --git a/src/tree-view-providers/post-categories-tree-data-provider.ts b/src/tree-view-providers/post-categories-tree-data-provider.ts index e82d2c65..721cf6ee 100644 --- a/src/tree-view-providers/post-categories-tree-data-provider.ts +++ b/src/tree-view-providers/post-categories-tree-data-provider.ts @@ -1,16 +1,16 @@ -import { flattenDepth, take } from 'lodash-es' -import { EventEmitter, ProviderResult, TreeDataProvider, TreeItem } from 'vscode' import { PostCategories } from '@/models/post-category' +import { Alert } from '@/services/alert.service' import { globalCtx } from '@/services/global-ctx' import { postCategoryService } from '@/services/post-category.service' import { PostService } from '@/services/post.service' +import { execCmd } from '@/utils/cmd' +import { flattenDepth, take } from 'lodash-es' +import { EventEmitter, ProviderResult, TreeDataProvider, TreeItem } from 'vscode' import { toTreeItem } from './converters' import { PostCategoriesListTreeItem } from './models/categories-list-tree-item' import { PostCategoryTreeItem } from './models/post-category-tree-item' import { PostEntryMetadata, PostMetadata, RootPostMetadataType } from './models/post-metadata' import { PostTreeItem } from './models/post-tree-item' -import { AlertService } from '@/services/alert.service' -import { execCmd } from '@/utils/cmd' export class PostCategoriesTreeDataProvider implements TreeDataProvider { private static _instance: PostCategoriesTreeDataProvider | null = null @@ -135,7 +135,7 @@ export class PostCategoriesTreeDataProvider implements TreeDataProvidere).message}`) + void Alert.err(`获取博文分类失败: ${(e).message}`) } finally { await this.setIsRefreshing(false) } diff --git a/src/tree-view-providers/posts-data-provider.ts b/src/tree-view-providers/posts-data-provider.ts index 904021d8..3155f413 100644 --- a/src/tree-view-providers/posts-data-provider.ts +++ b/src/tree-view-providers/posts-data-provider.ts @@ -1,10 +1,10 @@ -import { EventEmitter, ProviderResult, TreeDataProvider, TreeItem } from 'vscode' import { refreshPostsList } from '@/commands/posts-list/refresh-posts-list' -import { Post } from '@/models/post' import { PageModel } from '@/models/page-model' -import { AlertService } from '@/services/alert.service' +import { Post } from '@/models/post' +import { Alert } from '@/services/alert.service' import { PostService } from '@/services/post.service' import { Settings } from '@/services/settings.service' +import { EventEmitter, ProviderResult, TreeDataProvider, TreeItem } from 'vscode' import { toTreeItem } from './converters' import { PostEntryMetadata, PostMetadata } from './models/post-metadata' import { PostSearchResultEntry } from './models/post-search-result-entry' @@ -66,8 +66,8 @@ export class PostsDataProvider implements TreeDataProvider { const pageSize = Settings.postsListPageSize this._pagedPosts = await PostService.fetchPostsList({ pageIndex, pageSize }).catch(e => { - if (e instanceof Error) AlertService.err(e.message) - else AlertService.err(`加载博文失败\n${JSON.stringify(e)}`) + if (e instanceof Error) void Alert.err(e.message) + else void Alert.err(`加载博文失败\n${JSON.stringify(e)}`) return undefined }) diff --git a/src/tree-view-providers/tree-view-registration.ts b/src/tree-view-providers/tree-view-registration.ts index ab0c656f..0dd838d2 100644 --- a/src/tree-view-providers/tree-view-registration.ts +++ b/src/tree-view-providers/tree-view-registration.ts @@ -1,13 +1,13 @@ import { globalCtx } from '@/services/global-ctx' +import { BlogExportProvider } from '@/tree-view-providers/blog-export-provider' +import { BlogExportTreeItem } from '@/tree-view-providers/models/blog-export' +import { regTreeView } from '@/utils/tree-view' +import { IDisposable } from '@fluentui/react' import vscode from 'vscode' import { accountViewDataProvider } from './account-view-data-provider' -import { PostsListTreeItem, postsDataProvider } from './posts-data-provider' -import { postCategoriesDataProvider } from './post-categories-tree-data-provider' import { PostCategoriesListTreeItem } from './models/categories-list-tree-item' -import { IDisposable } from '@fluentui/react' -import { BlogExportTreeItem } from '@/tree-view-providers/models/blog-export' -import { BlogExportProvider } from '@/tree-view-providers/blog-export-provider' -import { regTreeView } from '@/utils/tree-view' +import { postCategoriesDataProvider } from './post-categories-tree-data-provider' +import { postsDataProvider, PostsListTreeItem } from './posts-data-provider' const _views: { postsList?: vscode.TreeView diff --git a/src/utils/chromium-path-provider.ts b/src/utils/chromium-path-provider.ts index 75f2b326..db66769f 100644 --- a/src/utils/chromium-path-provider.ts +++ b/src/utils/chromium-path-provider.ts @@ -1,8 +1,8 @@ -import { window, ProgressLocation } from 'vscode' +import { Alert } from '@/services/alert.service' import fs from 'fs' import os from 'os' import path from 'path' -import { AlertService } from '@/services/alert.service' +import { ProgressLocation, window } from 'vscode' // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-var-requires const download: (arg: Record) => Promise = require('download-chromium') @@ -74,7 +74,7 @@ namespace chromiumPathProvider { } } ) - if (chromiumPath) AlertService.info(`Chromium已下载至${chromiumPath}`) + if (chromiumPath) void Alert.info(`Chromium已下载至${chromiumPath}`) return chromiumPath } diff --git a/src/utils/cmd.ts b/src/utils/cmd.ts index e2bffe75..c734127f 100644 --- a/src/utils/cmd.ts +++ b/src/utils/cmd.ts @@ -1,9 +1,5 @@ import { commands } from 'vscode' -export function regCmd(cmd: string, f: (...args: any[]) => any) { - return commands.registerCommand(cmd, f) -} +export const regCmd = commands.registerCommand -export function execCmd(cmd: string, ...rest: any[]) { - return commands.executeCommand(cmd, rest) -} +export const execCmd = commands.executeCommand diff --git a/src/utils/get-clipboard-image.ts b/src/utils/get-clipboard-image.ts index feb72e72..693c8860 100644 --- a/src/utils/get-clipboard-image.ts +++ b/src/utils/get-clipboard-image.ts @@ -1,14 +1,14 @@ // reference: https://github.com/PicGo/PicGo-Core/blob/dev/src/utils/getClipboardImage.ts +import { IClipboardImage } from '@/models/clipboard-image' +import { Alert } from '@/services/alert.service' +import { globalCtx } from '@/services/global-ctx' import { spawn } from 'child_process' -import path from 'path' +import format from 'date-fns/format' import fs from 'fs' -import os from 'os' import isWsl from 'is-wsl' -import { globalCtx } from '@/services/global-ctx' -import { AlertService } from '@/services/alert.service' -import { IClipboardImage } from '@/models/clipboard-image' -import format from 'date-fns/format' +import os from 'os' +import path from 'path' export type Platform = 'darwin' | 'win32' | 'win10' | 'linux' | 'wsl' @@ -94,7 +94,7 @@ const getClipboardImage = (): Promise => { execution.stdout.on('data', (data: Buffer) => { if (platform === 'linux') { if (data.toString().trim() === 'no xclip') { - AlertService.warn('xclip not found, Please install xclip first') + void Alert.warn('xclip not found, Please install xclip first') return reject(new Error('Please install xclip first')) } } diff --git a/src/utils/http-client.ts b/src/utils/http-client.ts index a43343dc..da70b6ba 100644 --- a/src/utils/http-client.ts +++ b/src/utils/http-client.ts @@ -1,7 +1,7 @@ import { accountManager } from '@/auth/account-manager' +import { Oauth } from '@/services/oauth.api' import got, { BeforeRequestHook } from 'got' import { isString } from 'lodash-es' -import { Oauth } from '@/services/oauth.api' const bearerTokenHook: BeforeRequestHook = async opt => { const { headers } = opt @@ -24,6 +24,6 @@ const httpClient = got.extend({ https: { rejectUnauthorized: false }, }) -export { got } export * from 'got' +export { got } export default httpClient diff --git a/src/utils/input-post-settings.ts b/src/utils/input-post-settings.ts index 58ef8a17..0c264919 100644 --- a/src/utils/input-post-settings.ts +++ b/src/utils/input-post-settings.ts @@ -1,9 +1,9 @@ -import { QuickPickItem } from 'vscode' import { AccessPermission, Post } from '@/models/post' import { PostCategories, PostCategory } from '@/models/post-category' -import { AlertService } from '@/services/alert.service' +import { Alert } from '@/services/alert.service' import { InputFlowAction, InputStep, MultiStepInput, QuickPickParameters } from '@/services/multi-step-input' import { postCategoryService } from '@/services/post-category.service' +import { QuickPickItem } from 'vscode' class CategoryPickItem implements QuickPickItem { label: string @@ -102,7 +102,7 @@ export const inputPostSettings = ( try { categories = await postCategoryService.listCategories() } catch (err) { - AlertService.err(err instanceof Error ? err.message : JSON.stringify(err)) + void Alert.err(err instanceof Error ? err.message : JSON.stringify(err)) // 取消 throw InputFlowAction.cancel } diff --git a/src/utils/msg.ts b/src/utils/msg.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/utils/save-file-pending-changes.ts b/src/utils/save-file-pending-changes.ts index 5f830aab..10a2f3c7 100644 --- a/src/utils/save-file-pending-changes.ts +++ b/src/utils/save-file-pending-changes.ts @@ -1,4 +1,4 @@ -import { window, Uri } from 'vscode' +import { Uri, window } from 'vscode' export const saveFilePendingChanges = async (filePath: Uri | string | undefined) => { const localPath = typeof filePath === 'string' ? filePath : filePath?.fsPath diff --git a/src/utils/throw-if-not-ok-response.ts b/src/utils/throw-if-not-ok-response.ts index 6237cf0b..150536a1 100644 --- a/src/utils/throw-if-not-ok-response.ts +++ b/src/utils/throw-if-not-ok-response.ts @@ -1,6 +1,6 @@ -import { GotFetchResponse } from 'got-fetch/out/lib/response' -import { Response as GotResponse } from 'got' import { IErrorResponse, isErrorResponse } from '@/models/error-response' +import { Response as GotResponse } from 'got' +import { GotFetchResponse } from 'got-fetch/out/lib/response' import iconv from 'iconv-lite' const throwIfNotOkResponse = async (response: GotFetchResponse) => { diff --git a/src/utils/tree-view.ts b/src/utils/tree-view.ts index b65bd915..b9b43a96 100644 --- a/src/utils/tree-view.ts +++ b/src/utils/tree-view.ts @@ -1,5 +1,3 @@ -import vscode, { TreeViewOptions } from 'vscode' +import { window } from 'vscode' -export function regTreeView(id: string, opt: TreeViewOptions) { - return vscode.window.createTreeView(id, opt) -} +export const regTreeView = window.createTreeView diff --git a/src/utils/uri-handler.ts b/src/utils/uri-handler.ts index a635cbbb..9e058d9a 100644 --- a/src/utils/uri-handler.ts +++ b/src/utils/uri-handler.ts @@ -1,5 +1,5 @@ -import { Disposable, EventEmitter, ProviderResult, Uri, UriHandler, Event } from 'vscode' import { openPostInVscode } from '@/commands/posts-list/open-post-in-vscode' +import { Disposable, Event, EventEmitter, ProviderResult, Uri, UriHandler } from 'vscode' class ExtUriHandler implements UriHandler, Disposable { private _uriEventEmitter?: EventEmitter diff --git a/ui/ing/App.tsx b/ui/ing/App.tsx index fde339d5..9202d37f 100644 --- a/ui/ing/App.tsx +++ b/ui/ing/App.tsx @@ -1,13 +1,13 @@ -import React, { Component, ReactNode } from 'react' +import { Spinner, Stack } from '@fluentui/react' +import { ThemeProvider } from '@fluentui/react/lib/Theme' +import { Ing, IngComment } from '@models/ing' +import { IngAppState } from '@models/ing-view' import { IngWebviewUiCmd, WebviewCmd } from '@models/webview-cmd' import { IngList } from 'ing/IngList' -import { getVsCodeApiSingleton } from 'share/vscode-api' -import { IngAppState } from '@models/ing-view' -import { Ing, IngComment } from '@models/ing' -import { activeThemeProvider } from 'share/active-theme-provider' -import { ThemeProvider } from '@fluentui/react/lib/Theme' -import { Spinner, Stack } from '@fluentui/react' import { cloneWith } from 'lodash-es' +import React, { Component, ReactNode } from 'react' +import { activeThemeProvider } from 'share/active-theme-provider' +import { getVsCodeApiSingleton } from 'share/vscode-api' export class App extends Component { constructor(props: unknown) { diff --git a/ui/ing/IngItem.tsx b/ui/ing/IngItem.tsx index a1639f97..4e804c49 100644 --- a/ui/ing/IngItem.tsx +++ b/ui/ing/IngItem.tsx @@ -1,12 +1,12 @@ -import React, { Component } from 'react' +import { ActivityItem, IPersonaProps, Link, Text } from '@fluentui/react' import { Ing, IngComment, IngSendFromType } from '@models/ing' import { IngItemState } from '@models/ing-view' -import { take } from 'lodash-es' -import { ActivityItem, IPersonaProps, Link, Text } from '@fluentui/react' +import { IngWebviewHostCmd, WebviewCmd } from '@models/webview-cmd' import { format, formatDistanceStrict } from 'date-fns' import { zhCN } from 'date-fns/locale' +import { take } from 'lodash-es' +import React, { Component } from 'react' import { getVsCodeApiSingleton } from 'share/vscode-api' -import { IngWebviewHostCmd, WebviewCmd } from '@models/webview-cmd' interface IngItemProps { ing: Ing diff --git a/ui/ing/IngList.tsx b/ui/ing/IngList.tsx index a8dde0e4..48f92efa 100644 --- a/ui/ing/IngList.tsx +++ b/ui/ing/IngList.tsx @@ -1,7 +1,7 @@ -import React, { Component } from 'react' +import { Stack } from '@fluentui/react' import { Ing, IngComment } from '@models/ing' import { IngItem } from 'ing/IngItem' -import { Stack } from '@fluentui/react' +import React, { Component } from 'react' interface IngListProps { ings: Ing[] diff --git a/ui/ing/index.tsx b/ui/ing/index.tsx index 63f6866c..8412ec50 100644 --- a/ui/ing/index.tsx +++ b/ui/ing/index.tsx @@ -1,5 +1,5 @@ -import './index.less' import { App } from 'ing/App' import ReactDOM from 'react-dom' +import './index.less' ReactDOM.render(, document.getElementById('root')) diff --git a/ui/post-cfg/App.tsx b/ui/post-cfg/App.tsx index 38a41562..f1c08239 100644 --- a/ui/post-cfg/App.tsx +++ b/ui/post-cfg/App.tsx @@ -1,17 +1,17 @@ -import React, { Component } from 'react' +import { Breadcrumb, IBreadcrumbItem, initializeIcons, PartialTheme, Spinner, Stack, Theme } from '@fluentui/react' import { ThemeProvider } from '@fluentui/react/lib/Theme' -import { Theme, PartialTheme, Stack, Breadcrumb, IBreadcrumbItem, Spinner, initializeIcons } from '@fluentui/react' -import { PostForm } from './components/PostForm' import { Post } from '@models/post' -import { personalCategoriesStore } from './services/personal-categories-store' -import { siteCategoriesStore } from './services/site-categories-store' -import { tagsStore } from './services/tags-store' -import { webviewMessage } from '@models/webview-msg' import { WebviewCmd } from '@models/webview-cmd' -import { PostFormContextProvider } from './components/PostFormContextProvider' +import { webviewMessage } from '@models/webview-msg' +import React, { Component } from 'react' import { activeThemeProvider } from 'share/active-theme-provider' import { darkTheme, lightTheme } from 'share/theme' import { getVsCodeApiSingleton } from 'share/vscode-api' +import { PostForm } from './components/PostForm' +import { PostFormContextProvider } from './components/PostFormContextProvider' +import { personalCategoriesStore } from './services/personal-categories-store' +import { siteCategoriesStore } from './services/site-categories-store' +import { tagsStore } from './services/tags-store' interface AppState { post?: Post diff --git a/ui/post-cfg/components/InputSummary.tsx b/ui/post-cfg/components/InputSummary.tsx index 9848ff9c..52334f9e 100644 --- a/ui/post-cfg/components/InputSummary.tsx +++ b/ui/post-cfg/components/InputSummary.tsx @@ -1,4 +1,4 @@ -import { ActionButton, Label, MessageBar, MessageBarType, Stack, TextField, Text } from '@fluentui/react' +import { ActionButton, Label, MessageBar, MessageBarType, Stack, Text, TextField } from '@fluentui/react' import { ImageUploadStatusId } from '@models/image-upload-status' import { WebviewCmd } from '@models/webview-cmd' import { webviewMessage } from '@models/webview-msg' diff --git a/ui/post-cfg/components/PostForm.tsx b/ui/post-cfg/components/PostForm.tsx index 446c9349..5887dea9 100644 --- a/ui/post-cfg/components/PostForm.tsx +++ b/ui/post-cfg/components/PostForm.tsx @@ -1,25 +1,25 @@ +import { Label, Spinner } from '@fluentui/react' import { DefaultButton, PrimaryButton } from '@fluentui/react/lib/Button' import { Stack } from '@fluentui/react/lib/Stack' +import { Post } from '@models/post' +import { PostCfg } from '@models/post-cfg' +import { WebviewCmd } from '@models/webview-cmd' +import { webviewMessage } from '@models/webview-msg' +import NestCategoriesSelect from 'post-cfg/components/NestCategoriesSelect' +import PostTitleInput from 'post-cfg/components/PostTitleInput' import React from 'react' +import { getVsCodeApiSingleton } from '../../share/vscode-api' +import { AccessPermissionSelector } from './AccessPermissionSelector' import { CategoriesSelect } from './CategoriesSelect' -import { SiteHomeContributionOptionsSelector } from './SiteHomeContributionOptionsSelector' -import { PostCfg } from '@models/post-cfg' -import { Post } from '@models/post' -import { Label, Spinner } from '@fluentui/react' -import { SiteCategoriesSelector } from './SiteCategoriesSelector' -import { TagsInput } from './TagsInput' import { CommonOptions } from './CommonOptions' -import { AccessPermissionSelector } from './AccessPermissionSelector' -import { PasswordInput } from './PasswordInput' -import { getVsCodeApiSingleton } from '../../share/vscode-api' import { ErrorResponse } from './ErrorResponse' -import { WebviewCmd } from '@models/webview-cmd' -import { webviewMessage } from '@models/webview-msg' import { InputSummary } from './InputSummary' -import { IPostFormContext, PostFormContext } from './PostFormContext' +import { PasswordInput } from './PasswordInput' import PostEntryNameInput from './PostEntryNameInput' -import PostTitleInput from 'post-cfg/components/PostTitleInput' -import NestCategoriesSelect from 'post-cfg/components/NestCategoriesSelect' +import { IPostFormContext, PostFormContext } from './PostFormContext' +import { SiteCategoriesSelector } from './SiteCategoriesSelector' +import { SiteHomeContributionOptionsSelector } from './SiteHomeContributionOptionsSelector' +import { TagsInput } from './TagsInput' export interface IPostFormProps { post?: Post diff --git a/ui/post-cfg/components/PostFormContextProvider.tsx b/ui/post-cfg/components/PostFormContextProvider.tsx index b441f66f..e9b2fc5e 100644 --- a/ui/post-cfg/components/PostFormContextProvider.tsx +++ b/ui/post-cfg/components/PostFormContextProvider.tsx @@ -1,5 +1,5 @@ import * as React from 'react' -import { PostFormContext, IPostFormContext, defaultPostFormContext } from './PostFormContext' +import { defaultPostFormContext, IPostFormContext, PostFormContext } from './PostFormContext' export interface IPostFormContextProviderProps { value?: Partial diff --git a/ui/post-cfg/components/SiteHomeContributionOptionsSelector.tsx b/ui/post-cfg/components/SiteHomeContributionOptionsSelector.tsx index 3edc75f1..101a64f8 100644 --- a/ui/post-cfg/components/SiteHomeContributionOptionsSelector.tsx +++ b/ui/post-cfg/components/SiteHomeContributionOptionsSelector.tsx @@ -1,8 +1,8 @@ +import { ActionButton, Checkbox, Label } from '@fluentui/react' +import { Stack } from '@fluentui/react/lib/Stack' +import { Text } from '@fluentui/react/lib/Text' import React from 'react' import { SiteHomeContributionOptions as ISiteHomeContributionOptions } from '../models/site-home-contribution-options' -import { Text } from '@fluentui/react/lib/Text' -import { Stack } from '@fluentui/react/lib/Stack' -import { ActionButton, Checkbox, Label } from '@fluentui/react' export interface ISiteHomeContributionOptionsSelectorProps extends ISiteHomeContributionOptions { onInSiteHomeChange: (value: boolean) => void diff --git a/ui/post-cfg/components/TagsInput.tsx b/ui/post-cfg/components/TagsInput.tsx index d158fb01..369a6e41 100644 --- a/ui/post-cfg/components/TagsInput.tsx +++ b/ui/post-cfg/components/TagsInput.tsx @@ -7,12 +7,12 @@ import { TagItem, TagItemSuggestion, TagPicker, - ValidationState, Text, + ValidationState, } from '@fluentui/react' +import { PostTag, PostTags } from '@models/post-tag' import React from 'react' import { tagsStore } from '../services/tags-store' -import { PostTags, PostTag } from '@models/post-tag' export interface ITagsInputProps { selectedTagNames?: string[] diff --git a/ui/post-cfg/index.tsx b/ui/post-cfg/index.tsx index 55693c10..66328cea 100644 --- a/ui/post-cfg/index.tsx +++ b/ui/post-cfg/index.tsx @@ -1,5 +1,5 @@ -import './index.less' -import { App } from './App' import ReactDOM from 'react-dom' +import { App } from './App' +import './index.less' ReactDOM.render(, document.getElementById('root')) diff --git a/ui/post-cfg/services/personal-categories-store.ts b/ui/post-cfg/services/personal-categories-store.ts index c22cf8d0..24702a5f 100644 --- a/ui/post-cfg/services/personal-categories-store.ts +++ b/ui/post-cfg/services/personal-categories-store.ts @@ -1,5 +1,5 @@ import { PostCategories } from '@/models/post-category' -import { WebviewCommonCmd, WebviewCmd } from '@models/webview-cmd' +import { WebviewCmd, WebviewCommonCmd } from '@models/webview-cmd' import { getVsCodeApiSingleton } from 'share/vscode-api' let children: Map diff --git a/ui/webpack.config.mjs b/ui/webpack.config.mjs index 4ff12f76..1f7a55a2 100644 --- a/ui/webpack.config.mjs +++ b/ui/webpack.config.mjs @@ -1,12 +1,12 @@ /* eslint-disable @typescript-eslint/no-unsafe-call */ /* eslint-disable no-undef */ /* eslint-disable @typescript-eslint/naming-convention */ +import { cpSync, existsSync, readdirSync, rmSync } from 'fs' import MiniCssExtractPlugin from 'mini-css-extract-plugin' -import { rmSync, readdirSync, cpSync, existsSync } from 'fs' import { resolve } from 'path' -import tailwindConfig from './tailwind.config.js' -import TsconfigPathsPlugin from 'tsconfig-paths-webpack-plugin' import TerserPlugin from 'terser-webpack-plugin' +import TsconfigPathsPlugin from 'tsconfig-paths-webpack-plugin' +import tailwindConfig from './tailwind.config.js' const isDevEnv = process.env.ASPNETCORE_ENVIRONMENT === 'Development' || process.env.NODE_ENV === 'development' diff --git a/webpack.config.mjs b/webpack.config.mjs index 3f56b22b..43e3ef0b 100644 --- a/webpack.config.mjs +++ b/webpack.config.mjs @@ -4,8 +4,8 @@ 'use strict' -import path from 'path' import CopyWebpackPlugin from 'copy-webpack-plugin' +import path from 'path' import { TsconfigPathsPlugin } from 'tsconfig-paths-webpack-plugin' import { fileURLToPath } from 'url' import webpack from 'webpack' From 9a72c656aa3180211a0750c3c5c12a66fd2bc957 Mon Sep 17 00:00:00 2001 From: Thaumy Date: Thu, 20 Jul 2023 18:07:54 +0800 Subject: [PATCH 008/157] Revert "style: optimize imports" This reverts commit 1556f9ada9072a0759da12cdd29d94eeae92d6f5. --- .prettierrc.js | 1 - download-iconfont.mjs | 4 +- package-lock.json | 30 +---------- package.json | 1 - src/auth/account-manager.ts | 20 +++---- src/auth/auth-provider.ts | 14 ++--- src/commands/blog-export/create.ts | 10 ++-- src/commands/blog-export/delete.ts | 4 +- src/commands/blog-export/download.ts | 6 +-- src/commands/blog-export/edit.ts | 4 +- src/commands/blog-export/index.ts | 10 ++-- src/commands/blog-export/open-local.ts | 17 +++--- src/commands/blog-export/refresh.ts | 2 +- src/commands/cmd-register.ts | 52 +++++++++---------- src/commands/extract-images.ts | 10 ++-- src/commands/ing/ings-list-cmd-register.ts | 10 ++-- src/commands/ing/open-ing-in-browser.ts | 2 +- src/commands/ing/publish-ing.ts | 10 ++-- src/commands/open-my-account-settings.ts | 2 +- src/commands/open-my-blog-console.ts | 2 +- src/commands/open-my-blog.ts | 2 +- src/commands/open-post-in-blog-admin.ts | 4 +- src/commands/open-workspace.ts | 6 +-- src/commands/pdf/export-pdf.command.ts | 28 +++++----- src/commands/pdf/post-pdf-template-builder.ts | 8 +-- .../delete-selected-categories.ts | 8 +-- .../post-category/input-post-category.ts | 2 +- .../post-category/new-post-category.ts | 6 +-- .../post-category/update-post-category.ts | 8 +-- src/commands/posts-list/copy-link.ts | 4 +- src/commands/posts-list/create-local-draft.ts | 4 +- .../delete-post-to-local-file-map.ts | 6 +-- src/commands/posts-list/delete-post.ts | 16 +++--- .../posts-list/modify-post-settings.ts | 28 +++++----- src/commands/posts-list/open-post-file.ts | 4 +- .../posts-list/open-post-in-vscode.ts | 20 +++---- src/commands/posts-list/refresh-posts-list.ts | 10 ++-- src/commands/posts-list/rename-post.ts | 16 +++--- src/commands/posts-list/search.ts | 2 +- src/commands/posts-list/upload-post.ts | 42 +++++++-------- src/commands/pull-post-remote-updates.ts | 18 +++---- src/commands/reveal-local-post-file-in-os.ts | 4 +- src/commands/reveal-workspace-in-os.ts | 4 +- src/commands/set-workspace.ts | 6 +-- src/commands/show-local-file-to-post-info.ts | 18 +++---- .../upload-image/upload-clipboard-image.ts | 8 +-- .../upload-image/upload-image-utils.ts | 6 +-- src/commands/upload-image/upload-image.ts | 7 +-- .../upload-image/upload-local-disk-image.ts | 2 +- src/commands/view-post-online.ts | 6 +-- src/extension.ts | 8 +-- src/markdown/extend-markdownIt.ts | 2 +- src/models/ing-view.ts | 2 +- src/models/webview-msg.ts | 10 ++-- src/services/alert.service.ts | 15 ++++-- src/services/blog-export-post.store.ts | 2 +- src/services/blog-settings.service.ts | 2 +- src/services/check-workspace.ts | 6 +-- src/services/global-ctx.ts | 2 +- src/services/image.service.ts | 6 +-- src/services/ing.api.ts | 22 ++++---- src/services/ings-list-webview-provider.ts | 16 +++--- src/services/local-draft.service.ts | 2 +- src/services/mkd-img-extractor.service.ts | 12 ++--- src/services/oauth.api.ts | 4 +- src/services/parse-webview-html.ts | 2 +- src/services/post-category.service.ts | 4 +- src/services/post-cfg-panel.service.ts | 20 +++---- src/services/post-tag.service.ts | 2 +- src/services/post-title-sanitizer.service.ts | 2 +- src/services/post.service.ts | 23 ++++---- src/services/search-post-by-title.ts | 2 +- src/services/settings.service.ts | 6 +-- src/services/site-category.service.ts | 2 +- src/test/suite/extension.test.ts | 4 +- src/test/suite/index.ts | 4 +- .../blog-export-provider.ts | 10 ++-- src/tree-view-providers/converters.ts | 6 +-- .../models/blog-export/index.ts | 10 ++-- .../models/blog-export/parser.ts | 6 +-- .../models/blog-export/record.ts | 16 +++--- .../models/post-category-tree-item.ts | 2 +- .../models/post-metadata.ts | 12 ++--- .../models/post-search-result-entry.ts | 2 +- .../models/post-tree-item.ts | 2 +- .../post-categories-tree-data-provider.ts | 10 ++-- .../posts-data-provider.ts | 10 ++-- .../tree-view-registration.ts | 12 ++--- src/utils/chromium-path-provider.ts | 6 +-- src/utils/cmd.ts | 8 ++- src/utils/get-clipboard-image.ts | 14 ++--- src/utils/http-client.ts | 4 +- src/utils/input-post-settings.ts | 6 +-- src/utils/msg.ts | 0 src/utils/save-file-pending-changes.ts | 2 +- src/utils/throw-if-not-ok-response.ts | 4 +- src/utils/tree-view.ts | 6 ++- src/utils/uri-handler.ts | 2 +- ui/ing/App.tsx | 14 ++--- ui/ing/IngItem.tsx | 8 +-- ui/ing/IngList.tsx | 4 +- ui/ing/index.tsx | 2 +- ui/post-cfg/App.tsx | 16 +++--- ui/post-cfg/components/InputSummary.tsx | 2 +- ui/post-cfg/components/PostForm.tsx | 28 +++++----- .../components/PostFormContextProvider.tsx | 2 +- .../SiteHomeContributionOptionsSelector.tsx | 6 +-- ui/post-cfg/components/TagsInput.tsx | 4 +- ui/post-cfg/index.tsx | 4 +- .../services/personal-categories-store.ts | 2 +- ui/webpack.config.mjs | 6 +-- webpack.config.mjs | 2 +- 112 files changed, 467 insertions(+), 479 deletions(-) create mode 100644 src/utils/msg.ts diff --git a/.prettierrc.js b/.prettierrc.js index f370214b..767c7f06 100644 --- a/.prettierrc.js +++ b/.prettierrc.js @@ -2,5 +2,4 @@ module.exports = { ...require('@cnblogs/prettier-config'), tabWidth: 4, semi: false, - organizeImportsSkipDestructiveCodeActions: true, } diff --git a/download-iconfont.mjs b/download-iconfont.mjs index 53839c95..6013c5a5 100644 --- a/download-iconfont.mjs +++ b/download-iconfont.mjs @@ -1,7 +1,7 @@ /* eslint-disable no-console */ -import AdmZip from 'adm-zip' -import fs from 'fs' import fetch from 'node-fetch' +import fs from 'fs' +import AdmZip from 'adm-zip' const url = 'https://www.iconfont.cn/api/project/download.zip?spm=a313x.7781069.1998910419.d7543c303&pid=2996691&ctoken=ndNRCUzYy381Rxk59b1LjTrg' const cookie = diff --git a/package-lock.json b/package-lock.json index d94d0ddb..b4739722 100644 --- a/package-lock.json +++ b/package-lock.json @@ -79,7 +79,6 @@ "postcss-loader": "^6.2.1", "postcss-preset-env": "^7.4.3", "prettier": "^2.8.8", - "prettier-plugin-organize-imports": "^3.2.3", "style-loader": "^3.3.1", "tailwindcss": "^3.0.23", "terser-webpack-plugin": "^5.3.7", @@ -93,7 +92,7 @@ "webpack-cli": "^5.0.1" }, "engines": { - "vscode": "^1.80.0" + "vscode": "^1.70.0" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -12138,26 +12137,6 @@ "node": ">=6.0.0" } }, - "node_modules/prettier-plugin-organize-imports": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/prettier-plugin-organize-imports/-/prettier-plugin-organize-imports-3.2.3.tgz", - "integrity": "sha512-KFvk8C/zGyvUaE3RvxN2MhCLwzV6OBbFSkwZ2OamCrs9ZY4i5L77jQ/w4UmUr+lqX8qbaqVq6bZZkApn+IgJSg==", - "dev": true, - "peerDependencies": { - "@volar/vue-language-plugin-pug": "^1.0.4", - "@volar/vue-typescript": "^1.0.4", - "prettier": ">=2.0", - "typescript": ">=2.9" - }, - "peerDependenciesMeta": { - "@volar/vue-language-plugin-pug": { - "optional": true - }, - "@volar/vue-typescript": { - "optional": true - } - } - }, "node_modules/pretty-format": { "version": "29.4.3", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.4.3.tgz", @@ -23164,13 +23143,6 @@ "fast-diff": "^1.1.2" } }, - "prettier-plugin-organize-imports": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/prettier-plugin-organize-imports/-/prettier-plugin-organize-imports-3.2.3.tgz", - "integrity": "sha512-KFvk8C/zGyvUaE3RvxN2MhCLwzV6OBbFSkwZ2OamCrs9ZY4i5L77jQ/w4UmUr+lqX8qbaqVq6bZZkApn+IgJSg==", - "dev": true, - "requires": {} - }, "pretty-format": { "version": "29.4.3", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.4.3.tgz", diff --git a/package.json b/package.json index e7888a5a..3faa7d4e 100644 --- a/package.json +++ b/package.json @@ -1361,7 +1361,6 @@ "postcss-loader": "^6.2.1", "postcss-preset-env": "^7.4.3", "prettier": "^2.8.8", - "prettier-plugin-organize-imports": "^3.2.3", "style-loader": "^3.3.1", "tailwindcss": "^3.0.23", "terser-webpack-plugin": "^5.3.7", diff --git a/src/auth/account-manager.ts b/src/auth/account-manager.ts index 772df47b..5829ba86 100644 --- a/src/auth/account-manager.ts +++ b/src/auth/account-manager.ts @@ -1,15 +1,15 @@ -import { AuthProvider } from '@/auth/auth-provider' -import { AuthSession } from '@/auth/auth-session' -import { Alert } from '@/services/alert.service' +import { AccountInfo } from './account-info' import { globalCtx } from '@/services/global-ctx' -import { Oauth } from '@/services/oauth.api' +import vscode, { authentication, AuthenticationGetSessionOptions, Disposable } from 'vscode' import { accountViewDataProvider } from '@/tree-view-providers/account-view-data-provider' -import { BlogExportProvider } from '@/tree-view-providers/blog-export-provider' -import { postCategoriesDataProvider } from '@/tree-view-providers/post-categories-tree-data-provider' import { postsDataProvider } from '@/tree-view-providers/posts-data-provider' +import { postCategoriesDataProvider } from '@/tree-view-providers/post-categories-tree-data-provider' +import { Oauth } from '@/services/oauth.api' +import { AuthProvider } from '@/auth/auth-provider' +import { AuthSession } from '@/auth/auth-session' +import { BlogExportProvider } from '@/tree-view-providers/blog-export-provider' +import { AlertService } from '@/services/alert.service' import { execCmd } from '@/utils/cmd' -import vscode, { authentication, AuthenticationGetSessionOptions, Disposable } from 'vscode' -import { AccountInfo } from './account-info' const isAuthorizedStorageKey = 'isAuthorized' @@ -81,7 +81,7 @@ class AccountManager extends vscode.Disposable { await AuthProvider.instance.removeSession(session.id) await Oauth.revokeToken(session.accessToken) } catch (e: any) { - void Alert.err(`登出发生错误: ${e}`) + AlertService.err(`登出发生错误: ${e}`) } } @@ -102,7 +102,7 @@ class AccountManager extends vscode.Disposable { const session = await authentication.getSession(AuthProvider.instance.providerId, [], opt).then( session => (session ? AuthSession.from(session) : null), e => { - void Alert.err(`创建/获取 Session 失败: ${e}`) + AlertService.err(`创建/获取 Session 失败: ${e}`) } ) diff --git a/src/auth/auth-provider.ts b/src/auth/auth-provider.ts index 3c836668..44461c30 100644 --- a/src/auth/auth-provider.ts +++ b/src/auth/auth-provider.ts @@ -1,13 +1,6 @@ -import { AccountInfo } from '@/auth/account-info' import { AuthSession } from '@/auth/auth-session' -import { TokenInfo } from '@/models/token-info' import { genVerifyChallengePair } from '@/services/code-challenge.service' -import { globalCtx } from '@/services/global-ctx' -import { Oauth } from '@/services/oauth.api' -import { extUriHandler } from '@/utils/uri-handler' import { isArray, isUndefined } from 'lodash-es' -import RandomString from 'randomstring' -import { Optional } from 'utility-types' import { authentication, AuthenticationProvider, @@ -21,6 +14,13 @@ import { Uri, window, } from 'vscode' +import { globalCtx } from '@/services/global-ctx' +import RandomString from 'randomstring' +import { Oauth } from '@/services/oauth.api' +import { extUriHandler } from '@/utils/uri-handler' +import { AccountInfo } from '@/auth/account-info' +import { TokenInfo } from '@/models/token-info' +import { Optional } from 'utility-types' export class AuthProvider implements AuthenticationProvider, Disposable { static readonly providerId = 'cnblogs' diff --git a/src/commands/blog-export/create.ts b/src/commands/blog-export/create.ts index 4bde0275..cb71ef00 100644 --- a/src/commands/blog-export/create.ts +++ b/src/commands/blog-export/create.ts @@ -1,5 +1,5 @@ import { CmdHandler } from '@/commands/cmd-handler' -import { Alert } from '@/services/alert.service' +import { AlertService } from '@/services/alert.service' import { BlogExportApi } from '@/services/blog-export.api' import { BlogExportProvider } from '@/tree-view-providers/blog-export-provider' import { MessageItem, window } from 'vscode' @@ -12,7 +12,7 @@ export class CreateBlogExportCmdHandler extends CmdHandler { if ( (await BlogExportApi.create().catch((e: unknown) => { - void Alert.httpErr(typeof e === 'object' && e ? e : {}, { message: '创建博客备份失败' }) + AlertService.httpErr(typeof e === 'object' && e ? e : {}, { message: '创建博客备份失败' }) return false })) !== false ) @@ -21,7 +21,11 @@ export class CreateBlogExportCmdHandler extends CmdHandler { private async confirm(): Promise { const items: MessageItem[] = [{ title: '确定', isCloseAffordance: false }] - const result = await Alert.info('确定要创建备份吗?', { modal: true, detail: '一天可以创建一次备份' }, ...items) + const result = await AlertService.info( + '确定要创建备份吗?', + { modal: true, detail: '一天可以创建一次备份' }, + ...items + ) return result != null } } diff --git a/src/commands/blog-export/delete.ts b/src/commands/blog-export/delete.ts index e41279d3..66d7a5de 100644 --- a/src/commands/blog-export/delete.ts +++ b/src/commands/blog-export/delete.ts @@ -1,6 +1,6 @@ import { TreeViewCmdHandler } from '@/commands/cmd-handler' import { DownloadedBlogExport } from '@/models/blog-export' -import { Alert } from '@/services/alert.service' +import { AlertService } from '@/services/alert.service' import { BlogExportApi } from '@/services/blog-export.api' import { DownloadedExportStore } from '@/services/downloaded-export.store' import { BlogExportProvider } from '@/tree-view-providers/blog-export-provider' @@ -86,7 +86,7 @@ export class DeleteCmdHandler extends TreeViewCmdHandler true) .catch((e: unknown) => { - void Alert.httpErr(typeof e === 'object' && e != null ? e : {}) + AlertService.httpErr(typeof e === 'object' && e != null ? e : {}) return false }) if (hasDeleted) if (downloaded) await this.removeDownloadedBlogExport(downloaded, { shouldDeleteLocal }) diff --git a/src/commands/blog-export/download.ts b/src/commands/blog-export/download.ts index 6695a233..edb54bee 100644 --- a/src/commands/blog-export/download.ts +++ b/src/commands/blog-export/download.ts @@ -1,5 +1,5 @@ import { TreeViewCmdHandler } from '@/commands/cmd-handler' -import { Alert } from '@/services/alert.service' +import { AlertService } from '@/services/alert.service' import { BlogExportApi } from '@/services/blog-export.api' import { DownloadedExportStore } from '@/services/downloaded-export.store' import { globalCtx } from '@/services/global-ctx' @@ -7,12 +7,12 @@ import { Settings } from '@/services/settings.service' import { BlogExportProvider } from '@/tree-view-providers/blog-export-provider' import { BlogExportRecordTreeItem } from '@/tree-view-providers/models/blog-export' import { extViews } from '@/tree-view-providers/tree-view-registration' -import { execCmd } from '@/utils/cmd' import fs from 'fs' import { Progress } from 'got' import path from 'path' import { promisify } from 'util' import { commands } from 'vscode' +import { execCmd } from '@/utils/cmd' export class DownloadExportCmdHandler extends TreeViewCmdHandler { static readonly commandName = 'vscode-cnb.blog-export.download' @@ -47,7 +47,7 @@ export class DownloadExportCmdHandler extends TreeViewCmdHandler { - if (msg) void Alert.warn(msg) + if (msg) AlertService.warn(msg) if (!isFileExist) fs.rmSync(zipFilePath) blogExportProvider?.refreshItem(treeItem) this.setIsDownloading(false).then(undefined, console.warn) diff --git a/src/commands/blog-export/edit.ts b/src/commands/blog-export/edit.ts index 23c12389..d65f8c19 100644 --- a/src/commands/blog-export/edit.ts +++ b/src/commands/blog-export/edit.ts @@ -1,6 +1,6 @@ import { TreeViewCmdHandler } from '@/commands/cmd-handler' import { openPostFile } from '@/commands/posts-list/open-post-file' -import { Alert } from '@/services/alert.service' +import { AlertService } from '@/services/alert.service' import { Settings } from '@/services/settings.service' import { ExportPostTreeItem } from '@/tree-view-providers/models/blog-export/post' import fs from 'fs' @@ -21,7 +21,7 @@ export class EditExportPostCmdHandler extends TreeViewCmdHandler { const target = this.parseInput() - if (!target) return void Alert.warn('不支持的参数输入') + if (!target) return void AlertService.warn('不支持的参数输入') const { post: { title, isMarkdown, id: postId }, diff --git a/src/commands/blog-export/index.ts b/src/commands/blog-export/index.ts index 52c92ff4..a0f89fe0 100644 --- a/src/commands/blog-export/index.ts +++ b/src/commands/blog-export/index.ts @@ -1,12 +1,12 @@ +import { RefreshExportRecordsCmdHandler } from './refresh' +import { globalCtx } from '@/services/global-ctx' +import { OpenLocalExportCmdHandler } from '@/commands/blog-export/open-local' +import { EditExportPostCmdHandler } from '@/commands/blog-export/edit' import { CreateBlogExportCmdHandler } from '@/commands/blog-export/create' -import { DeleteCmdHandler } from '@/commands/blog-export/delete' import { DownloadExportCmdHandler } from '@/commands/blog-export/download' -import { EditExportPostCmdHandler } from '@/commands/blog-export/edit' -import { OpenLocalExportCmdHandler } from '@/commands/blog-export/open-local' import { ViewPostCmdHandler } from '@/commands/blog-export/view-post' -import { globalCtx } from '@/services/global-ctx' +import { DeleteCmdHandler } from '@/commands/blog-export/delete' import { regCmd } from '@/utils/cmd' -import { RefreshExportRecordsCmdHandler } from './refresh' export function regBlogExportCmds() { const { extName } = globalCtx diff --git a/src/commands/blog-export/open-local.ts b/src/commands/blog-export/open-local.ts index fa02974b..ed46ea9e 100644 --- a/src/commands/blog-export/open-local.ts +++ b/src/commands/blog-export/open-local.ts @@ -1,11 +1,11 @@ import { CmdHandler } from '@/commands/cmd-handler' -import { Alert } from '@/services/alert.service' -import { DownloadedExportStore } from '@/services/downloaded-export.store' -import { BlogExportProvider } from '@/tree-view-providers/blog-export-provider' -import fs from 'fs' +import { window } from 'vscode' import path from 'path' +import fs from 'fs' import { promisify } from 'util' -import { window } from 'vscode' +import { AlertService } from '@/services/alert.service' +import { DownloadedExportStore } from '@/services/downloaded-export.store' +import { BlogExportProvider } from '@/tree-view-providers/blog-export-provider' const defaultOptions = { confirmUnzip: true } @@ -28,7 +28,8 @@ export class OpenLocalExportCmdHandler extends CmdHandler { })) ?? [] if (fileUri == null) return const filePath = fileUri.fsPath - if (filePath.endsWith('.zip') && !filePath.endsWith('.db.zip')) return void Alert.warn('不支持的博客备份文件') + if (filePath.endsWith('.zip') && !filePath.endsWith('.db.zip')) + return void AlertService.warn('不支持的博客备份文件') const fileName = path.basename(filePath.replace(/\.db(\.zip)?$/, '')) const dirname = path.dirname(filePath) @@ -36,7 +37,7 @@ export class OpenLocalExportCmdHandler extends CmdHandler { isConfirmedToUnzip = filePath.endsWith('.db.zip') // if (!confirmUnzip && fileUri.fsPath.endsWith('db.zip')) { // const options: (MessageItem & { confirmed: boolean })[] = [{ title: '确定', confirmed: true }]; - // const selected = await Alert.info( + // const selected = await AlertService.info( // '浏览博客备份需要解决, 确定要解压吗?', // { modal: true }, // ...options @@ -55,7 +56,7 @@ export class OpenLocalExportCmdHandler extends CmdHandler { const dbFileName = path.basename(dbFilePath) const isExist = await promisify(fs.exists)(dbFilePath) - if (!isExist) return void Alert.warn('文件不存在') + if (!isExist) return void AlertService.warn('文件不存在') const treeProvider = BlogExportProvider.optionalInstance const dbFileSize = (await promisify(fs.stat)(dbFilePath)).size diff --git a/src/commands/blog-export/refresh.ts b/src/commands/blog-export/refresh.ts index 4759dded..08e85ab9 100644 --- a/src/commands/blog-export/refresh.ts +++ b/src/commands/blog-export/refresh.ts @@ -1,7 +1,7 @@ import { CmdHandler } from '@/commands/cmd-handler' +import { execCmd } from '@/utils/cmd' import { globalCtx } from '@/services/global-ctx' import { BlogExportProvider } from '@/tree-view-providers/blog-export-provider' -import { execCmd } from '@/utils/cmd' import { commands } from 'vscode' export class RefreshExportRecordsCmdHandler extends CmdHandler { diff --git a/src/commands/cmd-register.ts b/src/commands/cmd-register.ts index 21522e24..5fd9fd7d 100644 --- a/src/commands/cmd-register.ts +++ b/src/commands/cmd-register.ts @@ -1,42 +1,42 @@ -import { regBlogExportCmds } from '@/commands/blog-export' -import { PublishIngCmdHandler } from '@/commands/ing/publish-ing' -import { CopyPostLinkCmdHandler } from '@/commands/posts-list/copy-link' -import { globalCtx } from '@/services/global-ctx' -import { regCmd } from '@/utils/cmd' -import { regIngListCmds } from 'src/commands/ing/ings-list-cmd-register' -import { extractImages } from './extract-images' -import { login, logout } from './login' import { openMyAccountSettings } from './open-my-account-settings' -import { openMyBlog } from './open-my-blog' import { openMyWebBlogConsole } from './open-my-blog-console' import { openMyHomePage } from './open-my-home-page' -import { openPostInBlogAdmin } from './open-post-in-blog-admin' -import { openWorkspace } from './open-workspace' -import { handleDeletePostCategories } from './post-category/delete-selected-categories' -import { newPostCategory } from './post-category/new-post-category' -import { refreshPostCategoriesList } from './post-category/refresh-post-categories-list' -import { handleUpdatePostCategory } from './post-category/update-post-category' -import { createLocalDraft } from './posts-list/create-local-draft' -import { deleteSelectedPosts } from './posts-list/delete-post' -import { deletePostToLocalFileMap } from './posts-list/delete-post-to-local-file-map' -import { modifyPostSettings } from './posts-list/modify-post-settings' -import { openPostInVscode } from './posts-list/open-post-in-vscode' +import { login, logout } from './login' +import { openMyBlog } from './open-my-blog' +import { globalCtx } from '@/services/global-ctx' import { gotoNextPostsList, gotoPreviousPostsList, refreshPostsList, seekPostsList, } from './posts-list/refresh-posts-list' -import { renamePost } from './posts-list/rename-post' -import { clearPostsSearchResults, refreshPostsSearchResults, searchPosts } from './posts-list/search' import { uploadPostFileToCnblogs, uploadPostToCnblogs } from './posts-list/upload-post' -import { pullPostRemoteUpdates } from './pull-post-remote-updates' +import { createLocalDraft } from './posts-list/create-local-draft' +import { deleteSelectedPosts } from './posts-list/delete-post' +import { modifyPostSettings } from './posts-list/modify-post-settings' +import { uploadImage } from './upload-image/upload-image' import { revealLocalPostFileInOs } from './reveal-local-post-file-in-os' -import { revealWorkspaceInOs } from './reveal-workspace-in-os' -import { setWorkspace } from './set-workspace' import { showLocalFileToPostInfo } from './show-local-file-to-post-info' -import { uploadImage } from './upload-image/upload-image' +import { newPostCategory } from './post-category/new-post-category' +import { refreshPostCategoriesList } from './post-category/refresh-post-categories-list' +import { handleUpdatePostCategory } from './post-category/update-post-category' +import { openPostInVscode } from './posts-list/open-post-in-vscode' +import { deletePostToLocalFileMap } from './posts-list/delete-post-to-local-file-map' +import { renamePost } from './posts-list/rename-post' +import { openPostInBlogAdmin } from './open-post-in-blog-admin' +import { openWorkspace } from './open-workspace' +import { setWorkspace } from './set-workspace' +import { revealWorkspaceInOs } from './reveal-workspace-in-os' import { viewPostOnline } from './view-post-online' +import { pullPostRemoteUpdates } from './pull-post-remote-updates' +import { extractImages } from './extract-images' +import { clearPostsSearchResults, refreshPostsSearchResults, searchPosts } from './posts-list/search' +import { handleDeletePostCategories } from './post-category/delete-selected-categories' +import { PublishIngCmdHandler } from '@/commands/ing/publish-ing' +import { regIngListCmds } from 'src/commands/ing/ings-list-cmd-register' +import { CopyPostLinkCmdHandler } from '@/commands/posts-list/copy-link' +import { regBlogExportCmds } from '@/commands/blog-export' +import { regCmd } from '@/utils/cmd' export function setupExtCmd() { const ctx = globalCtx.extCtx diff --git a/src/commands/extract-images.ts b/src/commands/extract-images.ts index 35d41d42..6c1066e8 100644 --- a/src/commands/extract-images.ts +++ b/src/commands/extract-images.ts @@ -1,6 +1,6 @@ -import { Alert } from '@/services/alert.service' -import { ImageInfo, ImageSrc, MkdImgExtractor, newImageSrcFilter } from '@/services/mkd-img-extractor.service' import { MessageItem, MessageOptions, ProgressLocation, Range, Uri, window, workspace, WorkspaceEdit } from 'vscode' +import { ImageInfo, ImageSrc, MkdImgExtractor, newImageSrcFilter } from '@/services/mkd-img-extractor.service' +import { AlertService } from '@/services/alert.service' type ExtractOption = MessageItem & Partial<{ imageSrc: ImageSrc }> @@ -17,7 +17,7 @@ export async function extractImages(arg: unknown, inputImageSrc?: ImageSrc) { const extractor = new MkdImgExtractor(markdown, arg) const images = extractor.findImages() - if (images.length <= 0) void (!inputImageSrc != null ? Alert.warn('没有找到可以提取的图片') : undefined) + if (images.length <= 0) void (!inputImageSrc != null ? AlertService.warn('没有找到可以提取的图片') : undefined) const getExtractOption = () => { const webImgCount = images.filter(newImageSrcFilter(ImageSrc.web)).length @@ -36,7 +36,7 @@ export async function extractImages(arg: unknown, inputImageSrc?: ImageSrc) { return Promise.resolve(displayOptions.find(ent => ent.imageSrc === inputImageSrc)) // if src is not specified: - return Alert.info( + return AlertService.info( '要提取哪些图片? 此操作会替换源文件中的图片链接!', { modal: true, @@ -113,6 +113,6 @@ export async function extractImages(arg: unknown, inputImageSrc?: ImageSrc) { const info = failedImages .map(info => [info.data, extractor.errors.find(([link]) => link === info.data)?.[1] ?? ''].join(',')) .join('\n') - void Alert.err(`${failedImages.length} 张图片提取失败: ${info}`).then(undefined, console.warn) + AlertService.err(`${failedImages.length} 张图片提取失败: ${info}`).then(undefined, console.warn) } } diff --git a/src/commands/ing/ings-list-cmd-register.ts b/src/commands/ing/ings-list-cmd-register.ts index 7a655af3..892e9a79 100644 --- a/src/commands/ing/ings-list-cmd-register.ts +++ b/src/commands/ing/ings-list-cmd-register.ts @@ -1,13 +1,13 @@ -import { OpenIngInBrowser } from '@/commands/ing/open-ing-in-browser' -import { SelectIngType } from '@/commands/ing/select-ing-type' -import { regCmd } from '@/utils/cmd' +import { RefreshIngsList } from 'src/commands/ing/refresh-ings-list' +import { globalCtx } from 'src/services/global-ctx' import { GotoIngsListFirstPage, GotoIngsListNextPage, GotoIngsListPreviousPage, } from 'src/commands/ing/goto-ings-list-page' -import { RefreshIngsList } from 'src/commands/ing/refresh-ings-list' -import { globalCtx } from 'src/services/global-ctx' +import { SelectIngType } from '@/commands/ing/select-ing-type' +import { OpenIngInBrowser } from '@/commands/ing/open-ing-in-browser' +import { regCmd } from '@/utils/cmd' export const regIngListCmds = () => { const appName = globalCtx.extName diff --git a/src/commands/ing/open-ing-in-browser.ts b/src/commands/ing/open-ing-in-browser.ts index e1756b3c..fdc68b7c 100644 --- a/src/commands/ing/open-ing-in-browser.ts +++ b/src/commands/ing/open-ing-in-browser.ts @@ -1,6 +1,6 @@ import { CmdHandler } from '@/commands/cmd-handler' -import { globalCtx } from '@/services/global-ctx' import { execCmd } from '@/utils/cmd' +import { globalCtx } from '@/services/global-ctx' import { Uri } from 'vscode' export class OpenIngInBrowser extends CmdHandler { diff --git a/src/commands/ing/publish-ing.ts b/src/commands/ing/publish-ing.ts index 16967f1c..955ecd49 100644 --- a/src/commands/ing/publish-ing.ts +++ b/src/commands/ing/publish-ing.ts @@ -1,11 +1,11 @@ import { CmdHandler } from '@/commands/cmd-handler' +import { execCmd } from '@/utils/cmd' import { IngPublishModel, IngType } from '@/models/ing' -import { Alert } from '@/services/alert.service' +import { AlertService } from '@/services/alert.service' import { globalCtx } from '@/services/global-ctx' import { IngApi } from '@/services/ing.api' import { IngsListWebviewProvider } from '@/services/ings-list-webview-provider' import { InputStep, MultiStepInput, QuickPickParameters } from '@/services/multi-step-input' -import { execCmd } from '@/utils/cmd' import { MessageOptions, ProgressLocation, QuickPickItem, Uri, window } from 'vscode' export class PublishIngCmdHandler extends CmdHandler { @@ -134,7 +134,7 @@ export class PublishIngCmdHandler extends CmdHandler { ['编辑访问权限', async () => (await this.acquireInputContent(this.inputStep.access)) !== false], ['编辑标签', async () => (await this.acquireInputContent(this.inputStep.tags)) !== false], ] as const - const selected = await Alert.info( + const selected = await AlertService.info( '确定要发布闪存吗?', { modal: true, @@ -146,7 +146,7 @@ export class PublishIngCmdHandler extends CmdHandler { } private warnNoSelection() { - void Alert.warn(`无法${this.operation}, 当前没有选中的内容`) + AlertService.warn(`无法${this.operation}, 当前没有选中的内容`) } private async onPublished(isPublished: boolean): Promise { @@ -175,7 +175,7 @@ export class PublishIngCmdHandler extends CmdHandler { (): Thenable => execCmd('vscode.open', Uri.parse(globalCtx.config.ingSite + '/#mention')), ], ] as const - const option = await Alert.info( + const option = await AlertService.info( '闪存已发布, 快去看看吧', { modal: false }, ...options.map(v => ({ title: v[0], id: v[0] })) diff --git a/src/commands/open-my-account-settings.ts b/src/commands/open-my-account-settings.ts index 7f2c5d00..059194d0 100644 --- a/src/commands/open-my-account-settings.ts +++ b/src/commands/open-my-account-settings.ts @@ -1,5 +1,5 @@ -import { execCmd } from '@/utils/cmd' import vscode from 'vscode' +import { execCmd } from '@/utils/cmd' export const openMyAccountSettings = () => execCmd('vscode.open', vscode.Uri.parse('https://account.cnblogs.com/settings/account')) diff --git a/src/commands/open-my-blog-console.ts b/src/commands/open-my-blog-console.ts index 03d18959..c14e9d88 100644 --- a/src/commands/open-my-blog-console.ts +++ b/src/commands/open-my-blog-console.ts @@ -1,4 +1,4 @@ -import { execCmd } from '@/utils/cmd' import vscode from 'vscode' export const openMyWebBlogConsole = () => execCmd('vscode.open', vscode.Uri.parse('https://i.cnblogs.com')) +import { execCmd } from '@/utils/cmd' diff --git a/src/commands/open-my-blog.ts b/src/commands/open-my-blog.ts index d78b3a00..93dc2c74 100644 --- a/src/commands/open-my-blog.ts +++ b/src/commands/open-my-blog.ts @@ -1,6 +1,6 @@ import { accountManager } from '@/auth/account-manager' -import { execCmd } from '@/utils/cmd' import vscode from 'vscode' +import { execCmd } from '@/utils/cmd' export const openMyBlog = () => { const userBlogUrl = accountManager.currentUser?.website diff --git a/src/commands/open-post-in-blog-admin.ts b/src/commands/open-post-in-blog-admin.ts index 36475a74..32f3dba0 100644 --- a/src/commands/open-post-in-blog-admin.ts +++ b/src/commands/open-post-in-blog-admin.ts @@ -1,8 +1,8 @@ +import { Uri } from 'vscode' +import { execCmd } from '@/utils/cmd' import { Post } from '@/models/post' import { PostFileMapManager } from '@/services/post-file-map' import { PostTreeItem } from '@/tree-view-providers/models/post-tree-item' -import { execCmd } from '@/utils/cmd' -import { Uri } from 'vscode' export const openPostInBlogAdmin = (item: Post | PostTreeItem | Uri) => { if (!item) return diff --git a/src/commands/open-workspace.ts b/src/commands/open-workspace.ts index 2257c2cf..0104111d 100644 --- a/src/commands/open-workspace.ts +++ b/src/commands/open-workspace.ts @@ -1,13 +1,13 @@ -import { Alert } from '@/services/alert.service' +import { MessageOptions } from 'vscode' import { Settings } from '@/services/settings.service' import { execCmd } from '@/utils/cmd' -import { MessageOptions } from 'vscode' +import { AlertService } from '@/services/alert.service' export const openWorkspace = async () => { const uri = Settings.workspaceUri const { fsPath } = uri const options = ['在当前窗口中打开', '在新窗口中打开'] - const input = await Alert.info(`即将打开 ${fsPath}`, { modal: true } as MessageOptions, ...options) + const input = await AlertService.info(`即将打开 ${fsPath}`, { modal: true } as MessageOptions, ...options) if (!input) return const shouldOpenInNewWindow = input === options[1] diff --git a/src/commands/pdf/export-pdf.command.ts b/src/commands/pdf/export-pdf.command.ts index 46b48200..e2180db2 100644 --- a/src/commands/pdf/export-pdf.command.ts +++ b/src/commands/pdf/export-pdf.command.ts @@ -1,19 +1,19 @@ -import { accountManager } from '@/auth/account-manager' -import { postPdfTemplateBuilder } from '@/commands/pdf/post-pdf-template-builder' +import type puppeteer from 'puppeteer-core' +import fs from 'fs' +import path from 'path' +import os from 'os' +import { MessageOptions, Progress, ProgressLocation, Uri, window, workspace } from 'vscode' import { Post } from '@/models/post' -import { PostEditDto } from '@/models/post-edit-dto' -import { Alert } from '@/services/alert.service' import { PostFileMapManager } from '@/services/post-file-map' import { PostService } from '@/services/post.service' -import { Settings } from '@/services/settings.service' -import { PostTreeItem } from '@/tree-view-providers/models/post-tree-item' import { extViews } from '@/tree-view-providers/tree-view-registration' import { chromiumPathProvider } from '@/utils/chromium-path-provider' -import fs from 'fs' -import os from 'os' -import path from 'path' -import type puppeteer from 'puppeteer-core' -import { MessageOptions, Progress, ProgressLocation, Uri, window, workspace } from 'vscode' +import { Settings } from '@/services/settings.service' +import { accountManager } from '@/auth/account-manager' +import { AlertService } from '@/services/alert.service' +import { PostTreeItem } from '@/tree-view-providers/models/post-tree-item' +import { PostEditDto } from '@/models/post-edit-dto' +import { postPdfTemplateBuilder } from '@/commands/pdf/post-pdf-template-builder' const launchBrowser = async ( chromiumPath: string @@ -114,7 +114,7 @@ const retrieveChromiumPath = async (): Promise => { if (!path) { const { Options: options } = chromiumPathProvider - const input = await Alert.warn( + const input = await AlertService.warn( '未找到Chromium可执行文件', { modal: true, @@ -175,7 +175,7 @@ const mapToPostEditDto = async (posts: Post[]) => const reportErrors = (errors: string[] | undefined) => { if (errors && errors.length > 0) { - void Alert.err('导出 PDF 时遇到错误', { + void AlertService.err('导出 PDF 时遇到错误', { modal: true, detail: errors.join('\n'), } as MessageOptions) @@ -192,7 +192,7 @@ const exportPostToPdf = async (input: Post | PostTreeItem | Uri | unknown): Prom currentUser: { blogApp }, } = accountManager - if (!blogApp) return void Alert.warn('无法获取到博客地址, 请检查登录状态') + if (!blogApp) return void AlertService.warn('无法获取到博客地址, 请检查登录状态') reportErrors( await window.withProgress( diff --git a/src/commands/pdf/post-pdf-template-builder.ts b/src/commands/pdf/post-pdf-template-builder.ts index ac7dbec1..62e7647f 100644 --- a/src/commands/pdf/post-pdf-template-builder.ts +++ b/src/commands/pdf/post-pdf-template-builder.ts @@ -1,11 +1,11 @@ -import { accountManager } from '@/auth/account-manager' import { Post } from '@/models/post' -import { PostCategory } from '@/models/post-category' +import { PostFileMapManager } from '@/services/post-file-map' +import fs from 'fs' import { BlogSettingsService } from '@/services/blog-settings.service' +import { accountManager } from '@/auth/account-manager' import { postCategoryService } from '@/services/post-category.service' -import { PostFileMapManager } from '@/services/post-file-map' +import { PostCategory } from '@/models/post-category' import { markdownItFactory } from '@cnblogs/markdown-it-presets' -import fs from 'fs' export namespace postPdfTemplateBuilder { export const HighlightedMessage = 'markdown-highlight-finished' diff --git a/src/commands/post-category/delete-selected-categories.ts b/src/commands/post-category/delete-selected-categories.ts index f0239cf3..9f08622a 100644 --- a/src/commands/post-category/delete-selected-categories.ts +++ b/src/commands/post-category/delete-selected-categories.ts @@ -1,10 +1,10 @@ +import { MessageOptions, ProgressLocation, window } from 'vscode' import { PostCategory } from '@/models/post-category' -import { Alert } from '@/services/alert.service' import { postCategoryService } from '@/services/post-category.service' import { PostCategoriesListTreeItem } from '@/tree-view-providers/models/categories-list-tree-item' -import { MessageOptions, ProgressLocation, window } from 'vscode' import { BaseMultiSelectablePostCategoryTreeViewCmdHandler } from './base-tree-view-cmd-handler' import { refreshPostCategoriesList } from './refresh-post-categories-list' +import { AlertService } from '@/services/alert.service' export class DeletePostCategoriesHandler extends BaseMultiSelectablePostCategoryTreeViewCmdHandler { constructor(input: PostCategoriesListTreeItem) { @@ -45,7 +45,7 @@ export class DeletePostCategoriesHandler extends BaseMultiSelectablePostCategory p.report({ increment: 100 }) if (errs.length > 0) { - await Alert.err('删除博文分类时发生了一些错误', { + await AlertService.err('删除博文分类时发生了一些错误', { detail: errs .map( err => @@ -63,7 +63,7 @@ export class DeletePostCategoriesHandler extends BaseMultiSelectablePostCategory private async confirm() { const options = ['确定'] - const clicked = await Alert.warn( + const clicked = await AlertService.warn( '确定要删除这些博文分类吗', { detail: `${this.selections.map(x => `📂${x.title}`).join(', ')} 将被永久删除! 请谨慎操作!`, diff --git a/src/commands/post-category/input-post-category.ts b/src/commands/post-category/input-post-category.ts index 54a0fe22..2dd10471 100644 --- a/src/commands/post-category/input-post-category.ts +++ b/src/commands/post-category/input-post-category.ts @@ -1,6 +1,6 @@ +import { QuickPickItem } from 'vscode' import { PostCategory, PostCategoryAddDto } from '@/models/post-category' import { InputStep, MultiStepInput } from '@/services/multi-step-input' -import { QuickPickItem } from 'vscode' class InputOption { title = '编辑分类' diff --git a/src/commands/post-category/new-post-category.ts b/src/commands/post-category/new-post-category.ts index 6171d05d..2a9c923b 100644 --- a/src/commands/post-category/new-post-category.ts +++ b/src/commands/post-category/new-post-category.ts @@ -1,9 +1,9 @@ -import { Alert } from '@/services/alert.service' +import { MessageOptions, ProgressLocation, window } from 'vscode' import { postCategoryService } from '@/services/post-category.service' import { extViews } from '@/tree-view-providers/tree-view-registration' -import { MessageOptions, ProgressLocation, window } from 'vscode' import { inputPostCategory } from './input-post-category' import { refreshPostCategoriesList } from './refresh-post-categories-list' +import { AlertService } from '@/services/alert.service' export const newPostCategory = async () => { const input = await inputPostCategory({ @@ -29,7 +29,7 @@ export const newPostCategory = async () => { const newCategory = (await postCategoryService.listCategories()).find(x => x.title === input.title) if (newCategory) await extViews.postCategoriesList.reveal(newCategory) } catch (err) { - void Alert.err('新建博文分类时遇到了错误', { + void AlertService.err('新建博文分类时遇到了错误', { modal: true, detail: `服务器反回了错误\n${err instanceof Error ? err.message : JSON.stringify(err)}`, } as MessageOptions) diff --git a/src/commands/post-category/update-post-category.ts b/src/commands/post-category/update-post-category.ts index 297bd522..9d655170 100644 --- a/src/commands/post-category/update-post-category.ts +++ b/src/commands/post-category/update-post-category.ts @@ -1,11 +1,11 @@ +import fs from 'fs' +import { MessageOptions, ProgressLocation, window, Uri, workspace } from 'vscode' import { PostCategory } from '@/models/post-category' import { postCategoryService } from '@/services/post-category.service' -import { Settings } from '@/services/settings.service' -import fs from 'fs' -import { MessageOptions, ProgressLocation, Uri, window, workspace } from 'vscode' -import { BasePostCategoryTreeViewCmdHandler } from './base-tree-view-cmd-handler' import { inputPostCategory } from './input-post-category' import { refreshPostCategoriesList } from './refresh-post-categories-list' +import { Settings } from '@/services/settings.service' +import { BasePostCategoryTreeViewCmdHandler } from './base-tree-view-cmd-handler' class UpdatePostCategoryTreeViewCmdHandler extends BasePostCategoryTreeViewCmdHandler { async handle(): Promise { diff --git a/src/commands/posts-list/copy-link.ts b/src/commands/posts-list/copy-link.ts index e02333e2..5502d346 100644 --- a/src/commands/posts-list/copy-link.ts +++ b/src/commands/posts-list/copy-link.ts @@ -1,6 +1,6 @@ import { TreeViewCmdHandler } from '@/commands/cmd-handler' import { Post } from '@/models/post' -import { Alert } from '@/services/alert.service' +import { AlertService } from '@/services/alert.service' import { PostFileMapManager } from '@/services/post-file-map' import { PostService } from '@/services/post.service' import { PostTreeItem } from '@/tree-view-providers/models/post-tree-item' @@ -53,7 +53,7 @@ export class CopyPostLinkCmdHandler extends TreeViewCmdHandler void Alert.fileNotLinkedToPost(input)) + ? Promise.resolve(undefined).then(() => void AlertService.fileNotLinkedToPost(input)) : PostService.fetchPostEditDto(postId).then(v => v?.post) } diff --git a/src/commands/posts-list/create-local-draft.ts b/src/commands/posts-list/create-local-draft.ts index 90714c01..5c959555 100644 --- a/src/commands/posts-list/create-local-draft.ts +++ b/src/commands/posts-list/create-local-draft.ts @@ -1,8 +1,8 @@ -import { Settings } from '@/services/settings.service' -import { revealActiveFileInExplorer } from '@/utils/reveal-active-file' import { homedir } from 'os' import path from 'path' import { Uri, window, workspace } from 'vscode' +import { Settings } from '@/services/settings.service' +import { revealActiveFileInExplorer } from '@/utils/reveal-active-file' import { openPostFile } from './open-post-file' export const createLocalDraft = async () => { diff --git a/src/commands/posts-list/delete-post-to-local-file-map.ts b/src/commands/posts-list/delete-post-to-local-file-map.ts index e02e536a..0f2b861e 100644 --- a/src/commands/posts-list/delete-post-to-local-file-map.ts +++ b/src/commands/posts-list/delete-post-to-local-file-map.ts @@ -1,14 +1,14 @@ +import { MessageOptions, window } from 'vscode' import { Post } from '@/models/post' -import { Alert } from '@/services/alert.service' import { PostFileMap, PostFileMapManager } from '@/services/post-file-map' import { revealPostsListItem } from '@/services/posts-list-view' import { PostTreeItem } from '@/tree-view-providers/models/post-tree-item' import { extViews } from '@/tree-view-providers/tree-view-registration' -import { MessageOptions, window } from 'vscode' +import { AlertService } from '@/services/alert.service' const confirm = async (posts: Post[]): Promise => { const options = ['确定'] - const input = await Alert.info( + const input = await AlertService.info( '确定要取消这些博文与本地文件的关联吗?', { detail: posts.map(x => x.title).join(', '), diff --git a/src/commands/posts-list/delete-post.ts b/src/commands/posts-list/delete-post.ts index 4a609bce..cd204ab7 100644 --- a/src/commands/posts-list/delete-post.ts +++ b/src/commands/posts-list/delete-post.ts @@ -1,13 +1,13 @@ +import { MessageOptions, ProgressLocation, Uri, window, workspace } from 'vscode' import { Post } from '@/models/post' -import { Alert } from '@/services/alert.service' -import { PostFileMap, PostFileMapManager } from '@/services/post-file-map' +import { AlertService } from '@/services/alert.service' import { PostService } from '@/services/post.service' -import { PostTreeItem } from '@/tree-view-providers/models/post-tree-item' -import { postCategoriesDataProvider } from '@/tree-view-providers/post-categories-tree-data-provider' +import { PostFileMap, PostFileMapManager } from '@/services/post-file-map' import { postsDataProvider } from '@/tree-view-providers/posts-data-provider' import { extViews } from '@/tree-view-providers/tree-view-registration' -import { MessageOptions, ProgressLocation, Uri, window, workspace } from 'vscode' import { refreshPostsList } from './refresh-posts-list' +import { PostTreeItem } from '@/tree-view-providers/models/post-tree-item' +import { postCategoriesDataProvider } from '@/tree-view-providers/post-categories-tree-data-provider' let isDeleting = false @@ -18,7 +18,7 @@ const confirmDelete = async ( if (!selectedPosts || selectedPosts.length <= 0) return result const items = ['确定(保留本地文件)', '确定(同时删除本地文件)'] - const clicked = await Alert.warn( + const clicked = await AlertService.warn( '确定要删除吗?', { detail: `确认后将会删除 ${selectedPosts.map(x => x.title).join(', ')} 这${selectedPosts.length}篇博文吗?`, @@ -55,7 +55,7 @@ export const deleteSelectedPosts = async (arg: unknown) => { if (selectedPosts.length <= 0) return if (isDeleting) { - void Alert.warn('休息会儿再点吧~') + AlertService.warn('休息会儿再点吧~') return } @@ -91,7 +91,7 @@ export const deleteSelectedPosts = async (arg: unknown) => { postIds: selectedPosts.map(({ id }) => id), }) } catch (err) { - void Alert.err('删除博文失败', { + void AlertService.err('删除博文失败', { detail: `服务器返回了错误, ${err instanceof Error ? err.message : JSON.stringify(err)}`, } as MessageOptions) } finally { diff --git a/src/commands/posts-list/modify-post-settings.ts b/src/commands/posts-list/modify-post-settings.ts index c83f35ce..eaa0b653 100644 --- a/src/commands/posts-list/modify-post-settings.ts +++ b/src/commands/posts-list/modify-post-settings.ts @@ -1,29 +1,28 @@ +import { Uri } from 'vscode' import { Post } from '@/models/post' -import { Alert } from '@/services/alert.service' -import { LocalDraft } from '@/services/local-draft.service' -import { PostCfgPanel } from '@/services/post-cfg-panel.service' -import { PostFileMapManager } from '@/services/post-file-map' +import { AlertService } from '@/services/alert.service' import { PostService } from '@/services/post.service' +import { PostFileMapManager } from '@/services/post-file-map' import { revealPostsListItem } from '@/services/posts-list-view' +import { PostCfgPanel } from '@/services/post-cfg-panel.service' +import fs from 'fs' +import { LocalDraft } from '@/services/local-draft.service' +import { saveFilePendingChanges } from '@/utils/save-file-pending-changes' +import { postsDataProvider } from '@/tree-view-providers/posts-data-provider' import { PostTreeItem } from '@/tree-view-providers/models/post-tree-item' import { postCategoriesDataProvider } from '@/tree-view-providers/post-categories-tree-data-provider' -import { postsDataProvider } from '@/tree-view-providers/posts-data-provider' -import { saveFilePendingChanges } from '@/utils/save-file-pending-changes' -import fs from 'fs' -import { Uri } from 'vscode' export const modifyPostSettings = async (input: Post | PostTreeItem | Uri) => { let post: Post | undefined - let postId: number + let postId = -1 input = input instanceof PostTreeItem ? input.post : input if (input instanceof Post) { post = input postId = input.id - } else { - // input is Uri + } else if (input instanceof Uri) { postId = PostFileMapManager.getPostId(input.fsPath) ?? -1 - if (postId < 0) return void Alert.fileNotLinkedToPost(input) + if (postId < 0) return AlertService.fileNotLinkedToPost(input) } if (!(postId >= 0)) return @@ -41,14 +40,15 @@ export const modifyPostSettings = async (input: Post | PostTreeItem | Uri) => { post: postEditDto, localFileUri: localFilePath ? Uri.file(localFilePath) : undefined, successCallback: ({ id }) => { - void Alert.info('博文已更新') + AlertService.info('博文已更新') postsDataProvider.fireTreeDataChangedEvent(id) postCategoriesDataProvider.onPostUpdated({ refreshPosts: false, postIds: [id] }) }, beforeUpdate: async post => { if (localFilePath && fs.existsSync(localFilePath)) { await saveFilePendingChanges(localFilePath) - post.postBody = await new LocalDraft(localFilePath).readAllText() + const content = await new LocalDraft(localFilePath).readAllText() + post.postBody = content } return true }, diff --git a/src/commands/posts-list/open-post-file.ts b/src/commands/posts-list/open-post-file.ts index 40af1378..a11cac37 100644 --- a/src/commands/posts-list/open-post-file.ts +++ b/src/commands/posts-list/open-post-file.ts @@ -1,8 +1,8 @@ +import { TextDocumentShowOptions, Uri } from 'vscode' +import { execCmd } from '@/utils/cmd' import { Post } from '@/models/post' import { LocalDraft } from '@/services/local-draft.service' import { PostFileMapManager } from '@/services/post-file-map' -import { execCmd } from '@/utils/cmd' -import { TextDocumentShowOptions, Uri } from 'vscode' export const openPostFile = async (post: LocalDraft | Post | string, options?: TextDocumentShowOptions) => { let filePath = '' diff --git a/src/commands/posts-list/open-post-in-vscode.ts b/src/commands/posts-list/open-post-in-vscode.ts index 97ec93f5..efa8c1b9 100644 --- a/src/commands/posts-list/open-post-in-vscode.ts +++ b/src/commands/posts-list/open-post-in-vscode.ts @@ -1,15 +1,15 @@ -import { Post } from '@/models/post' -import { Alert } from '@/services/alert.service' -import { postCategoryService } from '@/services/post-category.service' -import { PostFileMapManager } from '@/services/post-file-map' -import { PostTitleSanitizer } from '@/services/post-title-sanitizer.service' -import { PostService } from '@/services/post.service' -import { Settings } from '@/services/settings.service' import fs from 'fs' import path from 'path' -import sanitizeFileName from 'sanitize-filename' import { FileSystemError, MessageOptions, Uri, window, workspace } from 'vscode' +import { Post } from '@/models/post' +import { AlertService } from '@/services/alert.service' +import { PostService } from '@/services/post.service' +import { PostFileMapManager } from '@/services/post-file-map' +import { Settings } from '@/services/settings.service' import { openPostFile } from './open-post-file' +import { PostTitleSanitizer } from '@/services/post-title-sanitizer.service' +import { postCategoryService } from '@/services/post-category.service' +import sanitizeFileName from 'sanitize-filename' const buildLocalPostFileUri = async (post: Post, includePostId = false): Promise => { const workspaceUri = Settings.workspaceUri @@ -68,7 +68,7 @@ export const openPostInVscode = async (postId: number, forceUpdateLocalPostFile '保留本地文件(这会新建另一个文件名中包含博文id的文件)', '覆盖本地文件(会导致本地文件中内容丢失)', ] - const selectedOption = await Alert.info( + const selectedOption = await AlertService.info( `无法新建博文与本地文件的关联, 文件名冲突`, { detail: `本地已存在名为"${path.basename(fileUri.fsPath)}"的文件`, modal: true } as MessageOptions, ...conflictOptions @@ -97,7 +97,7 @@ const createDirectoryIfNotExist = async (uri: Uri) => { } catch (err) { if (err instanceof FileSystemError) await workspace.fs.createDirectory(uri) - void Alert.err('Create workspace directory failed') + AlertService.err('Create workspace directory failed') console.error(err) } } diff --git a/src/commands/posts-list/refresh-posts-list.ts b/src/commands/posts-list/refresh-posts-list.ts index afb1adf1..5216cff2 100644 --- a/src/commands/posts-list/refresh-posts-list.ts +++ b/src/commands/posts-list/refresh-posts-list.ts @@ -1,11 +1,11 @@ -import { PostsListState } from '@/models/posts-list-state' -import { Alert } from '@/services/alert.service' import { globalCtx } from '@/services/global-ctx' import { PostService } from '@/services/post.service' +import vscode, { window } from 'vscode' import { postsDataProvider } from '@/tree-view-providers/posts-data-provider' +import { AlertService } from '@/services/alert.service' +import { PostsListState } from '@/models/posts-list-state' import { extViews } from '@/tree-view-providers/tree-view-registration' import { execCmd } from '@/utils/cmd' -import { window } from 'vscode' let refreshTask: Promise | null = null @@ -33,7 +33,7 @@ export const refreshPostsList = async ({ queue = false } = {}): Promise ) .then(pagedPosts => { if (pagedPosts == null) { - return Promise.resolve(false).finally(() => void Alert.err('刷新博文列表失败')) + return Promise.resolve(false).finally(() => AlertService.err('刷新博文列表失败')) } else { return PostService.updatePostsListState(pagedPosts) .then(() => updatePostsListViewTitle()) @@ -92,7 +92,7 @@ const setPostListContext = async (pageCount: number, hasPrevious: boolean, hasNe } const alertRefreshing = () => { - void Alert.info('正在刷新, 请勿重复操作') + AlertService.info('正在刷新, 请勿重复操作') } const gotoPage = async (pageIndex: (currentIndex: number) => number) => { diff --git a/src/commands/posts-list/rename-post.ts b/src/commands/posts-list/rename-post.ts index 886a351f..0c752ad3 100644 --- a/src/commands/posts-list/rename-post.ts +++ b/src/commands/posts-list/rename-post.ts @@ -1,13 +1,13 @@ +import { escapeRegExp } from 'lodash-es' +import path from 'path' +import { MessageOptions, ProgressLocation, Uri, window, workspace } from 'vscode' import { Post } from '@/models/post' -import { Alert } from '@/services/alert.service' -import { PostFileMapManager } from '@/services/post-file-map' import { PostService } from '@/services/post.service' +import { PostFileMapManager } from '@/services/post-file-map' +import { postsDataProvider } from '@/tree-view-providers/posts-data-provider' import { revealPostsListItem } from '@/services/posts-list-view' import { PostTreeItem } from '@/tree-view-providers/models/post-tree-item' -import { postsDataProvider } from '@/tree-view-providers/posts-data-provider' -import { escapeRegExp } from 'lodash-es' -import path from 'path' -import { MessageOptions, ProgressLocation, Uri, window, workspace } from 'vscode' +import { AlertService } from '@/services/alert.service' const renameLinkedFile = async (post: Post): Promise => { const filePath = PostFileMapManager.getFilePath(post.id) @@ -17,7 +17,7 @@ const renameLinkedFile = async (post: Post): Promise => { const fileUri = Uri.file(filePath) const options = ['是'] - const input = await Alert.info( + const input = await AlertService.info( '重命名博文成功, 发现与博文关联的本地文件, 是否要重名本地文件', { modal: true, @@ -70,7 +70,7 @@ export const renamePost = async (arg: Post | PostTreeItem) => { postsDataProvider.fireTreeDataChangedEvent(post) hasUpdated = true } catch (err) { - void Alert.err('更新博文失败', { + void AlertService.err('更新博文失败', { modal: true, detail: err instanceof Error ? err.message : '服务器返回异常', } as MessageOptions) diff --git a/src/commands/posts-list/search.ts b/src/commands/posts-list/search.ts index 5101c376..4492f99f 100644 --- a/src/commands/posts-list/search.ts +++ b/src/commands/posts-list/search.ts @@ -1,5 +1,5 @@ -import { postsDataProvider } from '@/tree-view-providers/posts-data-provider' import { window } from 'vscode' +import { postsDataProvider } from '@/tree-view-providers/posts-data-provider' export const searchPosts = async () => { const searchKey = await window.showInputBox({ diff --git a/src/commands/posts-list/upload-post.ts b/src/commands/posts-list/upload-post.ts index bfbe7c11..751af008 100644 --- a/src/commands/posts-list/upload-post.ts +++ b/src/commands/posts-list/upload-post.ts @@ -1,21 +1,21 @@ +import vscode, { Uri, workspace, window, ProgressLocation, MessageOptions } from 'vscode' import { Post } from '@/models/post' -import { PostEditDto } from '@/models/post-edit-dto' -import { Alert } from '@/services/alert.service' import { LocalDraft } from '@/services/local-draft.service' -import { PostCfgPanel } from '@/services/post-cfg-panel.service' -import { PostFileMapManager } from '@/services/post-file-map' +import { AlertService } from '@/services/alert.service' import { PostService } from '@/services/post.service' -import { searchPostsByTitle } from '@/services/search-post-by-title' -import { Settings } from '@/services/settings.service' -import { PostTreeItem } from '@/tree-view-providers/models/post-tree-item' +import { PostFileMapManager } from '@/services/post-file-map' import { postsDataProvider } from '@/tree-view-providers/posts-data-provider' -import { saveFilePendingChanges } from '@/utils/save-file-pending-changes' -import * as path from 'path' -import { MessageOptions, ProgressLocation, Uri, window, workspace } from 'vscode' -import { extractImages } from '../extract-images' -import { openPostFile } from './open-post-file' import { openPostInVscode } from './open-post-in-vscode' +import { openPostFile } from './open-post-file' +import { searchPostsByTitle } from '@/services/search-post-by-title' +import * as path from 'path' import { refreshPostsList } from './refresh-posts-list' +import { PostEditDto } from '@/models/post-edit-dto' +import { PostCfgPanel } from '@/services/post-cfg-panel.service' +import { saveFilePendingChanges } from '@/utils/save-file-pending-changes' +import { extractImages } from '../extract-images' +import { Settings } from '@/services/settings.service' +import { PostTreeItem } from '@/tree-view-providers/models/post-tree-item' const parseFileUri = async (fileUri: Uri | undefined): Promise => { if (fileUri && fileUri.scheme !== 'file') { @@ -44,7 +44,7 @@ export const uploadPostFileToCnblogs = async (fileUri: Uri | undefined) => { await uploadPostToCnblogs(await PostService.fetchPostEditDto(postId)) } else { const options = [`新建博文`, `关联已有博文`] - const selected = await Alert.info( + const selected = await AlertService.info( '本地文件尚未关联到博客园博文', { modal: true, @@ -84,7 +84,7 @@ export const saveLocalDraftToCnblogs = async (localDraft: LocalDraft) => { // check format if (!['.md'].some(x => localDraft.fileExt === x)) { - void Alert.warn('不受支持的文件格式! 只支持markdown格式') + AlertService.warn('不受支持的文件格式! 只支持markdown格式') return } const editDto = await PostService.fetchPostEditTemplate() @@ -106,13 +106,13 @@ export const saveLocalDraftToCnblogs = async (localDraft: LocalDraft) => { await PostFileMapManager.updateOrCreate(savedPost.id, localDraft.filePath) await openPostFile(localDraft) postsDataProvider.fireTreeDataChangedEvent(undefined) - void Alert.info('博文已创建') + AlertService.info('博文已创建') }, beforeUpdate: async (postToSave, panel) => { await saveFilePendingChanges(localDraft.filePath) // 本地文件已经被删除了 if (!localDraft.exist && panel) { - void Alert.warn('本地文件已删除, 无法新建博文') + AlertService.warn('本地文件已删除, 无法新建博文') return false } if (Settings.automaticallyExtractImagesType) @@ -136,7 +136,7 @@ export const uploadPostToCnblogs = async (input: Post | PostTreeItem | PostEditD const { id: postId } = post const localFilePath = PostFileMapManager.getFilePath(postId) - if (!localFilePath) return Alert.warn('本地无该博文的编辑记录') + if (!localFilePath) return AlertService.warn('本地无该博文的编辑记录') if (Settings.automaticallyExtractImagesType) await extractImages(Uri.file(localFilePath), Settings.automaticallyExtractImagesType).catch(console.warn) @@ -148,7 +148,7 @@ export const uploadPostToCnblogs = async (input: Post | PostTreeItem | PostEditD if (!validatePost(post)) return false if (Settings.showConfirmMsgWhenUploadPost) { - const answer = await Alert.warn( + const answer = await AlertService.warn( '确认上传吗?', { modal: true, @@ -177,11 +177,11 @@ export const uploadPostToCnblogs = async (input: Post | PostTreeItem | PostEditD hasSaved = true progress.report({ increment: 100 }) - void Alert.info('上传成功') + AlertService.info('上传成功') await refreshPostsList() } catch (err) { progress.report({ increment: 100 }) - void Alert.err(`上传失败\n${err instanceof Error ? err.message : JSON.stringify(err)}`) + AlertService.err(`上传失败\n${err instanceof Error ? err.message : JSON.stringify(err)}`) console.error(err) } return hasSaved @@ -191,7 +191,7 @@ export const uploadPostToCnblogs = async (input: Post | PostTreeItem | PostEditD const validatePost = (post: Post): boolean => { if (!post.postBody) { - void Alert.warn('文件内容为空!') + AlertService.warn('文件内容为空!') return false } diff --git a/src/commands/pull-post-remote-updates.ts b/src/commands/pull-post-remote-updates.ts index fb300aee..0f1b5543 100644 --- a/src/commands/pull-post-remote-updates.ts +++ b/src/commands/pull-post-remote-updates.ts @@ -1,14 +1,14 @@ +import { MessageOptions, Uri, window, workspace } from 'vscode' import { Post } from '@/models/post' -import { Alert } from '@/services/alert.service' import { PostFileMapManager } from '@/services/post-file-map' +import { openPostInVscode } from './posts-list/open-post-in-vscode' +import fs from 'fs' import { PostService } from '@/services/post.service' +import { AlertService } from '@/services/alert.service' +import path from 'path' import { revealPostsListItem } from '@/services/posts-list-view' -import { Settings } from '@/services/settings.service' import { PostTreeItem } from '@/tree-view-providers/models/post-tree-item' -import fs from 'fs' -import path from 'path' -import { MessageOptions, Uri, window, workspace } from 'vscode' -import { openPostInVscode } from './posts-list/open-post-in-vscode' +import { Settings } from '@/services/settings.service' const pullPostRemoteUpdates = async (input: Post | PostTreeItem | Uri | undefined | null): Promise => { const ctxs: CmdCtx[] = [] @@ -18,7 +18,7 @@ const pullPostRemoteUpdates = async (input: Post | PostTreeItem | Uri | undefine else if ((uri = parseUriInput(input))) await handleUriInput(uri, ctxs) if (Settings.showConfirmMsgWhenPullPost) { - const answer = await Alert.warn( + const answer = await AlertService.warn( '确认要拉取远程博文吗?', { modal: true, @@ -33,7 +33,7 @@ const pullPostRemoteUpdates = async (input: Post | PostTreeItem | Uri | undefine await update(ctxs) - void Alert.info(`本地文件${resolveFileNames(ctxs)}已更新`) + AlertService.info(`本地文件${resolveFileNames(ctxs)}已更新`) } export { pullPostRemoteUpdates } @@ -70,7 +70,7 @@ const parseUriInput = (input: InputType): Uri | undefined => { const handleUriInput = (fileUri: Uri, contexts: CmdCtx[]): Promise => { const postId = PostFileMapManager.getPostId(fileUri.fsPath) - if (!postId) return Promise.resolve().then(() => void Alert.fileNotLinkedToPost(fileUri)) + if (!postId) return Promise.resolve().then(() => AlertService.fileNotLinkedToPost(fileUri)) contexts.push({ postId, fileUri }) return Promise.resolve() diff --git a/src/commands/reveal-local-post-file-in-os.ts b/src/commands/reveal-local-post-file-in-os.ts index 0dbecbf8..e031ae48 100644 --- a/src/commands/reveal-local-post-file-in-os.ts +++ b/src/commands/reveal-local-post-file-in-os.ts @@ -1,7 +1,7 @@ +import { Uri } from 'vscode' +import { execCmd } from '@/utils/cmd' import { Post } from '@/models/post' import { PostFileMapManager } from '@/services/post-file-map' -import { execCmd } from '@/utils/cmd' -import { Uri } from 'vscode' export const revealLocalPostFileInOs = (post: Post) => { if (!post) return diff --git a/src/commands/reveal-workspace-in-os.ts b/src/commands/reveal-workspace-in-os.ts index 73701847..a9e696a6 100644 --- a/src/commands/reveal-workspace-in-os.ts +++ b/src/commands/reveal-workspace-in-os.ts @@ -1,5 +1,5 @@ -import { Settings } from '@/services/settings.service' -import { execCmd } from '@/utils/cmd' import { commands } from 'vscode' +import { execCmd } from '@/utils/cmd' +import { Settings } from '@/services/settings.service' export const revealWorkspaceInOs = () => execCmd('revealFileInOS', Settings.workspaceUri) diff --git a/src/commands/set-workspace.ts b/src/commands/set-workspace.ts index 88549c7e..56898e36 100644 --- a/src/commands/set-workspace.ts +++ b/src/commands/set-workspace.ts @@ -1,6 +1,6 @@ -import { Alert } from '@/services/alert.service' -import { Settings } from '@/services/settings.service' import { window } from 'vscode' +import { AlertService } from '@/services/alert.service' +import { Settings } from '@/services/settings.service' export const setWorkspace = async () => { const input = ((await window.showOpenDialog({ @@ -14,5 +14,5 @@ export const setWorkspace = async () => { if (!input) return await Settings.setWorkspaceUri(input) - void Alert.info(`工作空间成功修改为: "${Settings.workspaceUri.fsPath}"`) + AlertService.info(`工作空间成功修改为: "${Settings.workspaceUri.fsPath}"`) } diff --git a/src/commands/show-local-file-to-post-info.ts b/src/commands/show-local-file-to-post-info.ts index 8a8e5f96..fe83db27 100644 --- a/src/commands/show-local-file-to-post-info.ts +++ b/src/commands/show-local-file-to-post-info.ts @@ -1,12 +1,12 @@ -import { Alert } from '@/services/alert.service' +import path from 'path' +import { MessageOptions, Uri, window } from 'vscode' +import { AlertService } from '@/services/alert.service' +import { PostService } from '@/services/post.service' import { postCategoryService } from '@/services/post-category.service' import { PostFileMapManager } from '@/services/post-file-map' -import { PostService } from '@/services/post.service' import { searchPostsByTitle } from '@/services/search-post-by-title' -import format from 'date-fns/format' -import path from 'path' -import { MessageOptions, Uri, window } from 'vscode' import { viewPostOnline } from './view-post-online' +import format from 'date-fns/format' /** * 本地文件所关联的博文信息 @@ -22,7 +22,7 @@ export const showLocalFileToPostInfo = async (input: Uri | number): Promise 0 ? `博文标签: ${post.tags?.join(', ')}\n` : '' const options = ['在线查看博文', '取消关联'] const postUrl = post.url.startsWith('//') ? `https:${post.url}` : post.url - const selected = await Alert.info( + const selected = await AlertService.info( `关联博文 - ${post.title}(Id: ${post.id})`, { modal: true, @@ -75,6 +75,6 @@ export const showLocalFileToPostInfo = async (input: Uri | number): Promise { const clipboardImage = await getClipboardImage() if (clipboardImage.imgPath === noImagePath) { - void Alert.warn('剪贴板中没有找到图片') + AlertService.warn('剪贴板中没有找到图片') return } diff --git a/src/commands/upload-image/upload-image-utils.ts b/src/commands/upload-image/upload-image-utils.ts index ebbf106f..644bec04 100644 --- a/src/commands/upload-image/upload-image-utils.ts +++ b/src/commands/upload-image/upload-image-utils.ts @@ -1,6 +1,6 @@ -import { Alert } from '@/services/alert.service' -import { formatImageLink } from '@/utils/format-image-link' import { env, MessageOptions, SnippetString, window } from 'vscode' +import { formatImageLink } from '@/utils/format-image-link' +import { AlertService } from '@/services/alert.service' /** * 显示上传成功对话框, 支持复制不同格式的图片链接 @@ -10,7 +10,7 @@ import { env, MessageOptions, SnippetString, window } from 'vscode' */ export const showUploadSuccessModel = async (imgLink: string): Promise => { const copyOptions = ['复制链接', '复制链接(markdown)', '复制链接(html)'] - const option = await Alert.info( + const option = await AlertService.info( '上传图片成功', { modal: true, diff --git a/src/commands/upload-image/upload-image.ts b/src/commands/upload-image/upload-image.ts index 4024ea40..f434690c 100644 --- a/src/commands/upload-image/upload-image.ts +++ b/src/commands/upload-image/upload-image.ts @@ -1,4 +1,5 @@ -import { Alert } from '@/services/alert.service' +import { AlertService } from '@/services/alert.service' +import { window } from 'vscode' import { uploadImageFromClipboard } from './upload-clipboard-image' import { insertImageLinkToActiveEditor, showUploadSuccessModel } from './upload-image-utils' import { uploadLocalDiskImage } from './upload-local-disk-image' @@ -6,7 +7,7 @@ import { uploadLocalDiskImage } from './upload-local-disk-image' export const uploadImage = async (autoInsertToActiveEditor = true, from?: 'local' | 'clipboard') => { const options = ['本地图片文件', '剪贴板图片'] const selected = !from - ? await Alert.info( + ? await AlertService.info( '上传图片到博客园', { modal: true, @@ -18,7 +19,7 @@ export const uploadImage = async (autoInsertToActiveEditor = true, from?: 'local let imageUrl: string | undefined const caughtFailedUpload = (e: unknown) => - void Alert.httpErr(typeof e === 'object' && e != null ? e : {}, { message: '上传图片失败' }) + void AlertService.httpErr(typeof e === 'object' && e != null ? e : {}, { message: '上传图片失败' }) switch (selected) { case 'local': case options[0]: diff --git a/src/commands/upload-image/upload-local-disk-image.ts b/src/commands/upload-image/upload-local-disk-image.ts index 00880809..1556c621 100644 --- a/src/commands/upload-image/upload-local-disk-image.ts +++ b/src/commands/upload-image/upload-local-disk-image.ts @@ -1,6 +1,6 @@ +import { ProgressLocation, window } from 'vscode' import { ImageService } from '@/services/image.service' import fs from 'fs' -import { ProgressLocation, window } from 'vscode' export const uploadLocalDiskImage = async () => { const imageFileUri = ((await window.showOpenDialog({ diff --git a/src/commands/view-post-online.ts b/src/commands/view-post-online.ts index 7fb20bc9..a42b667a 100644 --- a/src/commands/view-post-online.ts +++ b/src/commands/view-post-online.ts @@ -1,9 +1,9 @@ +import { Uri, window } from 'vscode' +import { execCmd } from '@/utils/cmd' import { Post } from '@/models/post' -import { PostFileMapManager } from '@/services/post-file-map' import { PostService } from '@/services/post.service' +import { PostFileMapManager } from '@/services/post-file-map' import { PostTreeItem } from '@/tree-view-providers/models/post-tree-item' -import { execCmd } from '@/utils/cmd' -import { Uri, window } from 'vscode' export const viewPostOnline = async (input?: Post | PostTreeItem | Uri) => { let post: Post | undefined = input instanceof Post ? input : input instanceof PostTreeItem ? input.post : undefined diff --git a/src/extension.ts b/src/extension.ts index eaa1313b..7d3b75fb 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -1,18 +1,18 @@ +import { setupExtTreeView } from '@/tree-view-providers/tree-view-registration' import { setupExtCmd } from '@/commands/cmd-register' import { globalCtx } from '@/services/global-ctx' -import { setupExtTreeView } from '@/tree-view-providers/tree-view-registration' // The module 'vscode' contains the VS Code extensibility API // Import the module and reference it with the alias vscode in your code below +import vscode from 'vscode' import { accountManager } from '@/auth/account-manager' -import { extendMarkdownIt } from '@/markdown/extend-markdownIt' import { observeConfigurationChange, observeWorkspaceFolderAndFileChange as observeWorkspaceFolderChange, } from '@/services/check-workspace' -import { Settings } from '@/services/settings.service' import { extUriHandler } from '@/utils/uri-handler' import { IngsListWebviewProvider } from 'src/services/ings-list-webview-provider' -import vscode from 'vscode' +import { extendMarkdownIt } from '@/markdown/extend-markdownIt' +import { Settings } from '@/services/settings.service' // this method is called when your extension is activated // your extension is activated the very first time the commands is executed diff --git a/src/markdown/extend-markdownIt.ts b/src/markdown/extend-markdownIt.ts index 7184616b..c777c53d 100644 --- a/src/markdown/extend-markdownIt.ts +++ b/src/markdown/extend-markdownIt.ts @@ -1,6 +1,6 @@ import { Settings } from '@/services/settings.service' -import type { MarkdownIt } from '@cnblogs/markdown-it-presets' import { HighlightCodeLinesPlugin, MultilineBlockquotePlugin } from '@cnblogs/markdown-it-presets' +import type { MarkdownIt } from '@cnblogs/markdown-it-presets' export const extendMarkdownIt = (md: MarkdownIt) => md diff --git a/src/models/ing-view.ts b/src/models/ing-view.ts index fa3af854..1b878e6c 100644 --- a/src/models/ing-view.ts +++ b/src/models/ing-view.ts @@ -1,5 +1,5 @@ -import { PartialTheme, Theme } from '@fluentui/react' import { Ing, IngComment } from './ing' +import { PartialTheme, Theme } from '@fluentui/react' export interface IngAppState { ings?: Ing[] diff --git a/src/models/webview-msg.ts b/src/models/webview-msg.ts index 931f0d41..365f8ca0 100644 --- a/src/models/webview-msg.ts +++ b/src/models/webview-msg.ts @@ -1,11 +1,11 @@ -import { ColorThemeKind } from 'vscode' -import { IErrorResponse as ErrorResponse } from './error-response' -import { ImageUploadStatus } from './image-upload-status' import { Post } from './post' +import { WebviewCmd } from './webview-cmd' +import { ColorThemeKind } from 'vscode' import { PostCategories } from './post-category' -import { PostTags } from './post-tag' import { SiteCategories } from './site-category' -import { WebviewCmd } from './webview-cmd' +import { PostTags } from './post-tag' +import { IErrorResponse as ErrorResponse } from './error-response' +import { ImageUploadStatus } from './image-upload-status' export namespace webviewMessage { export interface Message { diff --git a/src/services/alert.service.ts b/src/services/alert.service.ts index 05f03c50..8d057d65 100644 --- a/src/services/alert.service.ts +++ b/src/services/alert.service.ts @@ -1,9 +1,10 @@ import type { HTTPError } from 'got' import { isArray } from 'lodash-es' import path from 'path' -import { MessageOptions, Uri, window } from 'vscode' +import vscode, { Uri } from 'vscode' +import { window } from 'vscode' -export namespace Alert { +export namespace AlertService { export const err = window.showErrorMessage export const info = window.showInformationMessage @@ -21,7 +22,7 @@ export namespace Alert { else if (httpError.message) parsedError = httpError.message else parsedError = '未知网络错误' - void Alert.warn((message ? message + (parsedError ? ', ' : '') : '') + parsedError) + void AlertService.warn((message ? message + (parsedError ? ', ' : '') : '') + parsedError) } /** @@ -32,12 +33,16 @@ export namespace Alert { export function fileNotLinkedToPost(file: string | Uri, { trimExt = true } = {}) { file = file instanceof Uri ? file.fsPath : file file = trimExt ? path.basename(file, path.extname(file)) : file - void Alert.warn(`本地文件"${file}"未关联博客园博文`) + void AlertService.warn(`本地文件"${file}"未关联博客园博文`) } export async function alertUnAuth({ onLoginActionHook }: { onLoginActionHook?: () => unknown } = {}) { const options = ['立即登录'] - const input = await Alert.warn('登录状态已过期, 请重新登录', { modal: true } as MessageOptions, ...options) + const input = await AlertService.warn( + '登录状态已过期, 请重新登录', + { modal: true } as vscode.MessageOptions, + ...options + ) if (input === options[0]) onLoginActionHook?.() } } diff --git a/src/services/blog-export-post.store.ts b/src/services/blog-export-post.store.ts index a7467fe5..7921283a 100644 --- a/src/services/blog-export-post.store.ts +++ b/src/services/blog-export-post.store.ts @@ -1,8 +1,8 @@ import { DownloadedBlogExport } from '@/models/blog-export' import { ExportPost, ExportPostModel } from '@/models/blog-export/export-post' import { DataTypes, Op, Sequelize } from 'sequelize' -import sqlite3 from 'sqlite3' import { Disposable } from 'vscode' +import sqlite3 from 'sqlite3' export class ExportPostStore implements Disposable { private _sequelize?: null | Sequelize diff --git a/src/services/blog-settings.service.ts b/src/services/blog-settings.service.ts index 4bd12c4e..f97f73be 100644 --- a/src/services/blog-settings.service.ts +++ b/src/services/blog-settings.service.ts @@ -1,5 +1,5 @@ -import { BlogSettings, BlogSiteDto, BlogSiteExtendDto } from '@/models/blog-settings' import fetch from '@/utils/fetch-client' +import { BlogSettings, BlogSiteDto, BlogSiteExtendDto } from '@/models/blog-settings' import { globalCtx } from './global-ctx' let settingCache: BlogSettings | null = null diff --git a/src/services/check-workspace.ts b/src/services/check-workspace.ts index ce5624f3..b25ad770 100644 --- a/src/services/check-workspace.ts +++ b/src/services/check-workspace.ts @@ -1,10 +1,10 @@ -import { refreshPostCategoriesList } from '@/commands/post-category/refresh-post-categories-list' -import { refreshPostsList } from '@/commands/posts-list/refresh-posts-list' -import { execCmd } from '@/utils/cmd' import os from 'os' import { workspace } from 'vscode' +import { refreshPostCategoriesList } from '@/commands/post-category/refresh-post-categories-list' +import { refreshPostsList } from '@/commands/posts-list/refresh-posts-list' import { globalCtx } from './global-ctx' import { PostFileMapManager } from './post-file-map' +import { execCmd } from '@/utils/cmd' import { Settings } from './settings.service' const diskSymbolRegex = /^(\S{1,5}:)(.*)/ diff --git a/src/services/global-ctx.ts b/src/services/global-ctx.ts index 035c83e5..928aaafc 100644 --- a/src/services/global-ctx.ts +++ b/src/services/global-ctx.ts @@ -1,6 +1,6 @@ +import { env, ExtensionContext, Uri } from 'vscode' import { defaultConfig, devConfig, IExtensionConfig, isDevEnv } from '@/models/config' import path from 'path' -import { env, ExtensionContext, Uri } from 'vscode' class GlobalCtx { private _extensionContext?: ExtensionContext diff --git a/src/services/image.service.ts b/src/services/image.service.ts index ae7e1fdf..7ae7f424 100644 --- a/src/services/image.service.ts +++ b/src/services/image.service.ts @@ -1,8 +1,8 @@ -import httpClient from '@/utils/http-client' +import { globalCtx } from './global-ctx' +import { Readable } from 'stream' import { isString, merge, pick } from 'lodash-es' +import httpClient from '@/utils/http-client' import path from 'path' -import { Readable } from 'stream' -import { globalCtx } from './global-ctx' export namespace ImageService { export async function upload< diff --git a/src/services/ing.api.ts b/src/services/ing.api.ts index 4284b812..269e1b7d 100644 --- a/src/services/ing.api.ts +++ b/src/services/ing.api.ts @@ -1,9 +1,9 @@ import { Ing, IngComment, IngPublishModel, IngType } from '@/models/ing' -import { Alert } from '@/services/alert.service' +import { AlertService } from '@/services/alert.service' import { globalCtx } from '@/services/global-ctx' import fetch from '@/utils/fetch-client' -import { isArray, isObject } from 'lodash-es' import { URLSearchParams } from 'url' +import { isArray, isObject } from 'lodash-es' export namespace IngApi { export async function publishIng(ing: IngPublishModel): Promise { @@ -11,10 +11,10 @@ export namespace IngApi { method: 'POST', body: JSON.stringify(ing), headers: [['Content-Type', 'application/json']], - }).catch(reason => void Alert.warn(JSON.stringify(reason))) + }).catch(reason => void AlertService.warn(JSON.stringify(reason))) if (!res || !res.ok) - void Alert.err(`闪存发布失败, ${res?.statusText ?? ''} ${JSON.stringify((await res?.text()) ?? '')}`) + AlertService.err(`闪存发布失败, ${res?.statusText ?? ''} ${JSON.stringify((await res?.text()) ?? '')}`) return res != null && res.ok } @@ -29,10 +29,10 @@ export namespace IngApi { method: 'GET', headers: [['Content-Type', 'application/json']], } - ).catch(e => void Alert.warn(JSON.stringify(e))) + ).catch(e => void AlertService.warn(JSON.stringify(e))) if (!res || !res.ok) { - void Alert.err(`获取闪存列表失败, ${res?.statusText ?? ''} ${JSON.stringify((await res?.text()) ?? '')}`) + AlertService.err(`获取闪存列表失败, ${res?.statusText ?? ''} ${JSON.stringify((await res?.text()) ?? '')}`) return [] } @@ -40,9 +40,9 @@ export namespace IngApi { try { if (isArray(arr) && arr.every(isObject)) return arr.map(Ing.parse) - void Alert.err('获取闪存列表失败, 无法读取响应') + AlertService.err('获取闪存列表失败, 无法读取响应') } catch (e) { - void Alert.err(JSON.stringify(e)) + AlertService.err(JSON.stringify(e)) } return [] @@ -57,7 +57,7 @@ export namespace IngApi { resp => resp?.json().then(obj => [id, obj as IngComment[] | null | undefined] as const) ?? Promise.resolve(undefined), - reason => void Alert.warn(JSON.stringify(reason)) + reason => void AlertService.warn(JSON.stringify(reason)) ) ) @@ -85,12 +85,12 @@ export namespace IngApi { }) if (!res.ok) { - void Alert.err(`发表评论失败, ${await res.text()}`) + AlertService.err(`发表评论失败, ${await res.text()}`) return false } } catch (e) { // eslint-disable-next-line @typescript-eslint/restrict-template-expressions - void Alert.err(`发表评论失败, ${e}`) + AlertService.err(`发表评论失败, ${e}`) return false } diff --git a/src/services/ings-list-webview-provider.ts b/src/services/ings-list-webview-provider.ts index f08cb9e9..0fc12c49 100644 --- a/src/services/ings-list-webview-provider.ts +++ b/src/services/ings-list-webview-provider.ts @@ -1,12 +1,4 @@ -import { CommentIngCmdHandler } from '@/commands/ing/comment-ing' -import { execCmd } from '@/utils/cmd' -import { isNumber } from 'lodash-es' -import { IngType, IngTypesMetadata } from 'src/models/ing' -import { IngAppState } from 'src/models/ing-view' -import { IngWebviewHostCmd, IngWebviewUiCmd, WebviewCmd } from 'src/models/webview-cmd' import { globalCtx } from 'src/services/global-ctx' -import { IngApi } from 'src/services/ing.api' -import { parseWebviewHtml } from 'src/services/parse-webview-html' import { CancellationToken, Disposable, @@ -16,6 +8,14 @@ import { WebviewViewResolveContext, window, } from 'vscode' +import { parseWebviewHtml } from 'src/services/parse-webview-html' +import { IngWebviewHostCmd, IngWebviewUiCmd, WebviewCmd } from 'src/models/webview-cmd' +import { IngApi } from 'src/services/ing.api' +import { IngAppState } from 'src/models/ing-view' +import { IngType, IngTypesMetadata } from 'src/models/ing' +import { isNumber } from 'lodash-es' +import { CommentIngCmdHandler } from '@/commands/ing/comment-ing' +import { execCmd } from '@/utils/cmd' export class IngsListWebviewProvider implements WebviewViewProvider { private static _instance: IngsListWebviewProvider | null = null diff --git a/src/services/local-draft.service.ts b/src/services/local-draft.service.ts index ee462a9d..c723d2cb 100644 --- a/src/services/local-draft.service.ts +++ b/src/services/local-draft.service.ts @@ -1,5 +1,5 @@ -import fs from 'fs' import path from 'path' +import fs from 'fs' import { Uri, workspace } from 'vscode' export class LocalDraft { diff --git a/src/services/mkd-img-extractor.service.ts b/src/services/mkd-img-extractor.service.ts index 1b90d095..05a2b5a9 100644 --- a/src/services/mkd-img-extractor.service.ts +++ b/src/services/mkd-img-extractor.service.ts @@ -1,12 +1,12 @@ -import { isErrorResponse } from '@/models/error-response' -import fs from 'fs' -import { isString } from 'lodash-es' -import { tmpdir } from 'os' import path from 'path' -import { Readable } from 'stream' -import { promisify } from 'util' +import { isString } from 'lodash-es' +import fs from 'fs' import { Uri, workspace } from 'vscode' import { ImageService } from './image.service' +import { isErrorResponse } from '@/models/error-response' +import { promisify } from 'util' +import { Readable } from 'stream' +import { tmpdir } from 'os' export const enum DataType { dataUrl, diff --git a/src/services/oauth.api.ts b/src/services/oauth.api.ts index 6c5ad147..5e5fb59b 100644 --- a/src/services/oauth.api.ts +++ b/src/services/oauth.api.ts @@ -1,12 +1,12 @@ /* eslint-disable @typescript-eslint/naming-convention */ -import { AccountInfo } from '@/auth/account-info' import { TokenInfo } from '@/models/token-info' +import { AccountInfo } from '@/auth/account-info' import { convertObjectKeysToCamelCase } from '@/services/converter' import { globalCtx } from '@/services/global-ctx' import fetch from '@/utils/fetch-client' import got from '@/utils/http-client' -import { AbortController } from 'node-abort-controller' import { CancellationToken } from 'vscode' +import { AbortController } from 'node-abort-controller' export type UserInfoSpec = Pick & { readonly blog_id: string diff --git a/src/services/parse-webview-html.ts b/src/services/parse-webview-html.ts index 7012e709..229ed5f5 100644 --- a/src/services/parse-webview-html.ts +++ b/src/services/parse-webview-html.ts @@ -1,5 +1,5 @@ -import { globalCtx } from 'src/services/global-ctx' import vscode from 'vscode' +import { globalCtx } from 'src/services/global-ctx' export type WebviewEntryName = 'ing' | 'post-cfg' diff --git a/src/services/post-category.service.ts b/src/services/post-category.service.ts index c8f89fcd..2f67e1cd 100644 --- a/src/services/post-category.service.ts +++ b/src/services/post-category.service.ts @@ -1,7 +1,7 @@ -import { PostCategories, PostCategory, PostCategoryAddDto } from '@/models/post-category' import fetch from '@/utils/fetch-client' -import { URLSearchParams } from 'url' +import { PostCategories, PostCategory, PostCategoryAddDto } from '@/models/post-category' import { globalCtx } from './global-ctx' +import { URLSearchParams } from 'url' export class PostCategoryService { private static _instance: PostCategoryService | null = null diff --git a/src/services/post-cfg-panel.service.ts b/src/services/post-cfg-panel.service.ts index 679b59b7..60313402 100644 --- a/src/services/post-cfg-panel.service.ts +++ b/src/services/post-cfg-panel.service.ts @@ -1,19 +1,19 @@ -import { openPostFile } from '@/commands/posts-list/open-post-file' -import { uploadImage } from '@/commands/upload-image/upload-image' -import { isErrorResponse } from '@/models/error-response' -import { ImageUploadStatusId } from '@/models/image-upload-status' -import { Post } from '@/models/post' -import { webviewMessage } from '@/models/webview-msg' import { cloneDeep } from 'lodash-es' -import path from 'path' -import { WebviewCmd, WebviewCommonCmd } from 'src/models/webview-cmd' -import { parseWebviewHtml } from 'src/services/parse-webview-html' import vscode, { Uri } from 'vscode' +import { Post } from '@/models/post' import { globalCtx } from './global-ctx' import { postCategoryService } from './post-category.service' +import { siteCategoryService } from './site-category.service' import { PostTagService } from './post-tag.service' import { PostService } from './post.service' -import { siteCategoryService } from './site-category.service' +import { isErrorResponse } from '@/models/error-response' +import { webviewMessage } from '@/models/webview-msg' +import { WebviewCommonCmd, WebviewCmd } from 'src/models/webview-cmd' +import { uploadImage } from '@/commands/upload-image/upload-image' +import { ImageUploadStatusId } from '@/models/image-upload-status' +import { openPostFile } from '@/commands/posts-list/open-post-file' +import { parseWebviewHtml } from 'src/services/parse-webview-html' +import path from 'path' const panels: Map = new Map() diff --git a/src/services/post-tag.service.ts b/src/services/post-tag.service.ts index 23835dcb..6c46e856 100644 --- a/src/services/post-tag.service.ts +++ b/src/services/post-tag.service.ts @@ -1,5 +1,5 @@ -import { PostTag } from '@/models/post-tag' import got from '@/utils/http-client' +import { PostTag } from '@/models/post-tag' import { globalCtx } from './global-ctx' let cachedTags: PostTag[] | null = null diff --git a/src/services/post-title-sanitizer.service.ts b/src/services/post-title-sanitizer.service.ts index 52375c24..6a7693f5 100644 --- a/src/services/post-title-sanitizer.service.ts +++ b/src/services/post-title-sanitizer.service.ts @@ -1,6 +1,6 @@ -import { Post } from '@/models/post' import path from 'path' import sanitizeFilename from 'sanitize-filename' +import { Post } from '@/models/post' import { globalCtx } from './global-ctx' import { PostFileMapManager } from './post-file-map' diff --git a/src/services/post.service.ts b/src/services/post.service.ts index 43fc1396..aa8412d3 100644 --- a/src/services/post.service.ts +++ b/src/services/post.service.ts @@ -1,17 +1,18 @@ -import { IErrorResponse } from '@/models/error-response' -import { PageModel } from '@/models/page-model' +import fetch from '@/utils/fetch-client' import { Post } from '@/models/post' +import { globalCtx } from './global-ctx' +import { PageModel } from '@/models/page-model' +import { PostsListState } from '@/models/posts-list-state' import { PostEditDto } from '@/models/post-edit-dto' import { PostUpdatedResponse } from '@/models/post-updated-response' -import { PostsListState } from '@/models/posts-list-state' -import { ZzkSearchResult } from '@/models/zzk-search-result' -import fetch from '@/utils/fetch-client' -import { default as got, default as httpClient } from '@/utils/http-client' import { throwIfNotOkGotResponse } from '@/utils/throw-if-not-ok-response' -import iconv from 'iconv-lite' -import { Alert } from './alert.service' -import { globalCtx } from './global-ctx' +import { IErrorResponse } from '@/models/error-response' +import { AlertService } from './alert.service' import { PostFileMapManager } from './post-file-map' +import { ZzkSearchResult } from '@/models/zzk-search-result' +import got from '@/utils/http-client' +import httpClient from '@/utils/http-client' +import iconv from 'iconv-lite' const defaultPageSize = 30 let newPostTemplate: PostEditDto | undefined @@ -72,11 +73,11 @@ export namespace PostService { const { statusCode, errors } = e as IErrorResponse if (!muteErrorNotification) { if (statusCode === 404) { - void Alert.err('博文不存在') + AlertService.err('博文不存在') const postFilePath = PostFileMapManager.getFilePath(postId) if (postFilePath) await PostFileMapManager.updateOrCreate(postId, '') } else { - void Alert.err(errors.join('\n')) + AlertService.err(errors.join('\n')) } } return undefined diff --git a/src/services/search-post-by-title.ts b/src/services/search-post-by-title.ts index 0aad9dd4..4d8260e7 100644 --- a/src/services/search-post-by-title.ts +++ b/src/services/search-post-by-title.ts @@ -1,5 +1,5 @@ -import { Post } from '@/models/post' import { QuickPickItem, window } from 'vscode' +import { Post } from '@/models/post' import { PostService } from './post.service' class PostPickItem implements QuickPickItem { diff --git a/src/services/settings.service.ts b/src/services/settings.service.ts index d97e93e1..733afa0d 100644 --- a/src/services/settings.service.ts +++ b/src/services/settings.service.ts @@ -1,9 +1,9 @@ -import { untildify } from '@/utils/untildify' -import fs from 'fs' -import { isNumber } from 'lodash-es' import os, { homedir } from 'os' +import fs from 'fs' import { ConfigurationTarget, Uri, workspace } from 'vscode' import { ImageSrc } from './mkd-img-extractor.service' +import { isNumber } from 'lodash-es' +import { untildify } from '@/utils/untildify' export class Settings { static readonly postsListPageSizeKey = 'pageSize.postsList' diff --git a/src/services/site-category.service.ts b/src/services/site-category.service.ts index ce975d7d..c053bf62 100644 --- a/src/services/site-category.service.ts +++ b/src/services/site-category.service.ts @@ -1,5 +1,5 @@ -import { SiteCategories, SiteCategory } from '@/models/site-category' import fetch from '@/utils/fetch-client' +import { SiteCategories, SiteCategory } from '@/models/site-category' import { globalCtx } from './global-ctx' export namespace siteCategoryService { diff --git a/src/test/suite/extension.test.ts b/src/test/suite/extension.test.ts index 89de4d8c..2bdec69c 100644 --- a/src/test/suite/extension.test.ts +++ b/src/test/suite/extension.test.ts @@ -1,4 +1,4 @@ -import { Alert } from '@/services/alert.service' +import { AlertService } from '@/services/alert.service' import assert from 'assert' // You can import and use all API from the 'vscode' module @@ -6,7 +6,7 @@ import assert from 'assert' // import * as myExtension from '../../extension'; suite('Extension Test Suite', () => { - void Alert.info('Start all tests.') + AlertService.info('Start all tests.') test('Sample test', () => { assert.strictEqual(-1, [1, 2, 3].indexOf(5)) diff --git a/src/test/suite/index.ts b/src/test/suite/index.ts index 3b69a023..6947a966 100644 --- a/src/test/suite/index.ts +++ b/src/test/suite/index.ts @@ -1,6 +1,6 @@ -import glob from 'glob' -import Mocha from 'mocha' import path from 'path' +import Mocha from 'mocha' +import glob from 'glob' export function run(): Promise { // Create the mocha test diff --git a/src/tree-view-providers/blog-export-provider.ts b/src/tree-view-providers/blog-export-provider.ts index 400042fc..78a42339 100644 --- a/src/tree-view-providers/blog-export-provider.ts +++ b/src/tree-view-providers/blog-export-provider.ts @@ -1,10 +1,7 @@ -import { BlogExportRecord } from '@/models/blog-export' -import { Alert } from '@/services/alert.service' import { BlogExportRecordsStore } from '@/services/blog-export-records.store' -import { Event, EventEmitter, ProviderResult, TreeDataProvider, TreeItem } from 'vscode' import { - BlogExportRecordMetadata, BlogExportRecordTreeItem, + BlogExportRecordMetadata, BlogExportTreeItem, parseBlogExportRecords, } from './models/blog-export' @@ -14,6 +11,9 @@ import { DownloadedExportTreeItem, ExportPostsEntryTreeItem, } from './models/blog-export/downloaded' +import { Event, EventEmitter, ProviderResult, TreeDataProvider, TreeItem } from 'vscode' +import { AlertService } from '@/services/alert.service' +import { BlogExportRecord } from '@/models/blog-export' export class BlogExportProvider implements TreeDataProvider { private static _instance: BlogExportProvider | null = null @@ -109,7 +109,7 @@ export class BlogExportProvider implements TreeDataProvider ?.refresh() .then(() => true) .catch(e => { - if (notifyOnError) void Alert.err(`刷新博客备份记录失败: ${e.message}`) + if (notifyOnError) AlertService.err(`刷新博客备份记录失败: ${e.message}`) }) : clearCache ? await this._store?.clearCache().then( diff --git a/src/tree-view-providers/converters.ts b/src/tree-view-providers/converters.ts index 73df604d..fa3e1e47 100644 --- a/src/tree-view-providers/converters.ts +++ b/src/tree-view-providers/converters.ts @@ -1,11 +1,11 @@ +import format from 'date-fns/format' +import { homedir } from 'os' +import { MarkdownString, ThemeIcon, TreeItem, TreeItemCollapsibleState, Uri } from 'vscode' import { Post } from '@/models/post' import { PostCategory } from '@/models/post-category' import { globalCtx } from '@/services/global-ctx' import { PostFileMapManager } from '@/services/post-file-map' import { Settings } from '@/services/settings.service' -import format from 'date-fns/format' -import { homedir } from 'os' -import { MarkdownString, ThemeIcon, TreeItem, TreeItemCollapsibleState, Uri } from 'vscode' import { BaseTreeItemSource } from './models/base-tree-item-source' const contextValues = { diff --git a/src/tree-view-providers/models/blog-export/index.ts b/src/tree-view-providers/models/blog-export/index.ts index c0a234b6..79f55d76 100644 --- a/src/tree-view-providers/models/blog-export/index.ts +++ b/src/tree-view-providers/models/blog-export/index.ts @@ -3,14 +3,12 @@ import { DownloadedExportsEntryTreeItem, DownloadedExportTreeItem, } from '@/tree-view-providers/models/blog-export/downloaded' -import { BlogExportRecordTreeItem } from '@/tree-view-providers/models/blog-export/record' import { BlogExportRecordMetadata } from '@/tree-view-providers/models/blog-export/record-metadata' +import { BlogExportRecordTreeItem } from '@/tree-view-providers/models/blog-export/record' -export * from '../post-tree-item' -export * from './downloaded' -export { parseBlogExportRecords, parseStatusIcon } from './parser' -export * from './record' export * from './record-metadata' +export * from './record' +export * from './downloaded' export type BlogExportTreeItem = | BlogExportRecordMetadata @@ -18,3 +16,5 @@ export type BlogExportTreeItem = | DownloadedExportTreeItem | DownloadedExportChildTreeItem | DownloadedExportsEntryTreeItem +export { parseBlogExportRecords, parseStatusIcon } from './parser' +export * from '../post-tree-item' diff --git a/src/tree-view-providers/models/blog-export/parser.ts b/src/tree-view-providers/models/blog-export/parser.ts index 6f28413f..91d88de7 100644 --- a/src/tree-view-providers/models/blog-export/parser.ts +++ b/src/tree-view-providers/models/blog-export/parser.ts @@ -1,11 +1,11 @@ import { BlogExportRecord, BlogExportStatus, DownloadedBlogExport } from '@/models/blog-export' -import { BlogExportProvider } from '@/tree-view-providers/blog-export-provider' +import { BlogExportRecordTreeItem } from './record' +import { ThemeColor, ThemeIcon } from 'vscode' import { DownloadedExportsEntryTreeItem, DownloadedExportTreeItem, } from '@/tree-view-providers/models/blog-export/downloaded' -import { ThemeColor, ThemeIcon } from 'vscode' -import { BlogExportRecordTreeItem } from './record' +import { BlogExportProvider } from '@/tree-view-providers/blog-export-provider' export function parseStatusIcon(status: BlogExportStatus) { switch (status) { diff --git a/src/tree-view-providers/models/blog-export/record.ts b/src/tree-view-providers/models/blog-export/record.ts index 72734d9e..40ea70d3 100644 --- a/src/tree-view-providers/models/blog-export/record.ts +++ b/src/tree-view-providers/models/blog-export/record.ts @@ -1,17 +1,17 @@ import { BlogExportRecord, BlogExportStatus, blogExportStatusNameMap } from '@/models/blog-export' -import { BlogExportApi } from '@/services/blog-export.api' -import { DownloadedExportStore } from '@/services/downloaded-export.store' -import { BlogExportProvider } from '@/tree-view-providers/blog-export-provider' import { BaseEntryTreeItem } from '@/tree-view-providers/models/base-entry-tree-item' import { BaseTreeItemSource } from '@/tree-view-providers/models/base-tree-item-source' -import { BlogExportTreeItem, DownloadedExportTreeItem } from '@/tree-view-providers/models/blog-export' +import { BlogExportRecordMetadata } from './record-metadata' +import { parseStatusIcon } from './parser' +import { TreeItem, TreeItemCollapsibleState, ThemeIcon } from 'vscode' import format from 'date-fns/format' import parseISO from 'date-fns/parseISO' -import { escapeRegExp } from 'lodash-es' +import { DownloadedExportStore } from '@/services/downloaded-export.store' +import { BlogExportTreeItem, DownloadedExportTreeItem } from '@/tree-view-providers/models/blog-export' import os from 'os' -import { ThemeIcon, TreeItem, TreeItemCollapsibleState } from 'vscode' -import { parseStatusIcon } from './parser' -import { BlogExportRecordMetadata } from './record-metadata' +import { escapeRegExp } from 'lodash-es' +import { BlogExportProvider } from '@/tree-view-providers/blog-export-provider' +import { BlogExportApi } from '@/services/blog-export.api' export class BlogExportRecordTreeItem extends BaseTreeItemSource implements BaseEntryTreeItem { static readonly contextValue = 'cnblogs-export-record' diff --git a/src/tree-view-providers/models/post-category-tree-item.ts b/src/tree-view-providers/models/post-category-tree-item.ts index 3791f112..a0010e4d 100644 --- a/src/tree-view-providers/models/post-category-tree-item.ts +++ b/src/tree-view-providers/models/post-category-tree-item.ts @@ -1,5 +1,5 @@ -import { PostCategory } from '@/models/post-category' import { TreeItem } from 'vscode' +import { PostCategory } from '@/models/post-category' import { toTreeItem } from '../converters' import { BaseTreeItemSource } from './base-tree-item-source' import { PostTreeItem } from './post-tree-item' diff --git a/src/tree-view-providers/models/post-metadata.ts b/src/tree-view-providers/models/post-metadata.ts index f76a7b42..bcfd06b6 100644 --- a/src/tree-view-providers/models/post-metadata.ts +++ b/src/tree-view-providers/models/post-metadata.ts @@ -1,17 +1,17 @@ -import { AccessPermission, formatAccessPermission, Post } from '@/models/post' -import { PostCategory } from '@/models/post-category' -import { PostEditDto } from '@/models/post-edit-dto' -import { postCategoryService } from '@/services/post-category.service' -import { PostService } from '@/services/post.service' import differenceInSeconds from 'date-fns/differenceInSeconds' import differenceInYears from 'date-fns/differenceInYears' import format from 'date-fns/format' import formatDistanceStrict from 'date-fns/formatDistanceStrict' import zhCN from 'date-fns/locale/zh-CN' -import { ThemeIcon, TreeItem, TreeItemCollapsibleState } from 'vscode' +import { TreeItem, TreeItemCollapsibleState, ThemeIcon } from 'vscode' +import { AccessPermission, Post, formatAccessPermission } from '@/models/post' +import { PostEditDto } from '@/models/post-edit-dto' +import { postCategoryService } from '@/services/post-category.service' +import { PostService } from '@/services/post.service' import { BaseEntryTreeItem } from './base-entry-tree-item' import { BaseTreeItemSource } from './base-tree-item-source' import { PostTreeItem } from './post-tree-item' +import { PostCategory } from '@/models/post-category' export enum RootPostMetadataType { categoryEntry = 'categoryEntry', diff --git a/src/tree-view-providers/models/post-search-result-entry.ts b/src/tree-view-providers/models/post-search-result-entry.ts index 1d027297..69a6e081 100644 --- a/src/tree-view-providers/models/post-search-result-entry.ts +++ b/src/tree-view-providers/models/post-search-result-entry.ts @@ -1,6 +1,6 @@ +import { ThemeIcon, TreeItem, TreeItemCollapsibleState } from 'vscode' import { Post } from '@/models/post' import { ZzkSearchResult } from '@/models/zzk-search-result' -import { ThemeIcon, TreeItem, TreeItemCollapsibleState } from 'vscode' import { BaseEntryTreeItem } from './base-entry-tree-item' import { BaseTreeItemSource } from './base-tree-item-source' import { PostTreeItem } from './post-tree-item' diff --git a/src/tree-view-providers/models/post-tree-item.ts b/src/tree-view-providers/models/post-tree-item.ts index bade85d0..76848158 100644 --- a/src/tree-view-providers/models/post-tree-item.ts +++ b/src/tree-view-providers/models/post-tree-item.ts @@ -1,5 +1,5 @@ -import { Post } from '@/models/post' import { TreeItem, TreeItemCollapsibleState } from 'vscode' +import { Post } from '@/models/post' import { toTreeItem } from '../converters' import { BaseTreeItemSource } from './base-tree-item-source' diff --git a/src/tree-view-providers/post-categories-tree-data-provider.ts b/src/tree-view-providers/post-categories-tree-data-provider.ts index 721cf6ee..e82d2c65 100644 --- a/src/tree-view-providers/post-categories-tree-data-provider.ts +++ b/src/tree-view-providers/post-categories-tree-data-provider.ts @@ -1,16 +1,16 @@ +import { flattenDepth, take } from 'lodash-es' +import { EventEmitter, ProviderResult, TreeDataProvider, TreeItem } from 'vscode' import { PostCategories } from '@/models/post-category' -import { Alert } from '@/services/alert.service' import { globalCtx } from '@/services/global-ctx' import { postCategoryService } from '@/services/post-category.service' import { PostService } from '@/services/post.service' -import { execCmd } from '@/utils/cmd' -import { flattenDepth, take } from 'lodash-es' -import { EventEmitter, ProviderResult, TreeDataProvider, TreeItem } from 'vscode' import { toTreeItem } from './converters' import { PostCategoriesListTreeItem } from './models/categories-list-tree-item' import { PostCategoryTreeItem } from './models/post-category-tree-item' import { PostEntryMetadata, PostMetadata, RootPostMetadataType } from './models/post-metadata' import { PostTreeItem } from './models/post-tree-item' +import { AlertService } from '@/services/alert.service' +import { execCmd } from '@/utils/cmd' export class PostCategoriesTreeDataProvider implements TreeDataProvider { private static _instance: PostCategoriesTreeDataProvider | null = null @@ -135,7 +135,7 @@ export class PostCategoriesTreeDataProvider implements TreeDataProvidere).message}`) + AlertService.err(`获取博文分类失败: ${(e).message}`) } finally { await this.setIsRefreshing(false) } diff --git a/src/tree-view-providers/posts-data-provider.ts b/src/tree-view-providers/posts-data-provider.ts index 3155f413..904021d8 100644 --- a/src/tree-view-providers/posts-data-provider.ts +++ b/src/tree-view-providers/posts-data-provider.ts @@ -1,10 +1,10 @@ +import { EventEmitter, ProviderResult, TreeDataProvider, TreeItem } from 'vscode' import { refreshPostsList } from '@/commands/posts-list/refresh-posts-list' -import { PageModel } from '@/models/page-model' import { Post } from '@/models/post' -import { Alert } from '@/services/alert.service' +import { PageModel } from '@/models/page-model' +import { AlertService } from '@/services/alert.service' import { PostService } from '@/services/post.service' import { Settings } from '@/services/settings.service' -import { EventEmitter, ProviderResult, TreeDataProvider, TreeItem } from 'vscode' import { toTreeItem } from './converters' import { PostEntryMetadata, PostMetadata } from './models/post-metadata' import { PostSearchResultEntry } from './models/post-search-result-entry' @@ -66,8 +66,8 @@ export class PostsDataProvider implements TreeDataProvider { const pageSize = Settings.postsListPageSize this._pagedPosts = await PostService.fetchPostsList({ pageIndex, pageSize }).catch(e => { - if (e instanceof Error) void Alert.err(e.message) - else void Alert.err(`加载博文失败\n${JSON.stringify(e)}`) + if (e instanceof Error) AlertService.err(e.message) + else AlertService.err(`加载博文失败\n${JSON.stringify(e)}`) return undefined }) diff --git a/src/tree-view-providers/tree-view-registration.ts b/src/tree-view-providers/tree-view-registration.ts index 0dd838d2..ab0c656f 100644 --- a/src/tree-view-providers/tree-view-registration.ts +++ b/src/tree-view-providers/tree-view-registration.ts @@ -1,13 +1,13 @@ import { globalCtx } from '@/services/global-ctx' -import { BlogExportProvider } from '@/tree-view-providers/blog-export-provider' -import { BlogExportTreeItem } from '@/tree-view-providers/models/blog-export' -import { regTreeView } from '@/utils/tree-view' -import { IDisposable } from '@fluentui/react' import vscode from 'vscode' import { accountViewDataProvider } from './account-view-data-provider' -import { PostCategoriesListTreeItem } from './models/categories-list-tree-item' +import { PostsListTreeItem, postsDataProvider } from './posts-data-provider' import { postCategoriesDataProvider } from './post-categories-tree-data-provider' -import { postsDataProvider, PostsListTreeItem } from './posts-data-provider' +import { PostCategoriesListTreeItem } from './models/categories-list-tree-item' +import { IDisposable } from '@fluentui/react' +import { BlogExportTreeItem } from '@/tree-view-providers/models/blog-export' +import { BlogExportProvider } from '@/tree-view-providers/blog-export-provider' +import { regTreeView } from '@/utils/tree-view' const _views: { postsList?: vscode.TreeView diff --git a/src/utils/chromium-path-provider.ts b/src/utils/chromium-path-provider.ts index db66769f..75f2b326 100644 --- a/src/utils/chromium-path-provider.ts +++ b/src/utils/chromium-path-provider.ts @@ -1,8 +1,8 @@ -import { Alert } from '@/services/alert.service' +import { window, ProgressLocation } from 'vscode' import fs from 'fs' import os from 'os' import path from 'path' -import { ProgressLocation, window } from 'vscode' +import { AlertService } from '@/services/alert.service' // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-var-requires const download: (arg: Record) => Promise = require('download-chromium') @@ -74,7 +74,7 @@ namespace chromiumPathProvider { } } ) - if (chromiumPath) void Alert.info(`Chromium已下载至${chromiumPath}`) + if (chromiumPath) AlertService.info(`Chromium已下载至${chromiumPath}`) return chromiumPath } diff --git a/src/utils/cmd.ts b/src/utils/cmd.ts index c734127f..e2bffe75 100644 --- a/src/utils/cmd.ts +++ b/src/utils/cmd.ts @@ -1,5 +1,9 @@ import { commands } from 'vscode' -export const regCmd = commands.registerCommand +export function regCmd(cmd: string, f: (...args: any[]) => any) { + return commands.registerCommand(cmd, f) +} -export const execCmd = commands.executeCommand +export function execCmd(cmd: string, ...rest: any[]) { + return commands.executeCommand(cmd, rest) +} diff --git a/src/utils/get-clipboard-image.ts b/src/utils/get-clipboard-image.ts index 693c8860..feb72e72 100644 --- a/src/utils/get-clipboard-image.ts +++ b/src/utils/get-clipboard-image.ts @@ -1,14 +1,14 @@ // reference: https://github.com/PicGo/PicGo-Core/blob/dev/src/utils/getClipboardImage.ts -import { IClipboardImage } from '@/models/clipboard-image' -import { Alert } from '@/services/alert.service' -import { globalCtx } from '@/services/global-ctx' import { spawn } from 'child_process' -import format from 'date-fns/format' +import path from 'path' import fs from 'fs' -import isWsl from 'is-wsl' import os from 'os' -import path from 'path' +import isWsl from 'is-wsl' +import { globalCtx } from '@/services/global-ctx' +import { AlertService } from '@/services/alert.service' +import { IClipboardImage } from '@/models/clipboard-image' +import format from 'date-fns/format' export type Platform = 'darwin' | 'win32' | 'win10' | 'linux' | 'wsl' @@ -94,7 +94,7 @@ const getClipboardImage = (): Promise => { execution.stdout.on('data', (data: Buffer) => { if (platform === 'linux') { if (data.toString().trim() === 'no xclip') { - void Alert.warn('xclip not found, Please install xclip first') + AlertService.warn('xclip not found, Please install xclip first') return reject(new Error('Please install xclip first')) } } diff --git a/src/utils/http-client.ts b/src/utils/http-client.ts index da70b6ba..a43343dc 100644 --- a/src/utils/http-client.ts +++ b/src/utils/http-client.ts @@ -1,7 +1,7 @@ import { accountManager } from '@/auth/account-manager' -import { Oauth } from '@/services/oauth.api' import got, { BeforeRequestHook } from 'got' import { isString } from 'lodash-es' +import { Oauth } from '@/services/oauth.api' const bearerTokenHook: BeforeRequestHook = async opt => { const { headers } = opt @@ -24,6 +24,6 @@ const httpClient = got.extend({ https: { rejectUnauthorized: false }, }) -export * from 'got' export { got } +export * from 'got' export default httpClient diff --git a/src/utils/input-post-settings.ts b/src/utils/input-post-settings.ts index 0c264919..58ef8a17 100644 --- a/src/utils/input-post-settings.ts +++ b/src/utils/input-post-settings.ts @@ -1,9 +1,9 @@ +import { QuickPickItem } from 'vscode' import { AccessPermission, Post } from '@/models/post' import { PostCategories, PostCategory } from '@/models/post-category' -import { Alert } from '@/services/alert.service' +import { AlertService } from '@/services/alert.service' import { InputFlowAction, InputStep, MultiStepInput, QuickPickParameters } from '@/services/multi-step-input' import { postCategoryService } from '@/services/post-category.service' -import { QuickPickItem } from 'vscode' class CategoryPickItem implements QuickPickItem { label: string @@ -102,7 +102,7 @@ export const inputPostSettings = ( try { categories = await postCategoryService.listCategories() } catch (err) { - void Alert.err(err instanceof Error ? err.message : JSON.stringify(err)) + AlertService.err(err instanceof Error ? err.message : JSON.stringify(err)) // 取消 throw InputFlowAction.cancel } diff --git a/src/utils/msg.ts b/src/utils/msg.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/utils/save-file-pending-changes.ts b/src/utils/save-file-pending-changes.ts index 10a2f3c7..5f830aab 100644 --- a/src/utils/save-file-pending-changes.ts +++ b/src/utils/save-file-pending-changes.ts @@ -1,4 +1,4 @@ -import { Uri, window } from 'vscode' +import { window, Uri } from 'vscode' export const saveFilePendingChanges = async (filePath: Uri | string | undefined) => { const localPath = typeof filePath === 'string' ? filePath : filePath?.fsPath diff --git a/src/utils/throw-if-not-ok-response.ts b/src/utils/throw-if-not-ok-response.ts index 150536a1..6237cf0b 100644 --- a/src/utils/throw-if-not-ok-response.ts +++ b/src/utils/throw-if-not-ok-response.ts @@ -1,6 +1,6 @@ -import { IErrorResponse, isErrorResponse } from '@/models/error-response' -import { Response as GotResponse } from 'got' import { GotFetchResponse } from 'got-fetch/out/lib/response' +import { Response as GotResponse } from 'got' +import { IErrorResponse, isErrorResponse } from '@/models/error-response' import iconv from 'iconv-lite' const throwIfNotOkResponse = async (response: GotFetchResponse) => { diff --git a/src/utils/tree-view.ts b/src/utils/tree-view.ts index b9b43a96..b65bd915 100644 --- a/src/utils/tree-view.ts +++ b/src/utils/tree-view.ts @@ -1,3 +1,5 @@ -import { window } from 'vscode' +import vscode, { TreeViewOptions } from 'vscode' -export const regTreeView = window.createTreeView +export function regTreeView(id: string, opt: TreeViewOptions) { + return vscode.window.createTreeView(id, opt) +} diff --git a/src/utils/uri-handler.ts b/src/utils/uri-handler.ts index 9e058d9a..a635cbbb 100644 --- a/src/utils/uri-handler.ts +++ b/src/utils/uri-handler.ts @@ -1,5 +1,5 @@ +import { Disposable, EventEmitter, ProviderResult, Uri, UriHandler, Event } from 'vscode' import { openPostInVscode } from '@/commands/posts-list/open-post-in-vscode' -import { Disposable, Event, EventEmitter, ProviderResult, Uri, UriHandler } from 'vscode' class ExtUriHandler implements UriHandler, Disposable { private _uriEventEmitter?: EventEmitter diff --git a/ui/ing/App.tsx b/ui/ing/App.tsx index 9202d37f..fde339d5 100644 --- a/ui/ing/App.tsx +++ b/ui/ing/App.tsx @@ -1,13 +1,13 @@ -import { Spinner, Stack } from '@fluentui/react' -import { ThemeProvider } from '@fluentui/react/lib/Theme' -import { Ing, IngComment } from '@models/ing' -import { IngAppState } from '@models/ing-view' +import React, { Component, ReactNode } from 'react' import { IngWebviewUiCmd, WebviewCmd } from '@models/webview-cmd' import { IngList } from 'ing/IngList' -import { cloneWith } from 'lodash-es' -import React, { Component, ReactNode } from 'react' -import { activeThemeProvider } from 'share/active-theme-provider' import { getVsCodeApiSingleton } from 'share/vscode-api' +import { IngAppState } from '@models/ing-view' +import { Ing, IngComment } from '@models/ing' +import { activeThemeProvider } from 'share/active-theme-provider' +import { ThemeProvider } from '@fluentui/react/lib/Theme' +import { Spinner, Stack } from '@fluentui/react' +import { cloneWith } from 'lodash-es' export class App extends Component { constructor(props: unknown) { diff --git a/ui/ing/IngItem.tsx b/ui/ing/IngItem.tsx index 4e804c49..a1639f97 100644 --- a/ui/ing/IngItem.tsx +++ b/ui/ing/IngItem.tsx @@ -1,12 +1,12 @@ -import { ActivityItem, IPersonaProps, Link, Text } from '@fluentui/react' +import React, { Component } from 'react' import { Ing, IngComment, IngSendFromType } from '@models/ing' import { IngItemState } from '@models/ing-view' -import { IngWebviewHostCmd, WebviewCmd } from '@models/webview-cmd' +import { take } from 'lodash-es' +import { ActivityItem, IPersonaProps, Link, Text } from '@fluentui/react' import { format, formatDistanceStrict } from 'date-fns' import { zhCN } from 'date-fns/locale' -import { take } from 'lodash-es' -import React, { Component } from 'react' import { getVsCodeApiSingleton } from 'share/vscode-api' +import { IngWebviewHostCmd, WebviewCmd } from '@models/webview-cmd' interface IngItemProps { ing: Ing diff --git a/ui/ing/IngList.tsx b/ui/ing/IngList.tsx index 48f92efa..a8dde0e4 100644 --- a/ui/ing/IngList.tsx +++ b/ui/ing/IngList.tsx @@ -1,7 +1,7 @@ -import { Stack } from '@fluentui/react' +import React, { Component } from 'react' import { Ing, IngComment } from '@models/ing' import { IngItem } from 'ing/IngItem' -import React, { Component } from 'react' +import { Stack } from '@fluentui/react' interface IngListProps { ings: Ing[] diff --git a/ui/ing/index.tsx b/ui/ing/index.tsx index 8412ec50..63f6866c 100644 --- a/ui/ing/index.tsx +++ b/ui/ing/index.tsx @@ -1,5 +1,5 @@ +import './index.less' import { App } from 'ing/App' import ReactDOM from 'react-dom' -import './index.less' ReactDOM.render(, document.getElementById('root')) diff --git a/ui/post-cfg/App.tsx b/ui/post-cfg/App.tsx index f1c08239..38a41562 100644 --- a/ui/post-cfg/App.tsx +++ b/ui/post-cfg/App.tsx @@ -1,17 +1,17 @@ -import { Breadcrumb, IBreadcrumbItem, initializeIcons, PartialTheme, Spinner, Stack, Theme } from '@fluentui/react' +import React, { Component } from 'react' import { ThemeProvider } from '@fluentui/react/lib/Theme' +import { Theme, PartialTheme, Stack, Breadcrumb, IBreadcrumbItem, Spinner, initializeIcons } from '@fluentui/react' +import { PostForm } from './components/PostForm' import { Post } from '@models/post' -import { WebviewCmd } from '@models/webview-cmd' +import { personalCategoriesStore } from './services/personal-categories-store' +import { siteCategoriesStore } from './services/site-categories-store' +import { tagsStore } from './services/tags-store' import { webviewMessage } from '@models/webview-msg' -import React, { Component } from 'react' +import { WebviewCmd } from '@models/webview-cmd' +import { PostFormContextProvider } from './components/PostFormContextProvider' import { activeThemeProvider } from 'share/active-theme-provider' import { darkTheme, lightTheme } from 'share/theme' import { getVsCodeApiSingleton } from 'share/vscode-api' -import { PostForm } from './components/PostForm' -import { PostFormContextProvider } from './components/PostFormContextProvider' -import { personalCategoriesStore } from './services/personal-categories-store' -import { siteCategoriesStore } from './services/site-categories-store' -import { tagsStore } from './services/tags-store' interface AppState { post?: Post diff --git a/ui/post-cfg/components/InputSummary.tsx b/ui/post-cfg/components/InputSummary.tsx index 52334f9e..9848ff9c 100644 --- a/ui/post-cfg/components/InputSummary.tsx +++ b/ui/post-cfg/components/InputSummary.tsx @@ -1,4 +1,4 @@ -import { ActionButton, Label, MessageBar, MessageBarType, Stack, Text, TextField } from '@fluentui/react' +import { ActionButton, Label, MessageBar, MessageBarType, Stack, TextField, Text } from '@fluentui/react' import { ImageUploadStatusId } from '@models/image-upload-status' import { WebviewCmd } from '@models/webview-cmd' import { webviewMessage } from '@models/webview-msg' diff --git a/ui/post-cfg/components/PostForm.tsx b/ui/post-cfg/components/PostForm.tsx index 5887dea9..446c9349 100644 --- a/ui/post-cfg/components/PostForm.tsx +++ b/ui/post-cfg/components/PostForm.tsx @@ -1,25 +1,25 @@ -import { Label, Spinner } from '@fluentui/react' import { DefaultButton, PrimaryButton } from '@fluentui/react/lib/Button' import { Stack } from '@fluentui/react/lib/Stack' -import { Post } from '@models/post' -import { PostCfg } from '@models/post-cfg' -import { WebviewCmd } from '@models/webview-cmd' -import { webviewMessage } from '@models/webview-msg' -import NestCategoriesSelect from 'post-cfg/components/NestCategoriesSelect' -import PostTitleInput from 'post-cfg/components/PostTitleInput' import React from 'react' -import { getVsCodeApiSingleton } from '../../share/vscode-api' -import { AccessPermissionSelector } from './AccessPermissionSelector' import { CategoriesSelect } from './CategoriesSelect' +import { SiteHomeContributionOptionsSelector } from './SiteHomeContributionOptionsSelector' +import { PostCfg } from '@models/post-cfg' +import { Post } from '@models/post' +import { Label, Spinner } from '@fluentui/react' +import { SiteCategoriesSelector } from './SiteCategoriesSelector' +import { TagsInput } from './TagsInput' import { CommonOptions } from './CommonOptions' +import { AccessPermissionSelector } from './AccessPermissionSelector' +import { PasswordInput } from './PasswordInput' +import { getVsCodeApiSingleton } from '../../share/vscode-api' import { ErrorResponse } from './ErrorResponse' +import { WebviewCmd } from '@models/webview-cmd' +import { webviewMessage } from '@models/webview-msg' import { InputSummary } from './InputSummary' -import { PasswordInput } from './PasswordInput' -import PostEntryNameInput from './PostEntryNameInput' import { IPostFormContext, PostFormContext } from './PostFormContext' -import { SiteCategoriesSelector } from './SiteCategoriesSelector' -import { SiteHomeContributionOptionsSelector } from './SiteHomeContributionOptionsSelector' -import { TagsInput } from './TagsInput' +import PostEntryNameInput from './PostEntryNameInput' +import PostTitleInput from 'post-cfg/components/PostTitleInput' +import NestCategoriesSelect from 'post-cfg/components/NestCategoriesSelect' export interface IPostFormProps { post?: Post diff --git a/ui/post-cfg/components/PostFormContextProvider.tsx b/ui/post-cfg/components/PostFormContextProvider.tsx index e9b2fc5e..b441f66f 100644 --- a/ui/post-cfg/components/PostFormContextProvider.tsx +++ b/ui/post-cfg/components/PostFormContextProvider.tsx @@ -1,5 +1,5 @@ import * as React from 'react' -import { defaultPostFormContext, IPostFormContext, PostFormContext } from './PostFormContext' +import { PostFormContext, IPostFormContext, defaultPostFormContext } from './PostFormContext' export interface IPostFormContextProviderProps { value?: Partial diff --git a/ui/post-cfg/components/SiteHomeContributionOptionsSelector.tsx b/ui/post-cfg/components/SiteHomeContributionOptionsSelector.tsx index 101a64f8..3edc75f1 100644 --- a/ui/post-cfg/components/SiteHomeContributionOptionsSelector.tsx +++ b/ui/post-cfg/components/SiteHomeContributionOptionsSelector.tsx @@ -1,8 +1,8 @@ -import { ActionButton, Checkbox, Label } from '@fluentui/react' -import { Stack } from '@fluentui/react/lib/Stack' -import { Text } from '@fluentui/react/lib/Text' import React from 'react' import { SiteHomeContributionOptions as ISiteHomeContributionOptions } from '../models/site-home-contribution-options' +import { Text } from '@fluentui/react/lib/Text' +import { Stack } from '@fluentui/react/lib/Stack' +import { ActionButton, Checkbox, Label } from '@fluentui/react' export interface ISiteHomeContributionOptionsSelectorProps extends ISiteHomeContributionOptions { onInSiteHomeChange: (value: boolean) => void diff --git a/ui/post-cfg/components/TagsInput.tsx b/ui/post-cfg/components/TagsInput.tsx index 369a6e41..d158fb01 100644 --- a/ui/post-cfg/components/TagsInput.tsx +++ b/ui/post-cfg/components/TagsInput.tsx @@ -7,12 +7,12 @@ import { TagItem, TagItemSuggestion, TagPicker, - Text, ValidationState, + Text, } from '@fluentui/react' -import { PostTag, PostTags } from '@models/post-tag' import React from 'react' import { tagsStore } from '../services/tags-store' +import { PostTags, PostTag } from '@models/post-tag' export interface ITagsInputProps { selectedTagNames?: string[] diff --git a/ui/post-cfg/index.tsx b/ui/post-cfg/index.tsx index 66328cea..55693c10 100644 --- a/ui/post-cfg/index.tsx +++ b/ui/post-cfg/index.tsx @@ -1,5 +1,5 @@ -import ReactDOM from 'react-dom' -import { App } from './App' import './index.less' +import { App } from './App' +import ReactDOM from 'react-dom' ReactDOM.render(, document.getElementById('root')) diff --git a/ui/post-cfg/services/personal-categories-store.ts b/ui/post-cfg/services/personal-categories-store.ts index 24702a5f..c22cf8d0 100644 --- a/ui/post-cfg/services/personal-categories-store.ts +++ b/ui/post-cfg/services/personal-categories-store.ts @@ -1,5 +1,5 @@ import { PostCategories } from '@/models/post-category' -import { WebviewCmd, WebviewCommonCmd } from '@models/webview-cmd' +import { WebviewCommonCmd, WebviewCmd } from '@models/webview-cmd' import { getVsCodeApiSingleton } from 'share/vscode-api' let children: Map diff --git a/ui/webpack.config.mjs b/ui/webpack.config.mjs index 1f7a55a2..4ff12f76 100644 --- a/ui/webpack.config.mjs +++ b/ui/webpack.config.mjs @@ -1,12 +1,12 @@ /* eslint-disable @typescript-eslint/no-unsafe-call */ /* eslint-disable no-undef */ /* eslint-disable @typescript-eslint/naming-convention */ -import { cpSync, existsSync, readdirSync, rmSync } from 'fs' import MiniCssExtractPlugin from 'mini-css-extract-plugin' +import { rmSync, readdirSync, cpSync, existsSync } from 'fs' import { resolve } from 'path' -import TerserPlugin from 'terser-webpack-plugin' -import TsconfigPathsPlugin from 'tsconfig-paths-webpack-plugin' import tailwindConfig from './tailwind.config.js' +import TsconfigPathsPlugin from 'tsconfig-paths-webpack-plugin' +import TerserPlugin from 'terser-webpack-plugin' const isDevEnv = process.env.ASPNETCORE_ENVIRONMENT === 'Development' || process.env.NODE_ENV === 'development' diff --git a/webpack.config.mjs b/webpack.config.mjs index 43e3ef0b..3f56b22b 100644 --- a/webpack.config.mjs +++ b/webpack.config.mjs @@ -4,8 +4,8 @@ 'use strict' -import CopyWebpackPlugin from 'copy-webpack-plugin' import path from 'path' +import CopyWebpackPlugin from 'copy-webpack-plugin' import { TsconfigPathsPlugin } from 'tsconfig-paths-webpack-plugin' import { fileURLToPath } from 'url' import webpack from 'webpack' From adef84b41e6984a8b55ccd0ca5a7066f205d7958 Mon Sep 17 00:00:00 2001 From: Thaumy Date: Thu, 20 Jul 2023 18:10:50 +0800 Subject: [PATCH 009/157] fix: fix cmd exec failed when ext init --- src/utils/cmd.ts | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/utils/cmd.ts b/src/utils/cmd.ts index e2bffe75..c734127f 100644 --- a/src/utils/cmd.ts +++ b/src/utils/cmd.ts @@ -1,9 +1,5 @@ import { commands } from 'vscode' -export function regCmd(cmd: string, f: (...args: any[]) => any) { - return commands.registerCommand(cmd, f) -} +export const regCmd = commands.registerCommand -export function execCmd(cmd: string, ...rest: any[]) { - return commands.executeCommand(cmd, rest) -} +export const execCmd = commands.executeCommand From ae7c587d7f234160f7d7a8b1572c6997cc93c9aa Mon Sep 17 00:00:00 2001 From: Thaumy Date: Thu, 20 Jul 2023 18:16:48 +0800 Subject: [PATCH 010/157] chore: rename `AlertService` to `Alert` --- src/auth/account-manager.ts | 6 +++--- src/commands/blog-export/create.ts | 6 +++--- src/commands/blog-export/delete.ts | 4 ++-- src/commands/blog-export/download.ts | 4 ++-- src/commands/blog-export/edit.ts | 4 ++-- src/commands/blog-export/open-local.ts | 8 ++++---- src/commands/extract-images.ts | 8 ++++---- src/commands/ing/publish-ing.ts | 8 ++++---- src/commands/open-workspace.ts | 4 ++-- src/commands/pdf/export-pdf.command.ts | 8 ++++---- .../delete-selected-categories.ts | 6 +++--- .../post-category/new-post-category.ts | 4 ++-- src/commands/posts-list/copy-link.ts | 4 ++-- .../delete-post-to-local-file-map.ts | 4 ++-- src/commands/posts-list/delete-post.ts | 8 ++++---- .../posts-list/modify-post-settings.ts | 6 +++--- .../posts-list/open-post-in-vscode.ts | 6 +++--- src/commands/posts-list/refresh-posts-list.ts | 6 +++--- src/commands/posts-list/rename-post.ts | 6 +++--- src/commands/posts-list/upload-post.ts | 20 +++++++++---------- src/commands/pull-post-remote-updates.ts | 8 ++++---- src/commands/set-workspace.ts | 4 ++-- src/commands/show-local-file-to-post-info.ts | 10 +++++----- .../upload-image/upload-clipboard-image.ts | 4 ++-- .../upload-image/upload-image-utils.ts | 4 ++-- src/commands/upload-image/upload-image.ts | 6 +++--- src/services/alert.service.ts | 8 ++++---- src/services/ing.api.ts | 20 +++++++++---------- src/services/post.service.ts | 6 +++--- src/test/suite/extension.test.ts | 4 ++-- .../blog-export-provider.ts | 4 ++-- .../post-categories-tree-data-provider.ts | 4 ++-- .../posts-data-provider.ts | 6 +++--- src/utils/chromium-path-provider.ts | 4 ++-- src/utils/get-clipboard-image.ts | 4 ++-- src/utils/input-post-settings.ts | 4 ++-- 36 files changed, 115 insertions(+), 115 deletions(-) diff --git a/src/auth/account-manager.ts b/src/auth/account-manager.ts index 5829ba86..175fbb51 100644 --- a/src/auth/account-manager.ts +++ b/src/auth/account-manager.ts @@ -8,7 +8,7 @@ import { Oauth } from '@/services/oauth.api' import { AuthProvider } from '@/auth/auth-provider' import { AuthSession } from '@/auth/auth-session' import { BlogExportProvider } from '@/tree-view-providers/blog-export-provider' -import { AlertService } from '@/services/alert.service' +import { Alert } from '@/services/alert.service' import { execCmd } from '@/utils/cmd' const isAuthorizedStorageKey = 'isAuthorized' @@ -81,7 +81,7 @@ class AccountManager extends vscode.Disposable { await AuthProvider.instance.removeSession(session.id) await Oauth.revokeToken(session.accessToken) } catch (e: any) { - AlertService.err(`登出发生错误: ${e}`) + Alert.err(`登出发生错误: ${e}`) } } @@ -102,7 +102,7 @@ class AccountManager extends vscode.Disposable { const session = await authentication.getSession(AuthProvider.instance.providerId, [], opt).then( session => (session ? AuthSession.from(session) : null), e => { - AlertService.err(`创建/获取 Session 失败: ${e}`) + Alert.err(`创建/获取 Session 失败: ${e}`) } ) diff --git a/src/commands/blog-export/create.ts b/src/commands/blog-export/create.ts index cb71ef00..3f60da34 100644 --- a/src/commands/blog-export/create.ts +++ b/src/commands/blog-export/create.ts @@ -1,5 +1,5 @@ import { CmdHandler } from '@/commands/cmd-handler' -import { AlertService } from '@/services/alert.service' +import { Alert } from '@/services/alert.service' import { BlogExportApi } from '@/services/blog-export.api' import { BlogExportProvider } from '@/tree-view-providers/blog-export-provider' import { MessageItem, window } from 'vscode' @@ -12,7 +12,7 @@ export class CreateBlogExportCmdHandler extends CmdHandler { if ( (await BlogExportApi.create().catch((e: unknown) => { - AlertService.httpErr(typeof e === 'object' && e ? e : {}, { message: '创建博客备份失败' }) + Alert.httpErr(typeof e === 'object' && e ? e : {}, { message: '创建博客备份失败' }) return false })) !== false ) @@ -21,7 +21,7 @@ export class CreateBlogExportCmdHandler extends CmdHandler { private async confirm(): Promise { const items: MessageItem[] = [{ title: '确定', isCloseAffordance: false }] - const result = await AlertService.info( + const result = await Alert.info( '确定要创建备份吗?', { modal: true, detail: '一天可以创建一次备份' }, ...items diff --git a/src/commands/blog-export/delete.ts b/src/commands/blog-export/delete.ts index 66d7a5de..14c1cccd 100644 --- a/src/commands/blog-export/delete.ts +++ b/src/commands/blog-export/delete.ts @@ -1,6 +1,6 @@ import { TreeViewCmdHandler } from '@/commands/cmd-handler' import { DownloadedBlogExport } from '@/models/blog-export' -import { AlertService } from '@/services/alert.service' +import { Alert } from '@/services/alert.service' import { BlogExportApi } from '@/services/blog-export.api' import { DownloadedExportStore } from '@/services/downloaded-export.store' import { BlogExportProvider } from '@/tree-view-providers/blog-export-provider' @@ -86,7 +86,7 @@ export class DeleteCmdHandler extends TreeViewCmdHandler true) .catch((e: unknown) => { - AlertService.httpErr(typeof e === 'object' && e != null ? e : {}) + Alert.httpErr(typeof e === 'object' && e != null ? e : {}) return false }) if (hasDeleted) if (downloaded) await this.removeDownloadedBlogExport(downloaded, { shouldDeleteLocal }) diff --git a/src/commands/blog-export/download.ts b/src/commands/blog-export/download.ts index edb54bee..f3a01446 100644 --- a/src/commands/blog-export/download.ts +++ b/src/commands/blog-export/download.ts @@ -1,5 +1,5 @@ import { TreeViewCmdHandler } from '@/commands/cmd-handler' -import { AlertService } from '@/services/alert.service' +import { Alert } from '@/services/alert.service' import { BlogExportApi } from '@/services/blog-export.api' import { DownloadedExportStore } from '@/services/downloaded-export.store' import { globalCtx } from '@/services/global-ctx' @@ -47,7 +47,7 @@ export class DownloadExportCmdHandler extends TreeViewCmdHandler { - if (msg) AlertService.warn(msg) + if (msg) Alert.warn(msg) if (!isFileExist) fs.rmSync(zipFilePath) blogExportProvider?.refreshItem(treeItem) this.setIsDownloading(false).then(undefined, console.warn) diff --git a/src/commands/blog-export/edit.ts b/src/commands/blog-export/edit.ts index d65f8c19..23c12389 100644 --- a/src/commands/blog-export/edit.ts +++ b/src/commands/blog-export/edit.ts @@ -1,6 +1,6 @@ import { TreeViewCmdHandler } from '@/commands/cmd-handler' import { openPostFile } from '@/commands/posts-list/open-post-file' -import { AlertService } from '@/services/alert.service' +import { Alert } from '@/services/alert.service' import { Settings } from '@/services/settings.service' import { ExportPostTreeItem } from '@/tree-view-providers/models/blog-export/post' import fs from 'fs' @@ -21,7 +21,7 @@ export class EditExportPostCmdHandler extends TreeViewCmdHandler { const target = this.parseInput() - if (!target) return void AlertService.warn('不支持的参数输入') + if (!target) return void Alert.warn('不支持的参数输入') const { post: { title, isMarkdown, id: postId }, diff --git a/src/commands/blog-export/open-local.ts b/src/commands/blog-export/open-local.ts index ed46ea9e..c2d29db1 100644 --- a/src/commands/blog-export/open-local.ts +++ b/src/commands/blog-export/open-local.ts @@ -3,7 +3,7 @@ import { window } from 'vscode' import path from 'path' import fs from 'fs' import { promisify } from 'util' -import { AlertService } from '@/services/alert.service' +import { Alert } from '@/services/alert.service' import { DownloadedExportStore } from '@/services/downloaded-export.store' import { BlogExportProvider } from '@/tree-view-providers/blog-export-provider' @@ -29,7 +29,7 @@ export class OpenLocalExportCmdHandler extends CmdHandler { if (fileUri == null) return const filePath = fileUri.fsPath if (filePath.endsWith('.zip') && !filePath.endsWith('.db.zip')) - return void AlertService.warn('不支持的博客备份文件') + return void Alert.warn('不支持的博客备份文件') const fileName = path.basename(filePath.replace(/\.db(\.zip)?$/, '')) const dirname = path.dirname(filePath) @@ -37,7 +37,7 @@ export class OpenLocalExportCmdHandler extends CmdHandler { isConfirmedToUnzip = filePath.endsWith('.db.zip') // if (!confirmUnzip && fileUri.fsPath.endsWith('db.zip')) { // const options: (MessageItem & { confirmed: boolean })[] = [{ title: '确定', confirmed: true }]; - // const selected = await AlertService.info( + // const selected = await Alert.info( // '浏览博客备份需要解决, 确定要解压吗?', // { modal: true }, // ...options @@ -56,7 +56,7 @@ export class OpenLocalExportCmdHandler extends CmdHandler { const dbFileName = path.basename(dbFilePath) const isExist = await promisify(fs.exists)(dbFilePath) - if (!isExist) return void AlertService.warn('文件不存在') + if (!isExist) return void Alert.warn('文件不存在') const treeProvider = BlogExportProvider.optionalInstance const dbFileSize = (await promisify(fs.stat)(dbFilePath)).size diff --git a/src/commands/extract-images.ts b/src/commands/extract-images.ts index 6c1066e8..0125ab78 100644 --- a/src/commands/extract-images.ts +++ b/src/commands/extract-images.ts @@ -1,6 +1,6 @@ import { MessageItem, MessageOptions, ProgressLocation, Range, Uri, window, workspace, WorkspaceEdit } from 'vscode' import { ImageInfo, ImageSrc, MkdImgExtractor, newImageSrcFilter } from '@/services/mkd-img-extractor.service' -import { AlertService } from '@/services/alert.service' +import { Alert } from '@/services/alert.service' type ExtractOption = MessageItem & Partial<{ imageSrc: ImageSrc }> @@ -17,7 +17,7 @@ export async function extractImages(arg: unknown, inputImageSrc?: ImageSrc) { const extractor = new MkdImgExtractor(markdown, arg) const images = extractor.findImages() - if (images.length <= 0) void (!inputImageSrc != null ? AlertService.warn('没有找到可以提取的图片') : undefined) + if (images.length <= 0) void (!inputImageSrc != null ? Alert.warn('没有找到可以提取的图片') : undefined) const getExtractOption = () => { const webImgCount = images.filter(newImageSrcFilter(ImageSrc.web)).length @@ -36,7 +36,7 @@ export async function extractImages(arg: unknown, inputImageSrc?: ImageSrc) { return Promise.resolve(displayOptions.find(ent => ent.imageSrc === inputImageSrc)) // if src is not specified: - return AlertService.info( + return Alert.info( '要提取哪些图片? 此操作会替换源文件中的图片链接!', { modal: true, @@ -113,6 +113,6 @@ export async function extractImages(arg: unknown, inputImageSrc?: ImageSrc) { const info = failedImages .map(info => [info.data, extractor.errors.find(([link]) => link === info.data)?.[1] ?? ''].join(',')) .join('\n') - AlertService.err(`${failedImages.length} 张图片提取失败: ${info}`).then(undefined, console.warn) + Alert.err(`${failedImages.length} 张图片提取失败: ${info}`).then(undefined, console.warn) } } diff --git a/src/commands/ing/publish-ing.ts b/src/commands/ing/publish-ing.ts index 955ecd49..da06df9b 100644 --- a/src/commands/ing/publish-ing.ts +++ b/src/commands/ing/publish-ing.ts @@ -1,7 +1,7 @@ import { CmdHandler } from '@/commands/cmd-handler' import { execCmd } from '@/utils/cmd' import { IngPublishModel, IngType } from '@/models/ing' -import { AlertService } from '@/services/alert.service' +import { Alert } from '@/services/alert.service' import { globalCtx } from '@/services/global-ctx' import { IngApi } from '@/services/ing.api' import { IngsListWebviewProvider } from '@/services/ings-list-webview-provider' @@ -134,7 +134,7 @@ export class PublishIngCmdHandler extends CmdHandler { ['编辑访问权限', async () => (await this.acquireInputContent(this.inputStep.access)) !== false], ['编辑标签', async () => (await this.acquireInputContent(this.inputStep.tags)) !== false], ] as const - const selected = await AlertService.info( + const selected = await Alert.info( '确定要发布闪存吗?', { modal: true, @@ -146,7 +146,7 @@ export class PublishIngCmdHandler extends CmdHandler { } private warnNoSelection() { - AlertService.warn(`无法${this.operation}, 当前没有选中的内容`) + Alert.warn(`无法${this.operation}, 当前没有选中的内容`) } private async onPublished(isPublished: boolean): Promise { @@ -175,7 +175,7 @@ export class PublishIngCmdHandler extends CmdHandler { (): Thenable => execCmd('vscode.open', Uri.parse(globalCtx.config.ingSite + '/#mention')), ], ] as const - const option = await AlertService.info( + const option = await Alert.info( '闪存已发布, 快去看看吧', { modal: false }, ...options.map(v => ({ title: v[0], id: v[0] })) diff --git a/src/commands/open-workspace.ts b/src/commands/open-workspace.ts index 0104111d..9920c7fc 100644 --- a/src/commands/open-workspace.ts +++ b/src/commands/open-workspace.ts @@ -1,13 +1,13 @@ import { MessageOptions } from 'vscode' import { Settings } from '@/services/settings.service' import { execCmd } from '@/utils/cmd' -import { AlertService } from '@/services/alert.service' +import { Alert } from '@/services/alert.service' export const openWorkspace = async () => { const uri = Settings.workspaceUri const { fsPath } = uri const options = ['在当前窗口中打开', '在新窗口中打开'] - const input = await AlertService.info(`即将打开 ${fsPath}`, { modal: true } as MessageOptions, ...options) + const input = await Alert.info(`即将打开 ${fsPath}`, { modal: true } as MessageOptions, ...options) if (!input) return const shouldOpenInNewWindow = input === options[1] diff --git a/src/commands/pdf/export-pdf.command.ts b/src/commands/pdf/export-pdf.command.ts index e2180db2..0da3224d 100644 --- a/src/commands/pdf/export-pdf.command.ts +++ b/src/commands/pdf/export-pdf.command.ts @@ -10,7 +10,7 @@ import { extViews } from '@/tree-view-providers/tree-view-registration' import { chromiumPathProvider } from '@/utils/chromium-path-provider' import { Settings } from '@/services/settings.service' import { accountManager } from '@/auth/account-manager' -import { AlertService } from '@/services/alert.service' +import { Alert } from '@/services/alert.service' import { PostTreeItem } from '@/tree-view-providers/models/post-tree-item' import { PostEditDto } from '@/models/post-edit-dto' import { postPdfTemplateBuilder } from '@/commands/pdf/post-pdf-template-builder' @@ -114,7 +114,7 @@ const retrieveChromiumPath = async (): Promise => { if (!path) { const { Options: options } = chromiumPathProvider - const input = await AlertService.warn( + const input = await Alert.warn( '未找到Chromium可执行文件', { modal: true, @@ -175,7 +175,7 @@ const mapToPostEditDto = async (posts: Post[]) => const reportErrors = (errors: string[] | undefined) => { if (errors && errors.length > 0) { - void AlertService.err('导出 PDF 时遇到错误', { + void Alert.err('导出 PDF 时遇到错误', { modal: true, detail: errors.join('\n'), } as MessageOptions) @@ -192,7 +192,7 @@ const exportPostToPdf = async (input: Post | PostTreeItem | Uri | unknown): Prom currentUser: { blogApp }, } = accountManager - if (!blogApp) return void AlertService.warn('无法获取到博客地址, 请检查登录状态') + if (!blogApp) return void Alert.warn('无法获取到博客地址, 请检查登录状态') reportErrors( await window.withProgress( diff --git a/src/commands/post-category/delete-selected-categories.ts b/src/commands/post-category/delete-selected-categories.ts index 9f08622a..e96494f4 100644 --- a/src/commands/post-category/delete-selected-categories.ts +++ b/src/commands/post-category/delete-selected-categories.ts @@ -4,7 +4,7 @@ import { postCategoryService } from '@/services/post-category.service' import { PostCategoriesListTreeItem } from '@/tree-view-providers/models/categories-list-tree-item' import { BaseMultiSelectablePostCategoryTreeViewCmdHandler } from './base-tree-view-cmd-handler' import { refreshPostCategoriesList } from './refresh-post-categories-list' -import { AlertService } from '@/services/alert.service' +import { Alert } from '@/services/alert.service' export class DeletePostCategoriesHandler extends BaseMultiSelectablePostCategoryTreeViewCmdHandler { constructor(input: PostCategoriesListTreeItem) { @@ -45,7 +45,7 @@ export class DeletePostCategoriesHandler extends BaseMultiSelectablePostCategory p.report({ increment: 100 }) if (errs.length > 0) { - await AlertService.err('删除博文分类时发生了一些错误', { + await Alert.err('删除博文分类时发生了一些错误', { detail: errs .map( err => @@ -63,7 +63,7 @@ export class DeletePostCategoriesHandler extends BaseMultiSelectablePostCategory private async confirm() { const options = ['确定'] - const clicked = await AlertService.warn( + const clicked = await Alert.warn( '确定要删除这些博文分类吗', { detail: `${this.selections.map(x => `📂${x.title}`).join(', ')} 将被永久删除! 请谨慎操作!`, diff --git a/src/commands/post-category/new-post-category.ts b/src/commands/post-category/new-post-category.ts index 2a9c923b..6afcf060 100644 --- a/src/commands/post-category/new-post-category.ts +++ b/src/commands/post-category/new-post-category.ts @@ -3,7 +3,7 @@ import { postCategoryService } from '@/services/post-category.service' import { extViews } from '@/tree-view-providers/tree-view-registration' import { inputPostCategory } from './input-post-category' import { refreshPostCategoriesList } from './refresh-post-categories-list' -import { AlertService } from '@/services/alert.service' +import { Alert } from '@/services/alert.service' export const newPostCategory = async () => { const input = await inputPostCategory({ @@ -29,7 +29,7 @@ export const newPostCategory = async () => { const newCategory = (await postCategoryService.listCategories()).find(x => x.title === input.title) if (newCategory) await extViews.postCategoriesList.reveal(newCategory) } catch (err) { - void AlertService.err('新建博文分类时遇到了错误', { + void Alert.err('新建博文分类时遇到了错误', { modal: true, detail: `服务器反回了错误\n${err instanceof Error ? err.message : JSON.stringify(err)}`, } as MessageOptions) diff --git a/src/commands/posts-list/copy-link.ts b/src/commands/posts-list/copy-link.ts index 5502d346..e02333e2 100644 --- a/src/commands/posts-list/copy-link.ts +++ b/src/commands/posts-list/copy-link.ts @@ -1,6 +1,6 @@ import { TreeViewCmdHandler } from '@/commands/cmd-handler' import { Post } from '@/models/post' -import { AlertService } from '@/services/alert.service' +import { Alert } from '@/services/alert.service' import { PostFileMapManager } from '@/services/post-file-map' import { PostService } from '@/services/post.service' import { PostTreeItem } from '@/tree-view-providers/models/post-tree-item' @@ -53,7 +53,7 @@ export class CopyPostLinkCmdHandler extends TreeViewCmdHandler void AlertService.fileNotLinkedToPost(input)) + ? Promise.resolve(undefined).then(() => void Alert.fileNotLinkedToPost(input)) : PostService.fetchPostEditDto(postId).then(v => v?.post) } diff --git a/src/commands/posts-list/delete-post-to-local-file-map.ts b/src/commands/posts-list/delete-post-to-local-file-map.ts index 0f2b861e..0786a92b 100644 --- a/src/commands/posts-list/delete-post-to-local-file-map.ts +++ b/src/commands/posts-list/delete-post-to-local-file-map.ts @@ -4,11 +4,11 @@ import { PostFileMap, PostFileMapManager } from '@/services/post-file-map' import { revealPostsListItem } from '@/services/posts-list-view' import { PostTreeItem } from '@/tree-view-providers/models/post-tree-item' import { extViews } from '@/tree-view-providers/tree-view-registration' -import { AlertService } from '@/services/alert.service' +import { Alert } from '@/services/alert.service' const confirm = async (posts: Post[]): Promise => { const options = ['确定'] - const input = await AlertService.info( + const input = await Alert.info( '确定要取消这些博文与本地文件的关联吗?', { detail: posts.map(x => x.title).join(', '), diff --git a/src/commands/posts-list/delete-post.ts b/src/commands/posts-list/delete-post.ts index cd204ab7..e00a2fd1 100644 --- a/src/commands/posts-list/delete-post.ts +++ b/src/commands/posts-list/delete-post.ts @@ -1,6 +1,6 @@ import { MessageOptions, ProgressLocation, Uri, window, workspace } from 'vscode' import { Post } from '@/models/post' -import { AlertService } from '@/services/alert.service' +import { Alert } from '@/services/alert.service' import { PostService } from '@/services/post.service' import { PostFileMap, PostFileMapManager } from '@/services/post-file-map' import { postsDataProvider } from '@/tree-view-providers/posts-data-provider' @@ -18,7 +18,7 @@ const confirmDelete = async ( if (!selectedPosts || selectedPosts.length <= 0) return result const items = ['确定(保留本地文件)', '确定(同时删除本地文件)'] - const clicked = await AlertService.warn( + const clicked = await Alert.warn( '确定要删除吗?', { detail: `确认后将会删除 ${selectedPosts.map(x => x.title).join(', ')} 这${selectedPosts.length}篇博文吗?`, @@ -55,7 +55,7 @@ export const deleteSelectedPosts = async (arg: unknown) => { if (selectedPosts.length <= 0) return if (isDeleting) { - AlertService.warn('休息会儿再点吧~') + Alert.warn('休息会儿再点吧~') return } @@ -91,7 +91,7 @@ export const deleteSelectedPosts = async (arg: unknown) => { postIds: selectedPosts.map(({ id }) => id), }) } catch (err) { - void AlertService.err('删除博文失败', { + void Alert.err('删除博文失败', { detail: `服务器返回了错误, ${err instanceof Error ? err.message : JSON.stringify(err)}`, } as MessageOptions) } finally { diff --git a/src/commands/posts-list/modify-post-settings.ts b/src/commands/posts-list/modify-post-settings.ts index eaa0b653..3f102a8a 100644 --- a/src/commands/posts-list/modify-post-settings.ts +++ b/src/commands/posts-list/modify-post-settings.ts @@ -1,6 +1,6 @@ import { Uri } from 'vscode' import { Post } from '@/models/post' -import { AlertService } from '@/services/alert.service' +import { Alert } from '@/services/alert.service' import { PostService } from '@/services/post.service' import { PostFileMapManager } from '@/services/post-file-map' import { revealPostsListItem } from '@/services/posts-list-view' @@ -22,7 +22,7 @@ export const modifyPostSettings = async (input: Post | PostTreeItem | Uri) => { postId = input.id } else if (input instanceof Uri) { postId = PostFileMapManager.getPostId(input.fsPath) ?? -1 - if (postId < 0) return AlertService.fileNotLinkedToPost(input) + if (postId < 0) return Alert.fileNotLinkedToPost(input) } if (!(postId >= 0)) return @@ -40,7 +40,7 @@ export const modifyPostSettings = async (input: Post | PostTreeItem | Uri) => { post: postEditDto, localFileUri: localFilePath ? Uri.file(localFilePath) : undefined, successCallback: ({ id }) => { - AlertService.info('博文已更新') + Alert.info('博文已更新') postsDataProvider.fireTreeDataChangedEvent(id) postCategoriesDataProvider.onPostUpdated({ refreshPosts: false, postIds: [id] }) }, diff --git a/src/commands/posts-list/open-post-in-vscode.ts b/src/commands/posts-list/open-post-in-vscode.ts index efa8c1b9..8b33a2ad 100644 --- a/src/commands/posts-list/open-post-in-vscode.ts +++ b/src/commands/posts-list/open-post-in-vscode.ts @@ -2,7 +2,7 @@ import fs from 'fs' import path from 'path' import { FileSystemError, MessageOptions, Uri, window, workspace } from 'vscode' import { Post } from '@/models/post' -import { AlertService } from '@/services/alert.service' +import { Alert } from '@/services/alert.service' import { PostService } from '@/services/post.service' import { PostFileMapManager } from '@/services/post-file-map' import { Settings } from '@/services/settings.service' @@ -68,7 +68,7 @@ export const openPostInVscode = async (postId: number, forceUpdateLocalPostFile '保留本地文件(这会新建另一个文件名中包含博文id的文件)', '覆盖本地文件(会导致本地文件中内容丢失)', ] - const selectedOption = await AlertService.info( + const selectedOption = await Alert.info( `无法新建博文与本地文件的关联, 文件名冲突`, { detail: `本地已存在名为"${path.basename(fileUri.fsPath)}"的文件`, modal: true } as MessageOptions, ...conflictOptions @@ -97,7 +97,7 @@ const createDirectoryIfNotExist = async (uri: Uri) => { } catch (err) { if (err instanceof FileSystemError) await workspace.fs.createDirectory(uri) - AlertService.err('Create workspace directory failed') + Alert.err('Create workspace directory failed') console.error(err) } } diff --git a/src/commands/posts-list/refresh-posts-list.ts b/src/commands/posts-list/refresh-posts-list.ts index 5216cff2..4eed50fa 100644 --- a/src/commands/posts-list/refresh-posts-list.ts +++ b/src/commands/posts-list/refresh-posts-list.ts @@ -2,7 +2,7 @@ import { globalCtx } from '@/services/global-ctx' import { PostService } from '@/services/post.service' import vscode, { window } from 'vscode' import { postsDataProvider } from '@/tree-view-providers/posts-data-provider' -import { AlertService } from '@/services/alert.service' +import { Alert } from '@/services/alert.service' import { PostsListState } from '@/models/posts-list-state' import { extViews } from '@/tree-view-providers/tree-view-registration' import { execCmd } from '@/utils/cmd' @@ -33,7 +33,7 @@ export const refreshPostsList = async ({ queue = false } = {}): Promise ) .then(pagedPosts => { if (pagedPosts == null) { - return Promise.resolve(false).finally(() => AlertService.err('刷新博文列表失败')) + return Promise.resolve(false).finally(() => Alert.err('刷新博文列表失败')) } else { return PostService.updatePostsListState(pagedPosts) .then(() => updatePostsListViewTitle()) @@ -92,7 +92,7 @@ const setPostListContext = async (pageCount: number, hasPrevious: boolean, hasNe } const alertRefreshing = () => { - AlertService.info('正在刷新, 请勿重复操作') + Alert.info('正在刷新, 请勿重复操作') } const gotoPage = async (pageIndex: (currentIndex: number) => number) => { diff --git a/src/commands/posts-list/rename-post.ts b/src/commands/posts-list/rename-post.ts index 0c752ad3..5b87bb63 100644 --- a/src/commands/posts-list/rename-post.ts +++ b/src/commands/posts-list/rename-post.ts @@ -7,7 +7,7 @@ import { PostFileMapManager } from '@/services/post-file-map' import { postsDataProvider } from '@/tree-view-providers/posts-data-provider' import { revealPostsListItem } from '@/services/posts-list-view' import { PostTreeItem } from '@/tree-view-providers/models/post-tree-item' -import { AlertService } from '@/services/alert.service' +import { Alert } from '@/services/alert.service' const renameLinkedFile = async (post: Post): Promise => { const filePath = PostFileMapManager.getFilePath(post.id) @@ -17,7 +17,7 @@ const renameLinkedFile = async (post: Post): Promise => { const fileUri = Uri.file(filePath) const options = ['是'] - const input = await AlertService.info( + const input = await Alert.info( '重命名博文成功, 发现与博文关联的本地文件, 是否要重名本地文件', { modal: true, @@ -70,7 +70,7 @@ export const renamePost = async (arg: Post | PostTreeItem) => { postsDataProvider.fireTreeDataChangedEvent(post) hasUpdated = true } catch (err) { - void AlertService.err('更新博文失败', { + void Alert.err('更新博文失败', { modal: true, detail: err instanceof Error ? err.message : '服务器返回异常', } as MessageOptions) diff --git a/src/commands/posts-list/upload-post.ts b/src/commands/posts-list/upload-post.ts index 751af008..182a7b96 100644 --- a/src/commands/posts-list/upload-post.ts +++ b/src/commands/posts-list/upload-post.ts @@ -1,7 +1,7 @@ import vscode, { Uri, workspace, window, ProgressLocation, MessageOptions } from 'vscode' import { Post } from '@/models/post' import { LocalDraft } from '@/services/local-draft.service' -import { AlertService } from '@/services/alert.service' +import { Alert } from '@/services/alert.service' import { PostService } from '@/services/post.service' import { PostFileMapManager } from '@/services/post-file-map' import { postsDataProvider } from '@/tree-view-providers/posts-data-provider' @@ -44,7 +44,7 @@ export const uploadPostFileToCnblogs = async (fileUri: Uri | undefined) => { await uploadPostToCnblogs(await PostService.fetchPostEditDto(postId)) } else { const options = [`新建博文`, `关联已有博文`] - const selected = await AlertService.info( + const selected = await Alert.info( '本地文件尚未关联到博客园博文', { modal: true, @@ -84,7 +84,7 @@ export const saveLocalDraftToCnblogs = async (localDraft: LocalDraft) => { // check format if (!['.md'].some(x => localDraft.fileExt === x)) { - AlertService.warn('不受支持的文件格式! 只支持markdown格式') + Alert.warn('不受支持的文件格式! 只支持markdown格式') return } const editDto = await PostService.fetchPostEditTemplate() @@ -106,13 +106,13 @@ export const saveLocalDraftToCnblogs = async (localDraft: LocalDraft) => { await PostFileMapManager.updateOrCreate(savedPost.id, localDraft.filePath) await openPostFile(localDraft) postsDataProvider.fireTreeDataChangedEvent(undefined) - AlertService.info('博文已创建') + Alert.info('博文已创建') }, beforeUpdate: async (postToSave, panel) => { await saveFilePendingChanges(localDraft.filePath) // 本地文件已经被删除了 if (!localDraft.exist && panel) { - AlertService.warn('本地文件已删除, 无法新建博文') + Alert.warn('本地文件已删除, 无法新建博文') return false } if (Settings.automaticallyExtractImagesType) @@ -136,7 +136,7 @@ export const uploadPostToCnblogs = async (input: Post | PostTreeItem | PostEditD const { id: postId } = post const localFilePath = PostFileMapManager.getFilePath(postId) - if (!localFilePath) return AlertService.warn('本地无该博文的编辑记录') + if (!localFilePath) return Alert.warn('本地无该博文的编辑记录') if (Settings.automaticallyExtractImagesType) await extractImages(Uri.file(localFilePath), Settings.automaticallyExtractImagesType).catch(console.warn) @@ -148,7 +148,7 @@ export const uploadPostToCnblogs = async (input: Post | PostTreeItem | PostEditD if (!validatePost(post)) return false if (Settings.showConfirmMsgWhenUploadPost) { - const answer = await AlertService.warn( + const answer = await Alert.warn( '确认上传吗?', { modal: true, @@ -177,11 +177,11 @@ export const uploadPostToCnblogs = async (input: Post | PostTreeItem | PostEditD hasSaved = true progress.report({ increment: 100 }) - AlertService.info('上传成功') + Alert.info('上传成功') await refreshPostsList() } catch (err) { progress.report({ increment: 100 }) - AlertService.err(`上传失败\n${err instanceof Error ? err.message : JSON.stringify(err)}`) + Alert.err(`上传失败\n${err instanceof Error ? err.message : JSON.stringify(err)}`) console.error(err) } return hasSaved @@ -191,7 +191,7 @@ export const uploadPostToCnblogs = async (input: Post | PostTreeItem | PostEditD const validatePost = (post: Post): boolean => { if (!post.postBody) { - AlertService.warn('文件内容为空!') + Alert.warn('文件内容为空!') return false } diff --git a/src/commands/pull-post-remote-updates.ts b/src/commands/pull-post-remote-updates.ts index 0f1b5543..e63d72cc 100644 --- a/src/commands/pull-post-remote-updates.ts +++ b/src/commands/pull-post-remote-updates.ts @@ -4,7 +4,7 @@ import { PostFileMapManager } from '@/services/post-file-map' import { openPostInVscode } from './posts-list/open-post-in-vscode' import fs from 'fs' import { PostService } from '@/services/post.service' -import { AlertService } from '@/services/alert.service' +import { Alert } from '@/services/alert.service' import path from 'path' import { revealPostsListItem } from '@/services/posts-list-view' import { PostTreeItem } from '@/tree-view-providers/models/post-tree-item' @@ -18,7 +18,7 @@ const pullPostRemoteUpdates = async (input: Post | PostTreeItem | Uri | undefine else if ((uri = parseUriInput(input))) await handleUriInput(uri, ctxs) if (Settings.showConfirmMsgWhenPullPost) { - const answer = await AlertService.warn( + const answer = await Alert.warn( '确认要拉取远程博文吗?', { modal: true, @@ -33,7 +33,7 @@ const pullPostRemoteUpdates = async (input: Post | PostTreeItem | Uri | undefine await update(ctxs) - AlertService.info(`本地文件${resolveFileNames(ctxs)}已更新`) + Alert.info(`本地文件${resolveFileNames(ctxs)}已更新`) } export { pullPostRemoteUpdates } @@ -70,7 +70,7 @@ const parseUriInput = (input: InputType): Uri | undefined => { const handleUriInput = (fileUri: Uri, contexts: CmdCtx[]): Promise => { const postId = PostFileMapManager.getPostId(fileUri.fsPath) - if (!postId) return Promise.resolve().then(() => AlertService.fileNotLinkedToPost(fileUri)) + if (!postId) return Promise.resolve().then(() => Alert.fileNotLinkedToPost(fileUri)) contexts.push({ postId, fileUri }) return Promise.resolve() diff --git a/src/commands/set-workspace.ts b/src/commands/set-workspace.ts index 56898e36..fbd1c92e 100644 --- a/src/commands/set-workspace.ts +++ b/src/commands/set-workspace.ts @@ -1,5 +1,5 @@ import { window } from 'vscode' -import { AlertService } from '@/services/alert.service' +import { Alert } from '@/services/alert.service' import { Settings } from '@/services/settings.service' export const setWorkspace = async () => { @@ -14,5 +14,5 @@ export const setWorkspace = async () => { if (!input) return await Settings.setWorkspaceUri(input) - AlertService.info(`工作空间成功修改为: "${Settings.workspaceUri.fsPath}"`) + Alert.info(`工作空间成功修改为: "${Settings.workspaceUri.fsPath}"`) } diff --git a/src/commands/show-local-file-to-post-info.ts b/src/commands/show-local-file-to-post-info.ts index fe83db27..67b2fe58 100644 --- a/src/commands/show-local-file-to-post-info.ts +++ b/src/commands/show-local-file-to-post-info.ts @@ -1,6 +1,6 @@ import path from 'path' import { MessageOptions, Uri, window } from 'vscode' -import { AlertService } from '@/services/alert.service' +import { Alert } from '@/services/alert.service' import { PostService } from '@/services/post.service' import { postCategoryService } from '@/services/post-category.service' import { PostFileMapManager } from '@/services/post-file-map' @@ -22,7 +22,7 @@ export const showLocalFileToPostInfo = async (input: Uri | number): Promise 0 ? `博文标签: ${post.tags?.join(', ')}\n` : '' const options = ['在线查看博文', '取消关联'] const postUrl = post.url.startsWith('//') ? `https:${post.url}` : post.url - const selected = await AlertService.info( + const selected = await Alert.info( `关联博文 - ${post.title}(Id: ${post.id})`, { modal: true, @@ -75,6 +75,6 @@ export const showLocalFileToPostInfo = async (input: Uri | number): Promise { const clipboardImage = await getClipboardImage() if (clipboardImage.imgPath === noImagePath) { - AlertService.warn('剪贴板中没有找到图片') + Alert.warn('剪贴板中没有找到图片') return } diff --git a/src/commands/upload-image/upload-image-utils.ts b/src/commands/upload-image/upload-image-utils.ts index 644bec04..1730050a 100644 --- a/src/commands/upload-image/upload-image-utils.ts +++ b/src/commands/upload-image/upload-image-utils.ts @@ -1,6 +1,6 @@ import { env, MessageOptions, SnippetString, window } from 'vscode' import { formatImageLink } from '@/utils/format-image-link' -import { AlertService } from '@/services/alert.service' +import { Alert } from '@/services/alert.service' /** * 显示上传成功对话框, 支持复制不同格式的图片链接 @@ -10,7 +10,7 @@ import { AlertService } from '@/services/alert.service' */ export const showUploadSuccessModel = async (imgLink: string): Promise => { const copyOptions = ['复制链接', '复制链接(markdown)', '复制链接(html)'] - const option = await AlertService.info( + const option = await Alert.info( '上传图片成功', { modal: true, diff --git a/src/commands/upload-image/upload-image.ts b/src/commands/upload-image/upload-image.ts index f434690c..4a15d001 100644 --- a/src/commands/upload-image/upload-image.ts +++ b/src/commands/upload-image/upload-image.ts @@ -1,4 +1,4 @@ -import { AlertService } from '@/services/alert.service' +import { Alert } from '@/services/alert.service' import { window } from 'vscode' import { uploadImageFromClipboard } from './upload-clipboard-image' import { insertImageLinkToActiveEditor, showUploadSuccessModel } from './upload-image-utils' @@ -7,7 +7,7 @@ import { uploadLocalDiskImage } from './upload-local-disk-image' export const uploadImage = async (autoInsertToActiveEditor = true, from?: 'local' | 'clipboard') => { const options = ['本地图片文件', '剪贴板图片'] const selected = !from - ? await AlertService.info( + ? await Alert.info( '上传图片到博客园', { modal: true, @@ -19,7 +19,7 @@ export const uploadImage = async (autoInsertToActiveEditor = true, from?: 'local let imageUrl: string | undefined const caughtFailedUpload = (e: unknown) => - void AlertService.httpErr(typeof e === 'object' && e != null ? e : {}, { message: '上传图片失败' }) + void Alert.httpErr(typeof e === 'object' && e != null ? e : {}, { message: '上传图片失败' }) switch (selected) { case 'local': case options[0]: diff --git a/src/services/alert.service.ts b/src/services/alert.service.ts index 8d057d65..31f31ecb 100644 --- a/src/services/alert.service.ts +++ b/src/services/alert.service.ts @@ -4,7 +4,7 @@ import path from 'path' import vscode, { Uri } from 'vscode' import { window } from 'vscode' -export namespace AlertService { +export namespace Alert { export const err = window.showErrorMessage export const info = window.showInformationMessage @@ -22,7 +22,7 @@ export namespace AlertService { else if (httpError.message) parsedError = httpError.message else parsedError = '未知网络错误' - void AlertService.warn((message ? message + (parsedError ? ', ' : '') : '') + parsedError) + void Alert.warn((message ? message + (parsedError ? ', ' : '') : '') + parsedError) } /** @@ -33,12 +33,12 @@ export namespace AlertService { export function fileNotLinkedToPost(file: string | Uri, { trimExt = true } = {}) { file = file instanceof Uri ? file.fsPath : file file = trimExt ? path.basename(file, path.extname(file)) : file - void AlertService.warn(`本地文件"${file}"未关联博客园博文`) + void Alert.warn(`本地文件"${file}"未关联博客园博文`) } export async function alertUnAuth({ onLoginActionHook }: { onLoginActionHook?: () => unknown } = {}) { const options = ['立即登录'] - const input = await AlertService.warn( + const input = await Alert.warn( '登录状态已过期, 请重新登录', { modal: true } as vscode.MessageOptions, ...options diff --git a/src/services/ing.api.ts b/src/services/ing.api.ts index 269e1b7d..b6b206d4 100644 --- a/src/services/ing.api.ts +++ b/src/services/ing.api.ts @@ -1,5 +1,5 @@ import { Ing, IngComment, IngPublishModel, IngType } from '@/models/ing' -import { AlertService } from '@/services/alert.service' +import { Alert } from '@/services/alert.service' import { globalCtx } from '@/services/global-ctx' import fetch from '@/utils/fetch-client' import { URLSearchParams } from 'url' @@ -11,10 +11,10 @@ export namespace IngApi { method: 'POST', body: JSON.stringify(ing), headers: [['Content-Type', 'application/json']], - }).catch(reason => void AlertService.warn(JSON.stringify(reason))) + }).catch(reason => void Alert.warn(JSON.stringify(reason))) if (!res || !res.ok) - AlertService.err(`闪存发布失败, ${res?.statusText ?? ''} ${JSON.stringify((await res?.text()) ?? '')}`) + Alert.err(`闪存发布失败, ${res?.statusText ?? ''} ${JSON.stringify((await res?.text()) ?? '')}`) return res != null && res.ok } @@ -29,10 +29,10 @@ export namespace IngApi { method: 'GET', headers: [['Content-Type', 'application/json']], } - ).catch(e => void AlertService.warn(JSON.stringify(e))) + ).catch(e => void Alert.warn(JSON.stringify(e))) if (!res || !res.ok) { - AlertService.err(`获取闪存列表失败, ${res?.statusText ?? ''} ${JSON.stringify((await res?.text()) ?? '')}`) + Alert.err(`获取闪存列表失败, ${res?.statusText ?? ''} ${JSON.stringify((await res?.text()) ?? '')}`) return [] } @@ -40,9 +40,9 @@ export namespace IngApi { try { if (isArray(arr) && arr.every(isObject)) return arr.map(Ing.parse) - AlertService.err('获取闪存列表失败, 无法读取响应') + Alert.err('获取闪存列表失败, 无法读取响应') } catch (e) { - AlertService.err(JSON.stringify(e)) + Alert.err(JSON.stringify(e)) } return [] @@ -57,7 +57,7 @@ export namespace IngApi { resp => resp?.json().then(obj => [id, obj as IngComment[] | null | undefined] as const) ?? Promise.resolve(undefined), - reason => void AlertService.warn(JSON.stringify(reason)) + reason => void Alert.warn(JSON.stringify(reason)) ) ) @@ -85,12 +85,12 @@ export namespace IngApi { }) if (!res.ok) { - AlertService.err(`发表评论失败, ${await res.text()}`) + Alert.err(`发表评论失败, ${await res.text()}`) return false } } catch (e) { // eslint-disable-next-line @typescript-eslint/restrict-template-expressions - AlertService.err(`发表评论失败, ${e}`) + Alert.err(`发表评论失败, ${e}`) return false } diff --git a/src/services/post.service.ts b/src/services/post.service.ts index aa8412d3..8ddc6a4f 100644 --- a/src/services/post.service.ts +++ b/src/services/post.service.ts @@ -7,7 +7,7 @@ import { PostEditDto } from '@/models/post-edit-dto' import { PostUpdatedResponse } from '@/models/post-updated-response' import { throwIfNotOkGotResponse } from '@/utils/throw-if-not-ok-response' import { IErrorResponse } from '@/models/error-response' -import { AlertService } from './alert.service' +import { Alert } from './alert.service' import { PostFileMapManager } from './post-file-map' import { ZzkSearchResult } from '@/models/zzk-search-result' import got from '@/utils/http-client' @@ -73,11 +73,11 @@ export namespace PostService { const { statusCode, errors } = e as IErrorResponse if (!muteErrorNotification) { if (statusCode === 404) { - AlertService.err('博文不存在') + Alert.err('博文不存在') const postFilePath = PostFileMapManager.getFilePath(postId) if (postFilePath) await PostFileMapManager.updateOrCreate(postId, '') } else { - AlertService.err(errors.join('\n')) + Alert.err(errors.join('\n')) } } return undefined diff --git a/src/test/suite/extension.test.ts b/src/test/suite/extension.test.ts index 2bdec69c..2dfc7e49 100644 --- a/src/test/suite/extension.test.ts +++ b/src/test/suite/extension.test.ts @@ -1,4 +1,4 @@ -import { AlertService } from '@/services/alert.service' +import { Alert } from '@/services/alert.service' import assert from 'assert' // You can import and use all API from the 'vscode' module @@ -6,7 +6,7 @@ import assert from 'assert' // import * as myExtension from '../../extension'; suite('Extension Test Suite', () => { - AlertService.info('Start all tests.') + Alert.info('Start all tests.') test('Sample test', () => { assert.strictEqual(-1, [1, 2, 3].indexOf(5)) diff --git a/src/tree-view-providers/blog-export-provider.ts b/src/tree-view-providers/blog-export-provider.ts index 78a42339..fb91eb3b 100644 --- a/src/tree-view-providers/blog-export-provider.ts +++ b/src/tree-view-providers/blog-export-provider.ts @@ -12,7 +12,7 @@ import { ExportPostsEntryTreeItem, } from './models/blog-export/downloaded' import { Event, EventEmitter, ProviderResult, TreeDataProvider, TreeItem } from 'vscode' -import { AlertService } from '@/services/alert.service' +import { Alert } from '@/services/alert.service' import { BlogExportRecord } from '@/models/blog-export' export class BlogExportProvider implements TreeDataProvider { @@ -109,7 +109,7 @@ export class BlogExportProvider implements TreeDataProvider ?.refresh() .then(() => true) .catch(e => { - if (notifyOnError) AlertService.err(`刷新博客备份记录失败: ${e.message}`) + if (notifyOnError) Alert.err(`刷新博客备份记录失败: ${e.message}`) }) : clearCache ? await this._store?.clearCache().then( diff --git a/src/tree-view-providers/post-categories-tree-data-provider.ts b/src/tree-view-providers/post-categories-tree-data-provider.ts index e82d2c65..0ebe5c7a 100644 --- a/src/tree-view-providers/post-categories-tree-data-provider.ts +++ b/src/tree-view-providers/post-categories-tree-data-provider.ts @@ -9,7 +9,7 @@ import { PostCategoriesListTreeItem } from './models/categories-list-tree-item' import { PostCategoryTreeItem } from './models/post-category-tree-item' import { PostEntryMetadata, PostMetadata, RootPostMetadataType } from './models/post-metadata' import { PostTreeItem } from './models/post-tree-item' -import { AlertService } from '@/services/alert.service' +import { Alert } from '@/services/alert.service' import { execCmd } from '@/utils/cmd' export class PostCategoriesTreeDataProvider implements TreeDataProvider { @@ -135,7 +135,7 @@ export class PostCategoriesTreeDataProvider implements TreeDataProvidere).message}`) + Alert.err(`获取博文分类失败: ${(e).message}`) } finally { await this.setIsRefreshing(false) } diff --git a/src/tree-view-providers/posts-data-provider.ts b/src/tree-view-providers/posts-data-provider.ts index 904021d8..9075970d 100644 --- a/src/tree-view-providers/posts-data-provider.ts +++ b/src/tree-view-providers/posts-data-provider.ts @@ -2,7 +2,7 @@ import { EventEmitter, ProviderResult, TreeDataProvider, TreeItem } from 'vscode import { refreshPostsList } from '@/commands/posts-list/refresh-posts-list' import { Post } from '@/models/post' import { PageModel } from '@/models/page-model' -import { AlertService } from '@/services/alert.service' +import { Alert } from '@/services/alert.service' import { PostService } from '@/services/post.service' import { Settings } from '@/services/settings.service' import { toTreeItem } from './converters' @@ -66,8 +66,8 @@ export class PostsDataProvider implements TreeDataProvider { const pageSize = Settings.postsListPageSize this._pagedPosts = await PostService.fetchPostsList({ pageIndex, pageSize }).catch(e => { - if (e instanceof Error) AlertService.err(e.message) - else AlertService.err(`加载博文失败\n${JSON.stringify(e)}`) + if (e instanceof Error) Alert.err(e.message) + else Alert.err(`加载博文失败\n${JSON.stringify(e)}`) return undefined }) diff --git a/src/utils/chromium-path-provider.ts b/src/utils/chromium-path-provider.ts index 75f2b326..eb93c859 100644 --- a/src/utils/chromium-path-provider.ts +++ b/src/utils/chromium-path-provider.ts @@ -2,7 +2,7 @@ import { window, ProgressLocation } from 'vscode' import fs from 'fs' import os from 'os' import path from 'path' -import { AlertService } from '@/services/alert.service' +import { Alert } from '@/services/alert.service' // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-var-requires const download: (arg: Record) => Promise = require('download-chromium') @@ -74,7 +74,7 @@ namespace chromiumPathProvider { } } ) - if (chromiumPath) AlertService.info(`Chromium已下载至${chromiumPath}`) + if (chromiumPath) Alert.info(`Chromium已下载至${chromiumPath}`) return chromiumPath } diff --git a/src/utils/get-clipboard-image.ts b/src/utils/get-clipboard-image.ts index feb72e72..49d428bd 100644 --- a/src/utils/get-clipboard-image.ts +++ b/src/utils/get-clipboard-image.ts @@ -6,7 +6,7 @@ import fs from 'fs' import os from 'os' import isWsl from 'is-wsl' import { globalCtx } from '@/services/global-ctx' -import { AlertService } from '@/services/alert.service' +import { Alert } from '@/services/alert.service' import { IClipboardImage } from '@/models/clipboard-image' import format from 'date-fns/format' @@ -94,7 +94,7 @@ const getClipboardImage = (): Promise => { execution.stdout.on('data', (data: Buffer) => { if (platform === 'linux') { if (data.toString().trim() === 'no xclip') { - AlertService.warn('xclip not found, Please install xclip first') + Alert.warn('xclip not found, Please install xclip first') return reject(new Error('Please install xclip first')) } } diff --git a/src/utils/input-post-settings.ts b/src/utils/input-post-settings.ts index 58ef8a17..296b1af7 100644 --- a/src/utils/input-post-settings.ts +++ b/src/utils/input-post-settings.ts @@ -1,7 +1,7 @@ import { QuickPickItem } from 'vscode' import { AccessPermission, Post } from '@/models/post' import { PostCategories, PostCategory } from '@/models/post-category' -import { AlertService } from '@/services/alert.service' +import { Alert } from '@/services/alert.service' import { InputFlowAction, InputStep, MultiStepInput, QuickPickParameters } from '@/services/multi-step-input' import { postCategoryService } from '@/services/post-category.service' @@ -102,7 +102,7 @@ export const inputPostSettings = ( try { categories = await postCategoryService.listCategories() } catch (err) { - AlertService.err(err instanceof Error ? err.message : JSON.stringify(err)) + Alert.err(err instanceof Error ? err.message : JSON.stringify(err)) // 取消 throw InputFlowAction.cancel } From 58b77df06fb9d7fc295377a7c17fb9d957ddadbe Mon Sep 17 00:00:00 2001 From: Thaumy Date: Thu, 20 Jul 2023 18:21:07 +0800 Subject: [PATCH 011/157] chore: update package-lock.json --- package-lock.json | 2 +- src/commands/blog-export/create.ts | 6 +----- src/commands/blog-export/open-local.ts | 3 +-- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index b4739722..167b2501 100644 --- a/package-lock.json +++ b/package-lock.json @@ -92,7 +92,7 @@ "webpack-cli": "^5.0.1" }, "engines": { - "vscode": "^1.70.0" + "vscode": "^1.80.0" } }, "node_modules/@aashutoshrathi/word-wrap": { diff --git a/src/commands/blog-export/create.ts b/src/commands/blog-export/create.ts index 3f60da34..67e6c43d 100644 --- a/src/commands/blog-export/create.ts +++ b/src/commands/blog-export/create.ts @@ -21,11 +21,7 @@ export class CreateBlogExportCmdHandler extends CmdHandler { private async confirm(): Promise { const items: MessageItem[] = [{ title: '确定', isCloseAffordance: false }] - const result = await Alert.info( - '确定要创建备份吗?', - { modal: true, detail: '一天可以创建一次备份' }, - ...items - ) + const result = await Alert.info('确定要创建备份吗?', { modal: true, detail: '一天可以创建一次备份' }, ...items) return result != null } } diff --git a/src/commands/blog-export/open-local.ts b/src/commands/blog-export/open-local.ts index c2d29db1..6eaa2f63 100644 --- a/src/commands/blog-export/open-local.ts +++ b/src/commands/blog-export/open-local.ts @@ -28,8 +28,7 @@ export class OpenLocalExportCmdHandler extends CmdHandler { })) ?? [] if (fileUri == null) return const filePath = fileUri.fsPath - if (filePath.endsWith('.zip') && !filePath.endsWith('.db.zip')) - return void Alert.warn('不支持的博客备份文件') + if (filePath.endsWith('.zip') && !filePath.endsWith('.db.zip')) return void Alert.warn('不支持的博客备份文件') const fileName = path.basename(filePath.replace(/\.db(\.zip)?$/, '')) const dirname = path.dirname(filePath) From c166733dc30eb266969b0c6fc8e98d168e8933b0 Mon Sep 17 00:00:00 2001 From: Thaumy Date: Fri, 21 Jul 2023 14:18:40 +0800 Subject: [PATCH 012/157] refactor: simplify code --- src/auth/auth-provider.ts | 9 ++---- src/commands/cmd-register.ts | 5 ++-- src/commands/ing/comment-ing.ts | 6 ++-- src/commands/ing/goto-ings-list-page.ts | 14 ++++----- src/commands/ing/publish-ing.ts | 15 ++++------ src/commands/ing/refresh-ings-list.ts | 4 +-- src/commands/ing/select-ing-type.ts | 6 ++-- .../{export-pdf.command.ts => export-pdf.ts} | 10 +++---- src/commands/pull-post-remote-updates.ts | 2 +- src/commands/set-workspace.ts | 23 ++++++++------- src/extension.ts | 29 +++++++++---------- src/markdown/extend-markdownIt.ts | 4 +-- src/services/ings-list-webview-provider.ts | 22 ++------------ src/utils/chromium-path-provider.ts | 10 +++---- src/utils/msg.ts | 0 15 files changed, 64 insertions(+), 95 deletions(-) rename src/commands/pdf/{export-pdf.command.ts => export-pdf.ts} (96%) delete mode 100644 src/utils/msg.ts diff --git a/src/auth/auth-provider.ts b/src/auth/auth-provider.ts index 44461c30..29df8b7b 100644 --- a/src/auth/auth-provider.ts +++ b/src/auth/auth-provider.ts @@ -26,8 +26,6 @@ export class AuthProvider implements AuthenticationProvider, Disposable { static readonly providerId = 'cnblogs' static readonly providerName = '博客园Cnblogs' - private static _instance: AuthProvider | null - readonly providerId = AuthProvider.providerId readonly providerName = AuthProvider.providerName @@ -47,11 +45,6 @@ export class AuthProvider implements AuthenticationProvider, Disposable { }) ) - static get instance() { - this._instance ??= new AuthProvider() - return this._instance - } - get onDidChangeSessions() { return this._sessionChangeEmitter.event } @@ -274,6 +267,8 @@ export class AuthProvider implements AuthenticationProvider, Disposable { } } +export const authProvider = new AuthProvider() + class LegacyTokenStore { static getAccessToken = () => globalCtx.storage.get>('user')?.authorizationInfo?.accessToken diff --git a/src/commands/cmd-register.ts b/src/commands/cmd-register.ts index 5fd9fd7d..efed50ec 100644 --- a/src/commands/cmd-register.ts +++ b/src/commands/cmd-register.ts @@ -37,6 +37,7 @@ import { regIngListCmds } from 'src/commands/ing/ings-list-cmd-register' import { CopyPostLinkCmdHandler } from '@/commands/posts-list/copy-link' import { regBlogExportCmds } from '@/commands/blog-export' import { regCmd } from '@/utils/cmd' +import { exportPostToPdf } from '@/commands/pdf/export-pdf' export function setupExtCmd() { const ctx = globalCtx.extCtx @@ -77,9 +78,7 @@ export function setupExtCmd() { regCmd(`${appName}.set-workspace`, setWorkspace), regCmd(`${appName}.reveal-workspace-in-os`, revealWorkspaceInOs), regCmd(`${appName}.view-post-online`, viewPostOnline), - regCmd(`${appName}.export-post-to-pdf`, (input: unknown) => - import('./pdf/export-pdf.command').then(m => m.exportPostToPdf(input)) - ), + regCmd(`${appName}.export-post-to-pdf`, (input: unknown) => exportPostToPdf(input)), regCmd(`${appName}.extract-images`, extractImages), regCmd(`${appName}.search-posts`, searchPosts), regCmd(`${appName}.clear-posts-search-results`, clearPostsSearchResults), diff --git a/src/commands/ing/comment-ing.ts b/src/commands/ing/comment-ing.ts index f0c9a90c..fdfe17d9 100644 --- a/src/commands/ing/comment-ing.ts +++ b/src/commands/ing/comment-ing.ts @@ -1,6 +1,6 @@ import { CmdHandler } from '@/commands/cmd-handler' import { IngApi } from '@/services/ing.api' -import { IngsListWebviewProvider } from '@/services/ings-list-webview-provider' +import { ingListWebviewProvider } from '@/services/ings-list-webview-provider' import { ProgressLocation, window } from 'vscode' export class CommentIngCmdHandler extends CmdHandler { @@ -16,8 +16,6 @@ export class CommentIngCmdHandler extends CmdHandler { } async handle(): Promise { - if (!IngsListWebviewProvider.instance) return - const maxIngContentLength = 50 const baseTitle = this._parentCommentId || 0 > 0 ? `回复@${this._atUser?.displayName}` : '评论闪存' const input = await window.showInputBox({ @@ -47,6 +45,6 @@ export class CommentIngCmdHandler extends CmdHandler { } private onCommented(): Promise { - return IngsListWebviewProvider.instance?.updateComments([this._ingId]) ?? Promise.resolve() + return ingListWebviewProvider.updateComments([this._ingId]) ?? Promise.resolve() } } diff --git a/src/commands/ing/goto-ings-list-page.ts b/src/commands/ing/goto-ings-list-page.ts index d7e47261..56a22c95 100644 --- a/src/commands/ing/goto-ings-list-page.ts +++ b/src/commands/ing/goto-ings-list-page.ts @@ -1,25 +1,23 @@ import { CmdHandler } from '@/commands/cmd-handler' -import { IngsListWebviewProvider } from 'src/services/ings-list-webview-provider' +import { ingListWebviewProvider } from 'src/services/ings-list-webview-provider' export class GotoIngsListNextPage extends CmdHandler { handle(): Promise { - const provider = IngsListWebviewProvider.ensureRegistered() - const { pageIndex } = provider - return provider.refreshIngsList({ pageIndex: pageIndex + 1 }) + const { pageIndex } = ingListWebviewProvider + return ingListWebviewProvider.refreshIngsList({ pageIndex: pageIndex + 1 }) } } export class GotoIngsListPreviousPage extends CmdHandler { handle(): Promise { - const provider = IngsListWebviewProvider.ensureRegistered() - const { pageIndex } = provider - if (pageIndex > 1) return provider.refreshIngsList({ pageIndex: pageIndex - 1 }) + const { pageIndex } = ingListWebviewProvider + if (pageIndex > 1) return ingListWebviewProvider.refreshIngsList({ pageIndex: pageIndex - 1 }) return Promise.resolve() } } export class GotoIngsListFirstPage extends CmdHandler { handle(): Promise { - return IngsListWebviewProvider.ensureRegistered().refreshIngsList({ pageIndex: 1 }) + return ingListWebviewProvider.refreshIngsList({ pageIndex: 1 }) } } diff --git a/src/commands/ing/publish-ing.ts b/src/commands/ing/publish-ing.ts index da06df9b..714853d2 100644 --- a/src/commands/ing/publish-ing.ts +++ b/src/commands/ing/publish-ing.ts @@ -4,7 +4,7 @@ import { IngPublishModel, IngType } from '@/models/ing' import { Alert } from '@/services/alert.service' import { globalCtx } from '@/services/global-ctx' import { IngApi } from '@/services/ing.api' -import { IngsListWebviewProvider } from '@/services/ings-list-webview-provider' +import { ingListWebviewProvider } from '@/services/ings-list-webview-provider' import { InputStep, MultiStepInput, QuickPickParameters } from '@/services/multi-step-input' import { MessageOptions, ProgressLocation, QuickPickItem, Uri, window } from 'vscode' @@ -146,18 +146,15 @@ export class PublishIngCmdHandler extends CmdHandler { } private warnNoSelection() { - Alert.warn(`无法${this.operation}, 当前没有选中的内容`) + void Alert.warn(`无法${this.operation}, 当前没有选中的内容`) } private async onPublished(isPublished: boolean): Promise { - const ingsListProvider = IngsListWebviewProvider.instance if (isPublished) { - if (ingsListProvider) { - return ingsListProvider.refreshIngsList({ - ingType: this.inputIsPrivate ? IngType.my : IngType.all, - pageIndex: 1, - }) - } + await ingListWebviewProvider.refreshIngsList({ + ingType: this.inputIsPrivate ? IngType.my : IngType.all, + pageIndex: 1, + }) const options = [ ['打开闪存', (): Thenable => execCmd('vscode.open', Uri.parse(globalCtx.config.ingSite))], diff --git a/src/commands/ing/refresh-ings-list.ts b/src/commands/ing/refresh-ings-list.ts index 711710fc..71b9fbb7 100644 --- a/src/commands/ing/refresh-ings-list.ts +++ b/src/commands/ing/refresh-ings-list.ts @@ -1,8 +1,8 @@ import { CmdHandler } from '@/commands/cmd-handler' -import { IngsListWebviewProvider } from 'src/services/ings-list-webview-provider' +import { ingListWebviewProvider } from 'src/services/ings-list-webview-provider' export class RefreshIngsList extends CmdHandler { handle(): Promise { - return IngsListWebviewProvider.ensureRegistered().refreshIngsList() + return ingListWebviewProvider.refreshIngsList() } } diff --git a/src/commands/ing/select-ing-type.ts b/src/commands/ing/select-ing-type.ts index 1b1ac4df..e716f242 100644 --- a/src/commands/ing/select-ing-type.ts +++ b/src/commands/ing/select-ing-type.ts @@ -1,12 +1,12 @@ import { CmdHandler } from '@/commands/cmd-handler' import { IngType, IngTypesMetadata } from '@/models/ing' -import { IngsListWebviewProvider } from '@/services/ings-list-webview-provider' +import { ingListWebviewProvider } from '@/services/ings-list-webview-provider' import { IDisposable } from '@fluentui/react' import { QuickPickItem, window } from 'vscode' export class SelectIngType extends CmdHandler { handle(): Promise { - const { ingType: curIngType } = IngsListWebviewProvider.ensureRegistered() + const { ingType: curIngType } = ingListWebviewProvider const options: (QuickPickItem & { ingType: IngType })[] = IngTypesMetadata.map( ([ingType, { displayName, description }]) => ({ label: displayName, @@ -27,7 +27,7 @@ export class SelectIngType extends CmdHandler { if (selectedItem) { const { ingType: selectedIngType } = selectedItem quickPick.hide() - return IngsListWebviewProvider.ensureRegistered().refreshIngsList({ + return ingListWebviewProvider.refreshIngsList({ pageIndex: 1, ingType: selectedIngType, }) diff --git a/src/commands/pdf/export-pdf.command.ts b/src/commands/pdf/export-pdf.ts similarity index 96% rename from src/commands/pdf/export-pdf.command.ts rename to src/commands/pdf/export-pdf.ts index 0da3224d..a4125ebf 100644 --- a/src/commands/pdf/export-pdf.command.ts +++ b/src/commands/pdf/export-pdf.ts @@ -7,7 +7,7 @@ import { Post } from '@/models/post' import { PostFileMapManager } from '@/services/post-file-map' import { PostService } from '@/services/post.service' import { extViews } from '@/tree-view-providers/tree-view-registration' -import { chromiumPathProvider } from '@/utils/chromium-path-provider' +import { ChromiumPathProvider } from '@/utils/chromium-path-provider' import { Settings } from '@/services/settings.service' import { accountManager } from '@/auth/account-manager' import { Alert } from '@/services/alert.service' @@ -98,22 +98,22 @@ const writePdfToFile = (dir: Uri, post: Post, buffer: Buffer) => }) const retrieveChromiumPath = async (): Promise => { - let path: string | undefined = chromiumPathProvider.lookupExecutableFromMacApp(Settings.chromiumPath) + let path: string | undefined = ChromiumPathProvider.lookupExecutableFromMacApp(Settings.chromiumPath) if (path && fs.existsSync(path)) return path const platform = os.platform() - const { defaultChromiumPath } = chromiumPathProvider + const { defaultChromiumPath } = ChromiumPathProvider if (platform === 'darwin') { // mac path = defaultChromiumPath.osx.find(x => fs.existsSync(x)) ?? '' - path = chromiumPathProvider.lookupExecutableFromMacApp(path) + path = ChromiumPathProvider.lookupExecutableFromMacApp(path) } else if (platform === 'win32') { // windows path = defaultChromiumPath.win.find(x => fs.existsSync(x)) ?? '' } if (!path) { - const { Options: options } = chromiumPathProvider + const { Options: options } = ChromiumPathProvider const input = await Alert.warn( '未找到Chromium可执行文件', { diff --git a/src/commands/pull-post-remote-updates.ts b/src/commands/pull-post-remote-updates.ts index e63d72cc..0c9f2baf 100644 --- a/src/commands/pull-post-remote-updates.ts +++ b/src/commands/pull-post-remote-updates.ts @@ -33,7 +33,7 @@ const pullPostRemoteUpdates = async (input: Post | PostTreeItem | Uri | undefine await update(ctxs) - Alert.info(`本地文件${resolveFileNames(ctxs)}已更新`) + void Alert.info(`本地文件${resolveFileNames(ctxs)}已更新`) } export { pullPostRemoteUpdates } diff --git a/src/commands/set-workspace.ts b/src/commands/set-workspace.ts index fbd1c92e..568f515a 100644 --- a/src/commands/set-workspace.ts +++ b/src/commands/set-workspace.ts @@ -3,16 +3,19 @@ import { Alert } from '@/services/alert.service' import { Settings } from '@/services/settings.service' export const setWorkspace = async () => { - const input = ((await window.showOpenDialog({ - title: '选择工作空间', - canSelectFolders: true, - canSelectFiles: false, - canSelectMany: false, - defaultUri: Settings.workspaceUri, - })) ?? [])[0] + const uris = + (await window.showOpenDialog({ + title: '选择工作空间', + canSelectFolders: true, + canSelectFiles: false, + canSelectMany: false, + defaultUri: Settings.workspaceUri, + })) ?? [] - if (!input) return + const firstUri = uris[0] - await Settings.setWorkspaceUri(input) - Alert.info(`工作空间成功修改为: "${Settings.workspaceUri.fsPath}"`) + if (firstUri === undefined) return + + await Settings.setWorkspaceUri(firstUri) + void Alert.info(`工作空间成功修改为: "${Settings.workspaceUri.fsPath}"`) } diff --git a/src/extension.ts b/src/extension.ts index 7d3b75fb..f41ad3a1 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -3,38 +3,35 @@ import { setupExtCmd } from '@/commands/cmd-register' import { globalCtx } from '@/services/global-ctx' // The module 'vscode' contains the VS Code extensibility API // Import the module and reference it with the alias vscode in your code below -import vscode from 'vscode' +import { window, ExtensionContext } from 'vscode' import { accountManager } from '@/auth/account-manager' -import { - observeConfigurationChange, - observeWorkspaceFolderAndFileChange as observeWorkspaceFolderChange, -} from '@/services/check-workspace' +import { observeCfgUpdate, observeWorkspaceFileUpdate, observeWorkspaceUpdate } from '@/services/check-workspace' import { extUriHandler } from '@/utils/uri-handler' -import { IngsListWebviewProvider } from 'src/services/ings-list-webview-provider' +import { ingListWebviewProvider } from 'src/services/ings-list-webview-provider' import { extendMarkdownIt } from '@/markdown/extend-markdownIt' import { Settings } from '@/services/settings.service' // this method is called when your extension is activated // your extension is activated the very first time the commands is executed -export function activate(context: vscode.ExtensionContext) { - globalCtx.extCtx = context +export function activate(ctx: ExtensionContext) { + globalCtx.extCtx = ctx - context.subscriptions.push(accountManager) + globalCtx.extCtx.subscriptions.push(accountManager) setupExtCmd() setupExtTreeView() - const timeoutId = setTimeout(() => { - IngsListWebviewProvider.ensureRegistered() - clearTimeout(timeoutId) - }, 1000) + globalCtx.extCtx.subscriptions.push( + window.registerWebviewViewProvider(ingListWebviewProvider.viewId, ingListWebviewProvider) + ) - observeConfigurationChange() - observeWorkspaceFolderChange() + observeCfgUpdate() + observeWorkspaceUpdate() + observeWorkspaceFileUpdate() Settings.migrateEnablePublishSelectionToIng().catch(console.warn) - vscode.window.registerUriHandler(extUriHandler) + window.registerUriHandler(extUriHandler) return { extendMarkdownIt } } diff --git a/src/markdown/extend-markdownIt.ts b/src/markdown/extend-markdownIt.ts index c777c53d..de261d7c 100644 --- a/src/markdown/extend-markdownIt.ts +++ b/src/markdown/extend-markdownIt.ts @@ -5,8 +5,8 @@ import type { MarkdownIt } from '@cnblogs/markdown-it-presets' export const extendMarkdownIt = (md: MarkdownIt) => md .use(MultilineBlockquotePlugin, { - enable: () => Settings.isEnableMarkdownEnhancement && Settings.isEnableMarkdownFenceBlockquote, + enable: () => Settings.enableMarkdownEnhancement && Settings.enableMarkdownFenceBlockquote, }) .use(HighlightCodeLinesPlugin, { - enable: () => Settings.isEnableMarkdownEnhancement && Settings.isEnableMarkdownHighlightCodeLines, + enable: () => Settings.enableMarkdownEnhancement && Settings.enableMarkdownHighlightCodeLines, }) diff --git a/src/services/ings-list-webview-provider.ts b/src/services/ings-list-webview-provider.ts index 0fc12c49..2cf6929d 100644 --- a/src/services/ings-list-webview-provider.ts +++ b/src/services/ings-list-webview-provider.ts @@ -18,8 +18,6 @@ import { CommentIngCmdHandler } from '@/commands/ing/comment-ing' import { execCmd } from '@/utils/cmd' export class IngsListWebviewProvider implements WebviewViewProvider { - private static _instance: IngsListWebviewProvider | null = null - readonly viewId = `${globalCtx.extName}.ings-list-webview` private readonly _baseTitle = '闪存' @@ -30,8 +28,6 @@ export class IngsListWebviewProvider implements WebviewViewProvider { private _ingType = IngType.all private _show: WebviewView['show'] | null = null - private constructor() {} - get observer(): IngWebviewMessageObserver { if (!this._view) throw Error('Cannot access the observer until the webviewView initialized!') this._observer ??= new IngWebviewMessageObserver(this) @@ -55,26 +51,10 @@ export class IngsListWebviewProvider implements WebviewViewProvider { return this._show } - static get instance() { - this._instance ??= new IngsListWebviewProvider() - return this._instance - } - private get assetsUri() { return globalCtx.assetsUri } - static ensureRegistered() { - if (!this._instance) { - this._instance = new IngsListWebviewProvider() - globalCtx.extCtx.subscriptions.push( - window.registerWebviewViewProvider(this._instance.viewId, this._instance) - ) - } - - return this._instance - } - // eslint-disable-next-line @typescript-eslint/no-unused-vars async resolveWebviewView(webviewView: WebviewView, context: WebviewViewResolveContext, token: CancellationToken) { if (this._view && this._view === webviewView) return @@ -183,6 +163,8 @@ export class IngsListWebviewProvider implements WebviewViewProvider { } } +export const ingListWebviewProvider = new IngsListWebviewProvider() + class IngWebviewMessageObserver { constructor(private _provider: IngsListWebviewProvider) {} diff --git a/src/utils/chromium-path-provider.ts b/src/utils/chromium-path-provider.ts index eb93c859..238ca3b3 100644 --- a/src/utils/chromium-path-provider.ts +++ b/src/utils/chromium-path-provider.ts @@ -6,7 +6,7 @@ import { Alert } from '@/services/alert.service' // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-var-requires const download: (arg: Record) => Promise = require('download-chromium') -namespace chromiumPathProvider { +namespace ChromiumPathProvider { export const defaultChromiumPath = { osx: [`${os.homedir()}/Applications/Google Chrome.app`, '/Applications/Google Chrome.app'], win: ['C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe'], @@ -79,10 +79,10 @@ namespace chromiumPathProvider { return chromiumPath } - export const Options: [string, chromiumPathProvider.ChromiumProviderFunc][] = [ - [selectFromLocalTitle, chromiumPathProvider.selectFromLocal], - [downloadFromInternetTitle, chromiumPathProvider.downloadFromInternet], + export const Options: [string, ChromiumPathProvider.ChromiumProviderFunc][] = [ + [selectFromLocalTitle, ChromiumPathProvider.selectFromLocal], + [downloadFromInternetTitle, ChromiumPathProvider.downloadFromInternet], ] } -export { chromiumPathProvider } +export { ChromiumPathProvider } diff --git a/src/utils/msg.ts b/src/utils/msg.ts deleted file mode 100644 index e69de29b..00000000 From 60570644008b058c2f1252d57eb3d056a743ca70 Mon Sep 17 00:00:00 2001 From: Thaumy Date: Fri, 21 Jul 2023 16:00:29 +0800 Subject: [PATCH 013/157] chore: update launch.json --- .vscode/launch.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 6111824d..6a3cd793 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -14,7 +14,7 @@ "preLaunchTask": "${defaultBuildTask}", "env": { "NODE_ENV": "Development", - "NODE_TLS_REJECT_UNAUTHORIZED": "0" + "NODE_TLS_REJECT_UNAUTHORIZED": "1" } }, { From e0a78b2dada37ec0741fddbc9611db6069177ad1 Mon Sep 17 00:00:00 2001 From: Thaumy Date: Fri, 21 Jul 2023 16:09:30 +0800 Subject: [PATCH 014/157] fix: fix auto extract img --- package.json | 8 +- src/commands/extract-images.ts | 41 +++++---- src/commands/posts-list/upload-post.ts | 22 ++--- src/services/settings.service.ts | 115 ++++++++++++------------- 4 files changed, 90 insertions(+), 96 deletions(-) diff --git a/package.json b/package.json index 3faa7d4e..a33aa658 100644 --- a/package.json +++ b/package.json @@ -419,7 +419,7 @@ { "title": "vscode-cnb", "properties": { - "cnblogsClient.workspace.windows": { + "cnblogsClient.windows.workspace": { "order": 0, "default": "~/Documents/Cnblogs", "scope": "application", @@ -427,7 +427,7 @@ "editPresentation": "singlelineText", "markdownDescription": "Windows 上存放博文的文件夹, 默认为 `~/Documents/Cnblogs`" }, - "cnblogsClient.workspace.macos": { + "cnblogsClient.macos.workspace": { "order": 1, "default": "~/Documents/Cnblogs", "scope": "application", @@ -435,7 +435,7 @@ "editPresentation": "singlelineText", "markdownDescription": "macOS 上存放博文的文件夹, 默认为 `~/Documents/Cnblogs`" }, - "cnblogsClient.workspace.linux": { + "cnblogsClient.linux.workspace": { "order": 2, "default": "~/Documents/Cnblogs", "scope": "application", @@ -472,7 +472,7 @@ "scope": "application", "enum": [ "disable", - "local", + "fs", "dataUrl", "web", "any" diff --git a/src/commands/extract-images.ts b/src/commands/extract-images.ts index 0125ab78..fc26ac2a 100644 --- a/src/commands/extract-images.ts +++ b/src/commands/extract-images.ts @@ -17,26 +17,30 @@ export async function extractImages(arg: unknown, inputImageSrc?: ImageSrc) { const extractor = new MkdImgExtractor(markdown, arg) const images = extractor.findImages() - if (images.length <= 0) void (!inputImageSrc != null ? Alert.warn('没有找到可以提取的图片') : undefined) + if (images.length <= 0) { + if (inputImageSrc !== undefined) void Alert.info('没有找到可以提取的图片') + return + } - const getExtractOption = () => { - const webImgCount = images.filter(newImageSrcFilter(ImageSrc.web)).length - const dataUrlImgCount = images.filter(newImageSrcFilter(ImageSrc.dataUrl)).length - const fsImgCount = images.filter(newImageSrcFilter(ImageSrc.fs)).length + const webImgCount = images.filter(newImageSrcFilter(ImageSrc.web)).length + const dataUrlImgCount = images.filter(newImageSrcFilter(ImageSrc.dataUrl)).length + const fsImgCount = images.filter(newImageSrcFilter(ImageSrc.fs)).length - const displayOptions: ExtractOption[] = [ - { title: '提取全部', imageSrc: ImageSrc.any }, - { title: '提取网络图片', imageSrc: ImageSrc.web }, - { title: '提取 Data Url 图片', imageSrc: ImageSrc.dataUrl }, - { title: '提取本地图片', imageSrc: ImageSrc.fs }, - { title: '取消', imageSrc: undefined, isCloseAffordance: true }, - ] + const displayOptions: ExtractOption[] = [ + { title: '提取全部', imageSrc: ImageSrc.any }, + { title: '提取网络图片', imageSrc: ImageSrc.web }, + { title: '提取 Data Url 图片', imageSrc: ImageSrc.dataUrl }, + { title: '提取本地图片', imageSrc: ImageSrc.fs }, + { title: '取消', imageSrc: undefined, isCloseAffordance: true }, + ] - if (inputImageSrc !== undefined) - return Promise.resolve(displayOptions.find(ent => ent.imageSrc === inputImageSrc)) + let selectedSrc + if (inputImageSrc !== undefined) { + selectedSrc = displayOptions.find(ent => ent.imageSrc === inputImageSrc)?.imageSrc + } else { // if src is not specified: - return Alert.info( + const selectedOption = await Alert.info( '要提取哪些图片? 此操作会替换源文件中的图片链接!', { modal: true, @@ -48,13 +52,12 @@ export async function extractImages(arg: unknown, inputImageSrc?: ImageSrc) { } as MessageOptions, ...displayOptions ) + selectedSrc = selectedOption?.imageSrc } - const extractImageSrc = (await getExtractOption())?.imageSrc - - if (extractImageSrc === undefined) return + if (selectedSrc === undefined) return - extractor.imageSrc = extractImageSrc + extractor.imageSrc = selectedSrc const failedImages = await window.withProgress( { title: '正在提取图片', location: ProgressLocation.Notification }, diff --git a/src/commands/posts-list/upload-post.ts b/src/commands/posts-list/upload-post.ts index 182a7b96..bd219e9f 100644 --- a/src/commands/posts-list/upload-post.ts +++ b/src/commands/posts-list/upload-post.ts @@ -1,4 +1,4 @@ -import vscode, { Uri, workspace, window, ProgressLocation, MessageOptions } from 'vscode' +import { Uri, workspace, window, ProgressLocation, MessageOptions } from 'vscode' import { Post } from '@/models/post' import { LocalDraft } from '@/services/local-draft.service' import { Alert } from '@/services/alert.service' @@ -84,7 +84,7 @@ export const saveLocalDraftToCnblogs = async (localDraft: LocalDraft) => { // check format if (!['.md'].some(x => localDraft.fileExt === x)) { - Alert.warn('不受支持的文件格式! 只支持markdown格式') + void Alert.warn('不受支持的文件格式! 只支持markdown格式') return } const editDto = await PostService.fetchPostEditTemplate() @@ -106,17 +106,17 @@ export const saveLocalDraftToCnblogs = async (localDraft: LocalDraft) => { await PostFileMapManager.updateOrCreate(savedPost.id, localDraft.filePath) await openPostFile(localDraft) postsDataProvider.fireTreeDataChangedEvent(undefined) - Alert.info('博文已创建') + void Alert.info('博文已创建') }, beforeUpdate: async (postToSave, panel) => { await saveFilePendingChanges(localDraft.filePath) // 本地文件已经被删除了 if (!localDraft.exist && panel) { - Alert.warn('本地文件已删除, 无法新建博文') + void Alert.warn('本地文件已删除, 无法新建博文') return false } - if (Settings.automaticallyExtractImagesType) - await extractImages(localDraft.filePathUri, Settings.automaticallyExtractImagesType).catch(console.warn) + if (Settings.autoExtractImgSrc !== undefined) + await extractImages(localDraft.filePathUri, Settings.autoExtractImgSrc).catch(console.warn) postToSave.postBody = await localDraft.readAllText() return true @@ -138,8 +138,8 @@ export const uploadPostToCnblogs = async (input: Post | PostTreeItem | PostEditD const localFilePath = PostFileMapManager.getFilePath(postId) if (!localFilePath) return Alert.warn('本地无该博文的编辑记录') - if (Settings.automaticallyExtractImagesType) - await extractImages(Uri.file(localFilePath), Settings.automaticallyExtractImagesType).catch(console.warn) + if (Settings.autoExtractImgSrc !== undefined) + await extractImages(Uri.file(localFilePath), Settings.autoExtractImgSrc).catch(console.warn) await saveFilePendingChanges(localFilePath) post.postBody = (await workspace.fs.readFile(Uri.file(localFilePath))).toString() @@ -177,11 +177,11 @@ export const uploadPostToCnblogs = async (input: Post | PostTreeItem | PostEditD hasSaved = true progress.report({ increment: 100 }) - Alert.info('上传成功') + void Alert.info('上传成功') await refreshPostsList() } catch (err) { progress.report({ increment: 100 }) - Alert.err(`上传失败\n${err instanceof Error ? err.message : JSON.stringify(err)}`) + void Alert.err(`上传失败\n${err instanceof Error ? err.message : JSON.stringify(err)}`) console.error(err) } return hasSaved @@ -191,7 +191,7 @@ export const uploadPostToCnblogs = async (input: Post | PostTreeItem | PostEditD const validatePost = (post: Post): boolean => { if (!post.postBody) { - Alert.warn('文件内容为空!') + void Alert.warn('文件内容为空!') return false } diff --git a/src/services/settings.service.ts b/src/services/settings.service.ts index 733afa0d..41eb1c77 100644 --- a/src/services/settings.service.ts +++ b/src/services/settings.service.ts @@ -6,20 +6,18 @@ import { isNumber } from 'lodash-es' import { untildify } from '@/utils/untildify' export class Settings { - static readonly postsListPageSizeKey = 'pageSize.postsList' - static readonly platform = os.platform() - static readonly prefix = `cnblogsClientForVSCode` - static readonly iconThemePrefix = 'workbench' - static readonly iconThemeKey = 'iconTheme' - static readonly chromiumPathKey = 'chromiumPath' - static readonly workspaceUriKey = 'workspace' + static postsListPageSizeKey = 'pageSize.postsList' + static cfgPrefix = `cnblogsClient` + static iconThemePrefix = 'workbench' + static iconThemeKey = 'iconTheme' + static chromiumPathKey = 'chromiumPath' + static workspaceUriKey = 'workspace' private static readonly _defaultWorkspaceUri = Uri.joinPath(Uri.file(homedir()), 'Documents', 'Cnblogs') private static _adaptLegacyWorkspaceTask?: Thenable | null static get platformPrefix() { - const { platform } = this - switch (platform) { + switch (os.platform()) { case 'darwin': return 'macos' case 'win32': @@ -32,123 +30,116 @@ export class Settings { } static get iconTheme() { - return workspace.getConfiguration(this.iconThemePrefix).get(this.iconThemeKey) + return workspace.getConfiguration(Settings.iconThemePrefix).get(Settings.iconThemeKey) } - static get configuration() { - return workspace.getConfiguration(this.prefix) + static get cfg() { + return workspace.getConfiguration(Settings.cfgPrefix) } - static get platformConfiguration() { - const { platformPrefix, prefix } = this - - if (platformPrefix != null) return workspace.getConfiguration(`${prefix}.${platformPrefix}`) - + static get platformCfg() { + if (this.platformPrefix != null) + return workspace.getConfiguration(`${Settings.cfgPrefix}.${this.platformPrefix}`) return null } static get workspaceUri(): Uri { - if (this.legacyWorkspaceUri != null) { - const legacy = this.legacyWorkspaceUri - if (this._adaptLegacyWorkspaceTask == null) { - try { - this._adaptLegacyWorkspaceTask = this.removeLegacyWorkspaceUri().then( - () => (legacy ? this.setWorkspaceUri(Uri.file(legacy)) : Promise.resolve()), - () => undefined - ) - } finally { - this._adaptLegacyWorkspaceTask = null - } - } - - if (legacy) return Uri.file(legacy) - } + const legacy = this.legacyWorkspaceUri + + this._adaptLegacyWorkspaceTask ??= this.removeLegacyWorkspaceUri().then( + () => (legacy ? this.setWorkspaceUri(legacy) : Promise.resolve()), + () => undefined + ) - const workspace = this.platformConfiguration?.get(this.workspaceUriKey) + if (legacy) return legacy + + const workspace = this.platformCfg?.get(Settings.workspaceUriKey) return workspace ? Uri.file(untildify(workspace)) : this._defaultWorkspaceUri } static get chromiumPath(): string { - return this.platformConfiguration?.get(this.chromiumPathKey) ?? '' + return this.platformCfg?.get(Settings.chromiumPathKey) ?? '' } static get createLocalPostFileWithCategory(): boolean { - return this.configuration.get('createLocalPostFileWithCategory') ?? false + return Settings.cfg.get('createLocalPostFileWithCategory') ?? false } - static get automaticallyExtractImagesType(): ImageSrc | null { - const cfg = - this.configuration.get<'disable' | 'web' | 'dataUrl' | 'fs' | 'any'>('automaticallyExtractImages') ?? null + static get autoExtractImgSrc(): ImageSrc | undefined { + const cfg = Settings.cfg.get<'disable' | 'web' | 'dataUrl' | 'fs' | 'any'>('autoExtractImages') + if (cfg === 'disable') return if (cfg === 'fs') return ImageSrc.fs if (cfg === 'dataUrl') return ImageSrc.dataUrl if (cfg === 'web') return ImageSrc.web if (cfg === 'any') return ImageSrc.any - - return null // 'disable' case } static get postsListPageSize() { - const size = this.configuration.get(this.postsListPageSizeKey) + const size = Settings.cfg.get(Settings.postsListPageSizeKey) return isNumber(size) ? size : 30 } static get showConfirmMsgWhenUploadPost() { - return this.configuration.get('markdown.showConfirmMsgWhenUploadPost') ?? true + return Settings.cfg.get('markdown.showConfirmMsgWhenUploadPost') ?? true } static get showConfirmMsgWhenPullPost() { - return this.configuration.get('markdown.showConfirmMsgWhenPullPost') ?? true + return Settings.cfg.get('markdown.showConfirmMsgWhenPullPost') ?? true } - static get isEnableMarkdownEnhancement() { - return this.configuration.get('markdown.enableEnhancement') ?? true + static get enableMarkdownEnhancement() { + return Settings.cfg.get('markdown.enableEnhancement') ?? true } - static get isEnableMarkdownFenceBlockquote() { - return this.configuration.get('markdown.enableFenceQuote') ?? true + static get enableMarkdownFenceBlockquote() { + return Settings.cfg.get('markdown.enableFenceQuote') ?? true } - static get isEnableMarkdownHighlightCodeLines() { - return this.configuration.get('markdown.enableHighlightCodeLines') + static get enableMarkdownHighlightCodeLines() { + return Settings.cfg.get('markdown.enableHighlightCodeLines') } - private static get legacyWorkspaceUri(): string | null | undefined { - return this.configuration.get(this.workspaceUriKey) + private static get legacyWorkspaceUri() { + const path = this.platformCfg?.get(Settings.workspaceUriKey)?.replace('~', os.homedir()) + + if (path === undefined) return undefined + + return Uri.file(path) } - static async setWorkspaceUri(value: Uri) { - if (!value.fsPath || !(value.scheme === 'file')) throw Error('Invalid uri') + static async setWorkspaceUri(uri: Uri) { + if (!uri.fsPath || uri.scheme !== 'file') throw Error('Invalid URI') - if (!fs.existsSync(value.fsPath)) throw Error(`Folder "${value.fsPath}" not exist`) + if (!fs.existsSync(uri.fsPath)) throw Error(`Path not exist: ${uri.fsPath}`) - await this.platformConfiguration?.update(this.workspaceUriKey, value.fsPath, ConfigurationTarget.Global) + await this.platformCfg?.update(Settings.workspaceUriKey, uri.fsPath, ConfigurationTarget.Global) } static async setChromiumPath(value: string) { - await this.platformConfiguration?.update(this.chromiumPathKey, value, ConfigurationTarget.Global) + await this.platformCfg?.update(Settings.chromiumPathKey, value, ConfigurationTarget.Global) } static async setCreateLocalPostFileWithCategory(value: boolean) { - await this.configuration.update('createLocalPostFileWithCategory', value, ConfigurationTarget.Global) + await Settings.cfg.update('createLocalPostFileWithCategory', value, ConfigurationTarget.Global) } static async migrateEnablePublishSelectionToIng() { const oldKey = 'ing.enablePublishSelectionToIng' - const isEnablePublishSelectionToIng = this.configuration.get(oldKey) - if (isEnablePublishSelectionToIng === true) { - const isOk = await this.configuration + const enablePublishSelectionToIng = Settings.cfg.get(oldKey) + if (enablePublishSelectionToIng === true) { + const isOk = await Settings.cfg .update('menus.context.editor', { 'ing:publish-selection': true }, ConfigurationTarget.Global) .then( () => true, () => false ) - if (isOk) await this.configuration.update(oldKey, undefined, ConfigurationTarget.Global) + if (isOk) await Settings.cfg.update(oldKey, undefined, ConfigurationTarget.Global) } } private static removeLegacyWorkspaceUri() { - return this.configuration.update(this.workspaceUriKey, undefined, ConfigurationTarget.Global) + return Settings.cfg.update(Settings.workspaceUriKey, undefined, ConfigurationTarget.Global) } } From 410474f8d2ff3c6fecbe6bf498fbf7b6cb4a6051 Mon Sep 17 00:00:00 2001 From: Thaumy Date: Fri, 21 Jul 2023 16:11:43 +0800 Subject: [PATCH 015/157] fix: fix ing list init --- src/commands/ing/comment-ing.ts | 4 ++-- src/commands/ing/goto-ings-list-page.ts | 14 ++++++++------ src/commands/ing/publish-ing.ts | 4 ++-- src/commands/ing/refresh-ings-list.ts | 4 ++-- src/commands/ing/select-ing-type.ts | 6 +++--- src/extension.ts | 8 ++++---- src/services/global-ctx.ts | 6 +++--- src/services/ings-list-webview-provider.ts | 13 +++++++------ 8 files changed, 31 insertions(+), 28 deletions(-) diff --git a/src/commands/ing/comment-ing.ts b/src/commands/ing/comment-ing.ts index fdfe17d9..7a66d7cf 100644 --- a/src/commands/ing/comment-ing.ts +++ b/src/commands/ing/comment-ing.ts @@ -1,6 +1,6 @@ import { CmdHandler } from '@/commands/cmd-handler' import { IngApi } from '@/services/ing.api' -import { ingListWebviewProvider } from '@/services/ings-list-webview-provider' +import { getIngListWebviewProvider } from '@/services/ings-list-webview-provider' import { ProgressLocation, window } from 'vscode' export class CommentIngCmdHandler extends CmdHandler { @@ -45,6 +45,6 @@ export class CommentIngCmdHandler extends CmdHandler { } private onCommented(): Promise { - return ingListWebviewProvider.updateComments([this._ingId]) ?? Promise.resolve() + return getIngListWebviewProvider().updateComments([this._ingId]) ?? Promise.resolve() } } diff --git a/src/commands/ing/goto-ings-list-page.ts b/src/commands/ing/goto-ings-list-page.ts index 56a22c95..43637d20 100644 --- a/src/commands/ing/goto-ings-list-page.ts +++ b/src/commands/ing/goto-ings-list-page.ts @@ -1,23 +1,25 @@ import { CmdHandler } from '@/commands/cmd-handler' -import { ingListWebviewProvider } from 'src/services/ings-list-webview-provider' +import { getIngListWebviewProvider } from 'src/services/ings-list-webview-provider' export class GotoIngsListNextPage extends CmdHandler { handle(): Promise { - const { pageIndex } = ingListWebviewProvider - return ingListWebviewProvider.refreshIngsList({ pageIndex: pageIndex + 1 }) + const provider = getIngListWebviewProvider() + const { pageIndex } = provider + return provider.refreshIngsList({ pageIndex: pageIndex + 1 }) } } export class GotoIngsListPreviousPage extends CmdHandler { handle(): Promise { - const { pageIndex } = ingListWebviewProvider - if (pageIndex > 1) return ingListWebviewProvider.refreshIngsList({ pageIndex: pageIndex - 1 }) + const provider = getIngListWebviewProvider() + const { pageIndex } = provider + if (pageIndex > 1) return provider.refreshIngsList({ pageIndex: pageIndex - 1 }) return Promise.resolve() } } export class GotoIngsListFirstPage extends CmdHandler { handle(): Promise { - return ingListWebviewProvider.refreshIngsList({ pageIndex: 1 }) + return getIngListWebviewProvider().refreshIngsList({ pageIndex: 1 }) } } diff --git a/src/commands/ing/publish-ing.ts b/src/commands/ing/publish-ing.ts index 714853d2..b4fa70b9 100644 --- a/src/commands/ing/publish-ing.ts +++ b/src/commands/ing/publish-ing.ts @@ -4,7 +4,7 @@ import { IngPublishModel, IngType } from '@/models/ing' import { Alert } from '@/services/alert.service' import { globalCtx } from '@/services/global-ctx' import { IngApi } from '@/services/ing.api' -import { ingListWebviewProvider } from '@/services/ings-list-webview-provider' +import { getIngListWebviewProvider } from '@/services/ings-list-webview-provider' import { InputStep, MultiStepInput, QuickPickParameters } from '@/services/multi-step-input' import { MessageOptions, ProgressLocation, QuickPickItem, Uri, window } from 'vscode' @@ -151,7 +151,7 @@ export class PublishIngCmdHandler extends CmdHandler { private async onPublished(isPublished: boolean): Promise { if (isPublished) { - await ingListWebviewProvider.refreshIngsList({ + await getIngListWebviewProvider().refreshIngsList({ ingType: this.inputIsPrivate ? IngType.my : IngType.all, pageIndex: 1, }) diff --git a/src/commands/ing/refresh-ings-list.ts b/src/commands/ing/refresh-ings-list.ts index 71b9fbb7..3e9ece81 100644 --- a/src/commands/ing/refresh-ings-list.ts +++ b/src/commands/ing/refresh-ings-list.ts @@ -1,8 +1,8 @@ import { CmdHandler } from '@/commands/cmd-handler' -import { ingListWebviewProvider } from 'src/services/ings-list-webview-provider' +import { getIngListWebviewProvider } from 'src/services/ings-list-webview-provider' export class RefreshIngsList extends CmdHandler { handle(): Promise { - return ingListWebviewProvider.refreshIngsList() + return getIngListWebviewProvider().refreshIngsList() } } diff --git a/src/commands/ing/select-ing-type.ts b/src/commands/ing/select-ing-type.ts index e716f242..775d01c8 100644 --- a/src/commands/ing/select-ing-type.ts +++ b/src/commands/ing/select-ing-type.ts @@ -1,12 +1,12 @@ import { CmdHandler } from '@/commands/cmd-handler' import { IngType, IngTypesMetadata } from '@/models/ing' -import { ingListWebviewProvider } from '@/services/ings-list-webview-provider' +import { getIngListWebviewProvider } from '@/services/ings-list-webview-provider' import { IDisposable } from '@fluentui/react' import { QuickPickItem, window } from 'vscode' export class SelectIngType extends CmdHandler { handle(): Promise { - const { ingType: curIngType } = ingListWebviewProvider + const { ingType: curIngType } = getIngListWebviewProvider() const options: (QuickPickItem & { ingType: IngType })[] = IngTypesMetadata.map( ([ingType, { displayName, description }]) => ({ label: displayName, @@ -27,7 +27,7 @@ export class SelectIngType extends CmdHandler { if (selectedItem) { const { ingType: selectedIngType } = selectedItem quickPick.hide() - return ingListWebviewProvider.refreshIngsList({ + return getIngListWebviewProvider().refreshIngsList({ pageIndex: 1, ingType: selectedIngType, }) diff --git a/src/extension.ts b/src/extension.ts index f41ad3a1..e2b745c5 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -7,22 +7,22 @@ import { window, ExtensionContext } from 'vscode' import { accountManager } from '@/auth/account-manager' import { observeCfgUpdate, observeWorkspaceFileUpdate, observeWorkspaceUpdate } from '@/services/check-workspace' import { extUriHandler } from '@/utils/uri-handler' -import { ingListWebviewProvider } from 'src/services/ings-list-webview-provider' import { extendMarkdownIt } from '@/markdown/extend-markdownIt' import { Settings } from '@/services/settings.service' +import { getIngListWebviewProvider } from '@/services/ings-list-webview-provider' // this method is called when your extension is activated // your extension is activated the very first time the commands is executed export function activate(ctx: ExtensionContext) { globalCtx.extCtx = ctx - globalCtx.extCtx.subscriptions.push(accountManager) + ctx.subscriptions.push(accountManager) setupExtCmd() setupExtTreeView() - globalCtx.extCtx.subscriptions.push( - window.registerWebviewViewProvider(ingListWebviewProvider.viewId, ingListWebviewProvider) + ctx.subscriptions.push( + window.registerWebviewViewProvider(getIngListWebviewProvider().viewId, getIngListWebviewProvider()) ) observeCfgUpdate() diff --git a/src/services/global-ctx.ts b/src/services/global-ctx.ts index 928aaafc..8feaa24b 100644 --- a/src/services/global-ctx.ts +++ b/src/services/global-ctx.ts @@ -2,8 +2,8 @@ import { env, ExtensionContext, Uri } from 'vscode' import { defaultConfig, devConfig, IExtensionConfig, isDevEnv } from '@/models/config' import path from 'path' -class GlobalCtx { - private _extensionContext?: ExtensionContext +export class GlobalCtx { + private _extensionContext: ExtensionContext | null = null private readonly _config: IExtensionConfig = defaultConfig private readonly _devConfig: IExtensionConfig = devConfig @@ -24,7 +24,7 @@ class GlobalCtx { return this._extensionContext } - set extCtx(v: ExtensionContext | undefined) { + set extCtx(v: ExtensionContext) { this._extensionContext = v } diff --git a/src/services/ings-list-webview-provider.ts b/src/services/ings-list-webview-provider.ts index 2cf6929d..56cb4630 100644 --- a/src/services/ings-list-webview-provider.ts +++ b/src/services/ings-list-webview-provider.ts @@ -51,10 +51,6 @@ export class IngsListWebviewProvider implements WebviewViewProvider { return this._show } - private get assetsUri() { - return globalCtx.assetsUri - } - // eslint-disable-next-line @typescript-eslint/no-unused-vars async resolveWebviewView(webviewView: WebviewView, context: WebviewViewResolveContext, token: CancellationToken) { if (this._view && this._view === webviewView) return @@ -63,7 +59,7 @@ export class IngsListWebviewProvider implements WebviewViewProvider { webviewView.webview.options = { enableScripts: true, - localResourceRoots: [this.assetsUri], + localResourceRoots: [globalCtx.assetsUri], } const disposables: Disposable[] = [] @@ -163,7 +159,12 @@ export class IngsListWebviewProvider implements WebviewViewProvider { } } -export const ingListWebviewProvider = new IngsListWebviewProvider() +let _getIngListWebviewProvider: any = null + +export function getIngListWebviewProvider(): IngsListWebviewProvider { + _getIngListWebviewProvider = new IngsListWebviewProvider() + return _getIngListWebviewProvider +} class IngWebviewMessageObserver { constructor(private _provider: IngsListWebviewProvider) {} From 3b122c954f64d9e7345bd235c6af83ebc0d5c0da Mon Sep 17 00:00:00 2001 From: Thaumy Date: Fri, 21 Jul 2023 16:21:32 +0800 Subject: [PATCH 016/157] refactor: simplify code --- package.json | 62 +++++++++---------- src/auth/account-manager.ts | 16 ++--- src/commands/cmd-register.ts | 2 +- src/commands/ing/comment-ing.ts | 2 +- src/commands/ing/goto-ing-list-page.ts | 25 ++++++++ src/commands/ing/goto-ings-list-page.ts | 25 -------- src/commands/ing/ing-list-cmd-register.ts | 19 ++++++ src/commands/ing/ings-list-cmd-register.ts | 23 ------- src/commands/ing/publish-ing.ts | 4 +- src/commands/ing/refresh-ing-list.ts | 8 +++ src/commands/ing/refresh-ings-list.ts | 8 --- src/commands/ing/select-ing-type.ts | 4 +- src/commands/posts-list/refresh-posts-list.ts | 2 +- src/extension.ts | 2 +- src/models/webview-cmd.ts | 2 +- src/services/check-workspace.ts | 23 ++++--- ...ovider.ts => ing-list-webview-provider.ts} | 22 +++---- ui/ing/App.tsx | 2 +- 18 files changed, 125 insertions(+), 126 deletions(-) create mode 100644 src/commands/ing/goto-ing-list-page.ts delete mode 100644 src/commands/ing/goto-ings-list-page.ts create mode 100644 src/commands/ing/ing-list-cmd-register.ts delete mode 100644 src/commands/ing/ings-list-cmd-register.ts create mode 100644 src/commands/ing/refresh-ing-list.ts delete mode 100644 src/commands/ing/refresh-ings-list.ts rename src/services/{ings-list-webview-provider.ts => ing-list-webview-provider.ts} (87%) diff --git a/package.json b/package.json index a33aa658..7f09ac78 100644 --- a/package.json +++ b/package.json @@ -309,7 +309,7 @@ "command": "vscode-cnb.ing.publish", "title": "发闪存", "category": "Cnblogs", - "enablement": "vscode-cnb.isAuthorized && !vscode-cnb.ingsList.isRefreshing", + "enablement": "vscode-cnb.isAuthorized && !vscode-cnb.ingList.isRefreshing", "icon": "$(add)" }, { @@ -319,42 +319,42 @@ "enablement": "vscode-cnb.isAuthorized && editorHasSelection == true && isInDiffEditor == false && isInEmbeddedEditor == false" }, { - "command": "vscode-cnb.ings-list.refresh", + "command": "vscode-cnb.ing-list.refresh", "title": "刷新闪存列表", "category": "Cnblogs", "icon": "$(refresh)", - "enablement": "vscode-cnb.isAuthorized && !vscode-cnb.ingsList.isRefreshing" + "enablement": "vscode-cnb.isAuthorized && !vscode-cnb.ingList.isRefreshing" }, { - "command": "vscode-cnb.ings-list.previous", + "command": "vscode-cnb.ing-list.previous", "title": "上一页", "category": "Cnblogs", "icon": "$(chevron-left)", - "enablement": "vscode-cnb.isAuthorized && !vscode-cnb.ingsList.isRefreshing && vscode-cnb.ingsList.pageIndex > 1" + "enablement": "vscode-cnb.isAuthorized && !vscode-cnb.ingList.isRefreshing && vscode-cnb.ingList.pageIndex > 1" }, { - "command": "vscode-cnb.ings-list.next", + "command": "vscode-cnb.ing-list.next", "title": "下一页", "category": "Cnblogs", "icon": "$(chevron-right)", - "enablement": "vscode-cnb.isAuthorized && !vscode-cnb.ingsList.isRefreshing && vscode-cnb.ingsList.pageIndex < 500" + "enablement": "vscode-cnb.isAuthorized && !vscode-cnb.ingList.isRefreshing && vscode-cnb.ingList.pageIndex < 500" }, { - "command": "vscode-cnb.ings-list.first", + "command": "vscode-cnb.ing-list.first", "title": "第一页", "category": "Cnblogs", "icon": "$(vscode-cnb-first-page)", - "enablement": "vscode-cnb.isAuthorized && !vscode-cnb.ingsList.isRefreshing && vscode-cnb.ingsList.pageIndex < 500" + "enablement": "vscode-cnb.isAuthorized && !vscode-cnb.ingList.isRefreshing && vscode-cnb.ingList.pageIndex < 500" }, { - "command": "vscode-cnb.ings-list.select-type", + "command": "vscode-cnb.ing-list.select-type", "title": "选择闪存列表", "category": "Cnblogs", "icon": "$(list-filter)", - "enablement": "vscode-cnb.isAuthorized && !vscode-cnb.ingsList.isRefreshing" + "enablement": "vscode-cnb.isAuthorized && !vscode-cnb.ingList.isRefreshing" }, { - "command": "vscode-cnb.ings-list.open-in-browser", + "command": "vscode-cnb.ing-list.open-in-browser", "title": "在浏览器中打开闪存", "icon": "$(globe)", "enablement": "vscode-cnb.isAuthorized" @@ -774,7 +774,7 @@ "visibility": "collapsed" }, { - "id": "vscode-cnb.ings-list-webview", + "id": "vscode-cnb.ing-list-webview", "type": "webview", "name": "闪存", "when": "vscode-cnb.isAuthorized", @@ -830,38 +830,38 @@ "group": "navigation@2" }, { - "command": "vscode-cnb.ings-list.open-in-browser", - "when": "view == vscode-cnb.ings-list-webview", + "command": "vscode-cnb.ing-list.open-in-browser", + "when": "view == vscode-cnb.ing-list-webview", "group": "navigation@0" }, { - "command": "vscode-cnb.ings-list.first", - "when": "view == vscode-cnb.ings-list-webview && vscode-cnb.isAuthorized && !vscode-cnb.ingsList.isRefreshing && vscode-cnb.ingsList.pageIndex > 2", + "command": "vscode-cnb.ing-list.first", + "when": "view == vscode-cnb.ing-list-webview && vscode-cnb.isAuthorized && !vscode-cnb.ingList.isRefreshing && vscode-cnb.ingList.pageIndex > 2", "group": "navigation@1" }, { - "command": "vscode-cnb.ings-list.previous", - "when": "view == vscode-cnb.ings-list-webview", + "command": "vscode-cnb.ing-list.previous", + "when": "view == vscode-cnb.ing-list-webview", "group": "navigation@2" }, { - "command": "vscode-cnb.ings-list.next", - "when": "view == vscode-cnb.ings-list-webview", + "command": "vscode-cnb.ing-list.next", + "when": "view == vscode-cnb.ing-list-webview", "group": "navigation@3" }, { - "command": "vscode-cnb.ings-list.select-type", - "when": "view == vscode-cnb.ings-list-webview", + "command": "vscode-cnb.ing-list.select-type", + "when": "view == vscode-cnb.ing-list-webview", "group": "navigation@4" }, { - "command": "vscode-cnb.ings-list.refresh", - "when": "view == vscode-cnb.ings-list-webview", + "command": "vscode-cnb.ing-list.refresh", + "when": "view == vscode-cnb.ing-list-webview", "group": "navigation@5" }, { "command": "vscode-cnb.ing.publish", - "when": "view == vscode-cnb.ings-list-webview", + "when": "view == vscode-cnb.ing-list-webview", "group": "navigation@6" }, { @@ -957,23 +957,23 @@ "when": "false" }, { - "command": "vscode-cnb.ings-list.refresh", + "command": "vscode-cnb.ing-list.refresh", "when": "false" }, { - "command": "vscode-cnb.ings-list.next", + "command": "vscode-cnb.ing-list.next", "when": "false" }, { - "command": "vscode-cnb.ings-list.first", + "command": "vscode-cnb.ing-list.first", "when": "false" }, { - "command": "vscode-cnb.ings-list.select-type", + "command": "vscode-cnb.ing-list.select-type", "when": "false" }, { - "command": "vscode-cnb.ings-list.open-in-browser", + "command": "vscode-cnb.ing-list.open-in-browser", "when": "false" }, { diff --git a/src/auth/account-manager.ts b/src/auth/account-manager.ts index 175fbb51..0c1b6dbf 100644 --- a/src/auth/account-manager.ts +++ b/src/auth/account-manager.ts @@ -5,7 +5,7 @@ import { accountViewDataProvider } from '@/tree-view-providers/account-view-data import { postsDataProvider } from '@/tree-view-providers/posts-data-provider' import { postCategoriesDataProvider } from '@/tree-view-providers/post-categories-tree-data-provider' import { Oauth } from '@/services/oauth.api' -import { AuthProvider } from '@/auth/auth-provider' +import { authProvider } from '@/auth/auth-provider' import { AuthSession } from '@/auth/auth-session' import { BlogExportProvider } from '@/tree-view-providers/blog-export-provider' import { Alert } from '@/services/alert.service' @@ -18,7 +18,7 @@ export const ACQUIRE_TOKEN_REJECT_EXPIRED = 'expired' class AccountManager extends vscode.Disposable { private readonly _disposable = Disposable.from( - AuthProvider.instance.onDidChangeSessions(async ({ added }) => { + authProvider.onDidChangeSessions(async ({ added }) => { this._session = null if (added != null && added.length > 0) await this.ensureSession() @@ -70,7 +70,7 @@ class AccountManager extends vscode.Disposable { async logout() { if (!this.isAuthorized) return - const session = await authentication.getSession(AuthProvider.providerId, []) + const session = await authentication.getSession(authProvider.providerId, []) // WRN: For old version compatibility, **never** remove this line await globalCtx.storage.update('user', undefined) @@ -78,10 +78,10 @@ class AccountManager extends vscode.Disposable { if (session === undefined) return try { - await AuthProvider.instance.removeSession(session.id) + await authProvider.removeSession(session.id) await Oauth.revokeToken(session.accessToken) } catch (e: any) { - Alert.err(`登出发生错误: ${e}`) + void Alert.err(`登出发生错误: ${e}`) } } @@ -99,16 +99,16 @@ class AccountManager extends vscode.Disposable { } private async ensureSession(opt?: AuthenticationGetSessionOptions): Promise { - const session = await authentication.getSession(AuthProvider.instance.providerId, [], opt).then( + const session = await authentication.getSession(authProvider.providerId, [], opt).then( session => (session ? AuthSession.from(session) : null), e => { - Alert.err(`创建/获取 Session 失败: ${e}`) + void Alert.err(`创建/获取 Session 失败: ${e}`) } ) if (session != null && session.account.accountId < 0) { this._session = null - await AuthProvider.instance.removeSession(session.id) + await authProvider.removeSession(session.id) } else { this._session = session } diff --git a/src/commands/cmd-register.ts b/src/commands/cmd-register.ts index efed50ec..dcd4b481 100644 --- a/src/commands/cmd-register.ts +++ b/src/commands/cmd-register.ts @@ -33,7 +33,7 @@ import { extractImages } from './extract-images' import { clearPostsSearchResults, refreshPostsSearchResults, searchPosts } from './posts-list/search' import { handleDeletePostCategories } from './post-category/delete-selected-categories' import { PublishIngCmdHandler } from '@/commands/ing/publish-ing' -import { regIngListCmds } from 'src/commands/ing/ings-list-cmd-register' +import { regIngListCmds } from 'src/commands/ing/ing-list-cmd-register' import { CopyPostLinkCmdHandler } from '@/commands/posts-list/copy-link' import { regBlogExportCmds } from '@/commands/blog-export' import { regCmd } from '@/utils/cmd' diff --git a/src/commands/ing/comment-ing.ts b/src/commands/ing/comment-ing.ts index 7a66d7cf..bcb8a666 100644 --- a/src/commands/ing/comment-ing.ts +++ b/src/commands/ing/comment-ing.ts @@ -1,6 +1,6 @@ import { CmdHandler } from '@/commands/cmd-handler' import { IngApi } from '@/services/ing.api' -import { getIngListWebviewProvider } from '@/services/ings-list-webview-provider' +import { getIngListWebviewProvider } from '@/services/ing-list-webview-provider' import { ProgressLocation, window } from 'vscode' export class CommentIngCmdHandler extends CmdHandler { diff --git a/src/commands/ing/goto-ing-list-page.ts b/src/commands/ing/goto-ing-list-page.ts new file mode 100644 index 00000000..d5be00b9 --- /dev/null +++ b/src/commands/ing/goto-ing-list-page.ts @@ -0,0 +1,25 @@ +import { CmdHandler } from '@/commands/cmd-handler' +import { getIngListWebviewProvider } from 'src/services/ing-list-webview-provider' + +export class GotoingListNextPage extends CmdHandler { + handle(): Promise { + const provider = getIngListWebviewProvider() + const { pageIndex } = provider + return provider.refreshingList({ pageIndex: pageIndex + 1 }) + } +} + +export class GotoingListPreviousPage extends CmdHandler { + handle(): Promise { + const provider = getIngListWebviewProvider() + const { pageIndex } = provider + if (pageIndex > 1) return provider.refreshingList({ pageIndex: pageIndex - 1 }) + return Promise.resolve() + } +} + +export class GotoingListFirstPage extends CmdHandler { + handle(): Promise { + return getIngListWebviewProvider().refreshingList({ pageIndex: 1 }) + } +} diff --git a/src/commands/ing/goto-ings-list-page.ts b/src/commands/ing/goto-ings-list-page.ts deleted file mode 100644 index 43637d20..00000000 --- a/src/commands/ing/goto-ings-list-page.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { CmdHandler } from '@/commands/cmd-handler' -import { getIngListWebviewProvider } from 'src/services/ings-list-webview-provider' - -export class GotoIngsListNextPage extends CmdHandler { - handle(): Promise { - const provider = getIngListWebviewProvider() - const { pageIndex } = provider - return provider.refreshIngsList({ pageIndex: pageIndex + 1 }) - } -} - -export class GotoIngsListPreviousPage extends CmdHandler { - handle(): Promise { - const provider = getIngListWebviewProvider() - const { pageIndex } = provider - if (pageIndex > 1) return provider.refreshIngsList({ pageIndex: pageIndex - 1 }) - return Promise.resolve() - } -} - -export class GotoIngsListFirstPage extends CmdHandler { - handle(): Promise { - return getIngListWebviewProvider().refreshIngsList({ pageIndex: 1 }) - } -} diff --git a/src/commands/ing/ing-list-cmd-register.ts b/src/commands/ing/ing-list-cmd-register.ts new file mode 100644 index 00000000..2674131d --- /dev/null +++ b/src/commands/ing/ing-list-cmd-register.ts @@ -0,0 +1,19 @@ +import { RefreshingList } from 'src/commands/ing/refresh-ing-list' +import { globalCtx } from 'src/services/global-ctx' +import { GotoingListFirstPage, GotoingListNextPage, GotoingListPreviousPage } from 'src/commands/ing/goto-ing-list-page' +import { SelectIngType } from '@/commands/ing/select-ing-type' +import { OpenIngInBrowser } from '@/commands/ing/open-ing-in-browser' +import { regCmd } from '@/utils/cmd' + +export const regIngListCmds = () => { + const appName = globalCtx.extName + + return [ + regCmd(`${appName}.ing-list.refresh`, () => new RefreshingList().handle()), + regCmd(`${appName}.ing-list.next`, () => new GotoingListNextPage().handle()), + regCmd(`${appName}.ing-list.previous`, () => new GotoingListPreviousPage().handle()), + regCmd(`${appName}.ing-list.first`, () => new GotoingListFirstPage().handle()), + regCmd(`${appName}.ing-list.select-type`, () => new SelectIngType().handle()), + regCmd(`${appName}.ing-list.open-in-browser`, () => new OpenIngInBrowser().handle()), + ] +} diff --git a/src/commands/ing/ings-list-cmd-register.ts b/src/commands/ing/ings-list-cmd-register.ts deleted file mode 100644 index 892e9a79..00000000 --- a/src/commands/ing/ings-list-cmd-register.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { RefreshIngsList } from 'src/commands/ing/refresh-ings-list' -import { globalCtx } from 'src/services/global-ctx' -import { - GotoIngsListFirstPage, - GotoIngsListNextPage, - GotoIngsListPreviousPage, -} from 'src/commands/ing/goto-ings-list-page' -import { SelectIngType } from '@/commands/ing/select-ing-type' -import { OpenIngInBrowser } from '@/commands/ing/open-ing-in-browser' -import { regCmd } from '@/utils/cmd' - -export const regIngListCmds = () => { - const appName = globalCtx.extName - - return [ - regCmd(`${appName}.ings-list.refresh`, () => new RefreshIngsList().handle()), - regCmd(`${appName}.ings-list.next`, () => new GotoIngsListNextPage().handle()), - regCmd(`${appName}.ings-list.previous`, () => new GotoIngsListPreviousPage().handle()), - regCmd(`${appName}.ings-list.first`, () => new GotoIngsListFirstPage().handle()), - regCmd(`${appName}.ings-list.select-type`, () => new SelectIngType().handle()), - regCmd(`${appName}.ings-list.open-in-browser`, () => new OpenIngInBrowser().handle()), - ] -} diff --git a/src/commands/ing/publish-ing.ts b/src/commands/ing/publish-ing.ts index b4fa70b9..de216f2c 100644 --- a/src/commands/ing/publish-ing.ts +++ b/src/commands/ing/publish-ing.ts @@ -4,7 +4,7 @@ import { IngPublishModel, IngType } from '@/models/ing' import { Alert } from '@/services/alert.service' import { globalCtx } from '@/services/global-ctx' import { IngApi } from '@/services/ing.api' -import { getIngListWebviewProvider } from '@/services/ings-list-webview-provider' +import { getIngListWebviewProvider } from '@/services/ing-list-webview-provider' import { InputStep, MultiStepInput, QuickPickParameters } from '@/services/multi-step-input' import { MessageOptions, ProgressLocation, QuickPickItem, Uri, window } from 'vscode' @@ -151,7 +151,7 @@ export class PublishIngCmdHandler extends CmdHandler { private async onPublished(isPublished: boolean): Promise { if (isPublished) { - await getIngListWebviewProvider().refreshIngsList({ + await getIngListWebviewProvider().refreshingList({ ingType: this.inputIsPrivate ? IngType.my : IngType.all, pageIndex: 1, }) diff --git a/src/commands/ing/refresh-ing-list.ts b/src/commands/ing/refresh-ing-list.ts new file mode 100644 index 00000000..53287886 --- /dev/null +++ b/src/commands/ing/refresh-ing-list.ts @@ -0,0 +1,8 @@ +import { CmdHandler } from '@/commands/cmd-handler' +import { getIngListWebviewProvider } from 'src/services/ing-list-webview-provider' + +export class RefreshingList extends CmdHandler { + handle(): Promise { + return getIngListWebviewProvider().refreshingList() + } +} diff --git a/src/commands/ing/refresh-ings-list.ts b/src/commands/ing/refresh-ings-list.ts deleted file mode 100644 index 3e9ece81..00000000 --- a/src/commands/ing/refresh-ings-list.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { CmdHandler } from '@/commands/cmd-handler' -import { getIngListWebviewProvider } from 'src/services/ings-list-webview-provider' - -export class RefreshIngsList extends CmdHandler { - handle(): Promise { - return getIngListWebviewProvider().refreshIngsList() - } -} diff --git a/src/commands/ing/select-ing-type.ts b/src/commands/ing/select-ing-type.ts index 775d01c8..6ba28546 100644 --- a/src/commands/ing/select-ing-type.ts +++ b/src/commands/ing/select-ing-type.ts @@ -1,6 +1,6 @@ import { CmdHandler } from '@/commands/cmd-handler' import { IngType, IngTypesMetadata } from '@/models/ing' -import { getIngListWebviewProvider } from '@/services/ings-list-webview-provider' +import { getIngListWebviewProvider } from '@/services/ing-list-webview-provider' import { IDisposable } from '@fluentui/react' import { QuickPickItem, window } from 'vscode' @@ -27,7 +27,7 @@ export class SelectIngType extends CmdHandler { if (selectedItem) { const { ingType: selectedIngType } = selectedItem quickPick.hide() - return getIngListWebviewProvider().refreshIngsList({ + return getIngListWebviewProvider().refreshingList({ pageIndex: 1, ingType: selectedIngType, }) diff --git a/src/commands/posts-list/refresh-posts-list.ts b/src/commands/posts-list/refresh-posts-list.ts index 4eed50fa..1014f163 100644 --- a/src/commands/posts-list/refresh-posts-list.ts +++ b/src/commands/posts-list/refresh-posts-list.ts @@ -92,7 +92,7 @@ const setPostListContext = async (pageCount: number, hasPrevious: boolean, hasNe } const alertRefreshing = () => { - Alert.info('正在刷新, 请勿重复操作') + void Alert.info('正在刷新, 请勿重复操作') } const gotoPage = async (pageIndex: (currentIndex: number) => number) => { diff --git a/src/extension.ts b/src/extension.ts index e2b745c5..54e51b53 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -9,7 +9,7 @@ import { observeCfgUpdate, observeWorkspaceFileUpdate, observeWorkspaceUpdate } import { extUriHandler } from '@/utils/uri-handler' import { extendMarkdownIt } from '@/markdown/extend-markdownIt' import { Settings } from '@/services/settings.service' -import { getIngListWebviewProvider } from '@/services/ings-list-webview-provider' +import { getIngListWebviewProvider } from '@/services/ing-list-webview-provider' // this method is called when your extension is activated // your extension is activated the very first time the commands is executed diff --git a/src/models/webview-cmd.ts b/src/models/webview-cmd.ts index 03435f27..fba945cf 100644 --- a/src/models/webview-cmd.ts +++ b/src/models/webview-cmd.ts @@ -35,7 +35,7 @@ export namespace WebviewCmd { } export enum ExtCmd { - refreshIngsList = 'refreshIngsList', + refreshingList = 'refreshingList', comment = 'comment', } diff --git a/src/services/check-workspace.ts b/src/services/check-workspace.ts index b25ad770..435bd942 100644 --- a/src/services/check-workspace.ts +++ b/src/services/check-workspace.ts @@ -25,35 +25,38 @@ export const isTargetWorkspace = (): boolean => { return isTarget } -export const observeConfigurationChange = () => { +export const observeCfgUpdate = () => { globalCtx.extCtx?.subscriptions.push( workspace.onDidChangeConfiguration(ev => { - if (ev.affectsConfiguration(Settings.prefix)) isTargetWorkspace() + if (ev.affectsConfiguration(Settings.cfgPrefix)) isTargetWorkspace() if (ev.affectsConfiguration(`${Settings.iconThemePrefix}.${Settings.iconThemeKey}`)) refreshPostCategoriesList() - if (ev.affectsConfiguration(`${Settings.prefix}.${Settings.postsListPageSizeKey}`)) + if (ev.affectsConfiguration(`${Settings.cfgPrefix}.${Settings.postsListPageSizeKey}`)) refreshPostsList({ queue: true }).catch(() => undefined) - if (ev.affectsConfiguration(`${Settings.prefix}.markdown`)) + if (ev.affectsConfiguration(`${Settings.cfgPrefix}.markdown`)) execCmd('markdown.preview.refresh').then(undefined, () => undefined) }) ) isTargetWorkspace() } -export const observeWorkspaceFolderAndFileChange = () => { - globalCtx.extCtx?.subscriptions.push( +export const observeWorkspaceUpdate = () => + void globalCtx.extCtx?.subscriptions.push( + workspace.onDidChangeWorkspaceFolders(() => { + isTargetWorkspace() + }) + ) + +export const observeWorkspaceFileUpdate = () => + void globalCtx.extCtx?.subscriptions.push( workspace.onDidRenameFiles(e => { for (const item of e.files) { const { oldUri, newUri } = item const postId = PostFileMapManager.getPostId(oldUri.fsPath) if (postId !== undefined) void PostFileMapManager.updateOrCreate(postId, newUri.fsPath) } - }), - workspace.onDidChangeWorkspaceFolders(() => { - isTargetWorkspace() }) ) -} diff --git a/src/services/ings-list-webview-provider.ts b/src/services/ing-list-webview-provider.ts similarity index 87% rename from src/services/ings-list-webview-provider.ts rename to src/services/ing-list-webview-provider.ts index 56cb4630..1e09de3f 100644 --- a/src/services/ings-list-webview-provider.ts +++ b/src/services/ing-list-webview-provider.ts @@ -17,8 +17,8 @@ import { isNumber } from 'lodash-es' import { CommentIngCmdHandler } from '@/commands/ing/comment-ing' import { execCmd } from '@/utils/cmd' -export class IngsListWebviewProvider implements WebviewViewProvider { - readonly viewId = `${globalCtx.extName}.ings-list-webview` +export class ingListWebviewProvider implements WebviewViewProvider { + readonly viewId = `${globalCtx.extName}.ing-list-webview` private readonly _baseTitle = '闪存' private _view: WebviewView | null = null @@ -76,7 +76,7 @@ export class IngsListWebviewProvider implements WebviewViewProvider { }, disposables) } - async refreshIngsList({ ingType = this.ingType, pageIndex = this.pageIndex } = {}) { + async refreshingList({ ingType = this.ingType, pageIndex = this.pageIndex } = {}) { if (!this._view || !this.show) return if (this._view.visible) { @@ -131,7 +131,7 @@ export class IngsListWebviewProvider implements WebviewViewProvider { } private async setIsRefreshing(value: boolean) { - await execCmd('setContext', `${globalCtx.extName}.ingsList.isRefreshing`, value ? true : undefined).then( + await execCmd('setContext', `${globalCtx.extName}.ingList.isRefreshing`, value ? true : undefined).then( undefined, () => undefined ) @@ -139,7 +139,7 @@ export class IngsListWebviewProvider implements WebviewViewProvider { } private async setPageIndex(value: number) { - await execCmd('setContext', `${globalCtx.extName}.ingsList.pageIndex`, value > 0 ? value : undefined).then( + await execCmd('setContext', `${globalCtx.extName}.ingList.pageIndex`, value > 0 ? value : undefined).then( undefined, () => undefined ) @@ -161,19 +161,19 @@ export class IngsListWebviewProvider implements WebviewViewProvider { let _getIngListWebviewProvider: any = null -export function getIngListWebviewProvider(): IngsListWebviewProvider { - _getIngListWebviewProvider = new IngsListWebviewProvider() - return _getIngListWebviewProvider +export function getIngListWebviewProvider(): ingListWebviewProvider { + _getIngListWebviewProvider = new ingListWebviewProvider() + return _getIngListWebviewProvider } class IngWebviewMessageObserver { - constructor(private _provider: IngsListWebviewProvider) {} + constructor(private _provider: ingListWebviewProvider) {} observer = ({ command, payload }: IngWebviewHostCmd) => { switch (command) { - case WebviewCmd.IngCmd.ExtCmd.refreshIngsList: { + case WebviewCmd.IngCmd.ExtCmd.refreshingList: { const { ingType, pageIndex } = payload - return this._provider.refreshIngsList({ + return this._provider.refreshingList({ ingType: ingType && Object.values(IngType).includes(ingType as IngType) ? (ingType as IngType) diff --git a/ui/ing/App.tsx b/ui/ing/App.tsx index fde339d5..0733b01c 100644 --- a/ui/ing/App.tsx +++ b/ui/ing/App.tsx @@ -76,7 +76,7 @@ export class App extends Component { private refresh() { getVsCodeApiSingleton().postMessage({ - command: WebviewCmd.IngCmd.ExtCmd.refreshIngsList, + command: WebviewCmd.IngCmd.ExtCmd.refreshingList, payload: {}, }) } From 07ece2ef84c89c523646f4f714fb3d0c1c04a633 Mon Sep 17 00:00:00 2001 From: Thaumy Date: Fri, 21 Jul 2023 16:34:09 +0800 Subject: [PATCH 017/157] refactor: simplify code --- .vscode/settings.json | 2 +- package.json | 110 +++++++++--------- src/auth/account-manager.ts | 4 +- src/commands/blog-export/edit.ts | 2 +- src/commands/cmd-register.ts | 41 +++---- src/commands/ing/select-ing-type.ts | 3 +- src/commands/pdf/export-pdf.ts | 28 ++--- .../{posts-list => post-list}/copy-link.ts | 0 .../create-local-draft.ts | 0 .../delete-post-to-local-file-map.ts | 22 ++-- .../{posts-list => post-list}/delete-post.ts | 38 +++--- .../modify-post-settings.ts | 10 +- .../open-post-file.ts | 0 .../open-post-in-vscode.ts | 2 +- .../refresh-post-list.ts} | 66 +++++------ .../{posts-list => post-list}/rename-post.ts | 10 +- .../{posts-list => post-list}/search.ts | 10 +- .../{posts-list => post-list}/upload-post.ts | 14 +-- src/commands/pull-post-remote-updates.ts | 6 +- src/commands/show-local-file-to-post-info.ts | 4 +- src/models/ing-view.ts | 2 +- src/models/ing.ts | 2 +- ...posts-list-state.ts => post-list-state.ts} | 2 +- src/services/check-workspace.ts | 6 +- src/services/ing-list-webview-provider.ts | 6 +- src/services/post-cfg-panel.service.ts | 2 +- src/services/post-file-map.ts | 6 +- .../{posts-list-view.ts => post-list-view.ts} | 4 +- src/services/post.service.ts | 46 ++++---- src/services/search-post-by-title.ts | 7 +- src/services/settings.service.ts | 6 +- .../blog-export-provider.ts | 6 +- .../models/blog-export/downloaded.ts | 6 +- .../models/blog-export/post.ts | 4 +- .../models/post-search-result-entry.ts | 10 +- .../post-categories-tree-data-provider.ts | 12 +- ...data-provider.ts => post-data-provider.ts} | 54 ++++----- .../tree-view-registration.ts | 38 +++--- src/utils/uri-handler.ts | 2 +- ui/ing/App.tsx | 8 +- ui/ing/IngList.tsx | 4 +- 41 files changed, 299 insertions(+), 306 deletions(-) rename src/commands/{posts-list => post-list}/copy-link.ts (100%) rename src/commands/{posts-list => post-list}/create-local-draft.ts (100%) rename src/commands/{posts-list => post-list}/delete-post-to-local-file-map.ts (61%) rename src/commands/{posts-list => post-list}/delete-post.ts (72%) rename src/commands/{posts-list => post-list}/modify-post-settings.ts (87%) rename src/commands/{posts-list => post-list}/open-post-file.ts (100%) rename src/commands/{posts-list => post-list}/open-post-in-vscode.ts (98%) rename src/commands/{posts-list/refresh-posts-list.ts => post-list/refresh-post-list.ts} (58%) rename src/commands/{posts-list => post-list}/rename-post.ts (90%) rename src/commands/{posts-list => post-list}/search.ts (52%) rename src/commands/{posts-list => post-list}/upload-post.ts (94%) rename src/models/{posts-list-state.ts => post-list-state.ts} (84%) rename src/services/{posts-list-view.ts => post-list-view.ts} (75%) rename src/tree-view-providers/{posts-data-provider.ts => post-data-provider.ts} (60%) diff --git a/.vscode/settings.json b/.vscode/settings.json index ee6b5d33..1c1617f8 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -17,7 +17,7 @@ "CLIENTSECRET", "fluentui", "iconfont", - "ings", + "ing", "nbsp", "OAUTHCLIENTID", "OAUTHCLIENTSECRET", diff --git a/package.json b/package.json index 7f09ac78..068413e0 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "workspaceContains:**", "onView:cnblogs-authorize", "onView:cnblogs-account", - "onView:cnblogs-posts-list", + "onView:cnblogs-post-list", "onView:vscode-cnb-workspace", "onCommand:vscode-cnb.open-workspace", "onCommand:vscode-cnb.login", @@ -84,15 +84,15 @@ "fontCharacter": "\\e65b" } }, - "vscode-cnb-posts-list-search": { - "description": "posts list search", + "vscode-cnb-post-list-search": { + "description": "post list search", "default": { "fontPath": "dist/assets/icons.woff2", "fontCharacter": "\\e610" } }, - "vscode-cnb-posts-list-search-result-summary": { - "description": "posts list search result summary", + "vscode-cnb-post-list-search-result-summary": { + "description": "post list search result summary", "default": { "fontPath": "dist/assets/icons.woff2", "fontCharacter": "\\e674" @@ -120,45 +120,45 @@ "enablement": "vscode-cnb.isAuthorized" }, { - "command": "vscode-cnb.previous-posts-list", + "command": "vscode-cnb.previous-post-list", "title": "上一页", "icon": "$(chevron-left)", - "enablement": "vscode-cnb.isAuthorized && !vscode-cnb.posts-list.refreshing && vscode-cnb.posts-list.hasPrevious", - "category": "Cnblogs Posts List" + "enablement": "vscode-cnb.isAuthorized && !vscode-cnb.post-list.refreshing && vscode-cnb.post-list.hasPrevious", + "category": "Cnblogs Post List" }, { - "command": "vscode-cnb.seek-posts-list", + "command": "vscode-cnb.seek-post-list", "title": "跳页", "icon": "$(vscode-cnb-icon-seek)", - "enablement": "vscode-cnb.isAuthorized && !vscode-cnb.posts-list.refreshing && vscode-cnb.posts-list.pageCount > 0", - "category": "Cnblogs Posts List" + "enablement": "vscode-cnb.isAuthorized && !vscode-cnb.post-list.refreshing && vscode-cnb.post-list.pageCount > 0", + "category": "Cnblogs Post List" }, { - "command": "vscode-cnb.next-posts-list", + "command": "vscode-cnb.next-post-list", "title": "下一页", "icon": "$(chevron-right)", - "enablement": "vscode-cnb.isAuthorized && !vscode-cnb.posts-list.refreshing && vscode-cnb.posts-list.hasNext", - "category": "Cnblogs Posts List" + "enablement": "vscode-cnb.isAuthorized && !vscode-cnb.post-list.refreshing && vscode-cnb.post-list.hasNext", + "category": "Cnblogs Post List" }, { - "command": "vscode-cnb.refresh-posts-list", + "command": "vscode-cnb.refresh-post-list", "title": "刷新", "icon": "$(refresh)", - "enablement": "vscode-cnb.isAuthorized && !vscode-cnb.posts-list.refreshing", - "category": "Cnblogs Posts List" + "enablement": "vscode-cnb.isAuthorized && !vscode-cnb.post-list.refreshing", + "category": "Cnblogs Post List" }, { "command": "vscode-cnb.upload-post", "title": "上传博文", "icon": "$(cloud-upload)", - "category": "Cnblogs Posts List", + "category": "Cnblogs Post List", "enablement": "vscode-cnb.isAuthorized" }, { "command": "vscode-cnb.delete-post", "title": "删除随笔(支持多选)", "icon": "$(trash)", - "category": "Cnblogs Posts List", + "category": "Cnblogs Post List", "enablement": "vscode-cnb.isAuthorized" }, { @@ -171,7 +171,7 @@ "command": "vscode-cnb.modify-post-settings", "title": "博文设置", "icon": "$(gear)", - "category": "Cnblogs Posts List", + "category": "Cnblogs Post List", "enablement": "vscode-cnb.isAuthorized" }, { @@ -248,12 +248,12 @@ { "command": "vscode-cnb.delete-post-to-local-file-map", "title": "取消关联本地文件(支持多选)", - "category": "Cnblogs Posts List" + "category": "Cnblogs Post List" }, { "command": "vscode-cnb.rename-post", "title": "重命名博文", - "category": "Cnblogs Posts List", + "category": "Cnblogs Post List", "enablement": "vscode-cnb.isAuthorized" }, { @@ -285,25 +285,25 @@ "enablement": "vscode-cnb.isAuthorized" }, { - "command": "vscode-cnb.search-posts", + "command": "vscode-cnb.search-post", "title": "搜索博文", "category": "Cnblogs", - "icon": "$(vscode-cnb-posts-list-search)", - "enablement": "vscode-cnb.isAuthorized && !vscode-cnb.posts-list.refreshing" + "icon": "$(vscode-cnb-post-list-search)", + "enablement": "vscode-cnb.isAuthorized && !vscode-cnb.post-list.refreshing" }, { - "command": "vscode-cnb.clear-posts-search-results", + "command": "vscode-cnb.clear-post-search-results", "title": "清除随笔搜索结果", "category": "Cnblogs", "icon": "$(clear-all)", - "enablement": "vscode-cnb.isAuthorized && !vscode-cnb.posts-list.refreshing" + "enablement": "vscode-cnb.isAuthorized && !vscode-cnb.post-list.refreshing" }, { - "command": "vscode-cnb.refresh-posts-search-results", + "command": "vscode-cnb.refresh-post-search-results", "title": "刷新随笔搜索结果", "category": "Cnblogs", "icon": "$(refresh)", - "enablement": "vscode-cnb.isAuthorized && !vscode-cnb.posts-list-refreshing" + "enablement": "vscode-cnb.isAuthorized && !vscode-cnb.post-list-refreshing" }, { "command": "vscode-cnb.ing.publish", @@ -487,7 +487,7 @@ "editPresentation": "singlelineText", "markdownDescription": "提取图片, 配置上传到博客园时要自动提取上传到博客园的图片" }, - "cnblogsClient.pageSize.postsList": { + "cnblogsClient.pageSize.postList": { "order": 7, "default": 30, "scope": "application", @@ -725,7 +725,7 @@ "views": { "explorer": [ { - "id": "cnblogs-posts-list", + "id": "cnblogs-post-list", "name": "随笔列表", "when": "vscode-cnb.isAuthorized && vscode-cnb.isTargetWorkspace" } @@ -744,7 +744,7 @@ "visibility": "collapsed" }, { - "id": "cnblogs-posts-list-another", + "id": "cnblogs-post-list-another", "name": "随笔列表", "when": "vscode-cnb.isAuthorized", "visibility": "collapsed" @@ -790,34 +790,34 @@ "group": "navigation" }, { - "command": "vscode-cnb.previous-posts-list", - "when": "view == cnblogs-posts-list || view == cnblogs-posts-list-another", + "command": "vscode-cnb.previous-post-list", + "when": "view == cnblogs-post-list || view == cnblogs-post-list-another", "group": "navigation@1" }, { - "command": "vscode-cnb.next-posts-list", - "when": "view == cnblogs-posts-list || view == cnblogs-posts-list-another", + "command": "vscode-cnb.next-post-list", + "when": "view == cnblogs-post-list || view == cnblogs-post-list-another", "group": "navigation@2" }, { - "command": "vscode-cnb.seek-posts-list", - "when": "view == cnblogs-posts-list || view == cnblogs-posts-list-another", + "command": "vscode-cnb.seek-post-list", + "when": "view == cnblogs-post-list || view == cnblogs-post-list-another", "group": "navigation@3" }, { - "command": "vscode-cnb.refresh-posts-list", - "when": "view == cnblogs-posts-list || view == cnblogs-posts-list-another", + "command": "vscode-cnb.refresh-post-list", + "when": "view == cnblogs-post-list || view == cnblogs-post-list-another", "group": "navigation@4" }, { - "command": "vscode-cnb.search-posts", - "when": "view == cnblogs-posts-list || view == cnblogs-posts-list-another", + "command": "vscode-cnb.search-post", + "when": "view == cnblogs-post-list || view == cnblogs-post-list-another", "group": "navigation@5" }, { "command": "vscode-cnb.create-local-draft", "group": "navigation@6", - "when": "view == cnblogs-posts-list || view == cnblogs-posts-list-another" + "when": "view == cnblogs-post-list || view == cnblogs-post-list-another" }, { "command": "vscode-cnb.new-post-category", @@ -921,11 +921,11 @@ "when": "false" }, { - "command": "vscode-cnb.next-posts-list", + "command": "vscode-cnb.next-post-list", "when": "false" }, { - "command": "vscode-cnb.seek-posts-list", + "command": "vscode-cnb.seek-post-list", "when": "false" }, { @@ -1091,24 +1091,24 @@ "when": "viewItem == cnb-post-category" }, { - "command": "vscode-cnb.refresh-posts-search-results", - "when": "viewItem == cnblogs-posts-search-results-entry", + "command": "vscode-cnb.refresh-post-search-results", + "when": "viewItem == cnblogs-post-search-results-entry", "group": "inline@1" }, { - "command": "vscode-cnb.clear-posts-search-results", - "when": "viewItem == cnblogs-posts-search-results-entry", + "command": "vscode-cnb.clear-post-search-results", + "when": "viewItem == cnblogs-post-search-results-entry", "group": "inline@2" }, { - "command": "vscode-cnb.refresh-posts-search-results", - "when": "viewItem == cnblogs-posts-search-results-entry", - "group": "cnblogs-posts-search-results-entry@1" + "command": "vscode-cnb.refresh-post-search-results", + "when": "viewItem == cnblogs-post-search-results-entry", + "group": "cnblogs-post-search-results-entry@1" }, { - "command": "vscode-cnb.clear-posts-search-results", - "when": "viewItem == cnblogs-posts-search-results-entry", - "group": "cnblogs-posts-search-results-entry@2" + "command": "vscode-cnb.clear-post-search-results", + "when": "viewItem == cnblogs-post-search-results-entry", + "group": "cnblogs-post-search-results-entry@2" }, { "command": "vscode-cnb.blog-export.open-local-export", diff --git a/src/auth/account-manager.ts b/src/auth/account-manager.ts index 0c1b6dbf..17fe54da 100644 --- a/src/auth/account-manager.ts +++ b/src/auth/account-manager.ts @@ -2,7 +2,7 @@ import { AccountInfo } from './account-info' import { globalCtx } from '@/services/global-ctx' import vscode, { authentication, AuthenticationGetSessionOptions, Disposable } from 'vscode' import { accountViewDataProvider } from '@/tree-view-providers/account-view-data-provider' -import { postsDataProvider } from '@/tree-view-providers/posts-data-provider' +import { postDataProvider } from '@/tree-view-providers/post-data-provider' import { postCategoriesDataProvider } from '@/tree-view-providers/post-categories-tree-data-provider' import { Oauth } from '@/services/oauth.api' import { authProvider } from '@/auth/auth-provider' @@ -25,7 +25,7 @@ class AccountManager extends vscode.Disposable { await this.updateAuthStatus() accountViewDataProvider.fireTreeDataChangedEvent() - postsDataProvider.fireTreeDataChangedEvent(undefined) + postDataProvider.fireTreeDataChangedEvent(undefined) postCategoriesDataProvider.fireTreeDataChangedEvent() BlogExportProvider.optionalInstance?.refreshRecords({ force: false, clearCache: true }).catch(console.warn) diff --git a/src/commands/blog-export/edit.ts b/src/commands/blog-export/edit.ts index 23c12389..43e46ff3 100644 --- a/src/commands/blog-export/edit.ts +++ b/src/commands/blog-export/edit.ts @@ -1,5 +1,5 @@ import { TreeViewCmdHandler } from '@/commands/cmd-handler' -import { openPostFile } from '@/commands/posts-list/open-post-file' +import { openPostFile } from '@/commands/post-list/open-post-file' import { Alert } from '@/services/alert.service' import { Settings } from '@/services/settings.service' import { ExportPostTreeItem } from '@/tree-view-providers/models/blog-export/post' diff --git a/src/commands/cmd-register.ts b/src/commands/cmd-register.ts index dcd4b481..18b50f8d 100644 --- a/src/commands/cmd-register.ts +++ b/src/commands/cmd-register.ts @@ -4,25 +4,20 @@ import { openMyHomePage } from './open-my-home-page' import { login, logout } from './login' import { openMyBlog } from './open-my-blog' import { globalCtx } from '@/services/global-ctx' -import { - gotoNextPostsList, - gotoPreviousPostsList, - refreshPostsList, - seekPostsList, -} from './posts-list/refresh-posts-list' -import { uploadPostFileToCnblogs, uploadPostToCnblogs } from './posts-list/upload-post' -import { createLocalDraft } from './posts-list/create-local-draft' -import { deleteSelectedPosts } from './posts-list/delete-post' -import { modifyPostSettings } from './posts-list/modify-post-settings' +import { gotoNextPostList, gotoPreviousPostList, refreshPostList, seekPostList } from './post-list/refresh-post-list' +import { uploadPostFileToCnblogs, uploadPostToCnblogs } from './post-list/upload-post' +import { createLocalDraft } from './post-list/create-local-draft' +import { deleteSelectedPost } from './post-list/delete-post' +import { modifyPostSettings } from './post-list/modify-post-settings' import { uploadImage } from './upload-image/upload-image' import { revealLocalPostFileInOs } from './reveal-local-post-file-in-os' import { showLocalFileToPostInfo } from './show-local-file-to-post-info' import { newPostCategory } from './post-category/new-post-category' import { refreshPostCategoriesList } from './post-category/refresh-post-categories-list' import { handleUpdatePostCategory } from './post-category/update-post-category' -import { openPostInVscode } from './posts-list/open-post-in-vscode' -import { deletePostToLocalFileMap } from './posts-list/delete-post-to-local-file-map' -import { renamePost } from './posts-list/rename-post' +import { openPostInVscode } from './post-list/open-post-in-vscode' +import { deletePostToLocalFileMap } from './post-list/delete-post-to-local-file-map' +import { renamePost } from './post-list/rename-post' import { openPostInBlogAdmin } from './open-post-in-blog-admin' import { openWorkspace } from './open-workspace' import { setWorkspace } from './set-workspace' @@ -30,11 +25,11 @@ import { revealWorkspaceInOs } from './reveal-workspace-in-os' import { viewPostOnline } from './view-post-online' import { pullPostRemoteUpdates } from './pull-post-remote-updates' import { extractImages } from './extract-images' -import { clearPostsSearchResults, refreshPostsSearchResults, searchPosts } from './posts-list/search' +import { clearPostSearchResults, refreshPostSearchResults, searchPost } from './post-list/search' import { handleDeletePostCategories } from './post-category/delete-selected-categories' import { PublishIngCmdHandler } from '@/commands/ing/publish-ing' import { regIngListCmds } from 'src/commands/ing/ing-list-cmd-register' -import { CopyPostLinkCmdHandler } from '@/commands/posts-list/copy-link' +import { CopyPostLinkCmdHandler } from '@/commands/post-list/copy-link' import { regBlogExportCmds } from '@/commands/blog-export' import { regCmd } from '@/utils/cmd' import { exportPostToPdf } from '@/commands/pdf/export-pdf' @@ -51,14 +46,14 @@ export function setupExtCmd() { regCmd(`${appName}.open-my-blog-console`, openMyWebBlogConsole), regCmd(`${appName}.open-my-account-settings`, openMyAccountSettings), regCmd(`${appName}.logout`, logout), - regCmd(`${appName}.refresh-posts-list`, refreshPostsList), - regCmd(`${appName}.previous-posts-list`, gotoPreviousPostsList), - regCmd(`${appName}.seek-posts-list`, seekPostsList), - regCmd(`${appName}.next-posts-list`, gotoNextPostsList), + regCmd(`${appName}.refresh-post-list`, refreshPostList), + regCmd(`${appName}.previous-post-list`, gotoPreviousPostList), + regCmd(`${appName}.seek-post-list`, seekPostList), + regCmd(`${appName}.next-post-list`, gotoNextPostList), regCmd(`${appName}.edit-post`, openPostInVscode), regCmd(`${appName}.upload-post`, uploadPostToCnblogs), regCmd(`${appName}.modify-post-settings`, modifyPostSettings), - regCmd(`${appName}.delete-post`, deleteSelectedPosts), + regCmd(`${appName}.delete-post`, deleteSelectedPost), regCmd(`${appName}.create-local-draft`, createLocalDraft), regCmd(`${appName}.upload-post-file-to-cnblogs`, uploadPostFileToCnblogs), regCmd(`${appName}.pull-post-remote-updates`, pullPostRemoteUpdates), @@ -80,9 +75,9 @@ export function setupExtCmd() { regCmd(`${appName}.view-post-online`, viewPostOnline), regCmd(`${appName}.export-post-to-pdf`, (input: unknown) => exportPostToPdf(input)), regCmd(`${appName}.extract-images`, extractImages), - regCmd(`${appName}.search-posts`, searchPosts), - regCmd(`${appName}.clear-posts-search-results`, clearPostsSearchResults), - regCmd(`${appName}.refresh-posts-search-results`, refreshPostsSearchResults), + regCmd(`${appName}.search-post`, searchPost), + regCmd(`${appName}.clear-post-search-results`, clearPostSearchResults), + regCmd(`${appName}.refresh-post-search-results`, refreshPostSearchResults), regCmd(`${appName}.copy-post-link`, input => new CopyPostLinkCmdHandler(input).handle()), regCmd(`${appName}.ing.publish`, () => new PublishIngCmdHandler('input').handle()), regCmd(`${appName}.ing.publish-selection`, () => new PublishIngCmdHandler('selection').handle()), diff --git a/src/commands/ing/select-ing-type.ts b/src/commands/ing/select-ing-type.ts index 6ba28546..9a7876e2 100644 --- a/src/commands/ing/select-ing-type.ts +++ b/src/commands/ing/select-ing-type.ts @@ -6,13 +6,12 @@ import { QuickPickItem, window } from 'vscode' export class SelectIngType extends CmdHandler { handle(): Promise { - const { ingType: curIngType } = getIngListWebviewProvider() const options: (QuickPickItem & { ingType: IngType })[] = IngTypesMetadata.map( ([ingType, { displayName, description }]) => ({ label: displayName, ingType: ingType, description: description, - picked: ingType === curIngType, + picked: ingType === getIngListWebviewProvider().ingType, }) ) const quickPick = window.createQuickPick<(typeof options)[0]>() diff --git a/src/commands/pdf/export-pdf.ts b/src/commands/pdf/export-pdf.ts index a4125ebf..26a96afd 100644 --- a/src/commands/pdf/export-pdf.ts +++ b/src/commands/pdf/export-pdf.ts @@ -139,16 +139,16 @@ const inputTargetFolder = async (): Promise => })) ?? [])[0] const handlePostInput = (post: Post | PostTreeItem): Promise => { - const posts: Post[] = [post instanceof PostTreeItem ? post.post : post] - extViews.visiblePostsList()?.selection.map(item => { + const postList: Post[] = [post instanceof PostTreeItem ? post.post : post] + extViews.visiblePostList()?.selection.map(item => { item = item instanceof PostTreeItem ? item.post : item - if (item instanceof Post && !posts.includes(item)) posts.push(item) + if (item instanceof Post && !postList.includes(item)) postList.push(item) }) - return Promise.resolve(posts) + return Promise.resolve(postList) } const handleUriInput = async (uri: Uri): Promise => { - const posts: Post[] = [] + const postList: Post[] = [] const { fsPath } = uri const postId = PostFileMapManager.getPostId(fsPath) const { post: inputPost } = (await PostService.fetchPostEditDto(postId && postId > 0 ? postId : -1)) ?? {} @@ -163,13 +163,13 @@ const handleUriInput = async (uri: Uri): Promise => { } as Post) } - posts.push(inputPost) + postList.push(inputPost) - return posts + return postList } -const mapToPostEditDto = async (posts: Post[]) => - (await Promise.all(posts.map(p => PostService.fetchPostEditDto(p.id)))) +const mapToPostEditDto = async (postList: Post[]) => + (await Promise.all(postList.map(p => PostService.fetchPostEditDto(p.id)))) .filter((x): x is PostEditDto => x != null) .map(x => x?.post) @@ -202,12 +202,12 @@ const exportPostToPdf = async (input: Post | PostTreeItem | Uri | unknown): Prom async progress => { const errors: string[] = [] progress.report({ message: '导出 PDF - 处理博文数据' }) - let selectedPosts = await (input instanceof Post || input instanceof PostTreeItem + let selectedPost = await (input instanceof Post || input instanceof PostTreeItem ? handlePostInput(input) : handleUriInput(input)) - if (selectedPosts.length <= 0) return + if (selectedPost.length <= 0) return - selectedPosts = input instanceof Post ? await mapToPostEditDto(selectedPosts) : selectedPosts + selectedPost = input instanceof Post ? await mapToPostEditDto(selectedPost) : selectedPost progress.report({ message: '选择输出文件夹' }) const dir = await inputTargetFolder() if (!dir || !chromiumPath) return @@ -217,8 +217,8 @@ const exportPostToPdf = async (input: Post | PostTreeItem | Uri | unknown): Prom if (!browser || !page) return ['启动 Chromium 失败'] let idx = 0 - const { length: total } = selectedPosts - for (const post of selectedPosts) { + const { length: total } = selectedPost + for (const post of selectedPost) { try { await exportOne(idx++, total, post, page, dir, progress, blogApp) } catch (err) { diff --git a/src/commands/posts-list/copy-link.ts b/src/commands/post-list/copy-link.ts similarity index 100% rename from src/commands/posts-list/copy-link.ts rename to src/commands/post-list/copy-link.ts diff --git a/src/commands/posts-list/create-local-draft.ts b/src/commands/post-list/create-local-draft.ts similarity index 100% rename from src/commands/posts-list/create-local-draft.ts rename to src/commands/post-list/create-local-draft.ts diff --git a/src/commands/posts-list/delete-post-to-local-file-map.ts b/src/commands/post-list/delete-post-to-local-file-map.ts similarity index 61% rename from src/commands/posts-list/delete-post-to-local-file-map.ts rename to src/commands/post-list/delete-post-to-local-file-map.ts index 0786a92b..0a97800e 100644 --- a/src/commands/posts-list/delete-post-to-local-file-map.ts +++ b/src/commands/post-list/delete-post-to-local-file-map.ts @@ -1,17 +1,17 @@ import { MessageOptions, window } from 'vscode' import { Post } from '@/models/post' import { PostFileMap, PostFileMapManager } from '@/services/post-file-map' -import { revealPostsListItem } from '@/services/posts-list-view' +import { revealPostListItem } from '@/services/post-list-view' import { PostTreeItem } from '@/tree-view-providers/models/post-tree-item' import { extViews } from '@/tree-view-providers/tree-view-registration' import { Alert } from '@/services/alert.service' -const confirm = async (posts: Post[]): Promise => { +const confirm = async (postList: Post[]): Promise => { const options = ['确定'] const input = await Alert.info( '确定要取消这些博文与本地文件的关联吗?', { - detail: posts.map(x => x.title).join(', '), + detail: postList.map(x => x.title).join(', '), modal: true, } as MessageOptions, ...options @@ -21,17 +21,17 @@ const confirm = async (posts: Post[]): Promise => { export const deletePostToLocalFileMap = async (post: Post | PostTreeItem) => { post = post instanceof PostTreeItem ? post.post : post - const view = extViews.postsList - let selectedPosts = view.selection + const view = extViews.postList + let selectedPost = view.selection .map(x => (x instanceof Post ? x : x instanceof PostTreeItem ? x.post : null)) .filter((x): x is Post => x != null) - if (!selectedPosts.includes(post)) { - await revealPostsListItem(post) - selectedPosts = post ? [post] : [] + if (!selectedPost.includes(post)) { + await revealPostListItem(post) + selectedPost = post ? [post] : [] } - if (selectedPosts.length <= 0) return + if (selectedPost.length <= 0) return - if (!(await confirm(selectedPosts))) return + if (!(await confirm(selectedPost))) return - await PostFileMapManager.updateOrCreateMany(selectedPosts.map(p => [p.id, ''] as PostFileMap)) + await PostFileMapManager.updateOrCreateMany(selectedPost.map(p => [p.id, ''] as PostFileMap)) } diff --git a/src/commands/posts-list/delete-post.ts b/src/commands/post-list/delete-post.ts similarity index 72% rename from src/commands/posts-list/delete-post.ts rename to src/commands/post-list/delete-post.ts index e00a2fd1..b9f2cf5f 100644 --- a/src/commands/posts-list/delete-post.ts +++ b/src/commands/post-list/delete-post.ts @@ -3,25 +3,25 @@ import { Post } from '@/models/post' import { Alert } from '@/services/alert.service' import { PostService } from '@/services/post.service' import { PostFileMap, PostFileMapManager } from '@/services/post-file-map' -import { postsDataProvider } from '@/tree-view-providers/posts-data-provider' +import { postDataProvider } from '@/tree-view-providers/post-data-provider' import { extViews } from '@/tree-view-providers/tree-view-registration' -import { refreshPostsList } from './refresh-posts-list' +import { refreshPostList } from './refresh-post-list' import { PostTreeItem } from '@/tree-view-providers/models/post-tree-item' import { postCategoriesDataProvider } from '@/tree-view-providers/post-categories-tree-data-provider' let isDeleting = false const confirmDelete = async ( - selectedPosts: Post[] + selectedPost: Post[] ): Promise<{ confirmed: boolean; deleteLocalFileAtSameTime: boolean }> => { const result = { confirmed: false, deleteLocalFileAtSameTime: false } - if (!selectedPosts || selectedPosts.length <= 0) return result + if (!selectedPost || selectedPost.length <= 0) return result const items = ['确定(保留本地文件)', '确定(同时删除本地文件)'] const clicked = await Alert.warn( '确定要删除吗?', { - detail: `确认后将会删除 ${selectedPosts.map(x => x.title).join(', ')} 这${selectedPosts.length}篇博文吗?`, + detail: `确认后将会删除 ${selectedPost.map(x => x.title).join(', ')} 这${selectedPost.length}篇博文吗?`, modal: true, } as MessageOptions, ...items @@ -38,21 +38,21 @@ const confirmDelete = async ( return result } -export const deleteSelectedPosts = async (arg: unknown) => { +export const deleteSelectedPost = async (arg: unknown) => { let post: Post if (arg instanceof Post) post = arg else if (arg instanceof PostTreeItem) post = arg.post else return - const selectedPosts: Post[] = post ? [post] : [] - extViews.visiblePostsList()?.selection.map(item => { + const selectedPost: Post[] = post ? [post] : [] + extViews.visiblePostList()?.selection.map(item => { const post = item instanceof PostTreeItem ? item.post : item - if (post instanceof Post && !selectedPosts.includes(post)) { - postsDataProvider.pagedPosts?.items.find(item => item === post) - selectedPosts.push(post) + if (post instanceof Post && !selectedPost.includes(post)) { + postDataProvider.pagedPost?.items.find(item => item === post) + selectedPost.push(post) } }) - if (selectedPosts.length <= 0) return + if (selectedPost.length <= 0) return if (isDeleting) { Alert.warn('休息会儿再点吧~') @@ -60,7 +60,7 @@ export const deleteSelectedPosts = async (arg: unknown) => { } const { confirmed: hasConfirmed, deleteLocalFileAtSameTime: isToDeleteLocalFile } = await confirmDelete( - selectedPosts + selectedPost ) if (!hasConfirmed) return @@ -72,9 +72,9 @@ export const deleteSelectedPosts = async (arg: unknown) => { increment: 0, }) try { - await PostService.deletePosts(selectedPosts.map(p => p.id)) + await PostService.deletePost(...selectedPost.map(p => p.id)) if (isToDeleteLocalFile) { - selectedPosts + selectedPost .map(p => PostFileMapManager.getFilePath(p.id) ?? '') .filter(x => !!x) .forEach(path => { @@ -83,12 +83,12 @@ export const deleteSelectedPosts = async (arg: unknown) => { } await PostFileMapManager.updateOrCreateMany({ emitEvent: false, - maps: selectedPosts.map(p => [p.id, '']), + maps: selectedPost.map(p => [p.id, '']), }) - await refreshPostsList().catch() + await refreshPostList().catch() postCategoriesDataProvider.onPostUpdated({ - refreshPosts: true, - postIds: selectedPosts.map(({ id }) => id), + refreshPost: true, + postIds: selectedPost.map(({ id }) => id), }) } catch (err) { void Alert.err('删除博文失败', { diff --git a/src/commands/posts-list/modify-post-settings.ts b/src/commands/post-list/modify-post-settings.ts similarity index 87% rename from src/commands/posts-list/modify-post-settings.ts rename to src/commands/post-list/modify-post-settings.ts index 3f102a8a..1d8d42aa 100644 --- a/src/commands/posts-list/modify-post-settings.ts +++ b/src/commands/post-list/modify-post-settings.ts @@ -3,12 +3,12 @@ import { Post } from '@/models/post' import { Alert } from '@/services/alert.service' import { PostService } from '@/services/post.service' import { PostFileMapManager } from '@/services/post-file-map' -import { revealPostsListItem } from '@/services/posts-list-view' +import { revealPostListItem } from '@/services/post-list-view' import { PostCfgPanel } from '@/services/post-cfg-panel.service' import fs from 'fs' import { LocalDraft } from '@/services/local-draft.service' import { saveFilePendingChanges } from '@/utils/save-file-pending-changes' -import { postsDataProvider } from '@/tree-view-providers/posts-data-provider' +import { postDataProvider } from '@/tree-view-providers/post-data-provider' import { PostTreeItem } from '@/tree-view-providers/models/post-tree-item' import { postCategoriesDataProvider } from '@/tree-view-providers/post-categories-tree-data-provider' @@ -27,7 +27,7 @@ export const modifyPostSettings = async (input: Post | PostTreeItem | Uri) => { if (!(postId >= 0)) return - if (post) await revealPostsListItem(post) + if (post) await revealPostListItem(post) const editDto = await PostService.fetchPostEditDto(postId) if (!editDto) return @@ -41,8 +41,8 @@ export const modifyPostSettings = async (input: Post | PostTreeItem | Uri) => { localFileUri: localFilePath ? Uri.file(localFilePath) : undefined, successCallback: ({ id }) => { Alert.info('博文已更新') - postsDataProvider.fireTreeDataChangedEvent(id) - postCategoriesDataProvider.onPostUpdated({ refreshPosts: false, postIds: [id] }) + postDataProvider.fireTreeDataChangedEvent(id) + postCategoriesDataProvider.onPostUpdated({ refreshPost: false, postIds: [id] }) }, beforeUpdate: async post => { if (localFilePath && fs.existsSync(localFilePath)) { diff --git a/src/commands/posts-list/open-post-file.ts b/src/commands/post-list/open-post-file.ts similarity index 100% rename from src/commands/posts-list/open-post-file.ts rename to src/commands/post-list/open-post-file.ts diff --git a/src/commands/posts-list/open-post-in-vscode.ts b/src/commands/post-list/open-post-in-vscode.ts similarity index 98% rename from src/commands/posts-list/open-post-in-vscode.ts rename to src/commands/post-list/open-post-in-vscode.ts index 8b33a2ad..b367ec2d 100644 --- a/src/commands/posts-list/open-post-in-vscode.ts +++ b/src/commands/post-list/open-post-in-vscode.ts @@ -1,6 +1,6 @@ import fs from 'fs' import path from 'path' -import { FileSystemError, MessageOptions, Uri, window, workspace } from 'vscode' +import { FileSystemError, MessageOptions, Uri, workspace } from 'vscode' import { Post } from '@/models/post' import { Alert } from '@/services/alert.service' import { PostService } from '@/services/post.service' diff --git a/src/commands/posts-list/refresh-posts-list.ts b/src/commands/post-list/refresh-post-list.ts similarity index 58% rename from src/commands/posts-list/refresh-posts-list.ts rename to src/commands/post-list/refresh-post-list.ts index 1014f163..cb608d97 100644 --- a/src/commands/posts-list/refresh-posts-list.ts +++ b/src/commands/post-list/refresh-post-list.ts @@ -1,47 +1,47 @@ import { globalCtx } from '@/services/global-ctx' import { PostService } from '@/services/post.service' import vscode, { window } from 'vscode' -import { postsDataProvider } from '@/tree-view-providers/posts-data-provider' +import { postDataProvider } from '@/tree-view-providers/post-data-provider' import { Alert } from '@/services/alert.service' -import { PostsListState } from '@/models/posts-list-state' +import { PostListState } from '@/models/post-list-state' import { extViews } from '@/tree-view-providers/tree-view-registration' import { execCmd } from '@/utils/cmd' let refreshTask: Promise | null = null -export const refreshPostsList = async ({ queue = false } = {}): Promise => { +export const refreshPostList = async ({ queue = false } = {}): Promise => { if (isRefreshing && !queue) { alertRefreshing() await refreshTask return false } else if (isRefreshing && refreshTask != null) { await refreshTask - return refreshPostsList() + return refreshPostList() } refreshTask = setRefreshing(true).then(() => - postsDataProvider - .loadPosts() - .then(pagedPosts => + postDataProvider + .loadPost() + .then(pagedPost => setPostListContext( - pagedPosts?.pageCount ?? 0, - pagedPosts?.hasPrevious ?? false, - pagedPosts?.hasNext ?? false + pagedPost?.pageCount ?? 0, + pagedPost?.hasPrevious ?? false, + pagedPost?.hasNext ?? false ) .catch() - .then(() => pagedPosts) + .then(() => pagedPost) ) - .then(pagedPosts => { - if (pagedPosts == null) { + .then(pagedPost => { + if (pagedPost == null) { return Promise.resolve(false).finally(() => Alert.err('刷新博文列表失败')) } else { - return PostService.updatePostsListState(pagedPosts) - .then(() => updatePostsListViewTitle()) + return PostService.updatePostListState(pagedPost) + .then(() => updatePostListViewTitle()) .then(() => true) } }) // TODO: impl `always` fn - .then(ok => postsDataProvider.refreshSearch().then(() => ok)) + .then(ok => postDataProvider.refreshSearch().then(() => ok)) .then(ok => setRefreshing(false).then(() => ok)) .catch(() => false) .finally(() => (refreshTask = null)) @@ -50,22 +50,22 @@ export const refreshPostsList = async ({ queue = false } = {}): Promise return refreshTask } -export const gotoNextPostsList = async () => { +export const gotoNextPostList = async () => { await gotoPage(c => c + 1) } -export const gotoPreviousPostsList = async () => { +export const gotoPreviousPostList = async () => { await gotoPage(c => c - 1) } -export const seekPostsList = async () => { +export const seekPostList = async () => { const input = await window.showInputBox({ placeHolder: '请输入页码', validateInput: i => { const n = Number.parseInt(i) if (isNaN(n) || !n) return '请输入正确格式的页码' - const state = PostService.getPostsListState() + const state = PostService.getPostListState() if (!state) return '博文列表尚未加载' if (isPageIndexInRange(n, state)) return undefined @@ -80,15 +80,15 @@ export const seekPostsList = async () => { let isRefreshing = false const setRefreshing = async (value = false) => { const extName = globalCtx.extName - await execCmd('setContext', `${extName}.posts-list.refreshing`, value).then(undefined, () => false) + await execCmd('setContext', `${extName}.post-list.refreshing`, value).then(undefined, () => false) isRefreshing = value } const setPostListContext = async (pageCount: number, hasPrevious: boolean, hasNext: boolean) => { const extName = globalCtx.extName - await execCmd('setContext', `${extName}.posts-list.hasPrevious`, hasPrevious) - await execCmd('setContext', `${extName}.posts-list.hasNext`, hasNext) - await execCmd('setContext', `${extName}.posts-list.pageCount`, pageCount) + await execCmd('setContext', `${extName}.post-list.hasPrevious`, hasPrevious) + await execCmd('setContext', `${extName}.post-list.hasNext`, hasNext) + await execCmd('setContext', `${extName}.post-list.pageCount`, pageCount) } const alertRefreshing = () => { @@ -100,31 +100,31 @@ const gotoPage = async (pageIndex: (currentIndex: number) => number) => { alertRefreshing() return } - const state = PostService.getPostsListState() + const state = PostService.getPostListState() if (!state) { - console.warn('Cannot goto previous page posts list because post list state not defined') + console.warn('Cannot goto previous page post list because post list state not defined') return } const idx = pageIndex(state.pageIndex) if (!isPageIndexInRange(idx, state)) { console.warn( - `Cannot goto page posts list, page index out of range, max value of page index is ${state.pageCount}` + `Cannot goto page post list, page index out of range, max value of page index is ${state.pageCount}` ) return } state.pageIndex = idx - await PostService.updatePostsListState(state) - await refreshPostsList() + await PostService.updatePostListState(state) + await refreshPostList() } -const isPageIndexInRange = (pageIndex: number, state: PostsListState) => pageIndex <= state.pageCount && pageIndex >= 1 +const isPageIndexInRange = (pageIndex: number, state: PostListState) => pageIndex <= state.pageCount && pageIndex >= 1 -const updatePostsListViewTitle = () => { - const state = PostService.getPostsListState() +const updatePostListViewTitle = () => { + const state = PostService.getPostListState() if (!state) return const { pageIndex, pageCount } = state - const views = [extViews.postsList, extViews.anotherPostsList] + const views = [extViews.postList, extViews.anotherPostList] for (const view of views) { let title = view.title ?? '' const idx = title.indexOf('(') diff --git a/src/commands/posts-list/rename-post.ts b/src/commands/post-list/rename-post.ts similarity index 90% rename from src/commands/posts-list/rename-post.ts rename to src/commands/post-list/rename-post.ts index 5b87bb63..cb884ff3 100644 --- a/src/commands/posts-list/rename-post.ts +++ b/src/commands/post-list/rename-post.ts @@ -4,8 +4,8 @@ import { MessageOptions, ProgressLocation, Uri, window, workspace } from 'vscode import { Post } from '@/models/post' import { PostService } from '@/services/post.service' import { PostFileMapManager } from '@/services/post-file-map' -import { postsDataProvider } from '@/tree-view-providers/posts-data-provider' -import { revealPostsListItem } from '@/services/posts-list-view' +import { postDataProvider } from '@/tree-view-providers/post-data-provider' +import { revealPostListItem } from '@/services/post-list-view' import { PostTreeItem } from '@/tree-view-providers/models/post-tree-item' import { Alert } from '@/services/alert.service' @@ -30,7 +30,7 @@ const renameLinkedFile = async (post: Post): Promise => { const newFilePath = filePath.replace(new RegExp(`${escapeRegExp(fileName)}$`), `${post.title}${ext}`) await workspace.fs.rename(fileUri, Uri.file(newFilePath)) await PostFileMapManager.updateOrCreate(post.id, newFilePath) - postsDataProvider.fireTreeDataChangedEvent(post) + postDataProvider.fireTreeDataChangedEvent(post) } } @@ -38,7 +38,7 @@ export const renamePost = async (arg: Post | PostTreeItem) => { const post = arg instanceof PostTreeItem ? arg.post : arg if (!post) return - await revealPostsListItem(post) + await revealPostListItem(post) const input = await window.showInputBox({ title: '请输入新的博文标题', @@ -67,7 +67,7 @@ export const renamePost = async (arg: Post | PostTreeItem) => { try { await PostService.updatePost(editingPost) post.title = input - postsDataProvider.fireTreeDataChangedEvent(post) + postDataProvider.fireTreeDataChangedEvent(post) hasUpdated = true } catch (err) { void Alert.err('更新博文失败', { diff --git a/src/commands/posts-list/search.ts b/src/commands/post-list/search.ts similarity index 52% rename from src/commands/posts-list/search.ts rename to src/commands/post-list/search.ts index 4492f99f..4d1eae7e 100644 --- a/src/commands/posts-list/search.ts +++ b/src/commands/post-list/search.ts @@ -1,7 +1,7 @@ import { window } from 'vscode' -import { postsDataProvider } from '@/tree-view-providers/posts-data-provider' +import { postDataProvider } from '@/tree-view-providers/post-data-provider' -export const searchPosts = async () => { +export const searchPost = async () => { const searchKey = await window.showInputBox({ ignoreFocusOut: true, title: '搜索博文', @@ -11,9 +11,9 @@ export const searchPosts = async () => { }) if (!searchKey) return - await postsDataProvider.search({ key: searchKey }) + await postDataProvider.search({ key: searchKey }) } -export const clearPostsSearchResults = () => postsDataProvider.clearSearch() +export const clearPostSearchResults = () => postDataProvider.clearSearch() -export const refreshPostsSearchResults = () => postsDataProvider.refreshSearch() +export const refreshPostSearchResults = () => postDataProvider.refreshSearch() diff --git a/src/commands/posts-list/upload-post.ts b/src/commands/post-list/upload-post.ts similarity index 94% rename from src/commands/posts-list/upload-post.ts rename to src/commands/post-list/upload-post.ts index bd219e9f..4e5e35f6 100644 --- a/src/commands/posts-list/upload-post.ts +++ b/src/commands/post-list/upload-post.ts @@ -4,12 +4,12 @@ import { LocalDraft } from '@/services/local-draft.service' import { Alert } from '@/services/alert.service' import { PostService } from '@/services/post.service' import { PostFileMapManager } from '@/services/post-file-map' -import { postsDataProvider } from '@/tree-view-providers/posts-data-provider' +import { postDataProvider } from '@/tree-view-providers/post-data-provider' import { openPostInVscode } from './open-post-in-vscode' import { openPostFile } from './open-post-file' -import { searchPostsByTitle } from '@/services/search-post-by-title' +import { searchPostByTitle } from '@/services/search-post-by-title' import * as path from 'path' -import { refreshPostsList } from './refresh-posts-list' +import { refreshPostList } from './refresh-post-list' import { PostEditDto } from '@/models/post-edit-dto' import { PostCfgPanel } from '@/services/post-cfg-panel.service' import { saveFilePendingChanges } from '@/utils/save-file-pending-changes' @@ -55,7 +55,7 @@ export const uploadPostFileToCnblogs = async (fileUri: Uri | undefined) => { switch (selected) { case options[1]: { - const selectedPost = await searchPostsByTitle({ + const selectedPost = await searchPostByTitle({ postTitle: path.basename(filePath, path.extname(filePath)), quickPickTitle: '搜索要关联的博文', }) @@ -100,12 +100,12 @@ export const saveLocalDraftToCnblogs = async (localDraft: LocalDraft) => { breadcrumbs: ['新建博文', '博文设置', post.title], post, successCallback: async savedPost => { - await refreshPostsList() + await refreshPostList() await openPostFile(localDraft) await PostFileMapManager.updateOrCreate(savedPost.id, localDraft.filePath) await openPostFile(localDraft) - postsDataProvider.fireTreeDataChangedEvent(undefined) + postDataProvider.fireTreeDataChangedEvent(undefined) void Alert.info('博文已创建') }, beforeUpdate: async (postToSave, panel) => { @@ -178,7 +178,7 @@ export const uploadPostToCnblogs = async (input: Post | PostTreeItem | PostEditD hasSaved = true progress.report({ increment: 100 }) void Alert.info('上传成功') - await refreshPostsList() + await refreshPostList() } catch (err) { progress.report({ increment: 100 }) void Alert.err(`上传失败\n${err instanceof Error ? err.message : JSON.stringify(err)}`) diff --git a/src/commands/pull-post-remote-updates.ts b/src/commands/pull-post-remote-updates.ts index 0c9f2baf..90a2a0f1 100644 --- a/src/commands/pull-post-remote-updates.ts +++ b/src/commands/pull-post-remote-updates.ts @@ -1,12 +1,12 @@ import { MessageOptions, Uri, window, workspace } from 'vscode' import { Post } from '@/models/post' import { PostFileMapManager } from '@/services/post-file-map' -import { openPostInVscode } from './posts-list/open-post-in-vscode' +import { openPostInVscode } from './post-list/open-post-in-vscode' import fs from 'fs' import { PostService } from '@/services/post.service' import { Alert } from '@/services/alert.service' import path from 'path' -import { revealPostsListItem } from '@/services/posts-list-view' +import { revealPostListItem } from '@/services/post-list-view' import { PostTreeItem } from '@/tree-view-providers/models/post-tree-item' import { Settings } from '@/services/settings.service' @@ -57,7 +57,7 @@ const handlePostInput = async (post: Post, contexts: CmdCtx[]) => { return void (await openPostInVscode(postId, false)) } - await revealPostsListItem(post) + await revealPostListItem(post) contexts.push({ postId: postId, fileUri: Uri.file(filePath) }) } diff --git a/src/commands/show-local-file-to-post-info.ts b/src/commands/show-local-file-to-post-info.ts index 67b2fe58..97989b93 100644 --- a/src/commands/show-local-file-to-post-info.ts +++ b/src/commands/show-local-file-to-post-info.ts @@ -4,7 +4,7 @@ import { Alert } from '@/services/alert.service' import { PostService } from '@/services/post.service' import { postCategoryService } from '@/services/post-category.service' import { PostFileMapManager } from '@/services/post-file-map' -import { searchPostsByTitle } from '@/services/search-post-by-title' +import { searchPostByTitle } from '@/services/search-post-by-title' import { viewPostOnline } from './view-post-online' import format from 'date-fns/format' @@ -31,7 +31,7 @@ export const showLocalFileToPostInfo = async (input: Uri | number): Promise diff --git a/src/models/ing.ts b/src/models/ing.ts index 2e4c3c2e..bdc6c473 100644 --- a/src/models/ing.ts +++ b/src/models/ing.ts @@ -72,7 +72,7 @@ export enum IngType { following = 1, my = 4, all = 5, - mycomment = 7, + myComment = 7, comment = 13, mention = 14, } diff --git a/src/models/posts-list-state.ts b/src/models/post-list-state.ts similarity index 84% rename from src/models/posts-list-state.ts rename to src/models/post-list-state.ts index caba5ec0..c075a782 100644 --- a/src/models/posts-list-state.ts +++ b/src/models/post-list-state.ts @@ -1,4 +1,4 @@ -export interface PostsListState { +export interface PostListState { pageIndex: number pageSize: number itemsCount: number diff --git a/src/services/check-workspace.ts b/src/services/check-workspace.ts index 435bd942..d9e560b0 100644 --- a/src/services/check-workspace.ts +++ b/src/services/check-workspace.ts @@ -1,7 +1,7 @@ import os from 'os' import { workspace } from 'vscode' import { refreshPostCategoriesList } from '@/commands/post-category/refresh-post-categories-list' -import { refreshPostsList } from '@/commands/posts-list/refresh-posts-list' +import { refreshPostList } from '@/commands/post-list/refresh-post-list' import { globalCtx } from './global-ctx' import { PostFileMapManager } from './post-file-map' import { execCmd } from '@/utils/cmd' @@ -33,8 +33,8 @@ export const observeCfgUpdate = () => { if (ev.affectsConfiguration(`${Settings.iconThemePrefix}.${Settings.iconThemeKey}`)) refreshPostCategoriesList() - if (ev.affectsConfiguration(`${Settings.cfgPrefix}.${Settings.postsListPageSizeKey}`)) - refreshPostsList({ queue: true }).catch(() => undefined) + if (ev.affectsConfiguration(`${Settings.cfgPrefix}.${Settings.postListPageSizeKey}`)) + refreshPostList({ queue: true }).catch(() => undefined) if (ev.affectsConfiguration(`${Settings.cfgPrefix}.markdown`)) execCmd('markdown.preview.refresh').then(undefined, () => undefined) diff --git a/src/services/ing-list-webview-provider.ts b/src/services/ing-list-webview-provider.ts index 1e09de3f..d9425c62 100644 --- a/src/services/ing-list-webview-provider.ts +++ b/src/services/ing-list-webview-provider.ts @@ -89,17 +89,17 @@ export class ingListWebviewProvider implements WebviewViewProvider { command: WebviewCmd.IngCmd.UiCmd.setAppState, } as IngWebviewUiCmd>) .then(undefined, () => undefined) - const ings = await IngApi.list({ + const ingList = await IngApi.list({ type: ingType, pageIndex, pageSize: 30, }) - const comments = await IngApi.listComments(...ings.map(x => x.id)) + const comments = await IngApi.listComments(...ingList.map(x => x.id)) await this._view.webview .postMessage({ command: WebviewCmd.IngCmd.UiCmd.setAppState, payload: { - ings, + ingList, isRefreshing: false, comments, }, diff --git a/src/services/post-cfg-panel.service.ts b/src/services/post-cfg-panel.service.ts index 60313402..f7be8e47 100644 --- a/src/services/post-cfg-panel.service.ts +++ b/src/services/post-cfg-panel.service.ts @@ -11,7 +11,7 @@ import { webviewMessage } from '@/models/webview-msg' import { WebviewCommonCmd, WebviewCmd } from 'src/models/webview-cmd' import { uploadImage } from '@/commands/upload-image/upload-image' import { ImageUploadStatusId } from '@/models/image-upload-status' -import { openPostFile } from '@/commands/posts-list/open-post-file' +import { openPostFile } from '@/commands/post-list/open-post-file' import { parseWebviewHtml } from 'src/services/parse-webview-html' import path from 'path' diff --git a/src/services/post-file-map.ts b/src/services/post-file-map.ts index 1f0b12bb..97ae308f 100644 --- a/src/services/post-file-map.ts +++ b/src/services/post-file-map.ts @@ -1,5 +1,5 @@ import { postCategoriesDataProvider } from '@/tree-view-providers/post-categories-tree-data-provider' -import { postsDataProvider } from '@/tree-view-providers/posts-data-provider' +import { postDataProvider } from '@/tree-view-providers/post-data-provider' import { globalCtx } from './global-ctx' const validatePostFileMap = (map: PostFileMap) => map[0] >= 0 && !!map[1] @@ -40,8 +40,8 @@ export class PostFileMapManager { await globalCtx.storage.update(this.storageKey, maps.filter(validatePostFileMap)) if (emitEvent) { - postsDataProvider.fireTreeDataChangedEvent(postId) - postCategoriesDataProvider.onPostUpdated({ refreshPosts: false, postIds: [postId] }) + postDataProvider.fireTreeDataChangedEvent(postId) + postCategoriesDataProvider.onPostUpdated({ refreshPost: false, postIds: [postId] }) } } diff --git a/src/services/posts-list-view.ts b/src/services/post-list-view.ts similarity index 75% rename from src/services/posts-list-view.ts rename to src/services/post-list-view.ts index ad9635f3..c957dfa4 100644 --- a/src/services/posts-list-view.ts +++ b/src/services/post-list-view.ts @@ -1,12 +1,12 @@ import { Post } from '@/models/post' import { extViews } from '@/tree-view-providers/tree-view-registration' -export const revealPostsListItem = async ( +export const revealPostListItem = async ( post: Post, options?: { select?: boolean; focus?: boolean; expand?: boolean | number } ) => { if (!post) return - const view = extViews.visiblePostsList() + const view = extViews.visiblePostList() await view?.reveal(post, options) } diff --git a/src/services/post.service.ts b/src/services/post.service.ts index 8ddc6a4f..357158d4 100644 --- a/src/services/post.service.ts +++ b/src/services/post.service.ts @@ -2,7 +2,7 @@ import fetch from '@/utils/fetch-client' import { Post } from '@/models/post' import { globalCtx } from './global-ctx' import { PageModel } from '@/models/page-model' -import { PostsListState } from '@/models/posts-list-state' +import { PostListState } from '@/models/post-list-state' import { PostEditDto } from '@/models/post-edit-dto' import { PostUpdatedResponse } from '@/models/post-updated-response' import { throwIfNotOkGotResponse } from '@/utils/throw-if-not-ok-response' @@ -20,9 +20,9 @@ let newPostTemplate: PostEditDto | undefined export namespace PostService { const getBaseUrl = () => globalCtx.config.apiBaseUrl - export const getPostsListState = () => globalCtx.storage.get('postsListState') + export const getPostListState = () => globalCtx.storage.get('postListState') - export async function fetchPostsList({ + export async function fetchPostList({ search = '', pageIndex = 1, pageSize = defaultPageSize, @@ -51,7 +51,7 @@ export namespace PostService { new PageModel( obj.pageIndex, obj.pageSize, - obj.postsCount, + obj.postCount, obj.postList.map(x => Object.assign(new Post(), x)) ), { zzkSearchResult: ZzkSearchResult.parse(zzkSearchResult) || undefined } @@ -73,11 +73,11 @@ export namespace PostService { const { statusCode, errors } = e as IErrorResponse if (!muteErrorNotification) { if (statusCode === 404) { - Alert.err('博文不存在') + void Alert.err('博文不存在') const postFilePath = PostFileMapManager.getFilePath(postId) if (postFilePath) await PostFileMapManager.updateOrCreate(postId, '') } else { - Alert.err(errors.join('\n')) + void Alert.err(errors.join('\n')) } } return undefined @@ -90,19 +90,19 @@ export namespace PostService { return blogPost ? new PostEditDto(Object.assign(new Post(), blogPost), myConfig) : undefined } - export async function deletePost(postId: number) { - const res = await fetch(`${getBaseUrl()}/api/posts/${postId}`, { - method: 'DELETE', - }) - if (!res.ok) throw Error(`删除博文失败!\n${res.status}\n${await res.text()}`) - } - - export async function deletePosts(postIds: number[]) { - const searchParams = new URLSearchParams(postIds.map<[string, string]>(id => ['postIds', `${id}`])) - const res = await fetch(`${getBaseUrl()}/api/bulk-operation/post?${searchParams.toString()}`, { - method: 'DELETE', - }) - if (!res.ok) throw Error(`删除博文失败!\n${res.status}\n${await res.text()}`) + export async function deletePost(...postIds: number[]) { + if (postIds.length === 1) { + const res = await fetch(`${getBaseUrl()}/api/posts/${postIds[0]}`, { + method: 'DELETE', + }) + if (!res.ok) throw Error(`删除博文失败!\n${res.status}\n${await res.text()}`) + } else { + const searchParams = new URLSearchParams(postIds.map<[string, string]>(id => ['postIds', `${id}`])) + const res = await fetch(`${getBaseUrl()}/api/bulk-operation/post?${searchParams.toString()}`, { + method: 'DELETE', + }) + if (!res.ok) throw Error(`删除博文失败!\n${res.status}\n${await res.text()}`) + } } export async function updatePost(post: Post): Promise { @@ -118,8 +118,8 @@ export namespace PostService { return PostUpdatedResponse.parse(body) } - export async function updatePostsListState(state: PostsListState | undefined | PageModel) { - const finalState: PostsListState | undefined = + export async function updatePostListState(state: PostListState | undefined | PageModel) { + const finalState: PostListState | undefined = state instanceof PageModel ? { pageIndex: state.pageIndex, @@ -132,7 +132,7 @@ export namespace PostService { pageCount: state.pageCount, } : state - await globalCtx.storage.update('postsListState', finalState) + await globalCtx.storage.update('postListState', finalState) } export async function fetchPostEditTemplate(): Promise { @@ -152,6 +152,6 @@ interface PostListModel { pageIndex: number pageSize: number postList: [] - postsCount: number + postCount: number zzkSearchResult?: ZzkSearchResult } diff --git a/src/services/search-post-by-title.ts b/src/services/search-post-by-title.ts index 4d8260e7..8629daec 100644 --- a/src/services/search-post-by-title.ts +++ b/src/services/search-post-by-title.ts @@ -15,7 +15,7 @@ class PostPickItem implements QuickPickItem { } } -export const searchPostsByTitle = ({ postTitle = '', quickPickTitle = '按标题搜索博文' }): Promise => +export const searchPostByTitle = ({ postTitle = '', quickPickTitle = '按标题搜索博文' }): Promise => new Promise(resolve => { const quickPick = window.createQuickPick() quickPick.title = quickPickTitle @@ -27,9 +27,8 @@ export const searchPostsByTitle = ({ postTitle = '', quickPickTitle = '按标题 const value = quickPick.value try { quickPick.busy = true - const paged = await PostService.fetchPostsList({ search: value }) - const posts = paged.items - const pickItems = posts.map(p => new PostPickItem(p)) + const paged = await PostService.fetchPostList({ search: value }) + const pickItems = paged.items.map(p => new PostPickItem(p)) if (value === quickPick.value) quickPick.items = pickItems } finally { quickPick.busy = false diff --git a/src/services/settings.service.ts b/src/services/settings.service.ts index 41eb1c77..de9b1078 100644 --- a/src/services/settings.service.ts +++ b/src/services/settings.service.ts @@ -6,7 +6,7 @@ import { isNumber } from 'lodash-es' import { untildify } from '@/utils/untildify' export class Settings { - static postsListPageSizeKey = 'pageSize.postsList' + static postListPageSizeKey = 'pageSize.postList' static cfgPrefix = `cnblogsClient` static iconThemePrefix = 'workbench' static iconThemeKey = 'iconTheme' @@ -75,8 +75,8 @@ export class Settings { if (cfg === 'any') return ImageSrc.any } - static get postsListPageSize() { - const size = Settings.cfg.get(Settings.postsListPageSizeKey) + static get postListPageSize() { + const size = Settings.cfg.get(Settings.postListPageSizeKey) return isNumber(size) ? size : 30 } diff --git a/src/tree-view-providers/blog-export-provider.ts b/src/tree-view-providers/blog-export-provider.ts index fb91eb3b..4ce1f287 100644 --- a/src/tree-view-providers/blog-export-provider.ts +++ b/src/tree-view-providers/blog-export-provider.ts @@ -9,7 +9,7 @@ import { DownloadedExportMetadata, DownloadedExportsEntryTreeItem, DownloadedExportTreeItem, - ExportPostsEntryTreeItem, + ExportPostEntryTreeItem, } from './models/blog-export/downloaded' import { Event, EventEmitter, ProviderResult, TreeDataProvider, TreeItem } from 'vscode' import { Alert } from '@/services/alert.service' @@ -49,7 +49,7 @@ export class BlogExportProvider implements TreeDataProvider if (element instanceof BlogExportRecordTreeItem) return element.getChildrenAsync() else if (element instanceof DownloadedExportsEntryTreeItem) return element.getChildrenAsync() else if (element instanceof DownloadedExportTreeItem) return element.getChildrenAsync() - else if (element instanceof ExportPostsEntryTreeItem) return element.getChildrenAsync() + else if (element instanceof ExportPostEntryTreeItem) return element.getChildrenAsync() else if (element == null) return [(this._downloadedExportEntry = new DownloadedExportsEntryTreeItem()), ...this.listRecords()] @@ -61,7 +61,7 @@ export class BlogExportProvider implements TreeDataProvider element instanceof BlogExportRecordMetadata || element instanceof DownloadedExportMetadata || element instanceof DownloadedExportTreeItem || - element instanceof ExportPostsEntryTreeItem + element instanceof ExportPostEntryTreeItem ) return element.parent diff --git a/src/tree-view-providers/models/blog-export/downloaded.ts b/src/tree-view-providers/models/blog-export/downloaded.ts index 7707a3d8..ec861dd0 100644 --- a/src/tree-view-providers/models/blog-export/downloaded.ts +++ b/src/tree-view-providers/models/blog-export/downloaded.ts @@ -9,7 +9,7 @@ import { PostTreeItem } from '@/tree-view-providers/models/post-tree-item' import path from 'path' import { ThemeIcon, TreeItem, TreeItemCollapsibleState } from 'vscode' -export type DownloadedExportChildTreeItem = PostTreeItem | TreeItem | ExportPostsEntryTreeItem +export type DownloadedExportChildTreeItem = PostTreeItem | TreeItem | ExportPostEntryTreeItem export class DownloadedExportMetadata extends TreeItem { readonly parent?: DownloadedExportTreeItem | null @@ -21,7 +21,7 @@ export class DownloadedExportMetadata extends TreeItem { } } -export class ExportPostsEntryTreeItem extends BaseTreeItemSource implements BaseEntryTreeItem { +export class ExportPostEntryTreeItem extends BaseTreeItemSource implements BaseEntryTreeItem { constructor(public readonly parent: BlogExportTreeItem, public readonly downloadedExport: DownloadedBlogExport) { super() } @@ -69,7 +69,7 @@ export class DownloadedExportTreeItem } getChildrenAsync: () => Promise = () => - Promise.resolve([new ExportPostsEntryTreeItem(this, this.downloadedExport)]) + Promise.resolve([new ExportPostEntryTreeItem(this, this.downloadedExport)]) toTreeItem(): TreeItem | Promise { const { diff --git a/src/tree-view-providers/models/blog-export/post.ts b/src/tree-view-providers/models/blog-export/post.ts index f3b37799..ac148991 100644 --- a/src/tree-view-providers/models/blog-export/post.ts +++ b/src/tree-view-providers/models/blog-export/post.ts @@ -2,13 +2,13 @@ import { ViewPostCmdHandler } from '@/commands/blog-export/view-post' import type { ExportPost } from '@/models/blog-export/export-post' import { Settings } from '@/services/settings.service' import { BaseTreeItemSource } from '@/tree-view-providers/models/base-tree-item-source' -import { ExportPostsEntryTreeItem } from '@/tree-view-providers/models/blog-export' +import { ExportPostEntryTreeItem } from '@/tree-view-providers/models/blog-export' import { ThemeIcon, TreeItem, TreeItemCollapsibleState, Uri } from 'vscode' export class ExportPostTreeItem extends BaseTreeItemSource { readonly contextValue = 'cnblogs-export-post' - constructor(public readonly parent: ExportPostsEntryTreeItem, public readonly post: ExportPost) { + constructor(public readonly parent: ExportPostEntryTreeItem, public readonly post: ExportPost) { super() } diff --git a/src/tree-view-providers/models/post-search-result-entry.ts b/src/tree-view-providers/models/post-search-result-entry.ts index 69a6e081..52cf7f0d 100644 --- a/src/tree-view-providers/models/post-search-result-entry.ts +++ b/src/tree-view-providers/models/post-search-result-entry.ts @@ -10,7 +10,7 @@ export class PostSearchResultEntry extends BaseTreeItemSource implements BaseEnt constructor( public searchKey: string, - public readonly posts: Post[], + public readonly postList: Post[], public readonly totalCount: number, public readonly zzkSearchResult?: ZzkSearchResult ) { @@ -26,9 +26,9 @@ export class PostSearchResultEntry extends BaseTreeItemSource implements BaseEnt toTreeItem = (): TreeItem | Promise => Object.assign(new TreeItem(`搜索结果: "${this.searchKey}"`), { - iconPath: new ThemeIcon('vscode-cnb-posts-list-search'), + iconPath: new ThemeIcon('vscode-cnb-post-list-search'), collapsibleState: TreeItemCollapsibleState.Expanded, - contextValue: 'cnblogs-posts-search-results-entry', + contextValue: 'cnblogs-post-search-results-entry', }) getChildren = () => this.children @@ -36,7 +36,7 @@ export class PostSearchResultEntry extends BaseTreeItemSource implements BaseEnt private readonly parseChildren = () => [ this.buildSummaryTreeItem(), - ...this.posts.map(post => new PostTreeItem(post, false)), + ...this.postList.map(post => new PostTreeItem(post, false)), ] private readonly buildSummaryTreeItem = (): TreeItem => @@ -45,6 +45,6 @@ export class PostSearchResultEntry extends BaseTreeItemSource implements BaseEnt `共找到 ${this.totalCount} 篇随笔` + (this.zzkCount > 0 ? `, ${this.zzkSearchResult?.postIds.length} 篇来自找找看` : '') ), - { iconPath: new ThemeIcon('vscode-cnb-posts-list-search-result-summary') } + { iconPath: new ThemeIcon('vscode-cnb-post-list-search-result-summary') } ) } diff --git a/src/tree-view-providers/post-categories-tree-data-provider.ts b/src/tree-view-providers/post-categories-tree-data-provider.ts index 0ebe5c7a..33e1aab5 100644 --- a/src/tree-view-providers/post-categories-tree-data-provider.ts +++ b/src/tree-view-providers/post-categories-tree-data-provider.ts @@ -64,8 +64,8 @@ export class PostCategoriesTreeDataProvider implements TreeDataProvider (parent.children = [...childCategories, ...childPosts]) + return Promise.all([this.getCategories(parent.category.categoryId), this.getPost(parent)]).then( + ([childCategories, childPost]) => (parent.children = [...childCategories, ...childPost]) ) } else if (parent instanceof PostTreeItem) { return this.getPostMetadataChildren(parent) @@ -88,12 +88,12 @@ export class PostCategoriesTreeDataProvider implements TreeDataProvider postIds.includes(x.post.id)) const categories = new Set() postTreeItems.forEach(treeItem => { if (treeItem.parent) { - if (refreshPosts) treeItem.parent.children = undefined + if (refreshPost) treeItem.parent.children = undefined else this.fireTreeDataChangedEvent(treeItem) if (!categories.has(treeItem.parent)) { @@ -104,13 +104,13 @@ export class PostCategoriesTreeDataProvider implements TreeDataProvider { + private async getPost(parent: PostCategoryTreeItem): Promise { const { category: { categoryId }, } = parent return take( - (await PostService.fetchPostsList({ categoryId, pageSize: 100 })).items.map(x => + (await PostService.fetchPostList({ categoryId, pageSize: 100 })).items.map(x => Object.assign, Partial>>( new PostTreeItem(x, true), { diff --git a/src/tree-view-providers/posts-data-provider.ts b/src/tree-view-providers/post-data-provider.ts similarity index 60% rename from src/tree-view-providers/posts-data-provider.ts rename to src/tree-view-providers/post-data-provider.ts index 9075970d..7f1cc2e6 100644 --- a/src/tree-view-providers/posts-data-provider.ts +++ b/src/tree-view-providers/post-data-provider.ts @@ -1,5 +1,5 @@ import { EventEmitter, ProviderResult, TreeDataProvider, TreeItem } from 'vscode' -import { refreshPostsList } from '@/commands/posts-list/refresh-posts-list' +import { refreshPostList } from '@/commands/post-list/refresh-post-list' import { Post } from '@/models/post' import { PageModel } from '@/models/page-model' import { Alert } from '@/services/alert.service' @@ -10,20 +10,20 @@ import { PostEntryMetadata, PostMetadata } from './models/post-metadata' import { PostSearchResultEntry } from './models/post-search-result-entry' import { PostTreeItem } from './models/post-tree-item' -export type PostsListTreeItem = Post | PostTreeItem | TreeItem | PostMetadata | PostSearchResultEntry +export type PostListTreeItem = Post | PostTreeItem | TreeItem | PostMetadata | PostSearchResultEntry -export class PostsDataProvider implements TreeDataProvider { - private static _instance: PostsDataProvider | null = null +export class PostDataProvider implements TreeDataProvider { + private static _instance: PostDataProvider | null = null - protected _pagedPosts?: PageModel - protected _onDidChangeTreeData = new EventEmitter() + protected _pagedPost?: PageModel + protected _onDidChangeTreeData = new EventEmitter() private _searchResultEntry: PostSearchResultEntry | null = null protected constructor() {} static get instance() { - this._instance ??= new PostsDataProvider() + this._instance ??= new PostDataProvider() return this._instance } @@ -31,19 +31,19 @@ export class PostsDataProvider implements TreeDataProvider { return this._onDidChangeTreeData.event } - get pagedPosts() { - return this._pagedPosts + get pagedPost() { + return this._pagedPost } - getChildren(parent?: PostsListTreeItem): ProviderResult { + getChildren(parent?: PostListTreeItem): ProviderResult { if (!parent) { - const items: PostsListTreeItem[] = this._searchResultEntry == null ? [] : [this._searchResultEntry] - const pagedPosts = this._pagedPosts - if (!pagedPosts) { - void refreshPostsList() + const items: PostListTreeItem[] = this._searchResultEntry == null ? [] : [this._searchResultEntry] + const pagedPost = this._pagedPost + if (!pagedPost) { + void refreshPostList() return items } - return items.concat(...pagedPosts.items) + return items.concat(...pagedPost.items) } else if (parent instanceof Post) { return PostMetadata.parseRoots({ post: parent }) } else if (parent instanceof PostEntryMetadata || parent instanceof PostSearchResultEntry) { @@ -53,19 +53,19 @@ export class PostsDataProvider implements TreeDataProvider { return [] } - getParent(el: PostsListTreeItem) { + getParent(el: PostListTreeItem) { return el instanceof PostMetadata ? el.parent : undefined } - getTreeItem(item: PostsListTreeItem): TreeItem | Thenable { + getTreeItem(item: PostListTreeItem): TreeItem | Thenable { return toTreeItem(item) } - async loadPosts(): Promise | null> { - const { pageIndex } = PostService.getPostsListState() ?? {} - const pageSize = Settings.postsListPageSize + async loadPost(): Promise | null> { + const { pageIndex } = PostService.getPostListState() ?? {} + const pageSize = Settings.postListPageSize - this._pagedPosts = await PostService.fetchPostsList({ pageIndex, pageSize }).catch(e => { + this._pagedPost = await PostService.fetchPostList({ pageIndex, pageSize }).catch(e => { if (e instanceof Error) Alert.err(e.message) else Alert.err(`加载博文失败\n${JSON.stringify(e)}`) return undefined @@ -73,15 +73,15 @@ export class PostsDataProvider implements TreeDataProvider { this.fireTreeDataChangedEvent(undefined) - return this._pagedPosts ?? null + return this._pagedPost ?? null } - fireTreeDataChangedEvent(item: PostsListTreeItem | undefined): void + fireTreeDataChangedEvent(item: PostListTreeItem | undefined): void fireTreeDataChangedEvent(id: number): void - fireTreeDataChangedEvent(item: PostsListTreeItem | number | undefined): void { + fireTreeDataChangedEvent(item: PostListTreeItem | number | undefined): void { return typeof item === 'number' ? [ - ...(this._pagedPosts?.items.filter(x => x.id === item) ?? []), + ...(this._pagedPost?.items.filter(x => x.id === item) ?? []), ...(this._searchResultEntry?.children.filter(x => x instanceof PostTreeItem && x.post.id === item) ?? []), ].forEach(data => this._onDidChangeTreeData.fire(data)) @@ -91,7 +91,7 @@ export class PostsDataProvider implements TreeDataProvider { async search({ key }: { key: string }): Promise { if (key.length <= 0) return - const { items, totalItemsCount, zzkSearchResult } = await PostService.fetchPostsList({ search: key }) + const { items, totalItemsCount, zzkSearchResult } = await PostService.fetchPostList({ search: key }) this._searchResultEntry = new PostSearchResultEntry(key, items, totalItemsCount, zzkSearchResult) this.fireTreeDataChangedEvent(undefined) @@ -113,4 +113,4 @@ export class PostsDataProvider implements TreeDataProvider { } } -export const postsDataProvider = PostsDataProvider.instance +export const postDataProvider = PostDataProvider.instance diff --git a/src/tree-view-providers/tree-view-registration.ts b/src/tree-view-providers/tree-view-registration.ts index ab0c656f..22c40fd2 100644 --- a/src/tree-view-providers/tree-view-registration.ts +++ b/src/tree-view-providers/tree-view-registration.ts @@ -1,7 +1,7 @@ import { globalCtx } from '@/services/global-ctx' import vscode from 'vscode' import { accountViewDataProvider } from './account-view-data-provider' -import { PostsListTreeItem, postsDataProvider } from './posts-data-provider' +import { PostListTreeItem, postDataProvider } from './post-data-provider' import { postCategoriesDataProvider } from './post-categories-tree-data-provider' import { PostCategoriesListTreeItem } from './models/categories-list-tree-item' import { IDisposable } from '@fluentui/react' @@ -10,17 +10,17 @@ import { BlogExportProvider } from '@/tree-view-providers/blog-export-provider' import { regTreeView } from '@/utils/tree-view' const _views: { - postsList?: vscode.TreeView - anotherPostsList?: vscode.TreeView + postList?: vscode.TreeView + anotherPostList?: vscode.TreeView account?: vscode.TreeView postCategoriesList?: vscode.TreeView blogExport?: vscode.TreeView - postsLists: () => vscode.TreeView[] - visiblePostsList: () => vscode.TreeView | undefined + postLists: () => vscode.TreeView[] + visiblePostList: () => vscode.TreeView | undefined } = { - postsLists: () => - [_views.postsList, _views.anotherPostsList].filter((x): x is vscode.TreeView => x != null), - visiblePostsList: () => _views.postsLists().find(x => x.visible), + postLists: () => + [_views.postList, _views.anotherPostList].filter((x): x is vscode.TreeView => x != null), + visiblePostList: () => _views.postLists().find(x => x.visible), } let _hasRegistered = false @@ -31,12 +31,12 @@ export function setupExtTreeView() { treeDataProvider: accountViewDataProvider, canSelectMany: false, }) - _views.postsList = regTreeView('cnblogs-posts-list', { - treeDataProvider: postsDataProvider, + _views.postList = regTreeView('cnblogs-post-list', { + treeDataProvider: postDataProvider, canSelectMany: true, }) - _views.anotherPostsList = regTreeView('cnblogs-posts-list-another', { - treeDataProvider: postsDataProvider, + _views.anotherPostList = regTreeView('cnblogs-post-list-another', { + treeDataProvider: postDataProvider, canSelectMany: true, }) _views.postCategoriesList = regTreeView('cnblogs-post-categories-list', { @@ -58,15 +58,15 @@ export function setupExtTreeView() { } class ExtViews implements Required { - postsLists = _views.postsLists - visiblePostsList = _views.visiblePostsList + postLists = _views.postLists + visiblePostList = _views.visiblePostList - get postsList(): vscode.TreeView { - return this.getTreeView('postsList') + get postList(): vscode.TreeView { + return this.getTreeView('postList') } - get anotherPostsList() { - return this.getTreeView('anotherPostsList') + get anotherPostList() { + return this.getTreeView('anotherPostList') } get account() { @@ -81,7 +81,7 @@ class ExtViews implements Required { return this.getTreeView('blogExport') } - private getTreeView>( + private getTreeView>( name: TKey ): NonNullable<(typeof _views)[TKey]> { const value = _views[name] diff --git a/src/utils/uri-handler.ts b/src/utils/uri-handler.ts index a635cbbb..3a5acf46 100644 --- a/src/utils/uri-handler.ts +++ b/src/utils/uri-handler.ts @@ -1,5 +1,5 @@ import { Disposable, EventEmitter, ProviderResult, Uri, UriHandler, Event } from 'vscode' -import { openPostInVscode } from '@/commands/posts-list/open-post-in-vscode' +import { openPostInVscode } from '@/commands/post-list/open-post-in-vscode' class ExtUriHandler implements UriHandler, Disposable { private _uriEventEmitter?: EventEmitter diff --git a/ui/ing/App.tsx b/ui/ing/App.tsx index 0733b01c..c3dfa32d 100644 --- a/ui/ing/App.tsx +++ b/ui/ing/App.tsx @@ -28,7 +28,7 @@ export class App extends Component { } render(): ReactNode { - const { ings, isRefreshing, theme, comments } = this.state + const { ingList, isRefreshing, theme, comments } = this.state return ( @@ -39,7 +39,7 @@ export class App extends Component { ) : ( - + )} @@ -50,9 +50,9 @@ export class App extends Component { window.addEventListener('message', ({ data: { command, payload } }: { data: IngWebviewUiCmd }) => { switch (command) { case WebviewCmd.IngCmd.UiCmd.setAppState: { - const { ings, isRefreshing, comments } = payload as Partial + const { ingList, isRefreshing, comments } = payload as Partial this.setState({ - ings: ings?.map(Ing.parse) ?? this.state.ings, + ingList: ingList?.map(Ing.parse) ?? this.state.ingList, isRefreshing: isRefreshing ?? this.state.isRefreshing, comments: comments ? Object.assign( diff --git a/ui/ing/IngList.tsx b/ui/ing/IngList.tsx index a8dde0e4..ad35cfd3 100644 --- a/ui/ing/IngList.tsx +++ b/ui/ing/IngList.tsx @@ -4,7 +4,7 @@ import { IngItem } from 'ing/IngItem' import { Stack } from '@fluentui/react' interface IngListProps { - ings: Ing[] + ingList: Ing[] comments: Record } @@ -25,7 +25,7 @@ class IngList extends Component { private renderItems() { const { comments } = this.props - return this.props.ings.map(ing => ( + return this.props.ingList.map(ing => ( From ba2723108267494d317c6ba2b4ea8ef4082eab72 Mon Sep 17 00:00:00 2001 From: Thaumy Date: Mon, 24 Jul 2023 10:41:12 +0800 Subject: [PATCH 018/157] fix: fix init login --- src/auth/auth-provider.ts | 20 ++++--------------- src/commands/cmd-register.ts | 2 +- src/extension.ts | 10 ++++++---- src/services/check-workspace.ts | 12 +++++------ .../tree-view-registration.ts | 4 ---- 5 files changed, 17 insertions(+), 31 deletions(-) diff --git a/src/auth/auth-provider.ts b/src/auth/auth-provider.ts index 29df8b7b..c3c06f4e 100644 --- a/src/auth/auth-provider.ts +++ b/src/auth/auth-provider.ts @@ -49,18 +49,6 @@ export class AuthProvider implements AuthenticationProvider, Disposable { return this._sessionChangeEmitter.event } - protected get context() { - return globalCtx.extCtx - } - - protected get secretStorage() { - return globalCtx.secretsStorage - } - - protected get config() { - return globalCtx.config - } - async getSessions(scopes?: readonly string[] | undefined): Promise { const sessions = await this.getAllSessions() const parsedScopes = this.ensureScopes(scopes) @@ -141,7 +129,7 @@ export class AuthProvider implements AuthenticationProvider, Disposable { }, { removed: [], keep: [] } ) - await this.context.secrets.store(this.sessionStorageKey, JSON.stringify(data.keep)) + await globalCtx.extCtx.secrets.store(this.sessionStorageKey, JSON.stringify(data.keep)) this._sessionChangeEmitter.fire({ removed: data.removed, added: undefined, changed: undefined }) } @@ -158,7 +146,7 @@ export class AuthProvider implements AuthenticationProvider, Disposable { } if (this._allSessions == null || this._allSessions.length <= 0) { - const sessions = JSON.parse((await this.secretStorage.get(this.sessionStorageKey)) ?? '[]') as + const sessions = JSON.parse((await globalCtx.secretsStorage.get(this.sessionStorageKey)) ?? '[]') as | AuthSession[] | null | undefined @@ -171,7 +159,7 @@ export class AuthProvider implements AuthenticationProvider, Disposable { private signInWithBrowser({ scopes }: { scopes: readonly string[] }) { const [verifyCode, challengeCode] = genVerifyChallengePair() - const { clientId, responseType, authorizeEndpoint, authority, clientSecret } = this.config.oauth + const { clientId, responseType, authorizeEndpoint, authority, clientSecret } = globalCtx.config.oauth const search = new URLSearchParams([ ['client_id', clientId], @@ -242,7 +230,7 @@ export class AuthProvider implements AuthenticationProvider, Disposable { const hasStored = await ifNotCancelledThen(() => { if (isUndefined(session)) return Promise.resolve(false) - return this.secretStorage.store(this.sessionStorageKey, JSON.stringify([session])).then( + return globalCtx.secretsStorage.store(this.sessionStorageKey, JSON.stringify([session])).then( () => true, () => false ) diff --git a/src/commands/cmd-register.ts b/src/commands/cmd-register.ts index 18b50f8d..d709e6f1 100644 --- a/src/commands/cmd-register.ts +++ b/src/commands/cmd-register.ts @@ -86,5 +86,5 @@ export function setupExtCmd() { ...regBlogExportCmds(), ] - ctx?.subscriptions.push(...disposables) + ctx.subscriptions.push(...disposables) } diff --git a/src/extension.ts b/src/extension.ts index 54e51b53..e919607b 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -5,7 +5,7 @@ import { globalCtx } from '@/services/global-ctx' // Import the module and reference it with the alias vscode in your code below import { window, ExtensionContext } from 'vscode' import { accountManager } from '@/auth/account-manager' -import { observeCfgUpdate, observeWorkspaceFileUpdate, observeWorkspaceUpdate } from '@/services/check-workspace' +import { watchCfgUpdate, watchWorkspaceFileUpdate, watchWorkspaceUpdate } from '@/services/check-workspace' import { extUriHandler } from '@/utils/uri-handler' import { extendMarkdownIt } from '@/markdown/extend-markdownIt' import { Settings } from '@/services/settings.service' @@ -25,14 +25,16 @@ export function activate(ctx: ExtensionContext) { window.registerWebviewViewProvider(getIngListWebviewProvider().viewId, getIngListWebviewProvider()) ) - observeCfgUpdate() - observeWorkspaceUpdate() - observeWorkspaceFileUpdate() + watchCfgUpdate() + watchWorkspaceUpdate() + watchWorkspaceFileUpdate() Settings.migrateEnablePublishSelectionToIng().catch(console.warn) window.registerUriHandler(extUriHandler) + void accountManager.updateAuthStatus() + return { extendMarkdownIt } } diff --git a/src/services/check-workspace.ts b/src/services/check-workspace.ts index d9e560b0..364376a5 100644 --- a/src/services/check-workspace.ts +++ b/src/services/check-workspace.ts @@ -25,8 +25,8 @@ export const isTargetWorkspace = (): boolean => { return isTarget } -export const observeCfgUpdate = () => { - globalCtx.extCtx?.subscriptions.push( +export const watchCfgUpdate = () => { + globalCtx.extCtx.subscriptions.push( workspace.onDidChangeConfiguration(ev => { if (ev.affectsConfiguration(Settings.cfgPrefix)) isTargetWorkspace() @@ -43,15 +43,15 @@ export const observeCfgUpdate = () => { isTargetWorkspace() } -export const observeWorkspaceUpdate = () => - void globalCtx.extCtx?.subscriptions.push( +export const watchWorkspaceUpdate = () => + void globalCtx.extCtx.subscriptions.push( workspace.onDidChangeWorkspaceFolders(() => { isTargetWorkspace() }) ) -export const observeWorkspaceFileUpdate = () => - void globalCtx.extCtx?.subscriptions.push( +export const watchWorkspaceFileUpdate = () => + void globalCtx.extCtx.subscriptions.push( workspace.onDidRenameFiles(e => { for (const item of e.files) { const { oldUri, newUri } = item diff --git a/src/tree-view-providers/tree-view-registration.ts b/src/tree-view-providers/tree-view-registration.ts index 22c40fd2..472e8ea3 100644 --- a/src/tree-view-providers/tree-view-registration.ts +++ b/src/tree-view-providers/tree-view-registration.ts @@ -22,11 +22,8 @@ const _views: { [_views.postList, _views.anotherPostList].filter((x): x is vscode.TreeView => x != null), visiblePostList: () => _views.postLists().find(x => x.visible), } -let _hasRegistered = false export function setupExtTreeView() { - if (_hasRegistered) return extViews - _views.account = regTreeView('cnblogs-account', { treeDataProvider: accountViewDataProvider, canSelectMany: false, @@ -47,7 +44,6 @@ export function setupExtTreeView() { canSelectMany: false, treeDataProvider: BlogExportProvider.instance, }) - _hasRegistered = true const disposables: IDisposable[] = [] for (const [, item] of Object.entries(_views)) typeof item === 'function' ? undefined : disposables.push(item) From 9ebd5a6882d268f5d049b8cc684035bf4b344318 Mon Sep 17 00:00:00 2001 From: Thaumy Date: Mon, 24 Jul 2023 12:14:23 +0800 Subject: [PATCH 019/157] fix: switch ing --- download-iconfont.mjs | 11 +++++----- package.json | 8 +++---- src/commands/blog-export/create.ts | 4 ++-- src/commands/blog-export/delete.ts | 12 +++++----- src/commands/blog-export/download.ts | 9 +++----- src/commands/blog-export/edit.ts | 8 +++---- src/commands/blog-export/index.ts | 12 +++++----- src/commands/blog-export/open-local.ts | 4 ++-- src/commands/blog-export/refresh.ts | 2 +- src/commands/blog-export/view-post.ts | 10 ++++----- src/commands/cmd-handler.ts | 9 ++++---- src/commands/ing/comment-ing.ts | 6 ++--- src/commands/ing/goto-ing-list-page.ts | 6 ++--- src/commands/ing/ing-list-cmd-register.ts | 4 ++-- src/commands/ing/open-ing-in-browser.ts | 2 +- src/commands/ing/publish-ing.ts | 6 ++--- src/commands/ing/refresh-ing-list.ts | 2 +- src/commands/ing/select-ing-type.ts | 16 ++++++++------ src/commands/post-list/copy-link.ts | 7 +++--- src/models/ing.ts | 5 ++--- src/services/ing-list-webview-provider.ts | 22 +++++++------------ src/tree-view-providers/converters.ts | 9 +++----- .../models/blog-export/post.ts | 2 +- 23 files changed, 78 insertions(+), 98 deletions(-) diff --git a/download-iconfont.mjs b/download-iconfont.mjs index 6013c5a5..297d270e 100644 --- a/download-iconfont.mjs +++ b/download-iconfont.mjs @@ -2,6 +2,7 @@ import fetch from 'node-fetch' import fs from 'fs' import AdmZip from 'adm-zip' + const url = 'https://www.iconfont.cn/api/project/download.zip?spm=a313x.7781069.1998910419.d7543c303&pid=2996691&ctoken=ndNRCUzYy381Rxk59b1LjTrg' const cookie = @@ -21,14 +22,14 @@ fetch(url, { headers: { cookie: cookie } }).then(f => { zip.extractEntryTo(e, './dist/assets', false, true, undefined, outFileName) zip.extractEntryTo(e, 'src/assets', false, true, undefined, outFileName) }) - fs.unlink(filename, err => { - if (err) { - console.log(err) + fs.unlink(filename, e => { + if (e != null) { + console.log(e) } console.log('iconfont assets downloaded') }) - } catch (ex) { - console.warn('Failed to unzip iconfont assets! Some icons may not work correctly.', ex) + } catch (e) { + console.warn('Failed to unzip iconfont assets! Some icons may not work correctly.', e) } }) }, undefined) diff --git a/package.json b/package.json index 068413e0..36e7b0be 100644 --- a/package.json +++ b/package.json @@ -347,8 +347,8 @@ "enablement": "vscode-cnb.isAuthorized && !vscode-cnb.ingList.isRefreshing && vscode-cnb.ingList.pageIndex < 500" }, { - "command": "vscode-cnb.ing-list.select-type", - "title": "选择闪存列表", + "command": "vscode-cnb.ing-list.switch-type", + "title": "切换闪存类型", "category": "Cnblogs", "icon": "$(list-filter)", "enablement": "vscode-cnb.isAuthorized && !vscode-cnb.ingList.isRefreshing" @@ -850,7 +850,7 @@ "group": "navigation@3" }, { - "command": "vscode-cnb.ing-list.select-type", + "command": "vscode-cnb.ing-list.switch-type", "when": "view == vscode-cnb.ing-list-webview", "group": "navigation@4" }, @@ -969,7 +969,7 @@ "when": "false" }, { - "command": "vscode-cnb.ing-list.select-type", + "command": "vscode-cnb.ing-list.switch-type", "when": "false" }, { diff --git a/src/commands/blog-export/create.ts b/src/commands/blog-export/create.ts index 67e6c43d..12c599c7 100644 --- a/src/commands/blog-export/create.ts +++ b/src/commands/blog-export/create.ts @@ -4,8 +4,8 @@ import { BlogExportApi } from '@/services/blog-export.api' import { BlogExportProvider } from '@/tree-view-providers/blog-export-provider' import { MessageItem, window } from 'vscode' -export class CreateBlogExportCmdHandler extends CmdHandler { - static readonly commandName = 'vscode-cnb.blog-export.create' +export class CreateBlogExportCmdHandler implements CmdHandler { + static readonly cmd = 'vscode-cnb.blog-export.create' async handle(): Promise { if (!(await this.confirm())) return diff --git a/src/commands/blog-export/delete.ts b/src/commands/blog-export/delete.ts index 14c1cccd..cc81e5b2 100644 --- a/src/commands/blog-export/delete.ts +++ b/src/commands/blog-export/delete.ts @@ -10,16 +10,14 @@ import path from 'path' import { promisify } from 'util' import { MessageItem, window } from 'vscode' -export class DeleteCmdHandler extends TreeViewCmdHandler { - static readonly commandName = 'vscode-cnb.blog-export.delete' +export class DeleteCmdHandler implements TreeViewCmdHandler { + static readonly cmd = 'vscode-cnb.blog-export.delete' - constructor(private readonly _input: unknown) { - super() - } + constructor(public input: unknown) {} parseInput(): DownloadedExportTreeItem | BlogExportRecordTreeItem | null | undefined { - return this._input instanceof DownloadedExportTreeItem || this._input instanceof BlogExportRecordTreeItem - ? this._input + return this.input instanceof DownloadedExportTreeItem || this.input instanceof BlogExportRecordTreeItem + ? this.input : null } diff --git a/src/commands/blog-export/download.ts b/src/commands/blog-export/download.ts index f3a01446..809e0721 100644 --- a/src/commands/blog-export/download.ts +++ b/src/commands/blog-export/download.ts @@ -11,15 +11,12 @@ import fs from 'fs' import { Progress } from 'got' import path from 'path' import { promisify } from 'util' -import { commands } from 'vscode' import { execCmd } from '@/utils/cmd' -export class DownloadExportCmdHandler extends TreeViewCmdHandler { - static readonly commandName = 'vscode-cnb.blog-export.download' +export class DownloadExportCmdHandler implements TreeViewCmdHandler { + static readonly cmd = 'vscode-cnb.blog-export.download' - constructor(public readonly input: unknown) { - super() - } + constructor(public readonly input: unknown) {} parseInput(): BlogExportRecordTreeItem | null | undefined { return this.input instanceof BlogExportRecordTreeItem ? this.input : null diff --git a/src/commands/blog-export/edit.ts b/src/commands/blog-export/edit.ts index 43e46ff3..6487907a 100644 --- a/src/commands/blog-export/edit.ts +++ b/src/commands/blog-export/edit.ts @@ -8,12 +8,10 @@ import path from 'path' import sanitizeFileName from 'sanitize-filename' import { promisify } from 'util' -export class EditExportPostCmdHandler extends TreeViewCmdHandler { - static readonly commandName = 'vscode-cnb.blog-export.edit' +export class EditExportPostCmdHandler implements TreeViewCmdHandler { + static readonly cmd = 'vscode-cnb.blog-export.edit' - constructor(public readonly input: unknown) { - super() - } + constructor(public readonly input: unknown) {} parseInput(): ExportPostTreeItem | null | undefined { return this.input instanceof ExportPostTreeItem ? this.input : null diff --git a/src/commands/blog-export/index.ts b/src/commands/blog-export/index.ts index a0f89fe0..2e81b951 100644 --- a/src/commands/blog-export/index.ts +++ b/src/commands/blog-export/index.ts @@ -13,11 +13,11 @@ export function regBlogExportCmds() { return [ regCmd(`${extName}.blog-export.refresh-records`, () => new RefreshExportRecordsCmdHandler().handle()), - regCmd(OpenLocalExportCmdHandler.commandName, () => new OpenLocalExportCmdHandler().handle()), - regCmd(EditExportPostCmdHandler.commandName, input => new EditExportPostCmdHandler(input).handle()), - regCmd(CreateBlogExportCmdHandler.commandName, () => new CreateBlogExportCmdHandler().handle()), - regCmd(DownloadExportCmdHandler.commandName, input => new DownloadExportCmdHandler(input).handle()), - regCmd(ViewPostCmdHandler.commandName, input => new ViewPostCmdHandler(input).handle()), - regCmd(DeleteCmdHandler.commandName, input => new DeleteCmdHandler(input).handle()), + regCmd(OpenLocalExportCmdHandler.cmd, () => new OpenLocalExportCmdHandler().handle()), + regCmd(EditExportPostCmdHandler.cmd, input => new EditExportPostCmdHandler(input).handle()), + regCmd(CreateBlogExportCmdHandler.cmd, () => new CreateBlogExportCmdHandler().handle()), + regCmd(DownloadExportCmdHandler.cmd, input => new DownloadExportCmdHandler(input).handle()), + regCmd(ViewPostCmdHandler.cmd, input => new ViewPostCmdHandler(input).handle()), + regCmd(DeleteCmdHandler.cmd, input => new DeleteCmdHandler(input).handle()), ] } diff --git a/src/commands/blog-export/open-local.ts b/src/commands/blog-export/open-local.ts index 6eaa2f63..468d30c8 100644 --- a/src/commands/blog-export/open-local.ts +++ b/src/commands/blog-export/open-local.ts @@ -9,8 +9,8 @@ import { BlogExportProvider } from '@/tree-view-providers/blog-export-provider' const defaultOptions = { confirmUnzip: true } -export class OpenLocalExportCmdHandler extends CmdHandler { - static readonly commandName = `vscode-cnb.blog-export.open-local-export` +export class OpenLocalExportCmdHandler implements CmdHandler { + static readonly cmd = `vscode-cnb.blog-export.open-local-export` async handle(opts: Partial = defaultOptions): Promise { let isConfirmedToUnzip = opts?.confirmUnzip === true ? true : defaultOptions.confirmUnzip diff --git a/src/commands/blog-export/refresh.ts b/src/commands/blog-export/refresh.ts index 08e85ab9..0bdae02f 100644 --- a/src/commands/blog-export/refresh.ts +++ b/src/commands/blog-export/refresh.ts @@ -4,7 +4,7 @@ import { globalCtx } from '@/services/global-ctx' import { BlogExportProvider } from '@/tree-view-providers/blog-export-provider' import { commands } from 'vscode' -export class RefreshExportRecordsCmdHandler extends CmdHandler { +export class RefreshExportRecordsCmdHandler implements CmdHandler { async handle(): Promise { await this.setIsRefreshing(true) diff --git a/src/commands/blog-export/view-post.ts b/src/commands/blog-export/view-post.ts index 008a7a5a..d49466b2 100644 --- a/src/commands/blog-export/view-post.ts +++ b/src/commands/blog-export/view-post.ts @@ -5,16 +5,14 @@ import { ExportPostTreeItem } from '@/tree-view-providers/models/blog-export/pos import { URLSearchParams } from 'url' import { languages, TextDocumentContentProvider, Uri, window, workspace } from 'vscode' -export class ViewPostCmdHandler extends TreeViewCmdHandler { - static readonly commandName = 'vscode-cnb.blog-export.view-post' +export class ViewPostCmdHandler implements TreeViewCmdHandler { + static readonly cmd = 'vscode-cnb.blog-export.view-post' static readonly schema = 'vscode-cnb.blog-export.post' - constructor(private _input: unknown) { - super() - } + constructor(public input: unknown) {} parseInput(): ExportPostTreeItem | null | undefined { - return this._input instanceof ExportPostTreeItem ? this._input : null + return this.input instanceof ExportPostTreeItem ? this.input : null } async handle(): Promise { diff --git a/src/commands/cmd-handler.ts b/src/commands/cmd-handler.ts index 926a9187..76c73995 100644 --- a/src/commands/cmd-handler.ts +++ b/src/commands/cmd-handler.ts @@ -1,15 +1,16 @@ -export abstract class CmdHandler { - abstract handle(): Promise | void +export interface CmdHandler { + handle(): Promise | void } -export abstract class TreeViewCmdHandler extends CmdHandler { +export interface TreeViewCmdHandler { readonly input: unknown - abstract parseInput(): TData | null | undefined + parseInput(): TData | null | undefined } export abstract class MultiSelectableTreeViewCmdHandler implements TreeViewCmdHandler { private _selections: TData[] | null = null + constructor(public readonly input: TArgument) {} get selections(): TData[] { diff --git a/src/commands/ing/comment-ing.ts b/src/commands/ing/comment-ing.ts index bcb8a666..6ba16b30 100644 --- a/src/commands/ing/comment-ing.ts +++ b/src/commands/ing/comment-ing.ts @@ -3,7 +3,7 @@ import { IngApi } from '@/services/ing.api' import { getIngListWebviewProvider } from '@/services/ing-list-webview-provider' import { ProgressLocation, window } from 'vscode' -export class CommentIngCmdHandler extends CmdHandler { +export class CommentIngCmdHandler implements CmdHandler { private _content = '' constructor( @@ -11,9 +11,7 @@ export class CommentIngCmdHandler extends CmdHandler { private _ingContent: string, private _parentCommentId?: number, private _atUser?: { id: number; displayName: string } - ) { - super() - } + ) {} async handle(): Promise { const maxIngContentLength = 50 diff --git a/src/commands/ing/goto-ing-list-page.ts b/src/commands/ing/goto-ing-list-page.ts index d5be00b9..6e729a8a 100644 --- a/src/commands/ing/goto-ing-list-page.ts +++ b/src/commands/ing/goto-ing-list-page.ts @@ -1,7 +1,7 @@ import { CmdHandler } from '@/commands/cmd-handler' import { getIngListWebviewProvider } from 'src/services/ing-list-webview-provider' -export class GotoingListNextPage extends CmdHandler { +export class GotoingListNextPage implements CmdHandler { handle(): Promise { const provider = getIngListWebviewProvider() const { pageIndex } = provider @@ -9,7 +9,7 @@ export class GotoingListNextPage extends CmdHandler { } } -export class GotoingListPreviousPage extends CmdHandler { +export class GotoingListPreviousPage implements CmdHandler { handle(): Promise { const provider = getIngListWebviewProvider() const { pageIndex } = provider @@ -18,7 +18,7 @@ export class GotoingListPreviousPage extends CmdHandler { } } -export class GotoingListFirstPage extends CmdHandler { +export class GotoingListFirstPage implements CmdHandler { handle(): Promise { return getIngListWebviewProvider().refreshingList({ pageIndex: 1 }) } diff --git a/src/commands/ing/ing-list-cmd-register.ts b/src/commands/ing/ing-list-cmd-register.ts index 2674131d..be9f4388 100644 --- a/src/commands/ing/ing-list-cmd-register.ts +++ b/src/commands/ing/ing-list-cmd-register.ts @@ -1,7 +1,7 @@ import { RefreshingList } from 'src/commands/ing/refresh-ing-list' import { globalCtx } from 'src/services/global-ctx' import { GotoingListFirstPage, GotoingListNextPage, GotoingListPreviousPage } from 'src/commands/ing/goto-ing-list-page' -import { SelectIngType } from '@/commands/ing/select-ing-type' +import { SwitchIngType } from '@/commands/ing/select-ing-type' import { OpenIngInBrowser } from '@/commands/ing/open-ing-in-browser' import { regCmd } from '@/utils/cmd' @@ -13,7 +13,7 @@ export const regIngListCmds = () => { regCmd(`${appName}.ing-list.next`, () => new GotoingListNextPage().handle()), regCmd(`${appName}.ing-list.previous`, () => new GotoingListPreviousPage().handle()), regCmd(`${appName}.ing-list.first`, () => new GotoingListFirstPage().handle()), - regCmd(`${appName}.ing-list.select-type`, () => new SelectIngType().handle()), + regCmd(`${appName}.ing-list.switch-type`, () => new SwitchIngType().handle()), regCmd(`${appName}.ing-list.open-in-browser`, () => new OpenIngInBrowser().handle()), ] } diff --git a/src/commands/ing/open-ing-in-browser.ts b/src/commands/ing/open-ing-in-browser.ts index fdc68b7c..dadebabe 100644 --- a/src/commands/ing/open-ing-in-browser.ts +++ b/src/commands/ing/open-ing-in-browser.ts @@ -3,7 +3,7 @@ import { execCmd } from '@/utils/cmd' import { globalCtx } from '@/services/global-ctx' import { Uri } from 'vscode' -export class OpenIngInBrowser extends CmdHandler { +export class OpenIngInBrowser implements CmdHandler { async handle(): Promise { await execCmd('vscode.open', Uri.parse(globalCtx.config.ingSite)) } diff --git a/src/commands/ing/publish-ing.ts b/src/commands/ing/publish-ing.ts index de216f2c..11f75a8a 100644 --- a/src/commands/ing/publish-ing.ts +++ b/src/commands/ing/publish-ing.ts @@ -8,7 +8,7 @@ import { getIngListWebviewProvider } from '@/services/ing-list-webview-provider' import { InputStep, MultiStepInput, QuickPickParameters } from '@/services/multi-step-input' import { MessageOptions, ProgressLocation, QuickPickItem, Uri, window } from 'vscode' -export class PublishIngCmdHandler extends CmdHandler { +export class PublishIngCmdHandler implements CmdHandler { readonly maxLength = 0 readonly operation = '发布闪存' readonly editingText = '编辑闪存' @@ -73,9 +73,7 @@ export class PublishIngCmdHandler extends CmdHandler { inputIsPrivate = false currentStep = 0 - constructor(public readonly contentSource: 'selection' | 'input' = 'selection') { - super() - } + constructor(public readonly contentSource: 'selection' | 'input' = 'selection') {} private get formattedIngContent() { return `${this.inputTags.map(x => `[${x}]`).join('')}${this.inputContent}` diff --git a/src/commands/ing/refresh-ing-list.ts b/src/commands/ing/refresh-ing-list.ts index 53287886..9c3e3a3b 100644 --- a/src/commands/ing/refresh-ing-list.ts +++ b/src/commands/ing/refresh-ing-list.ts @@ -1,7 +1,7 @@ import { CmdHandler } from '@/commands/cmd-handler' import { getIngListWebviewProvider } from 'src/services/ing-list-webview-provider' -export class RefreshingList extends CmdHandler { +export class RefreshingList implements CmdHandler { handle(): Promise { return getIngListWebviewProvider().refreshingList() } diff --git a/src/commands/ing/select-ing-type.ts b/src/commands/ing/select-ing-type.ts index 9a7876e2..6c76feeb 100644 --- a/src/commands/ing/select-ing-type.ts +++ b/src/commands/ing/select-ing-type.ts @@ -1,10 +1,9 @@ import { CmdHandler } from '@/commands/cmd-handler' import { IngType, IngTypesMetadata } from '@/models/ing' import { getIngListWebviewProvider } from '@/services/ing-list-webview-provider' -import { IDisposable } from '@fluentui/react' import { QuickPickItem, window } from 'vscode' -export class SelectIngType extends CmdHandler { +export class SwitchIngType implements CmdHandler { handle(): Promise { const options: (QuickPickItem & { ingType: IngType })[] = IngTypesMetadata.map( ([ingType, { displayName, description }]) => ({ @@ -15,20 +14,23 @@ export class SelectIngType extends CmdHandler { }) ) const quickPick = window.createQuickPick<(typeof options)[0]>() - quickPick.title = '闪存列表选择' + + quickPick.title = '选择闪存类型' quickPick.items = options quickPick.canSelectMany = false - quickPick.selectedItems = quickPick.activeItems = options.filter(x => x.picked) + quickPick.activeItems = options.filter(x => x.picked) + quickPick.selectedItems = quickPick.activeItems quickPick.ignoreFocusOut = false - const disposables: IDisposable[] = [quickPick] + + const disposables = [quickPick] + quickPick.onDidChangeSelection( ([selectedItem]) => { if (selectedItem) { - const { ingType: selectedIngType } = selectedItem quickPick.hide() return getIngListWebviewProvider().refreshingList({ pageIndex: 1, - ingType: selectedIngType, + ingType: selectedItem.ingType, }) } }, diff --git a/src/commands/post-list/copy-link.ts b/src/commands/post-list/copy-link.ts index e02333e2..7b8a7fc0 100644 --- a/src/commands/post-list/copy-link.ts +++ b/src/commands/post-list/copy-link.ts @@ -7,12 +7,13 @@ import { PostTreeItem } from '@/tree-view-providers/models/post-tree-item' import { env, MessageItem, Uri, window } from 'vscode' type LinkFormat = 'markdown' | 'raw' | 'id' + interface CopyStrategy { name: string provideContent: (post: Post) => Thenable } -export class CopyPostLinkCmdHandler extends TreeViewCmdHandler> { +export class CopyPostLinkCmdHandler implements TreeViewCmdHandler> { private readonly _strategies: { [key in LinkFormat]: CopyStrategy } = { raw: { name: '复制链接', @@ -28,9 +29,7 @@ export class CopyPostLinkCmdHandler extends TreeViewCmdHandler { const post = await this.parseInput() diff --git a/src/models/ing.ts b/src/models/ing.ts index bdc6c473..6788e678 100644 --- a/src/models/ing.ts +++ b/src/models/ing.ts @@ -30,9 +30,8 @@ export class Ing { } get userIconUrl(): string { - return (this._userIconUrl = this._userIconUrl.startsWith('//') - ? `https:${this._userIconUrl}` - : this._userIconUrl) + if (this._userIconUrl.startsWith('//')) this._userIconUrl = `https:${this._userIconUrl}` + return this._userIconUrl } set userIconUrl(value: string) { diff --git a/src/services/ing-list-webview-provider.ts b/src/services/ing-list-webview-provider.ts index d9425c62..34ac514e 100644 --- a/src/services/ing-list-webview-provider.ts +++ b/src/services/ing-list-webview-provider.ts @@ -17,7 +17,7 @@ import { isNumber } from 'lodash-es' import { CommentIngCmdHandler } from '@/commands/ing/comment-ing' import { execCmd } from '@/utils/cmd' -export class ingListWebviewProvider implements WebviewViewProvider { +export class IngListWebviewProvider implements WebviewViewProvider { readonly viewId = `${globalCtx.extName}.ing-list-webview` private readonly _baseTitle = '闪存' @@ -26,7 +26,6 @@ export class ingListWebviewProvider implements WebviewViewProvider { private _pageIndex = 1 private _isRefreshing = false private _ingType = IngType.all - private _show: WebviewView['show'] | null = null get observer(): IngWebviewMessageObserver { if (!this._view) throw Error('Cannot access the observer until the webviewView initialized!') @@ -46,11 +45,6 @@ export class ingListWebviewProvider implements WebviewViewProvider { return this._ingType } - get show() { - this._show ??= this._view ? this._view.show.bind(this._view) : null - return this._show - } - // eslint-disable-next-line @typescript-eslint/no-unused-vars async resolveWebviewView(webviewView: WebviewView, context: WebviewViewResolveContext, token: CancellationToken) { if (this._view && this._view === webviewView) return @@ -77,7 +71,7 @@ export class ingListWebviewProvider implements WebviewViewProvider { } async refreshingList({ ingType = this.ingType, pageIndex = this.pageIndex } = {}) { - if (!this._view || !this.show) return + if (this._view == null) return if (this._view.visible) { if (this.isRefreshing) return @@ -106,7 +100,7 @@ export class ingListWebviewProvider implements WebviewViewProvider { } as IngWebviewUiCmd>) .then(undefined, () => undefined) } else { - this.show() + this._view.show() } await this.setIngType(ingType) @@ -159,15 +153,15 @@ export class ingListWebviewProvider implements WebviewViewProvider { } } -let _getIngListWebviewProvider: any = null +let _ingListWebviewProvider: any = null -export function getIngListWebviewProvider(): ingListWebviewProvider { - _getIngListWebviewProvider = new ingListWebviewProvider() - return _getIngListWebviewProvider +export function getIngListWebviewProvider(): IngListWebviewProvider { + _ingListWebviewProvider ??= new IngListWebviewProvider() + return _ingListWebviewProvider } class IngWebviewMessageObserver { - constructor(private _provider: ingListWebviewProvider) {} + constructor(private _provider: IngListWebviewProvider) {} observer = ({ command, payload }: IngWebviewHostCmd) => { switch (command) { diff --git a/src/tree-view-providers/converters.ts b/src/tree-view-providers/converters.ts index fa3e1e47..57073f44 100644 --- a/src/tree-view-providers/converters.ts +++ b/src/tree-view-providers/converters.ts @@ -27,9 +27,7 @@ const categoryIcon = () => { export type TreeItemSource = Post | PostCategory | TreeItem | BaseTreeItemSource -interface Converter { - (s: T): TreeItem | Promise -} +type Converter = (s: T) => TreeItem | Promise const postConverter: Converter = obj => { const descDatePublished = obj.datePublished ? ` \n发布于: ${format(obj.datePublished, 'yyyy-MM-dd HH:mm')}` : '' @@ -60,11 +58,10 @@ const categoryConverter: Converter = ({ title, count }) => }) const baseTreeItemSourceConverter: Converter = obj => obj.toTreeItem() -const converter: Converter = obj => { + +export const toTreeItem = (obj: T) => { if (obj instanceof TreeItem) return obj else if (obj instanceof BaseTreeItemSource) return baseTreeItemSourceConverter(obj) else if (obj instanceof PostCategory) return categoryConverter(obj) else return postConverter(obj) } - -export const toTreeItem = (obj: T) => converter(obj) diff --git a/src/tree-view-providers/models/blog-export/post.ts b/src/tree-view-providers/models/blog-export/post.ts index ac148991..720b26bb 100644 --- a/src/tree-view-providers/models/blog-export/post.ts +++ b/src/tree-view-providers/models/blog-export/post.ts @@ -24,7 +24,7 @@ export class ExportPostTreeItem extends BaseTreeItemSource { collapsibleState: TreeItemCollapsibleState.None, command: { title: '查看博文', - command: ViewPostCmdHandler.commandName, + command: ViewPostCmdHandler.cmd, arguments: [this], }, resourceUri: Uri.joinPath(Settings.workspaceUri, title + (isMarkdown ? '.md' : '.html')), From ef274f70e9465925d8c9f7162adaea146be510b8 Mon Sep 17 00:00:00 2001 From: Thaumy Date: Mon, 24 Jul 2023 12:36:30 +0800 Subject: [PATCH 020/157] chore: move open cmds --- src/commands/cmd-register.ts | 12 ++++++------ src/commands/{ => open}/open-my-account-settings.ts | 0 src/commands/{ => open}/open-my-blog-console.ts | 0 src/commands/{ => open}/open-my-blog.ts | 0 src/commands/{ => open}/open-my-home-page.ts | 0 src/commands/{ => open}/open-post-in-blog-admin.ts | 0 src/commands/{ => open}/open-workspace.ts | 0 7 files changed, 6 insertions(+), 6 deletions(-) rename src/commands/{ => open}/open-my-account-settings.ts (100%) rename src/commands/{ => open}/open-my-blog-console.ts (100%) rename src/commands/{ => open}/open-my-blog.ts (100%) rename src/commands/{ => open}/open-my-home-page.ts (100%) rename src/commands/{ => open}/open-post-in-blog-admin.ts (100%) rename src/commands/{ => open}/open-workspace.ts (100%) diff --git a/src/commands/cmd-register.ts b/src/commands/cmd-register.ts index d709e6f1..5b8b1a72 100644 --- a/src/commands/cmd-register.ts +++ b/src/commands/cmd-register.ts @@ -1,8 +1,8 @@ -import { openMyAccountSettings } from './open-my-account-settings' -import { openMyWebBlogConsole } from './open-my-blog-console' -import { openMyHomePage } from './open-my-home-page' +import { openMyAccountSettings } from './open/open-my-account-settings' +import { openMyWebBlogConsole } from './open/open-my-blog-console' +import { openMyHomePage } from './open/open-my-home-page' import { login, logout } from './login' -import { openMyBlog } from './open-my-blog' +import { openMyBlog } from './open/open-my-blog' import { globalCtx } from '@/services/global-ctx' import { gotoNextPostList, gotoPreviousPostList, refreshPostList, seekPostList } from './post-list/refresh-post-list' import { uploadPostFileToCnblogs, uploadPostToCnblogs } from './post-list/upload-post' @@ -18,8 +18,8 @@ import { handleUpdatePostCategory } from './post-category/update-post-category' import { openPostInVscode } from './post-list/open-post-in-vscode' import { deletePostToLocalFileMap } from './post-list/delete-post-to-local-file-map' import { renamePost } from './post-list/rename-post' -import { openPostInBlogAdmin } from './open-post-in-blog-admin' -import { openWorkspace } from './open-workspace' +import { openPostInBlogAdmin } from './open/open-post-in-blog-admin' +import { openWorkspace } from './open/open-workspace' import { setWorkspace } from './set-workspace' import { revealWorkspaceInOs } from './reveal-workspace-in-os' import { viewPostOnline } from './view-post-online' diff --git a/src/commands/open-my-account-settings.ts b/src/commands/open/open-my-account-settings.ts similarity index 100% rename from src/commands/open-my-account-settings.ts rename to src/commands/open/open-my-account-settings.ts diff --git a/src/commands/open-my-blog-console.ts b/src/commands/open/open-my-blog-console.ts similarity index 100% rename from src/commands/open-my-blog-console.ts rename to src/commands/open/open-my-blog-console.ts diff --git a/src/commands/open-my-blog.ts b/src/commands/open/open-my-blog.ts similarity index 100% rename from src/commands/open-my-blog.ts rename to src/commands/open/open-my-blog.ts diff --git a/src/commands/open-my-home-page.ts b/src/commands/open/open-my-home-page.ts similarity index 100% rename from src/commands/open-my-home-page.ts rename to src/commands/open/open-my-home-page.ts diff --git a/src/commands/open-post-in-blog-admin.ts b/src/commands/open/open-post-in-blog-admin.ts similarity index 100% rename from src/commands/open-post-in-blog-admin.ts rename to src/commands/open/open-post-in-blog-admin.ts diff --git a/src/commands/open-workspace.ts b/src/commands/open/open-workspace.ts similarity index 100% rename from src/commands/open-workspace.ts rename to src/commands/open/open-workspace.ts From 5fedfdefb203244dc737011f64ec24d2f36269f3 Mon Sep 17 00:00:00 2001 From: Thaumy Date: Tue, 25 Jul 2023 12:30:02 +0800 Subject: [PATCH 021/157] feat: treeview text style option --- src/commands/blog-export/download.ts | 8 +- src/commands/cmd-register.ts | 96 +++++++++++-------- src/commands/open/open-cnb-home.ts | 4 + src/commands/open/open-cnb-ing.ts | 4 + src/commands/open/open-cnb-news.ts | 4 + src/commands/open/open-cnb-q.ts | 4 + src/commands/pdf/export-pdf.ts | 10 +- .../base-tree-view-cmd-handler.ts | 6 +- .../post-category/new-post-category.ts | 8 +- .../delete-post-to-local-file-map.ts | 6 +- src/commands/post-list/delete-post.ts | 8 +- src/commands/post-list/refresh-post-list.ts | 8 +- src/services/post-list-view.ts | 4 +- src/tree-view-providers/navi-view.ts | 47 +++++++++ .../tree-view-registration.ts | 49 ++++++---- 15 files changed, 176 insertions(+), 90 deletions(-) create mode 100644 src/commands/open/open-cnb-home.ts create mode 100644 src/commands/open/open-cnb-ing.ts create mode 100644 src/commands/open/open-cnb-news.ts create mode 100644 src/commands/open/open-cnb-q.ts create mode 100644 src/tree-view-providers/navi-view.ts diff --git a/src/commands/blog-export/download.ts b/src/commands/blog-export/download.ts index 809e0721..f6d6ca1d 100644 --- a/src/commands/blog-export/download.ts +++ b/src/commands/blog-export/download.ts @@ -1,12 +1,12 @@ import { TreeViewCmdHandler } from '@/commands/cmd-handler' -import { Alert } from '@/services/alert.service' +import { Alert } from '@/services/alert' import { BlogExportApi } from '@/services/blog-export.api' import { DownloadedExportStore } from '@/services/downloaded-export.store' import { globalCtx } from '@/services/global-ctx' -import { Settings } from '@/services/settings.service' +import { Settings } from '@/services/settings' import { BlogExportProvider } from '@/tree-view-providers/blog-export-provider' import { BlogExportRecordTreeItem } from '@/tree-view-providers/models/blog-export' -import { extViews } from '@/tree-view-providers/tree-view-registration' +import { extTreeViews } from '@/tree-view-providers/tree-view-registration' import fs from 'fs' import { Progress } from 'got' import path from 'path' @@ -38,7 +38,7 @@ export class DownloadExportCmdHandler implements TreeViewCmdHandler `${prefix}${rest}` +} export function setupExtCmd() { const ctx = globalCtx.extCtx - const appName = globalCtx.extName + const withAppName = withPrefix(globalCtx.extName) // TODO: simplify register const disposables = [ - regCmd(`${appName}.login`, login), - regCmd(`${appName}.open-my-blog`, openMyBlog), - regCmd(`${appName}.open-my-home-page`, openMyHomePage), - regCmd(`${appName}.open-my-blog-console`, openMyWebBlogConsole), - regCmd(`${appName}.open-my-account-settings`, openMyAccountSettings), - regCmd(`${appName}.logout`, logout), - regCmd(`${appName}.refresh-post-list`, refreshPostList), - regCmd(`${appName}.previous-post-list`, gotoPreviousPostList), - regCmd(`${appName}.seek-post-list`, seekPostList), - regCmd(`${appName}.next-post-list`, gotoNextPostList), - regCmd(`${appName}.edit-post`, openPostInVscode), - regCmd(`${appName}.upload-post`, uploadPostToCnblogs), - regCmd(`${appName}.modify-post-settings`, modifyPostSettings), - regCmd(`${appName}.delete-post`, deleteSelectedPost), - regCmd(`${appName}.create-local-draft`, createLocalDraft), - regCmd(`${appName}.upload-post-file-to-cnblogs`, uploadPostFileToCnblogs), - regCmd(`${appName}.pull-post-remote-updates`, pullPostRemoteUpdates), - regCmd(`${appName}.upload-clipboard-image`, () => uploadImage(true, 'clipboard')), - regCmd(`${appName}.upload-local-disk-image`, () => uploadImage(true, 'local')), - regCmd(`${appName}.upload-image`, () => uploadImage(true)), - regCmd(`${appName}.reveal-local-post-file-in-os`, revealLocalPostFileInOs), - regCmd(`${appName}.show-post-to-local-file-info`, showLocalFileToPostInfo), - regCmd(`${appName}.new-post-category`, newPostCategory), - regCmd(`${appName}.delete-selected-post-categories`, handleDeletePostCategories), - regCmd(`${appName}.refresh-post-categories-list`, refreshPostCategoriesList), - regCmd(`${appName}.update-post-category`, handleUpdatePostCategory), - regCmd(`${appName}.delete-post-to-local-file-map`, deletePostToLocalFileMap), - regCmd(`${appName}.rename-post`, renamePost), - regCmd(`${appName}.open-post-in-blog-admin`, openPostInBlogAdmin), - regCmd(`${appName}.open-workspace`, openWorkspace), - regCmd(`${appName}.set-workspace`, setWorkspace), - regCmd(`${appName}.reveal-workspace-in-os`, revealWorkspaceInOs), - regCmd(`${appName}.view-post-online`, viewPostOnline), - regCmd(`${appName}.export-post-to-pdf`, (input: unknown) => exportPostToPdf(input)), - regCmd(`${appName}.extract-images`, extractImages), - regCmd(`${appName}.search-post`, searchPost), - regCmd(`${appName}.clear-post-search-results`, clearPostSearchResults), - regCmd(`${appName}.refresh-post-search-results`, refreshPostSearchResults), - regCmd(`${appName}.copy-post-link`, input => new CopyPostLinkCmdHandler(input).handle()), - regCmd(`${appName}.ing.publish`, () => new PublishIngCmdHandler('input').handle()), - regCmd(`${appName}.ing.publish-selection`, () => new PublishIngCmdHandler('selection').handle()), + regCmd(withAppName('.login'), login), + regCmd(withAppName('.open-my-blog'), openMyBlog), + regCmd(withAppName('.open-my-home-page'), openMyHomePage), + regCmd(withAppName('.open-my-blog-console'), openMyWebBlogConsole), + regCmd(withAppName('.open-my-account-settings'), openMyAccountSettings), + regCmd(withAppName('.logout'), logout), + regCmd(withAppName('.refresh-post-list'), refreshPostList), + regCmd(withAppName('.previous-post-list'), gotoPreviousPostList), + regCmd(withAppName('.seek-post-list'), seekPostList), + regCmd(withAppName('.next-post-list'), gotoNextPostList), + regCmd(withAppName('.edit-post'), openPostInVscode), + regCmd(withAppName('.upload-post'), uploadPostToCnblogs), + regCmd(withAppName('.modify-post-settings'), modifyPostSettings), + regCmd(withAppName('.delete-post'), deleteSelectedPost), + regCmd(withAppName('.create-local-draft'), createLocalDraft), + regCmd(withAppName('.upload-post-file-to-cnblogs'), uploadPostFileToCnblogs), + regCmd(withAppName('.pull-post-remote-updates'), pullPostRemoteUpdates), + regCmd(withAppName('.upload-clipboard-image'), () => uploadImage(true, 'clipboard')), + regCmd(withAppName('.upload-local-disk-image'), () => uploadImage(true, 'local')), + regCmd(withAppName('.upload-image'), () => uploadImage(true)), + regCmd(withAppName('.reveal-local-post-file-in-os'), revealLocalPostFileInOs), + regCmd(withAppName('.show-post-to-local-file-info'), showLocalFileToPostInfo), + regCmd(withAppName('.new-post-category'), newPostCategory), + regCmd(withAppName('.delete-selected-post-categories'), handleDeletePostCategories), + regCmd(withAppName('.refresh-post-categories-list'), refreshPostCategoriesList), + regCmd(withAppName('.update-post-category'), handleUpdatePostCategory), + regCmd(withAppName('.delete-post-to-local-file-map'), deletePostToLocalFileMap), + regCmd(withAppName('.rename-post'), renamePost), + regCmd(withAppName('.open-post-in-blog-admin'), openPostInBlogAdmin), + regCmd(withAppName('.open-workspace'), openWorkspace), + regCmd(withAppName('.set-workspace'), setWorkspace), + regCmd(withAppName('.reveal-workspace-in-os'), revealWorkspaceInOs), + regCmd(withAppName('.view-post-online'), viewPostOnline), + regCmd(withAppName('.export-post-to-pdf'), (input: unknown) => exportPostToPdf(input)), + regCmd(withAppName('.extract-images'), extractImages), + regCmd(withAppName('.search-post'), searchPost), + regCmd(withAppName('.clear-post-search-results'), clearPostSearchResults), + regCmd(withAppName('.refresh-post-search-results'), refreshPostSearchResults), + regCmd(withAppName('.copy-post-link'), input => new CopyPostLinkCmdHandler(input).handle()), + regCmd(withAppName('.ing.publish'), () => new PublishIngCmdHandler('input').handle()), + regCmd(withAppName('.ing.publish-selection'), () => new PublishIngCmdHandler('selection').handle()), + regCmd(withAppName('.open-cnb-home'), openCnbHome), + regCmd(withAppName('.open-cnb-news'), openCnbNews), + regCmd(withAppName('.open-cnb-q'), openCnbQ), + regCmd(withAppName('.open-cnb-ing'), openCnbIng), ...regIngListCmds(), ...regBlogExportCmds(), diff --git a/src/commands/open/open-cnb-home.ts b/src/commands/open/open-cnb-home.ts new file mode 100644 index 00000000..720fe346 --- /dev/null +++ b/src/commands/open/open-cnb-home.ts @@ -0,0 +1,4 @@ +import { execCmd } from '@/utils/cmd' +import { Uri } from 'vscode' + +export const openCnbHome = () => execCmd('vscode.open', Uri.parse('https://www.cnblogs.com')) diff --git a/src/commands/open/open-cnb-ing.ts b/src/commands/open/open-cnb-ing.ts new file mode 100644 index 00000000..4ab558ba --- /dev/null +++ b/src/commands/open/open-cnb-ing.ts @@ -0,0 +1,4 @@ +import { Uri } from 'vscode' +import { execCmd } from '@/utils/cmd' + +export const openCnbIng = () => execCmd('vscode.open', Uri.parse('https://ing.cnblogs.com')) diff --git a/src/commands/open/open-cnb-news.ts b/src/commands/open/open-cnb-news.ts new file mode 100644 index 00000000..da0bdc34 --- /dev/null +++ b/src/commands/open/open-cnb-news.ts @@ -0,0 +1,4 @@ +import { execCmd } from '@/utils/cmd' +import { Uri } from 'vscode' + +export const openCnbNews = () => execCmd('vscode.open', Uri.parse('https://news.cnblogs.com')) diff --git a/src/commands/open/open-cnb-q.ts b/src/commands/open/open-cnb-q.ts new file mode 100644 index 00000000..0be3f4e1 --- /dev/null +++ b/src/commands/open/open-cnb-q.ts @@ -0,0 +1,4 @@ +import { execCmd } from '@/utils/cmd' +import { Uri } from 'vscode' + +export const openCnbQ = () => execCmd('vscode.open', Uri.parse('https://q.cnblogs.com')) diff --git a/src/commands/pdf/export-pdf.ts b/src/commands/pdf/export-pdf.ts index 26a96afd..82886a23 100644 --- a/src/commands/pdf/export-pdf.ts +++ b/src/commands/pdf/export-pdf.ts @@ -5,12 +5,12 @@ import os from 'os' import { MessageOptions, Progress, ProgressLocation, Uri, window, workspace } from 'vscode' import { Post } from '@/models/post' import { PostFileMapManager } from '@/services/post-file-map' -import { PostService } from '@/services/post.service' -import { extViews } from '@/tree-view-providers/tree-view-registration' +import { PostService } from '@/services/post' +import { extTreeViews } from '@/tree-view-providers/tree-view-registration' import { ChromiumPathProvider } from '@/utils/chromium-path-provider' -import { Settings } from '@/services/settings.service' +import { Settings } from '@/services/settings' import { accountManager } from '@/auth/account-manager' -import { Alert } from '@/services/alert.service' +import { Alert } from '@/services/alert' import { PostTreeItem } from '@/tree-view-providers/models/post-tree-item' import { PostEditDto } from '@/models/post-edit-dto' import { postPdfTemplateBuilder } from '@/commands/pdf/post-pdf-template-builder' @@ -140,7 +140,7 @@ const inputTargetFolder = async (): Promise => const handlePostInput = (post: Post | PostTreeItem): Promise => { const postList: Post[] = [post instanceof PostTreeItem ? post.post : post] - extViews.visiblePostList()?.selection.map(item => { + extTreeViews.visiblePostList()?.selection.map(item => { item = item instanceof PostTreeItem ? item.post : item if (item instanceof Post && !postList.includes(item)) postList.push(item) }) diff --git a/src/commands/post-category/base-tree-view-cmd-handler.ts b/src/commands/post-category/base-tree-view-cmd-handler.ts index d649d3c0..342d5e16 100644 --- a/src/commands/post-category/base-tree-view-cmd-handler.ts +++ b/src/commands/post-category/base-tree-view-cmd-handler.ts @@ -1,11 +1,11 @@ import { PostCategory } from '@/models/post-category' import { PostCategoriesListTreeItem } from '@/tree-view-providers/models/categories-list-tree-item' import { PostCategoryTreeItem } from '@/tree-view-providers/models/post-category-tree-item' -import { extViews } from '@/tree-view-providers/tree-view-registration' +import { extTreeViews } from '@/tree-view-providers/tree-view-registration' import { MultiSelectableTreeViewCmdHandler, TreeViewCmdHandler } from '../cmd-handler' export abstract class BasePostCategoryTreeViewCmdHandler implements TreeViewCmdHandler { - protected readonly view = extViews.postCategoriesList + protected readonly view = extTreeViews.postCategoriesList constructor(public readonly input: unknown) {} @@ -28,7 +28,7 @@ export abstract class BaseMultiSelectablePostCategoryTreeViewCmdHandler extends PostCategory > { protected get view() { - return extViews.postCategoriesList + return extTreeViews.postCategoriesList } protected parseSelections() { diff --git a/src/commands/post-category/new-post-category.ts b/src/commands/post-category/new-post-category.ts index 6afcf060..7c8bb401 100644 --- a/src/commands/post-category/new-post-category.ts +++ b/src/commands/post-category/new-post-category.ts @@ -1,9 +1,9 @@ import { MessageOptions, ProgressLocation, window } from 'vscode' -import { postCategoryService } from '@/services/post-category.service' -import { extViews } from '@/tree-view-providers/tree-view-registration' +import { postCategoryService } from '@/services/post-category' +import { extTreeViews } from '@/tree-view-providers/tree-view-registration' import { inputPostCategory } from './input-post-category' import { refreshPostCategoriesList } from './refresh-post-categories-list' -import { Alert } from '@/services/alert.service' +import { Alert } from '@/services/alert' export const newPostCategory = async () => { const input = await inputPostCategory({ @@ -27,7 +27,7 @@ export const newPostCategory = async () => { }) refreshPostCategoriesList() const newCategory = (await postCategoryService.listCategories()).find(x => x.title === input.title) - if (newCategory) await extViews.postCategoriesList.reveal(newCategory) + if (newCategory) await extTreeViews.postCategoriesList.reveal(newCategory) } catch (err) { void Alert.err('新建博文分类时遇到了错误', { modal: true, diff --git a/src/commands/post-list/delete-post-to-local-file-map.ts b/src/commands/post-list/delete-post-to-local-file-map.ts index 0a97800e..21b900b8 100644 --- a/src/commands/post-list/delete-post-to-local-file-map.ts +++ b/src/commands/post-list/delete-post-to-local-file-map.ts @@ -3,8 +3,8 @@ import { Post } from '@/models/post' import { PostFileMap, PostFileMapManager } from '@/services/post-file-map' import { revealPostListItem } from '@/services/post-list-view' import { PostTreeItem } from '@/tree-view-providers/models/post-tree-item' -import { extViews } from '@/tree-view-providers/tree-view-registration' -import { Alert } from '@/services/alert.service' +import { extTreeViews } from '@/tree-view-providers/tree-view-registration' +import { Alert } from '@/services/alert' const confirm = async (postList: Post[]): Promise => { const options = ['确定'] @@ -21,7 +21,7 @@ const confirm = async (postList: Post[]): Promise => { export const deletePostToLocalFileMap = async (post: Post | PostTreeItem) => { post = post instanceof PostTreeItem ? post.post : post - const view = extViews.postList + const view = extTreeViews.postList let selectedPost = view.selection .map(x => (x instanceof Post ? x : x instanceof PostTreeItem ? x.post : null)) .filter((x): x is Post => x != null) diff --git a/src/commands/post-list/delete-post.ts b/src/commands/post-list/delete-post.ts index b9f2cf5f..cf4721b2 100644 --- a/src/commands/post-list/delete-post.ts +++ b/src/commands/post-list/delete-post.ts @@ -1,10 +1,10 @@ import { MessageOptions, ProgressLocation, Uri, window, workspace } from 'vscode' import { Post } from '@/models/post' -import { Alert } from '@/services/alert.service' -import { PostService } from '@/services/post.service' +import { Alert } from '@/services/alert' +import { PostService } from '@/services/post' import { PostFileMap, PostFileMapManager } from '@/services/post-file-map' import { postDataProvider } from '@/tree-view-providers/post-data-provider' -import { extViews } from '@/tree-view-providers/tree-view-registration' +import { extTreeViews } from '@/tree-view-providers/tree-view-registration' import { refreshPostList } from './refresh-post-list' import { PostTreeItem } from '@/tree-view-providers/models/post-tree-item' import { postCategoriesDataProvider } from '@/tree-view-providers/post-categories-tree-data-provider' @@ -45,7 +45,7 @@ export const deleteSelectedPost = async (arg: unknown) => { else return const selectedPost: Post[] = post ? [post] : [] - extViews.visiblePostList()?.selection.map(item => { + extTreeViews.visiblePostList()?.selection.map(item => { const post = item instanceof PostTreeItem ? item.post : item if (post instanceof Post && !selectedPost.includes(post)) { postDataProvider.pagedPost?.items.find(item => item === post) diff --git a/src/commands/post-list/refresh-post-list.ts b/src/commands/post-list/refresh-post-list.ts index cb608d97..993a1c40 100644 --- a/src/commands/post-list/refresh-post-list.ts +++ b/src/commands/post-list/refresh-post-list.ts @@ -1,10 +1,10 @@ import { globalCtx } from '@/services/global-ctx' -import { PostService } from '@/services/post.service' +import { PostService } from '@/services/post' import vscode, { window } from 'vscode' import { postDataProvider } from '@/tree-view-providers/post-data-provider' -import { Alert } from '@/services/alert.service' +import { Alert } from '@/services/alert' import { PostListState } from '@/models/post-list-state' -import { extViews } from '@/tree-view-providers/tree-view-registration' +import { extTreeViews } from '@/tree-view-providers/tree-view-registration' import { execCmd } from '@/utils/cmd' let refreshTask: Promise | null = null @@ -124,7 +124,7 @@ const updatePostListViewTitle = () => { if (!state) return const { pageIndex, pageCount } = state - const views = [extViews.postList, extViews.anotherPostList] + const views = [extTreeViews.postList, extTreeViews.anotherPostList] for (const view of views) { let title = view.title ?? '' const idx = title.indexOf('(') diff --git a/src/services/post-list-view.ts b/src/services/post-list-view.ts index c957dfa4..3f9646c7 100644 --- a/src/services/post-list-view.ts +++ b/src/services/post-list-view.ts @@ -1,5 +1,5 @@ import { Post } from '@/models/post' -import { extViews } from '@/tree-view-providers/tree-view-registration' +import { extTreeViews } from '@/tree-view-providers/tree-view-registration' export const revealPostListItem = async ( post: Post, @@ -7,6 +7,6 @@ export const revealPostListItem = async ( ) => { if (!post) return - const view = extViews.visiblePostList() + const view = extTreeViews.visiblePostList() await view?.reveal(post, options) } diff --git a/src/tree-view-providers/navi-view.ts b/src/tree-view-providers/navi-view.ts new file mode 100644 index 00000000..df57616e --- /dev/null +++ b/src/tree-view-providers/navi-view.ts @@ -0,0 +1,47 @@ +import { ProviderResult, TreeItem, TreeDataProvider, ThemeIcon } from 'vscode' + +export class NaviViewDataProvider implements TreeDataProvider { + getTreeItem(element: TreeItem): TreeItem | Thenable { + return element + } + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + getChildren(element?: TreeItem): ProviderResult { + return [ + { + label: '首页', + command: { + title: '打开博客园首页', + command: 'vscode-cnb.open-cnb-home', + }, + iconPath: new ThemeIcon('home'), + }, + { + label: '新闻', + command: { + title: '打开博客园新闻', + command: 'vscode-cnb.open-cnb-news', + }, + iconPath: new ThemeIcon('preview'), + }, + { + label: '博问', + command: { + title: '打开博问', + command: 'vscode-cnb.open-cnb-q', + }, + iconPath: new ThemeIcon('question'), + }, + { + label: '闪存', + command: { + title: '打开闪存', + command: 'vscode-cnb.open-cnb-ing', + }, + iconPath: new ThemeIcon('comment'), + }, + ] + } +} + +export const naviViewDataProvider = new NaviViewDataProvider() diff --git a/src/tree-view-providers/tree-view-registration.ts b/src/tree-view-providers/tree-view-registration.ts index 472e8ea3..4e08b9ed 100644 --- a/src/tree-view-providers/tree-view-registration.ts +++ b/src/tree-view-providers/tree-view-registration.ts @@ -1,5 +1,5 @@ import { globalCtx } from '@/services/global-ctx' -import vscode from 'vscode' +import { TreeView, TreeItem } from 'vscode' import { accountViewDataProvider } from './account-view-data-provider' import { PostListTreeItem, postDataProvider } from './post-data-provider' import { postCategoriesDataProvider } from './post-categories-tree-data-provider' @@ -8,26 +8,25 @@ import { IDisposable } from '@fluentui/react' import { BlogExportTreeItem } from '@/tree-view-providers/models/blog-export' import { BlogExportProvider } from '@/tree-view-providers/blog-export-provider' import { regTreeView } from '@/utils/tree-view' +import { naviViewDataProvider } from '@/tree-view-providers/navi-view' const _views: { - postList?: vscode.TreeView - anotherPostList?: vscode.TreeView - account?: vscode.TreeView - postCategoriesList?: vscode.TreeView - blogExport?: vscode.TreeView - postLists: () => vscode.TreeView[] - visiblePostList: () => vscode.TreeView | undefined + postList?: TreeView + anotherPostList?: TreeView + postCategoriesList?: TreeView + blogExport?: TreeView + account?: TreeView + navi?: TreeView + + postLists: () => TreeView[] + visiblePostList: () => TreeView | undefined } = { postLists: () => - [_views.postList, _views.anotherPostList].filter((x): x is vscode.TreeView => x != null), + [_views.postList, _views.anotherPostList].filter((x): x is TreeView => x != null), visiblePostList: () => _views.postLists().find(x => x.visible), } export function setupExtTreeView() { - _views.account = regTreeView('cnblogs-account', { - treeDataProvider: accountViewDataProvider, - canSelectMany: false, - }) _views.postList = regTreeView('cnblogs-post-list', { treeDataProvider: postDataProvider, canSelectMany: true, @@ -44,20 +43,28 @@ export function setupExtTreeView() { canSelectMany: false, treeDataProvider: BlogExportProvider.instance, }) + _views.account = regTreeView('cnblogs-account', { + treeDataProvider: accountViewDataProvider, + canSelectMany: false, + }) + _views.navi = regTreeView('cnblogs-navi', { + treeDataProvider: naviViewDataProvider, + canSelectMany: false, + }) const disposables: IDisposable[] = [] for (const [, item] of Object.entries(_views)) typeof item === 'function' ? undefined : disposables.push(item) globalCtx.extCtx.subscriptions.push(...disposables) - return extViews + return extTreeViews } -class ExtViews implements Required { +export class ExtTreeViews implements Required { postLists = _views.postLists visiblePostList = _views.visiblePostList - get postList(): vscode.TreeView { + get postList(): TreeView { return this.getTreeView('postList') } @@ -65,6 +72,10 @@ class ExtViews implements Required { return this.getTreeView('anotherPostList') } + get blogExport() { + return this.getTreeView('blogExport') + } + get account() { return this.getTreeView('account') } @@ -73,8 +84,8 @@ class ExtViews implements Required { return this.getTreeView('postCategoriesList') } - get blogExport() { - return this.getTreeView('blogExport') + get navi() { + return this.getTreeView('navi') } private getTreeView>( @@ -86,4 +97,4 @@ class ExtViews implements Required { } } -export const extViews = new ExtViews() +export const extTreeViews = new ExtTreeViews() From a4d82444b925ed6119e3dc9591600c47c5e0d2a9 Mon Sep 17 00:00:00 2001 From: Thaumy Date: Tue, 25 Jul 2023 12:37:14 +0800 Subject: [PATCH 022/157] feat: ing style options --- package.json | 29 +++++++---------------- src/services/ing-list-webview-provider.ts | 13 +++++++--- src/utils/ingStarToText.ts | 7 ++++++ 3 files changed, 25 insertions(+), 24 deletions(-) create mode 100644 src/utils/ingStarToText.ts diff --git a/package.json b/package.json index 36e7b0be..edf30d14 100644 --- a/package.json +++ b/package.json @@ -682,42 +682,33 @@ "additionalProperties": false, "markdownDescription": "控制要在编辑器右键菜单中显示的命令" }, - "cnblogsClient.ui.symbolicIngEmoji": { + "cnblogsClient.ui.textIngStar": { "order": 15, "type": "boolean", "scope": "application", "default": false, - "markdownDescription": "符号化闪存表情" + "markdownDescription": "闪存星文本化" }, - "cnblogsClient.ui.disableIngAvatar": { + "cnblogsClient.ui.disableIngUserAvatar": { "order": 16, "type": "boolean", "scope": "application", "default": false, - "markdownDescription": "禁用闪存头像" + "markdownDescription": "禁用闪存用户头像" }, - "cnblogsClient.ui.explorerTitleStyle": { + "cnblogsClient.ui.treeViewTitleStyle": { "order": 17, "scope": "application", "default": "normal", "markdownDescription": "侧栏标题风格", "enum": [ "normal", - "short", - "short-english" + "short" ], "enumItemLabels": [ "正常", - "精简", - "英文精简" + "简洁" ] - }, - "cnblogsClient.ui.fakeExtIcon": { - "order": 18, - "type": "boolean", - "scope": "application", - "default": false, - "markdownDescription": "伪装扩展图标" } } } @@ -768,7 +759,7 @@ "visibility": "collapsed" }, { - "id": "cnblogs-navigation", + "id": "cnblogs-navi", "name": "博客园导航", "when": "vscode-cnb.isAuthorized", "visibility": "collapsed" @@ -1280,10 +1271,6 @@ "view": "cnblogs-authorize", "contents": "[Login](command:vscode-cnb.login)" }, - { - "view": "cnblogs-navigation", - "contents": "[首页](https://www.cnblogs.com)\n[新闻](https://news.cnblogs.com/)\n[博问](https://q.cnblogs.com/)\n[闪存](https://ing.cnblogs.com/)" - }, { "view": "vscode-cnb-workspace", "contents": "[在 VSCode 中打开工作空间](command:vscode-cnb.open-workspace)", diff --git a/src/services/ing-list-webview-provider.ts b/src/services/ing-list-webview-provider.ts index 34ac514e..03dddc52 100644 --- a/src/services/ing-list-webview-provider.ts +++ b/src/services/ing-list-webview-provider.ts @@ -16,11 +16,13 @@ import { IngType, IngTypesMetadata } from 'src/models/ing' import { isNumber } from 'lodash-es' import { CommentIngCmdHandler } from '@/commands/ing/comment-ing' import { execCmd } from '@/utils/cmd' +import { ingStarToText } from '@/utils/ingStarToText' +import { Settings } from '@/services/settings' +import { isDisableIngUserAvatar, isEnableTextIngStar } from '@/services/setup-ui' export class IngListWebviewProvider implements WebviewViewProvider { readonly viewId = `${globalCtx.extName}.ing-list-webview` - private readonly _baseTitle = '闪存' private _view: WebviewView | null = null private _observer: IngWebviewMessageObserver | null = null private _pageIndex = 1 @@ -83,11 +85,16 @@ export class IngListWebviewProvider implements WebviewViewProvider { command: WebviewCmd.IngCmd.UiCmd.setAppState, } as IngWebviewUiCmd>) .then(undefined, () => undefined) - const ingList = await IngApi.list({ + const rawIngList = await IngApi.list({ type: ingType, pageIndex, pageSize: 30, }) + const ingList = rawIngList.map(ing => { + if (isDisableIngUserAvatar(Settings.cfg)) ing.userIconUrl = '' + if (isEnableTextIngStar(Settings.cfg)) ing.icons = ingStarToText(ing.icons) + return ing + }) const comments = await IngApi.listComments(...ingList.map(x => x.id)) await this._view.webview .postMessage({ @@ -149,7 +156,7 @@ export class IngListWebviewProvider implements WebviewViewProvider { if (!this._view) return const ingTypeSuffix = IngTypesMetadata.find(([x]) => x === this.ingType)?.[1].displayName ?? '' const pageIndexSuffix = this.pageIndex > 1 ? `(第${this.pageIndex}页)` : '' - this._view.title = `${this._baseTitle}${ingTypeSuffix ? ' - ' + ingTypeSuffix : ''}${pageIndexSuffix}` + this._view.title = `闪存 ${ingTypeSuffix ? ' - ' + ingTypeSuffix : ''}${pageIndexSuffix}` } } diff --git a/src/utils/ingStarToText.ts b/src/utils/ingStarToText.ts new file mode 100644 index 00000000..4c2ce2f2 --- /dev/null +++ b/src/utils/ingStarToText.ts @@ -0,0 +1,7 @@ +export function ingStarToText(ingIcon: string) { + const imgTagReg = //gi + const mg = Array.from(ingIcon.matchAll(imgTagReg)) + + if (mg[0] !== undefined) return `「${mg[0][1]}」` + else return '' +} From c6ced2e2861c89cf88677baef5eb2d867f6f6b4b Mon Sep 17 00:00:00 2001 From: Thaumy Date: Tue, 25 Jul 2023 12:37:51 +0800 Subject: [PATCH 023/157] refactor: simplify code --- src/auth/account-manager.ts | 2 +- src/auth/auth-provider.ts | 2 +- src/commands/blog-export/create.ts | 2 +- src/commands/blog-export/delete.ts | 2 +- src/commands/blog-export/edit.ts | 4 +- src/commands/blog-export/open-local.ts | 2 +- src/commands/extract-images.ts | 4 +- src/commands/ing/publish-ing.ts | 2 +- src/commands/open/open-my-account-settings.ts | 4 +- src/commands/open/open-my-blog-console.ts | 6 +- src/commands/open/open-my-blog.ts | 4 +- src/commands/open/open-my-home-page.ts | 4 +- src/commands/open/open-workspace.ts | 4 +- src/commands/pdf/post-pdf-template-builder.ts | 4 +- .../delete-selected-categories.ts | 4 +- .../post-category/update-post-category.ts | 4 +- src/commands/post-list/copy-link.ts | 4 +- src/commands/post-list/create-local-draft.ts | 2 +- .../post-list/modify-post-settings.ts | 8 +- src/commands/post-list/open-post-file.ts | 2 +- src/commands/post-list/open-post-in-vscode.ts | 10 +-- src/commands/post-list/rename-post.ts | 4 +- src/commands/post-list/upload-post.ts | 10 +-- src/commands/pull-post-remote-updates.ts | 6 +- src/commands/reveal-workspace-in-os.ts | 2 +- src/commands/set-workspace.ts | 4 +- src/commands/show-local-file-to-post-info.ts | 6 +- .../upload-image/upload-clipboard-image.ts | 4 +- .../upload-image/upload-image-utils.ts | 2 +- src/commands/upload-image/upload-image.ts | 2 +- .../upload-image/upload-local-disk-image.ts | 2 +- src/commands/view-post-online.ts | 2 +- src/extension.ts | 5 +- src/markdown/extend-markdownIt.ts | 2 +- src/services/{alert.service.ts => alert.ts} | 0 ...g-settings.service.ts => blog-settings.ts} | 0 src/services/check-workspace.ts | 5 +- ...challenge.service.ts => code-challenge.ts} | 0 src/services/{image.service.ts => image.ts} | 0 src/services/ing.api.ts | 10 +-- ...{local-draft.service.ts => local-draft.ts} | 0 ...ractor.service.ts => mkd-img-extractor.ts} | 2 +- ...t-category.service.ts => post-category.ts} | 0 ...cfg-panel.service.ts => post-cfg-panel.ts} | 8 +- .../{post-tag.service.ts => post-tag.ts} | 0 ...zer.service.ts => post-title-sanitizer.ts} | 0 src/services/{post.service.ts => post.ts} | 2 +- src/services/search-post-by-title.ts | 2 +- src/services/settings.service.test.ts | 35 -------- .../{settings.service.ts => settings.ts} | 2 +- src/services/setup-ui.ts | 90 +++++++++++++++++++ ...e-category.service.ts => site-category.ts} | 0 src/test/suite/extension.test.ts | 2 +- .../account-view-data-provider.ts | 8 -- .../blog-export-provider.ts | 2 +- src/tree-view-providers/converters.ts | 2 +- .../models/blog-export/post.ts | 2 +- .../models/post-metadata.ts | 4 +- .../post-categories-tree-data-provider.ts | 6 +- src/tree-view-providers/post-data-provider.ts | 6 +- src/utils/chromium-path-provider.ts | 2 +- src/utils/get-clipboard-image.ts | 2 +- src/utils/input-post-settings.ts | 4 +- 63 files changed, 190 insertions(+), 137 deletions(-) rename src/services/{alert.service.ts => alert.ts} (100%) rename src/services/{blog-settings.service.ts => blog-settings.ts} (100%) rename src/services/{code-challenge.service.ts => code-challenge.ts} (100%) rename src/services/{image.service.ts => image.ts} (100%) rename src/services/{local-draft.service.ts => local-draft.ts} (100%) rename src/services/{mkd-img-extractor.service.ts => mkd-img-extractor.ts} (99%) rename src/services/{post-category.service.ts => post-category.ts} (100%) rename src/services/{post-cfg-panel.service.ts => post-cfg-panel.ts} (97%) rename src/services/{post-tag.service.ts => post-tag.ts} (100%) rename src/services/{post-title-sanitizer.service.ts => post-title-sanitizer.ts} (100%) rename src/services/{post.service.ts => post.ts} (99%) delete mode 100644 src/services/settings.service.test.ts rename src/services/{settings.service.ts => settings.ts} (98%) create mode 100644 src/services/setup-ui.ts rename src/services/{site-category.service.ts => site-category.ts} (100%) diff --git a/src/auth/account-manager.ts b/src/auth/account-manager.ts index 17fe54da..06522faf 100644 --- a/src/auth/account-manager.ts +++ b/src/auth/account-manager.ts @@ -8,7 +8,7 @@ import { Oauth } from '@/services/oauth.api' import { authProvider } from '@/auth/auth-provider' import { AuthSession } from '@/auth/auth-session' import { BlogExportProvider } from '@/tree-view-providers/blog-export-provider' -import { Alert } from '@/services/alert.service' +import { Alert } from '@/services/alert' import { execCmd } from '@/utils/cmd' const isAuthorizedStorageKey = 'isAuthorized' diff --git a/src/auth/auth-provider.ts b/src/auth/auth-provider.ts index c3c06f4e..b00fda50 100644 --- a/src/auth/auth-provider.ts +++ b/src/auth/auth-provider.ts @@ -1,5 +1,5 @@ import { AuthSession } from '@/auth/auth-session' -import { genVerifyChallengePair } from '@/services/code-challenge.service' +import { genVerifyChallengePair } from '@/services/code-challenge' import { isArray, isUndefined } from 'lodash-es' import { authentication, diff --git a/src/commands/blog-export/create.ts b/src/commands/blog-export/create.ts index 12c599c7..54f05abe 100644 --- a/src/commands/blog-export/create.ts +++ b/src/commands/blog-export/create.ts @@ -1,5 +1,5 @@ import { CmdHandler } from '@/commands/cmd-handler' -import { Alert } from '@/services/alert.service' +import { Alert } from '@/services/alert' import { BlogExportApi } from '@/services/blog-export.api' import { BlogExportProvider } from '@/tree-view-providers/blog-export-provider' import { MessageItem, window } from 'vscode' diff --git a/src/commands/blog-export/delete.ts b/src/commands/blog-export/delete.ts index cc81e5b2..4f7c2d04 100644 --- a/src/commands/blog-export/delete.ts +++ b/src/commands/blog-export/delete.ts @@ -1,6 +1,6 @@ import { TreeViewCmdHandler } from '@/commands/cmd-handler' import { DownloadedBlogExport } from '@/models/blog-export' -import { Alert } from '@/services/alert.service' +import { Alert } from '@/services/alert' import { BlogExportApi } from '@/services/blog-export.api' import { DownloadedExportStore } from '@/services/downloaded-export.store' import { BlogExportProvider } from '@/tree-view-providers/blog-export-provider' diff --git a/src/commands/blog-export/edit.ts b/src/commands/blog-export/edit.ts index 6487907a..9be70b03 100644 --- a/src/commands/blog-export/edit.ts +++ b/src/commands/blog-export/edit.ts @@ -1,7 +1,7 @@ import { TreeViewCmdHandler } from '@/commands/cmd-handler' import { openPostFile } from '@/commands/post-list/open-post-file' -import { Alert } from '@/services/alert.service' -import { Settings } from '@/services/settings.service' +import { Alert } from '@/services/alert' +import { Settings } from '@/services/settings' import { ExportPostTreeItem } from '@/tree-view-providers/models/blog-export/post' import fs from 'fs' import path from 'path' diff --git a/src/commands/blog-export/open-local.ts b/src/commands/blog-export/open-local.ts index 468d30c8..76ecc8cd 100644 --- a/src/commands/blog-export/open-local.ts +++ b/src/commands/blog-export/open-local.ts @@ -3,7 +3,7 @@ import { window } from 'vscode' import path from 'path' import fs from 'fs' import { promisify } from 'util' -import { Alert } from '@/services/alert.service' +import { Alert } from '@/services/alert' import { DownloadedExportStore } from '@/services/downloaded-export.store' import { BlogExportProvider } from '@/tree-view-providers/blog-export-provider' diff --git a/src/commands/extract-images.ts b/src/commands/extract-images.ts index fc26ac2a..c96ccb27 100644 --- a/src/commands/extract-images.ts +++ b/src/commands/extract-images.ts @@ -1,6 +1,6 @@ import { MessageItem, MessageOptions, ProgressLocation, Range, Uri, window, workspace, WorkspaceEdit } from 'vscode' -import { ImageInfo, ImageSrc, MkdImgExtractor, newImageSrcFilter } from '@/services/mkd-img-extractor.service' -import { Alert } from '@/services/alert.service' +import { ImageInfo, ImageSrc, MkdImgExtractor, newImageSrcFilter } from '@/services/mkd-img-extractor' +import { Alert } from '@/services/alert' type ExtractOption = MessageItem & Partial<{ imageSrc: ImageSrc }> diff --git a/src/commands/ing/publish-ing.ts b/src/commands/ing/publish-ing.ts index 11f75a8a..59edfa3f 100644 --- a/src/commands/ing/publish-ing.ts +++ b/src/commands/ing/publish-ing.ts @@ -1,7 +1,7 @@ import { CmdHandler } from '@/commands/cmd-handler' import { execCmd } from '@/utils/cmd' import { IngPublishModel, IngType } from '@/models/ing' -import { Alert } from '@/services/alert.service' +import { Alert } from '@/services/alert' import { globalCtx } from '@/services/global-ctx' import { IngApi } from '@/services/ing.api' import { getIngListWebviewProvider } from '@/services/ing-list-webview-provider' diff --git a/src/commands/open/open-my-account-settings.ts b/src/commands/open/open-my-account-settings.ts index 059194d0..fbfda00f 100644 --- a/src/commands/open/open-my-account-settings.ts +++ b/src/commands/open/open-my-account-settings.ts @@ -1,5 +1,5 @@ -import vscode from 'vscode' +import { Uri } from 'vscode' import { execCmd } from '@/utils/cmd' export const openMyAccountSettings = () => - execCmd('vscode.open', vscode.Uri.parse('https://account.cnblogs.com/settings/account')) + execCmd('vscode.open', Uri.parse('https://account.cnblogs.com/settings/account')) diff --git a/src/commands/open/open-my-blog-console.ts b/src/commands/open/open-my-blog-console.ts index c14e9d88..1d2fd24a 100644 --- a/src/commands/open/open-my-blog-console.ts +++ b/src/commands/open/open-my-blog-console.ts @@ -1,4 +1,4 @@ -import vscode from 'vscode' - -export const openMyWebBlogConsole = () => execCmd('vscode.open', vscode.Uri.parse('https://i.cnblogs.com')) +import { Uri } from 'vscode' import { execCmd } from '@/utils/cmd' + +export const openMyWebBlogConsole = () => execCmd('vscode.open', Uri.parse('https://i.cnblogs.com')) diff --git a/src/commands/open/open-my-blog.ts b/src/commands/open/open-my-blog.ts index 93dc2c74..32e1b186 100644 --- a/src/commands/open/open-my-blog.ts +++ b/src/commands/open/open-my-blog.ts @@ -1,8 +1,8 @@ import { accountManager } from '@/auth/account-manager' -import vscode from 'vscode' import { execCmd } from '@/utils/cmd' +import { Uri } from 'vscode' export const openMyBlog = () => { const userBlogUrl = accountManager.currentUser?.website - if (userBlogUrl) return execCmd('vscode.open', vscode.Uri.parse(userBlogUrl)) + if (userBlogUrl) return execCmd('vscode.open', Uri.parse(userBlogUrl)) } diff --git a/src/commands/open/open-my-home-page.ts b/src/commands/open/open-my-home-page.ts index 2d4664aa..bd384b85 100644 --- a/src/commands/open/open-my-home-page.ts +++ b/src/commands/open/open-my-home-page.ts @@ -1,11 +1,11 @@ import { accountManager } from '@/auth/account-manager' import { execCmd } from '@/utils/cmd' -import vscode from 'vscode' +import { Uri } from 'vscode' export const openMyHomePage = () => { const { accountId } = accountManager.currentUser if (!accountId || accountId <= 0) return const userHomePageUrl = `https://home.cnblogs.com/u/${accountId}` - if (userHomePageUrl) void execCmd('vscode.open', vscode.Uri.parse(userHomePageUrl)) + if (userHomePageUrl) void execCmd('vscode.open', Uri.parse(userHomePageUrl)) } diff --git a/src/commands/open/open-workspace.ts b/src/commands/open/open-workspace.ts index 9920c7fc..d2e032d9 100644 --- a/src/commands/open/open-workspace.ts +++ b/src/commands/open/open-workspace.ts @@ -1,7 +1,7 @@ import { MessageOptions } from 'vscode' -import { Settings } from '@/services/settings.service' +import { Settings } from '@/services/settings' import { execCmd } from '@/utils/cmd' -import { Alert } from '@/services/alert.service' +import { Alert } from '@/services/alert' export const openWorkspace = async () => { const uri = Settings.workspaceUri diff --git a/src/commands/pdf/post-pdf-template-builder.ts b/src/commands/pdf/post-pdf-template-builder.ts index 62e7647f..9617222c 100644 --- a/src/commands/pdf/post-pdf-template-builder.ts +++ b/src/commands/pdf/post-pdf-template-builder.ts @@ -1,9 +1,9 @@ import { Post } from '@/models/post' import { PostFileMapManager } from '@/services/post-file-map' import fs from 'fs' -import { BlogSettingsService } from '@/services/blog-settings.service' +import { BlogSettingsService } from '@/services/blog-settings' import { accountManager } from '@/auth/account-manager' -import { postCategoryService } from '@/services/post-category.service' +import { postCategoryService } from '@/services/post-category' import { PostCategory } from '@/models/post-category' import { markdownItFactory } from '@cnblogs/markdown-it-presets' diff --git a/src/commands/post-category/delete-selected-categories.ts b/src/commands/post-category/delete-selected-categories.ts index e96494f4..9ea341df 100644 --- a/src/commands/post-category/delete-selected-categories.ts +++ b/src/commands/post-category/delete-selected-categories.ts @@ -1,10 +1,10 @@ import { MessageOptions, ProgressLocation, window } from 'vscode' import { PostCategory } from '@/models/post-category' -import { postCategoryService } from '@/services/post-category.service' +import { postCategoryService } from '@/services/post-category' import { PostCategoriesListTreeItem } from '@/tree-view-providers/models/categories-list-tree-item' import { BaseMultiSelectablePostCategoryTreeViewCmdHandler } from './base-tree-view-cmd-handler' import { refreshPostCategoriesList } from './refresh-post-categories-list' -import { Alert } from '@/services/alert.service' +import { Alert } from '@/services/alert' export class DeletePostCategoriesHandler extends BaseMultiSelectablePostCategoryTreeViewCmdHandler { constructor(input: PostCategoriesListTreeItem) { diff --git a/src/commands/post-category/update-post-category.ts b/src/commands/post-category/update-post-category.ts index 9d655170..18c352fa 100644 --- a/src/commands/post-category/update-post-category.ts +++ b/src/commands/post-category/update-post-category.ts @@ -1,10 +1,10 @@ import fs from 'fs' import { MessageOptions, ProgressLocation, window, Uri, workspace } from 'vscode' import { PostCategory } from '@/models/post-category' -import { postCategoryService } from '@/services/post-category.service' +import { postCategoryService } from '@/services/post-category' import { inputPostCategory } from './input-post-category' import { refreshPostCategoriesList } from './refresh-post-categories-list' -import { Settings } from '@/services/settings.service' +import { Settings } from '@/services/settings' import { BasePostCategoryTreeViewCmdHandler } from './base-tree-view-cmd-handler' class UpdatePostCategoryTreeViewCmdHandler extends BasePostCategoryTreeViewCmdHandler { diff --git a/src/commands/post-list/copy-link.ts b/src/commands/post-list/copy-link.ts index 7b8a7fc0..1afdc0ff 100644 --- a/src/commands/post-list/copy-link.ts +++ b/src/commands/post-list/copy-link.ts @@ -1,8 +1,8 @@ import { TreeViewCmdHandler } from '@/commands/cmd-handler' import { Post } from '@/models/post' -import { Alert } from '@/services/alert.service' +import { Alert } from '@/services/alert' import { PostFileMapManager } from '@/services/post-file-map' -import { PostService } from '@/services/post.service' +import { PostService } from '@/services/post' import { PostTreeItem } from '@/tree-view-providers/models/post-tree-item' import { env, MessageItem, Uri, window } from 'vscode' diff --git a/src/commands/post-list/create-local-draft.ts b/src/commands/post-list/create-local-draft.ts index 5c959555..45f9d875 100644 --- a/src/commands/post-list/create-local-draft.ts +++ b/src/commands/post-list/create-local-draft.ts @@ -1,7 +1,7 @@ import { homedir } from 'os' import path from 'path' import { Uri, window, workspace } from 'vscode' -import { Settings } from '@/services/settings.service' +import { Settings } from '@/services/settings' import { revealActiveFileInExplorer } from '@/utils/reveal-active-file' import { openPostFile } from './open-post-file' diff --git a/src/commands/post-list/modify-post-settings.ts b/src/commands/post-list/modify-post-settings.ts index 1d8d42aa..645e7f8a 100644 --- a/src/commands/post-list/modify-post-settings.ts +++ b/src/commands/post-list/modify-post-settings.ts @@ -1,12 +1,12 @@ import { Uri } from 'vscode' import { Post } from '@/models/post' -import { Alert } from '@/services/alert.service' -import { PostService } from '@/services/post.service' +import { Alert } from '@/services/alert' +import { PostService } from '@/services/post' import { PostFileMapManager } from '@/services/post-file-map' import { revealPostListItem } from '@/services/post-list-view' -import { PostCfgPanel } from '@/services/post-cfg-panel.service' +import { PostCfgPanel } from '@/services/post-cfg-panel' import fs from 'fs' -import { LocalDraft } from '@/services/local-draft.service' +import { LocalDraft } from '@/services/local-draft' import { saveFilePendingChanges } from '@/utils/save-file-pending-changes' import { postDataProvider } from '@/tree-view-providers/post-data-provider' import { PostTreeItem } from '@/tree-view-providers/models/post-tree-item' diff --git a/src/commands/post-list/open-post-file.ts b/src/commands/post-list/open-post-file.ts index a11cac37..1f0e898f 100644 --- a/src/commands/post-list/open-post-file.ts +++ b/src/commands/post-list/open-post-file.ts @@ -1,7 +1,7 @@ import { TextDocumentShowOptions, Uri } from 'vscode' import { execCmd } from '@/utils/cmd' import { Post } from '@/models/post' -import { LocalDraft } from '@/services/local-draft.service' +import { LocalDraft } from '@/services/local-draft' import { PostFileMapManager } from '@/services/post-file-map' export const openPostFile = async (post: LocalDraft | Post | string, options?: TextDocumentShowOptions) => { diff --git a/src/commands/post-list/open-post-in-vscode.ts b/src/commands/post-list/open-post-in-vscode.ts index b367ec2d..b32e82c4 100644 --- a/src/commands/post-list/open-post-in-vscode.ts +++ b/src/commands/post-list/open-post-in-vscode.ts @@ -2,13 +2,13 @@ import fs from 'fs' import path from 'path' import { FileSystemError, MessageOptions, Uri, workspace } from 'vscode' import { Post } from '@/models/post' -import { Alert } from '@/services/alert.service' -import { PostService } from '@/services/post.service' +import { Alert } from '@/services/alert' +import { PostService } from '@/services/post' import { PostFileMapManager } from '@/services/post-file-map' -import { Settings } from '@/services/settings.service' +import { Settings } from '@/services/settings' import { openPostFile } from './open-post-file' -import { PostTitleSanitizer } from '@/services/post-title-sanitizer.service' -import { postCategoryService } from '@/services/post-category.service' +import { PostTitleSanitizer } from '@/services/post-title-sanitizer' +import { postCategoryService } from '@/services/post-category' import sanitizeFileName from 'sanitize-filename' const buildLocalPostFileUri = async (post: Post, includePostId = false): Promise => { diff --git a/src/commands/post-list/rename-post.ts b/src/commands/post-list/rename-post.ts index cb884ff3..38b35dfa 100644 --- a/src/commands/post-list/rename-post.ts +++ b/src/commands/post-list/rename-post.ts @@ -2,12 +2,12 @@ import { escapeRegExp } from 'lodash-es' import path from 'path' import { MessageOptions, ProgressLocation, Uri, window, workspace } from 'vscode' import { Post } from '@/models/post' -import { PostService } from '@/services/post.service' +import { PostService } from '@/services/post' import { PostFileMapManager } from '@/services/post-file-map' import { postDataProvider } from '@/tree-view-providers/post-data-provider' import { revealPostListItem } from '@/services/post-list-view' import { PostTreeItem } from '@/tree-view-providers/models/post-tree-item' -import { Alert } from '@/services/alert.service' +import { Alert } from '@/services/alert' const renameLinkedFile = async (post: Post): Promise => { const filePath = PostFileMapManager.getFilePath(post.id) diff --git a/src/commands/post-list/upload-post.ts b/src/commands/post-list/upload-post.ts index 4e5e35f6..b5741db6 100644 --- a/src/commands/post-list/upload-post.ts +++ b/src/commands/post-list/upload-post.ts @@ -1,8 +1,8 @@ import { Uri, workspace, window, ProgressLocation, MessageOptions } from 'vscode' import { Post } from '@/models/post' -import { LocalDraft } from '@/services/local-draft.service' -import { Alert } from '@/services/alert.service' -import { PostService } from '@/services/post.service' +import { LocalDraft } from '@/services/local-draft' +import { Alert } from '@/services/alert' +import { PostService } from '@/services/post' import { PostFileMapManager } from '@/services/post-file-map' import { postDataProvider } from '@/tree-view-providers/post-data-provider' import { openPostInVscode } from './open-post-in-vscode' @@ -11,10 +11,10 @@ import { searchPostByTitle } from '@/services/search-post-by-title' import * as path from 'path' import { refreshPostList } from './refresh-post-list' import { PostEditDto } from '@/models/post-edit-dto' -import { PostCfgPanel } from '@/services/post-cfg-panel.service' +import { PostCfgPanel } from '@/services/post-cfg-panel' import { saveFilePendingChanges } from '@/utils/save-file-pending-changes' import { extractImages } from '../extract-images' -import { Settings } from '@/services/settings.service' +import { Settings } from '@/services/settings' import { PostTreeItem } from '@/tree-view-providers/models/post-tree-item' const parseFileUri = async (fileUri: Uri | undefined): Promise => { diff --git a/src/commands/pull-post-remote-updates.ts b/src/commands/pull-post-remote-updates.ts index 90a2a0f1..66549030 100644 --- a/src/commands/pull-post-remote-updates.ts +++ b/src/commands/pull-post-remote-updates.ts @@ -3,12 +3,12 @@ import { Post } from '@/models/post' import { PostFileMapManager } from '@/services/post-file-map' import { openPostInVscode } from './post-list/open-post-in-vscode' import fs from 'fs' -import { PostService } from '@/services/post.service' -import { Alert } from '@/services/alert.service' +import { PostService } from '@/services/post' +import { Alert } from '@/services/alert' import path from 'path' import { revealPostListItem } from '@/services/post-list-view' import { PostTreeItem } from '@/tree-view-providers/models/post-tree-item' -import { Settings } from '@/services/settings.service' +import { Settings } from '@/services/settings' const pullPostRemoteUpdates = async (input: Post | PostTreeItem | Uri | undefined | null): Promise => { const ctxs: CmdCtx[] = [] diff --git a/src/commands/reveal-workspace-in-os.ts b/src/commands/reveal-workspace-in-os.ts index a9e696a6..e9957454 100644 --- a/src/commands/reveal-workspace-in-os.ts +++ b/src/commands/reveal-workspace-in-os.ts @@ -1,5 +1,5 @@ import { commands } from 'vscode' import { execCmd } from '@/utils/cmd' -import { Settings } from '@/services/settings.service' +import { Settings } from '@/services/settings' export const revealWorkspaceInOs = () => execCmd('revealFileInOS', Settings.workspaceUri) diff --git a/src/commands/set-workspace.ts b/src/commands/set-workspace.ts index 568f515a..91d5870b 100644 --- a/src/commands/set-workspace.ts +++ b/src/commands/set-workspace.ts @@ -1,6 +1,6 @@ import { window } from 'vscode' -import { Alert } from '@/services/alert.service' -import { Settings } from '@/services/settings.service' +import { Alert } from '@/services/alert' +import { Settings } from '@/services/settings' export const setWorkspace = async () => { const uris = diff --git a/src/commands/show-local-file-to-post-info.ts b/src/commands/show-local-file-to-post-info.ts index 97989b93..04bc5ad4 100644 --- a/src/commands/show-local-file-to-post-info.ts +++ b/src/commands/show-local-file-to-post-info.ts @@ -1,8 +1,8 @@ import path from 'path' import { MessageOptions, Uri, window } from 'vscode' -import { Alert } from '@/services/alert.service' -import { PostService } from '@/services/post.service' -import { postCategoryService } from '@/services/post-category.service' +import { Alert } from '@/services/alert' +import { PostService } from '@/services/post' +import { postCategoryService } from '@/services/post-category' import { PostFileMapManager } from '@/services/post-file-map' import { searchPostByTitle } from '@/services/search-post-by-title' import { viewPostOnline } from './view-post-online' diff --git a/src/commands/upload-image/upload-clipboard-image.ts b/src/commands/upload-image/upload-clipboard-image.ts index 9b2653d7..edf168d2 100644 --- a/src/commands/upload-image/upload-clipboard-image.ts +++ b/src/commands/upload-image/upload-clipboard-image.ts @@ -1,7 +1,7 @@ import fs from 'fs' import { ProgressLocation, Uri, window, workspace } from 'vscode' -import { Alert } from '@/services/alert.service' -import { ImageService } from '@/services/image.service' +import { Alert } from '@/services/alert' +import { ImageService } from '@/services/image' import getClipboardImage from '@/utils/get-clipboard-image' const noImagePath = 'no image' diff --git a/src/commands/upload-image/upload-image-utils.ts b/src/commands/upload-image/upload-image-utils.ts index 1730050a..2fa894d3 100644 --- a/src/commands/upload-image/upload-image-utils.ts +++ b/src/commands/upload-image/upload-image-utils.ts @@ -1,6 +1,6 @@ import { env, MessageOptions, SnippetString, window } from 'vscode' import { formatImageLink } from '@/utils/format-image-link' -import { Alert } from '@/services/alert.service' +import { Alert } from '@/services/alert' /** * 显示上传成功对话框, 支持复制不同格式的图片链接 diff --git a/src/commands/upload-image/upload-image.ts b/src/commands/upload-image/upload-image.ts index 4a15d001..c8fa7d69 100644 --- a/src/commands/upload-image/upload-image.ts +++ b/src/commands/upload-image/upload-image.ts @@ -1,4 +1,4 @@ -import { Alert } from '@/services/alert.service' +import { Alert } from '@/services/alert' import { window } from 'vscode' import { uploadImageFromClipboard } from './upload-clipboard-image' import { insertImageLinkToActiveEditor, showUploadSuccessModel } from './upload-image-utils' diff --git a/src/commands/upload-image/upload-local-disk-image.ts b/src/commands/upload-image/upload-local-disk-image.ts index 1556c621..fb61f273 100644 --- a/src/commands/upload-image/upload-local-disk-image.ts +++ b/src/commands/upload-image/upload-local-disk-image.ts @@ -1,5 +1,5 @@ import { ProgressLocation, window } from 'vscode' -import { ImageService } from '@/services/image.service' +import { ImageService } from '@/services/image' import fs from 'fs' export const uploadLocalDiskImage = async () => { diff --git a/src/commands/view-post-online.ts b/src/commands/view-post-online.ts index a42b667a..3f179acb 100644 --- a/src/commands/view-post-online.ts +++ b/src/commands/view-post-online.ts @@ -1,7 +1,7 @@ import { Uri, window } from 'vscode' import { execCmd } from '@/utils/cmd' import { Post } from '@/models/post' -import { PostService } from '@/services/post.service' +import { PostService } from '@/services/post' import { PostFileMapManager } from '@/services/post-file-map' import { PostTreeItem } from '@/tree-view-providers/models/post-tree-item' diff --git a/src/extension.ts b/src/extension.ts index e919607b..132506d2 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -8,8 +8,9 @@ import { accountManager } from '@/auth/account-manager' import { watchCfgUpdate, watchWorkspaceFileUpdate, watchWorkspaceUpdate } from '@/services/check-workspace' import { extUriHandler } from '@/utils/uri-handler' import { extendMarkdownIt } from '@/markdown/extend-markdownIt' -import { Settings } from '@/services/settings.service' +import { Settings } from '@/services/settings' import { getIngListWebviewProvider } from '@/services/ing-list-webview-provider' +import { setupUi } from '@/services/setup-ui' // this method is called when your extension is activated // your extension is activated the very first time the commands is executed @@ -35,6 +36,8 @@ export function activate(ctx: ExtensionContext) { void accountManager.updateAuthStatus() + setupUi(Settings.cfg) + return { extendMarkdownIt } } diff --git a/src/markdown/extend-markdownIt.ts b/src/markdown/extend-markdownIt.ts index de261d7c..11060c06 100644 --- a/src/markdown/extend-markdownIt.ts +++ b/src/markdown/extend-markdownIt.ts @@ -1,4 +1,4 @@ -import { Settings } from '@/services/settings.service' +import { Settings } from '@/services/settings' import { HighlightCodeLinesPlugin, MultilineBlockquotePlugin } from '@cnblogs/markdown-it-presets' import type { MarkdownIt } from '@cnblogs/markdown-it-presets' diff --git a/src/services/alert.service.ts b/src/services/alert.ts similarity index 100% rename from src/services/alert.service.ts rename to src/services/alert.ts diff --git a/src/services/blog-settings.service.ts b/src/services/blog-settings.ts similarity index 100% rename from src/services/blog-settings.service.ts rename to src/services/blog-settings.ts diff --git a/src/services/check-workspace.ts b/src/services/check-workspace.ts index 364376a5..05485675 100644 --- a/src/services/check-workspace.ts +++ b/src/services/check-workspace.ts @@ -5,7 +5,8 @@ import { refreshPostList } from '@/commands/post-list/refresh-post-list' import { globalCtx } from './global-ctx' import { PostFileMapManager } from './post-file-map' import { execCmd } from '@/utils/cmd' -import { Settings } from './settings.service' +import { Settings } from './settings' +import { setupUi } from '@/services/setup-ui' const diskSymbolRegex = /^(\S{1,5}:)(.*)/ @@ -38,6 +39,8 @@ export const watchCfgUpdate = () => { if (ev.affectsConfiguration(`${Settings.cfgPrefix}.markdown`)) execCmd('markdown.preview.refresh').then(undefined, () => undefined) + + if (ev.affectsConfiguration(`${Settings.cfgPrefix}.ui`)) setupUi(Settings.cfg) }) ) isTargetWorkspace() diff --git a/src/services/code-challenge.service.ts b/src/services/code-challenge.ts similarity index 100% rename from src/services/code-challenge.service.ts rename to src/services/code-challenge.ts diff --git a/src/services/image.service.ts b/src/services/image.ts similarity index 100% rename from src/services/image.service.ts rename to src/services/image.ts diff --git a/src/services/ing.api.ts b/src/services/ing.api.ts index b6b206d4..0c2b8843 100644 --- a/src/services/ing.api.ts +++ b/src/services/ing.api.ts @@ -1,5 +1,5 @@ import { Ing, IngComment, IngPublishModel, IngType } from '@/models/ing' -import { Alert } from '@/services/alert.service' +import { Alert } from '@/services/alert' import { globalCtx } from '@/services/global-ctx' import fetch from '@/utils/fetch-client' import { URLSearchParams } from 'url' @@ -14,7 +14,7 @@ export namespace IngApi { }).catch(reason => void Alert.warn(JSON.stringify(reason))) if (!res || !res.ok) - Alert.err(`闪存发布失败, ${res?.statusText ?? ''} ${JSON.stringify((await res?.text()) ?? '')}`) + void Alert.err(`闪存发布失败, ${res?.statusText ?? ''} ${JSON.stringify((await res?.text()) ?? '')}`) return res != null && res.ok } @@ -32,7 +32,7 @@ export namespace IngApi { ).catch(e => void Alert.warn(JSON.stringify(e))) if (!res || !res.ok) { - Alert.err(`获取闪存列表失败, ${res?.statusText ?? ''} ${JSON.stringify((await res?.text()) ?? '')}`) + void Alert.err(`获取闪存列表失败, ${res?.statusText ?? ''} ${JSON.stringify((await res?.text()) ?? '')}`) return [] } @@ -40,9 +40,9 @@ export namespace IngApi { try { if (isArray(arr) && arr.every(isObject)) return arr.map(Ing.parse) - Alert.err('获取闪存列表失败, 无法读取响应') + void Alert.err('获取闪存列表失败, 无法读取响应') } catch (e) { - Alert.err(JSON.stringify(e)) + void Alert.err(JSON.stringify(e)) } return [] diff --git a/src/services/local-draft.service.ts b/src/services/local-draft.ts similarity index 100% rename from src/services/local-draft.service.ts rename to src/services/local-draft.ts diff --git a/src/services/mkd-img-extractor.service.ts b/src/services/mkd-img-extractor.ts similarity index 99% rename from src/services/mkd-img-extractor.service.ts rename to src/services/mkd-img-extractor.ts index 05a2b5a9..035725d1 100644 --- a/src/services/mkd-img-extractor.service.ts +++ b/src/services/mkd-img-extractor.ts @@ -2,7 +2,7 @@ import path from 'path' import { isString } from 'lodash-es' import fs from 'fs' import { Uri, workspace } from 'vscode' -import { ImageService } from './image.service' +import { ImageService } from './image' import { isErrorResponse } from '@/models/error-response' import { promisify } from 'util' import { Readable } from 'stream' diff --git a/src/services/post-category.service.ts b/src/services/post-category.ts similarity index 100% rename from src/services/post-category.service.ts rename to src/services/post-category.ts diff --git a/src/services/post-cfg-panel.service.ts b/src/services/post-cfg-panel.ts similarity index 97% rename from src/services/post-cfg-panel.service.ts rename to src/services/post-cfg-panel.ts index f7be8e47..b6b014ab 100644 --- a/src/services/post-cfg-panel.service.ts +++ b/src/services/post-cfg-panel.ts @@ -2,10 +2,10 @@ import { cloneDeep } from 'lodash-es' import vscode, { Uri } from 'vscode' import { Post } from '@/models/post' import { globalCtx } from './global-ctx' -import { postCategoryService } from './post-category.service' -import { siteCategoryService } from './site-category.service' -import { PostTagService } from './post-tag.service' -import { PostService } from './post.service' +import { postCategoryService } from './post-category' +import { siteCategoryService } from './site-category' +import { PostTagService } from './post-tag' +import { PostService } from './post' import { isErrorResponse } from '@/models/error-response' import { webviewMessage } from '@/models/webview-msg' import { WebviewCommonCmd, WebviewCmd } from 'src/models/webview-cmd' diff --git a/src/services/post-tag.service.ts b/src/services/post-tag.ts similarity index 100% rename from src/services/post-tag.service.ts rename to src/services/post-tag.ts diff --git a/src/services/post-title-sanitizer.service.ts b/src/services/post-title-sanitizer.ts similarity index 100% rename from src/services/post-title-sanitizer.service.ts rename to src/services/post-title-sanitizer.ts diff --git a/src/services/post.service.ts b/src/services/post.ts similarity index 99% rename from src/services/post.service.ts rename to src/services/post.ts index 357158d4..33511908 100644 --- a/src/services/post.service.ts +++ b/src/services/post.ts @@ -7,7 +7,7 @@ import { PostEditDto } from '@/models/post-edit-dto' import { PostUpdatedResponse } from '@/models/post-updated-response' import { throwIfNotOkGotResponse } from '@/utils/throw-if-not-ok-response' import { IErrorResponse } from '@/models/error-response' -import { Alert } from './alert.service' +import { Alert } from './alert' import { PostFileMapManager } from './post-file-map' import { ZzkSearchResult } from '@/models/zzk-search-result' import got from '@/utils/http-client' diff --git a/src/services/search-post-by-title.ts b/src/services/search-post-by-title.ts index 8629daec..6175ffbe 100644 --- a/src/services/search-post-by-title.ts +++ b/src/services/search-post-by-title.ts @@ -1,6 +1,6 @@ import { QuickPickItem, window } from 'vscode' import { Post } from '@/models/post' -import { PostService } from './post.service' +import { PostService } from './post' class PostPickItem implements QuickPickItem { label: string diff --git a/src/services/settings.service.test.ts b/src/services/settings.service.test.ts deleted file mode 100644 index ebf138ac..00000000 --- a/src/services/settings.service.test.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { Settings } from '@/services/settings.service' -import { workspace, WorkspaceConfiguration } from 'vscode' - -describe('Settings', () => { - let mockSetWorkspaceUri: jest.Mock - let mockedWorkspace: jest.MockedObjectDeep - - beforeEach(() => { - mockedWorkspace = jest.mocked(workspace) - - mockSetWorkspaceUri = jest.fn().mockReturnValue(Promise.resolve()) - Settings.setWorkspaceUri = mockSetWorkspaceUri - }) - - it('should adapt old configured workspace uri', async () => { - // eslint-disable-next-line @typescript-eslint/no-unsafe-argument - const mockedConfiguration = { - get: jest.fn().mockReturnValue('path/fake'), - update: jest.fn().mockReturnValue(Promise.resolve()), - } as Partial - // eslint-disable-next-line @typescript-eslint/no-unsafe-argument - mockedWorkspace.getConfiguration.mockReturnValue(mockedConfiguration as any) - - console.log(Settings.workspaceUri) - // eslint-disable-next-line @typescript-eslint/unbound-method - await new Promise(process.nextTick) - - // old workspace configuration should be removed - expect(mockedConfiguration.update).toHaveBeenCalled() - // old workspace configuration should be saved to new place - expect(mockSetWorkspaceUri).toHaveBeenCalled() - - expect(mockedConfiguration.get).toHaveBeenCalled() - }) -}) diff --git a/src/services/settings.service.ts b/src/services/settings.ts similarity index 98% rename from src/services/settings.service.ts rename to src/services/settings.ts index de9b1078..6ce3c903 100644 --- a/src/services/settings.service.ts +++ b/src/services/settings.ts @@ -1,7 +1,7 @@ import os, { homedir } from 'os' import fs from 'fs' import { ConfigurationTarget, Uri, workspace } from 'vscode' -import { ImageSrc } from './mkd-img-extractor.service' +import { ImageSrc } from './mkd-img-extractor' import { isNumber } from 'lodash-es' import { untildify } from '@/utils/untildify' diff --git a/src/services/setup-ui.ts b/src/services/setup-ui.ts new file mode 100644 index 00000000..3932f7b2 --- /dev/null +++ b/src/services/setup-ui.ts @@ -0,0 +1,90 @@ +import { WorkspaceConfiguration as WorkspaceCfg } from 'vscode' +import { extTreeViews } from '@/tree-view-providers/tree-view-registration' +import { getIngListWebviewProvider } from '@/services/ing-list-webview-provider' + +/* +"cnblogsClient.ui.textIngStar": { + "order": 15, + "type": "boolean", + "scope": "application", + "default": false, + "markdownDescription": "符号化闪存表情" +}, +"cnblogsClient.ui.disableIngUserAvatar": { + "order": 16, + "type": "boolean", + "scope": "application", + "default": false, + "markdownDescription": "禁用闪存头像" +}, +"cnblogsClient.ui.treeViewTitleStyle": { + "order": 17, + "scope": "application", + "default": "normal", + "markdownDescription": "侧栏标题风格", + "enum": [ + "normal", + "short", + "short-english" + ], + "enumItemLabels": [ + "正常", + "简洁", + "英文简洁" + ] +}, +"cnblogsClient.ui.fakeExtIcon": { + "order": 18, + "type": "boolean", + "scope": "application", + "default": false, + "markdownDescription": "伪装扩展图标" +} +* */ + +export function setupUi(cfg: WorkspaceCfg) { + void getIngListWebviewProvider().refreshingList() + applyTreeViewTitleStyle(cfg) +} + +export const isEnableTextIngStar = (cfg: WorkspaceCfg) => cfg.get('ui.textIngStar') + +export const isDisableIngUserAvatar = (cfg: WorkspaceCfg) => cfg.get('ui.disableIngUserAvatar') + +export function applyTreeViewTitleStyle(cfg: WorkspaceCfg) { + type Enum = 'normal' | 'short' + const option = cfg.get('ui.treeViewTitleStyle') + if (option === 'normal') { + extTreeViews.postList.title = '随笔列表' + extTreeViews.anotherPostList.title = '随笔列表' + extTreeViews.account.title = '账户信息' + extTreeViews.postCategoriesList.title = '分类列表' + extTreeViews.blogExport.title = '博客备份' + extTreeViews.navi.title = '博客园导航' + return + } + if (option === 'short') { + extTreeViews.postList.title = '随笔' + extTreeViews.anotherPostList.title = '随笔' + extTreeViews.account.title = '账户' + extTreeViews.postCategoriesList.title = '分类' + extTreeViews.blogExport.title = '备份' + extTreeViews.navi.title = '导航' + return + } +} + +/* +// TODO: Wait for VSC API support +"cnblogsClient.ui.fakeExtIcon": { + "order": 18, + "type": "boolean", + "scope": "application", + "default": false, + "markdownDescription": "伪装扩展图标" +} +export function applyFakeExtIcon(cfg: WorkspaceCfg) { + const isEnable = cfg.get('ui.fakeExtIcon') + console.log(isEnable) +} +*/ diff --git a/src/services/site-category.service.ts b/src/services/site-category.ts similarity index 100% rename from src/services/site-category.service.ts rename to src/services/site-category.ts diff --git a/src/test/suite/extension.test.ts b/src/test/suite/extension.test.ts index 2dfc7e49..49ff70cd 100644 --- a/src/test/suite/extension.test.ts +++ b/src/test/suite/extension.test.ts @@ -1,4 +1,4 @@ -import { Alert } from '@/services/alert.service' +import { Alert } from '@/services/alert' import assert from 'assert' // You can import and use all API from the 'vscode' module diff --git a/src/tree-view-providers/account-view-data-provider.ts b/src/tree-view-providers/account-view-data-provider.ts index 661341b7..7ddc2c01 100644 --- a/src/tree-view-providers/account-view-data-provider.ts +++ b/src/tree-view-providers/account-view-data-provider.ts @@ -29,41 +29,33 @@ export class AccountViewDataProvider implements TreeDataProvider { { label: u.name, tooltip: '用户名', iconPath: new ThemeIcon('account') }, { label: '账户设置', - tooltip: '账户设置', command: { title: '打开账户设置', command: 'vscode-cnb.open-my-account-settings', - tooltip: '浏览器中打开我的账户设置', }, iconPath: new ThemeIcon('gear'), }, { label: '博客后台', - tooltip: '博客后台', command: { title: '打开博客后台', command: 'vscode-cnb.open-my-blog-console', - tooltip: '浏览器中打开我的博客后台', }, iconPath: new ThemeIcon('console'), }, { label: '我的博客', - tooltip: '点击在浏览器中打开我的主页', command: { title: '打开我的博客', command: 'vscode-cnb.open-my-blog', - tooltip: '浏览器中打开我的博客', }, iconPath: new ThemeIcon('window'), }, { label: '我的主页', - tooltip: '点击在浏览器中打开我的主页', command: { title: '打开我的主页', command: 'vscode-cnb.open-my-home-page', - tooltip: '浏览器中打开我的博客', }, iconPath: new ThemeIcon('home'), }, diff --git a/src/tree-view-providers/blog-export-provider.ts b/src/tree-view-providers/blog-export-provider.ts index 4ce1f287..a928b09a 100644 --- a/src/tree-view-providers/blog-export-provider.ts +++ b/src/tree-view-providers/blog-export-provider.ts @@ -12,7 +12,7 @@ import { ExportPostEntryTreeItem, } from './models/blog-export/downloaded' import { Event, EventEmitter, ProviderResult, TreeDataProvider, TreeItem } from 'vscode' -import { Alert } from '@/services/alert.service' +import { Alert } from '@/services/alert' import { BlogExportRecord } from '@/models/blog-export' export class BlogExportProvider implements TreeDataProvider { diff --git a/src/tree-view-providers/converters.ts b/src/tree-view-providers/converters.ts index 57073f44..197ec4ec 100644 --- a/src/tree-view-providers/converters.ts +++ b/src/tree-view-providers/converters.ts @@ -5,7 +5,7 @@ import { Post } from '@/models/post' import { PostCategory } from '@/models/post-category' import { globalCtx } from '@/services/global-ctx' import { PostFileMapManager } from '@/services/post-file-map' -import { Settings } from '@/services/settings.service' +import { Settings } from '@/services/settings' import { BaseTreeItemSource } from './models/base-tree-item-source' const contextValues = { diff --git a/src/tree-view-providers/models/blog-export/post.ts b/src/tree-view-providers/models/blog-export/post.ts index 720b26bb..300bc063 100644 --- a/src/tree-view-providers/models/blog-export/post.ts +++ b/src/tree-view-providers/models/blog-export/post.ts @@ -1,6 +1,6 @@ import { ViewPostCmdHandler } from '@/commands/blog-export/view-post' import type { ExportPost } from '@/models/blog-export/export-post' -import { Settings } from '@/services/settings.service' +import { Settings } from '@/services/settings' import { BaseTreeItemSource } from '@/tree-view-providers/models/base-tree-item-source' import { ExportPostEntryTreeItem } from '@/tree-view-providers/models/blog-export' import { ThemeIcon, TreeItem, TreeItemCollapsibleState, Uri } from 'vscode' diff --git a/src/tree-view-providers/models/post-metadata.ts b/src/tree-view-providers/models/post-metadata.ts index bcfd06b6..1493ea68 100644 --- a/src/tree-view-providers/models/post-metadata.ts +++ b/src/tree-view-providers/models/post-metadata.ts @@ -6,8 +6,8 @@ import zhCN from 'date-fns/locale/zh-CN' import { TreeItem, TreeItemCollapsibleState, ThemeIcon } from 'vscode' import { AccessPermission, Post, formatAccessPermission } from '@/models/post' import { PostEditDto } from '@/models/post-edit-dto' -import { postCategoryService } from '@/services/post-category.service' -import { PostService } from '@/services/post.service' +import { postCategoryService } from '@/services/post-category' +import { PostService } from '@/services/post' import { BaseEntryTreeItem } from './base-entry-tree-item' import { BaseTreeItemSource } from './base-tree-item-source' import { PostTreeItem } from './post-tree-item' diff --git a/src/tree-view-providers/post-categories-tree-data-provider.ts b/src/tree-view-providers/post-categories-tree-data-provider.ts index 33e1aab5..4558979d 100644 --- a/src/tree-view-providers/post-categories-tree-data-provider.ts +++ b/src/tree-view-providers/post-categories-tree-data-provider.ts @@ -2,14 +2,14 @@ import { flattenDepth, take } from 'lodash-es' import { EventEmitter, ProviderResult, TreeDataProvider, TreeItem } from 'vscode' import { PostCategories } from '@/models/post-category' import { globalCtx } from '@/services/global-ctx' -import { postCategoryService } from '@/services/post-category.service' -import { PostService } from '@/services/post.service' +import { postCategoryService } from '@/services/post-category' +import { PostService } from '@/services/post' import { toTreeItem } from './converters' import { PostCategoriesListTreeItem } from './models/categories-list-tree-item' import { PostCategoryTreeItem } from './models/post-category-tree-item' import { PostEntryMetadata, PostMetadata, RootPostMetadataType } from './models/post-metadata' import { PostTreeItem } from './models/post-tree-item' -import { Alert } from '@/services/alert.service' +import { Alert } from '@/services/alert' import { execCmd } from '@/utils/cmd' export class PostCategoriesTreeDataProvider implements TreeDataProvider { diff --git a/src/tree-view-providers/post-data-provider.ts b/src/tree-view-providers/post-data-provider.ts index 7f1cc2e6..ee378927 100644 --- a/src/tree-view-providers/post-data-provider.ts +++ b/src/tree-view-providers/post-data-provider.ts @@ -2,9 +2,9 @@ import { EventEmitter, ProviderResult, TreeDataProvider, TreeItem } from 'vscode import { refreshPostList } from '@/commands/post-list/refresh-post-list' import { Post } from '@/models/post' import { PageModel } from '@/models/page-model' -import { Alert } from '@/services/alert.service' -import { PostService } from '@/services/post.service' -import { Settings } from '@/services/settings.service' +import { Alert } from '@/services/alert' +import { PostService } from '@/services/post' +import { Settings } from '@/services/settings' import { toTreeItem } from './converters' import { PostEntryMetadata, PostMetadata } from './models/post-metadata' import { PostSearchResultEntry } from './models/post-search-result-entry' diff --git a/src/utils/chromium-path-provider.ts b/src/utils/chromium-path-provider.ts index 238ca3b3..516e5ea6 100644 --- a/src/utils/chromium-path-provider.ts +++ b/src/utils/chromium-path-provider.ts @@ -2,7 +2,7 @@ import { window, ProgressLocation } from 'vscode' import fs from 'fs' import os from 'os' import path from 'path' -import { Alert } from '@/services/alert.service' +import { Alert } from '@/services/alert' // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-var-requires const download: (arg: Record) => Promise = require('download-chromium') diff --git a/src/utils/get-clipboard-image.ts b/src/utils/get-clipboard-image.ts index 49d428bd..185cf668 100644 --- a/src/utils/get-clipboard-image.ts +++ b/src/utils/get-clipboard-image.ts @@ -6,7 +6,7 @@ import fs from 'fs' import os from 'os' import isWsl from 'is-wsl' import { globalCtx } from '@/services/global-ctx' -import { Alert } from '@/services/alert.service' +import { Alert } from '@/services/alert' import { IClipboardImage } from '@/models/clipboard-image' import format from 'date-fns/format' diff --git a/src/utils/input-post-settings.ts b/src/utils/input-post-settings.ts index 296b1af7..4531e672 100644 --- a/src/utils/input-post-settings.ts +++ b/src/utils/input-post-settings.ts @@ -1,9 +1,9 @@ import { QuickPickItem } from 'vscode' import { AccessPermission, Post } from '@/models/post' import { PostCategories, PostCategory } from '@/models/post-category' -import { Alert } from '@/services/alert.service' +import { Alert } from '@/services/alert' import { InputFlowAction, InputStep, MultiStepInput, QuickPickParameters } from '@/services/multi-step-input' -import { postCategoryService } from '@/services/post-category.service' +import { postCategoryService } from '@/services/post-category' class CategoryPickItem implements QuickPickItem { label: string From 921a753e618c62b6df697b4b54cf39aa72a228ee Mon Sep 17 00:00:00 2001 From: Thaumy Date: Tue, 25 Jul 2023 12:38:46 +0800 Subject: [PATCH 024/157] docs: update --- CHANGELOG.md | 3 -- LICENSE.txt => LICENSE | 0 README.md | 90 +++++++++++++++++++++--------------------- 3 files changed, 45 insertions(+), 48 deletions(-) delete mode 100644 CHANGELOG.md rename LICENSE.txt => LICENSE (100%) diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index 68def039..00000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,3 +0,0 @@ -# Change Log - -see [Github release](https://github.com/cnblogs/vscode-cnb/releases) diff --git a/LICENSE.txt b/LICENSE similarity index 100% rename from LICENSE.txt rename to LICENSE diff --git a/README.md b/README.md index 9ec5025c..ce088101 100644 --- a/README.md +++ b/README.md @@ -7,10 +7,9 @@ **目录** -- [简介](#简介) -- [主要功能](#主要功能) - - [登录 / 授权](#登录--授权) - - [将本地 markdown 文件发布到博客园](#将本地-markdown-文件发布到博客园) +- [功能概览](#功能概览) + - [登录 / 授权](#登录-%2F-授权) + - [将本地 Markdown 文件发布到博客园](#将本地-markdown-文件发布到博客园) - [博客园博文列表](#博客园博文列表) - [搜索博文](#搜索博文) - [将本地文件关联到博客园博文](#将本地文件关联到博客园博文) @@ -21,17 +20,14 @@ - [提取图片](#提取图片) - [博文设置面板](#博文设置面板) - [闪存](#闪存) - - [markdown语法扩展](#markdown语法扩展) + - [Markdown 语法扩展](#markdown-语法扩展) - [复制博文链接](#复制博文链接) - [博客备份](#博客备份) -- [vscode 版本要求](#vscode-版本要求) +- [VSCode 版本要求](#vscode-版本要求) - [插件设置](#插件设置) +- [问题反馈](#问题反馈) -## 简介 - -博客园 vscode 插件,主要功能是将本地 markdown 文件对应到博文园中博文,从而让 vscode 用户可以一键发布 markdown 博文到博客园。 - -## 主要功能 +## 功能概览 ### 登录 / 授权 @@ -39,7 +35,7 @@ -### 将本地 markdown 文件发布到博客园 +### 将本地 Markdown 文件发布到博客园 @@ -47,7 +43,7 @@ 若本地文件已经关联到一篇博客园博文,那么会直接更新这篇博文。 -也通过 vscode 的 `Command Palette`(唤起 `Command Palette` 快捷键,windows:`ctrl+shift+p`,macos:`command+shift+p`)调用 `Cnblogs: 上传到博客园`命令,将当前正在编辑的 markdown 文件上传到博客园上 +也通过 VSCode 的 `Command Palette`(唤起 `Command Palette` 快捷键,windows:`ctrl+shift+p`,macos:`command+shift+p`)调用 `Cnblogs: 上传到博客园`命令,将当前正在编辑的 Markdown 文件上传到博客园上 @@ -59,11 +55,11 @@ ### 搜索博文 -在博文列表的工具栏中, 包含一个搜索的图标, 点击这个图标可以触发搜索功能, 点击后会先要求输入关键词, 输入完成后按回车确认, 搜索结果将在列表中进行展示 +在博文列表的工具栏中,包含一个搜索的图标,点击这个图标可以触发搜索功能,点击后会先要求输入关键词,输入完成后按回车确认,搜索结果将在列表中进行展示 -列表中的 `搜索结果` 那一项的工具栏包含两个可以使用的命令, 分别是 `刷新搜索结果` 和 `清除搜索结果`; 也可以通过右键上下文菜单调用这两个命令 +列表中的 `搜索结果` 那一项的工具栏包含两个可以使用的命令,分别是 `刷新搜索结果` 和 `清除搜索结果`; 也可以通过右键上下文菜单调用这两个命令 @@ -83,15 +79,15 @@ -- 编辑器上下文菜单中的`拉取博文`(仅针对 markdown 文件) +- 编辑器上下文菜单中的`拉取博文`(仅针对 Markdown 文件) -- 文件浏览器上下文菜单中的`拉取博文`(仅针对 markdown 文件) +- 文件浏览器上下文菜单中的`拉取博文`(仅针对 Markdown 文件) -- vscode 命令面板 `Cnblogs: 拉取博文`,此时会尝试去寻找当前正在编辑的文件对其进行更新 +- VSCode 命令面板 `Cnblogs: 拉取博文`,此时会尝试去寻找当前正在编辑的文件对其进行更新 @@ -99,7 +95,7 @@ ### 图片上传 -当 vscode 处于配置好的 `vscode-cnb` 工作空间时,可以通过快捷键,上下文菜单,编辑器工具栏等方式上传本地或剪贴板中的图片到博客园 +当 VSCode 处于配置好的 `vscode-cnb` 工作空间时,可以通过快捷键,上下文菜单,编辑器工具栏等方式上传本地或剪贴板中的图片到博客园 @@ -115,17 +111,17 @@ -也可以在 vscode 的设置中手动配置 **Chromium 或其他基于 Chromium 的浏览器的可执行文件路径**,这个路径针对 windows 和 macos 是不同的两个配置,可以根据自己使用的系统进行配置 +也可以在 VSCode 的设置中手动配置 **Chromium 或其他基于 Chromium 的浏览器的可执行文件路径**,这个路径针对 windows 和 macos 是不同的两个配置,可以根据自己使用的系统进行配置 -列表中选择要导出的博文时, 支持多选 +列表中选择要导出的博文时,支持多选 ### 提取图片 -你可能会在markdown文件中使用本地的相对路径的图片, 将这样的markdown发布到博客园会导致图片无法正常展示, 为此我们提供了 `提取图片` 功能, 你可以通过编辑器的上下文菜单调用此功能 +您可能会在 Markdown 文件中使用本地的相对路径的图片,将这样的 Markdown 发布到博客园会导致图片无法正常展示,为此我们提供了 `提取图片` 功能,您可以通过编辑器的上下文菜单调用此功能 ![image](https://img2022.cnblogs.com/blog/1596066/202209/1596066-20220917215536822-836105648.png) @@ -133,19 +129,19 @@ ![image](https://img2022.cnblogs.com/blog/1596066/202209/1596066-20220917215650930-372126612.png) -此功能除了可以提取本地图片, 也可以提取其他承载在第三方图床中的图片 +此功能除了可以提取本地图片,也可以提取其他承载在第三方图床中的图片 ![image](https://img2022.cnblogs.com/blog/1596066/202209/1596066-20220917215802986-44248462.png) -此功能会上传图片到博客园然后替换源markdown文件中的图片链接 +此功能会上传图片到博客园然后替换源 Markdown 文件中的图片链接 ### 博文设置面板 -首次发布本地 markdown 文件到博客园时,会打开博文设置面板允许编辑博文相关的设置 +首次发布本地 Markdown 文件到博客园时,会打开博文设置面板允许编辑博文相关的设置 -同时,也可以在博客园随笔列表视图,文件列表视图和 markdown 编辑器中上下文菜单中可以通过**博文设置**命令打开博文设置面板 +同时,也可以在博客园随笔列表视图,文件列表视图和 Markdown 编辑器中上下文菜单中可以通过**博文设置**命令打开博文设置面板 @@ -153,30 +149,32 @@ -本插件支持对闪存进行**查看**, **发布**, **评论**等操作, 在侧边栏博客园视图中, 展开 `闪存` 即可; 点击闪存标题栏中的加号图标可以发布新闪存; +本插件支持对闪存进行**查看**,**发布**,**评论**等操作,在侧边栏博客园视图中,展开 `闪存` 即可; 点击闪存标题栏中的加号图标可以发布新闪存; -也可以在编辑器中选中一段文本或代码, 然后鼠标右键唤起上下文菜单, 可以将选中的内容发到闪存; +也可以在编辑器中选中一段文本或代码,然后鼠标右键唤起上下文菜单,可以将选中的内容发到闪存; -> PS: 上下文菜单的"将选中内容发到闪存"功能默认处于禁用, 您可以在vscode设置中启用此功能 +> PS: 上下文菜单的"将选中内容发到闪存"功能默认处于禁用,您可以在 VSCode 设置中启用此功能 > demo-settings-enable-publish-selection-to-ing -编辑完内容后回车会弹出确认框, 此时如果需要添加标签或者修改访问权限, 可以使用确认对话框中的 `编辑访问权限` `编辑标签` 或 `编辑内容` 选项 +编辑完内容后回车会弹出确认框,此时如果需要添加标签或者修改访问权限,可以使用确认对话框中的 `编辑访问权限` `编辑标签` 或 `编辑内容` 选项 -也可以通过VSCode命令面板(`ctrl/cmd + p`唤起命令面板)调用发闪存命令 +也可以通过 VSCode 命令面板(`ctrl/cmd + p`唤起命令面板)调用发闪存命令 -通过本插件发布的闪存, 在尾部会显示一个vscode图标 +通过本插件发布的闪存,在尾部会显示一个 VSCode 图标 + +此外,插件设置中提供了用于调整闪存用户头像和星星样式的选项,或许能进一步改善您的摸鱼体验 -### markdown语法扩展 +### Markdown 语法扩展 -本插件可以让vscode中的markdown预览支持博客园中扩展的markdown语法, 您可以通过设置来控制是否要启用此功能 +本插件可以让 VSCode 中的 Markdown 预览支持博客园中扩展的 Markdown 语法,您可以通过设置来控制是否要启用此功能 @@ -186,13 +184,13 @@ ### 复制博文链接 -文件浏览器和随笔列表中的上下文菜单里有`复制博文链接`选项, 点击后可以复制不同格式的博文链接 +文件浏览器和随笔列表中的上下文菜单里有`复制博文链接`选项,点击后可以复制不同格式的博文链接 https://img2023.cnblogs.com/blog/35695/202301/35695-20230130155516202-1979736560.png 默认的的链接形如: `https://www.cnblogs.com/cmt/p/47365.html` -markdown格式链接形如: `[博文标题](https://www.cnblogs.com/cmt/p/47365.html)` + Markdown 格式链接形如: `[博文标题](https://www.cnblogs.com/cmt/p/47365.html)` 也可以选择仅复制博文的Id ## 博客备份 @@ -201,32 +199,34 @@ markdown格式链接形如: `[博文标题](https://www.cnblogs.com/cmt/p/47365. > **博客备份说明** > -> 博客备份会将您的博客中的随笔, 文章等数据导出到一个 sqlite 的数据库文件中, 此操作为耗时的任务式操作, 完成后您可以在 [博客后台](https://i.cnblogs.com/posts/export) 或 [本插件](https://marketplace.visualstudio.com/items?itemName=cnblogs.vscode-cnb) 中下载备份文件(后缀名为 `.db.zip`) +> 博客备份会将您的博客中的随笔,文章等数据导出到一个 SqLite 的数据库文件中,此操作为耗时的任务式操作,完成后您可以在 [博客后台](https://i.cnblogs.com/posts/export) 或 [本插件](https://marketplace.visualstudio.com/items?itemName=cnblogs.vscode-cnb) 中下载备份文件(后缀名为 `.db.zip`) -创建博客备份后, 在博客备份记录列表中, 您可以看到博客备份记录的状态会实时更新 +创建博客备份后,在博客备份记录列表中,您可以看到博客备份记录的状态会实时更新 -您可以通过下载按钮将博客备份下载到本地; 下载过程中您可以看到实时的下载进度; 下载完成后, 插件会帮您自动进行解压(解压完成后会自动删除源压缩文件) +您可以通过下载按钮将博客备份下载到本地; 下载过程中您可以看到实时的下载进度; 下载完成后,插件会帮您自动进行解压(解压完成后会自动删除源压缩文件) 您可以在插件中浏览您博客备份中的博文 -您可以删除博客列表中的备份记录, 已下载备份; 删除前, 会弹出确认对话框, 你可以根据提示确认删除操作或取消(友情提示: 请谨慎删除数据) +您可以删除博客列表中的备份记录,已下载备份; 删除前,会弹出确认对话框,您可以根据提示确认删除操作或取消(友情提示: 请谨慎删除数据) -## vscode 版本要求 +## VSCode 版本要求 -\>=1.70.0 - -> 自 v1.7 开始, Visual Studio Code 的最低版本要求调整为 1.70.0 +`1.80.0` 或更高 ## 插件设置 -* `workspace`:`vscode-cnb` 需要用到的一个工作空间,`vscode-cnb` 只有检测到 vscode 处于此目录下才会生效,默认会使用 `~/Documents/Cnblogs` 作为工作空间 +* `workspace`:`vscode-cnb` 需要用到的一个工作空间,`vscode-cnb` 只有检测到 VSCode 处于此目录下才会生效,默认会使用 `~/Documents/Cnblogs` 作为工作空间 + +## 问题反馈 + +您可以将任何问题或建议反馈至 [GitHub Issues](https://github.com/cnblogs/vscode-cnb/issues),我们会尽力解决。这对改善插件体验至关重要。 From 08dfc739de7ea0f2f99254eaf6ef2c3b3d1631be Mon Sep 17 00:00:00 2001 From: Thaumy Date: Tue, 25 Jul 2023 15:14:15 +0800 Subject: [PATCH 025/157] refactor: simplify code --- package.json | 46 ++++----- src/auth/account-info.ts | 2 +- src/auth/account-manager.ts | 18 ++-- src/auth/auth-provider.ts | 10 +- src/{commands => cmd}/blog-export/create.ts | 8 +- src/{commands => cmd}/blog-export/delete.ts | 14 +-- src/{commands => cmd}/blog-export/download.ts | 20 ++-- src/{commands => cmd}/blog-export/edit.ts | 12 +-- src/{commands => cmd}/blog-export/index.ts | 16 +-- .../blog-export/open-local.ts | 8 +- src/{commands => cmd}/blog-export/refresh.ts | 8 +- .../blog-export/view-post.ts | 10 +- src/{commands => cmd}/cmd-handler.ts | 0 .../extract-images.ts => cmd/extract-img.ts} | 4 +- src/{commands => cmd}/ing/comment-ing.ts | 6 +- src/cmd/ing/ing-list-cmd-register.ts | 19 ++++ .../ing/ing-list-go-next-page.ts} | 6 +- src/{commands => cmd}/ing/publish-ing.ts | 16 +-- src/{commands => cmd}/ing/refresh-ing-list.ts | 4 +- src/cmd/ing/select-ing-type.ts | 42 ++++++++ src/{commands => cmd}/login.ts | 0 src/{commands => cmd}/open/open-cnb-home.ts | 2 +- src/{commands => cmd}/open/open-cnb-ing.ts | 2 +- src/{commands => cmd}/open/open-cnb-news.ts | 2 +- src/{commands => cmd}/open/open-cnb-q.ts | 2 +- src/cmd/open/open-ing-site.ts | 5 + .../open/open-my-account-settings.ts | 2 +- .../open/open-my-blog-console.ts | 2 +- src/{commands => cmd}/open/open-my-blog.ts | 2 +- .../open/open-my-home-page.ts | 2 +- .../open/open-post-in-blog-admin.ts | 8 +- src/{commands => cmd}/open/open-workspace.ts | 6 +- src/{commands => cmd}/pdf/export-pdf.ts | 20 ++-- .../pdf/post-pdf-template-builder.ts | 10 +- .../base-tree-view-cmd-handler.ts | 8 +- .../delete-selected-category.ts} | 15 ++- .../post-category/input-post-category.ts | 4 +- .../post-category/new-post-category.ts | 10 +- .../refresh-post-category-list.ts | 5 + .../post-category/update-post-category.ts | 10 +- src/{commands => cmd}/post-list/copy-link.ts | 12 +-- .../post-list/create-local-draft.ts | 4 +- .../delete-post-to-local-file-map.ts | 14 +-- .../post-list/delete-post.ts | 18 ++-- .../post-list/modify-post-settings.ts | 24 ++--- .../post-list/open-post-file.ts | 8 +- .../post-list/open-post-in-vscode.ts | 14 +-- .../post-list/refresh-post-list.ts | 16 +-- .../post-list/rename-post.ts | 14 +-- src/{commands => cmd}/post-list/search.ts | 2 +- .../post-list/upload-post.ts | 26 ++--- .../pull-post-remote-updates.ts | 18 ++-- .../reveal-local-post-file-in-os.ts | 6 +- .../reveal-workspace-in-os.ts | 4 +- src/{commands => cmd}/set-workspace.ts | 4 +- .../show-local-file-to-post-info.ts | 10 +- .../upload-img/upload-clipboard-img.ts} | 10 +- .../upload-img/upload-fs-img.ts} | 6 +- .../upload-img/upload-img-util.ts} | 4 +- .../upload-img/upload-img.ts} | 11 +-- src/{commands => cmd}/view-post-online.ts | 10 +- src/commands/ing/ing-list-cmd-register.ts | 19 ---- src/commands/ing/open-ing-in-browser.ts | 10 -- src/commands/ing/select-ing-type.ts | 45 --------- .../refresh-post-categories-list.ts | 5 - src/extension.ts | 35 +++---- .../chromium-path-provider.ts | 8 +- src/{utils => infra}/cmd.ts | 0 .../convert/ing-star-to-text.ts} | 0 .../convert/object-keys-to-camel-case.ts} | 2 +- src/{utils => infra}/fetch-client.ts | 2 +- .../fmt-img-link.ts} | 0 .../get-clipboard-img.ts} | 6 +- src/{utils => infra}/http-client.ts | 2 +- src/{utils => infra}/input-post-settings.ts | 10 +- src/infra/response-err.ts | 50 ++++++++++ src/{utils => infra}/reveal-active-file.ts | 2 +- .../save-file-pending-changes.ts | 0 src/{utils => infra}/tree-view.ts | 0 src/{utils => infra}/typed-keys.ts | 0 src/{utils => infra}/untildify.test.ts | 2 +- src/{utils => infra}/untildify.ts | 0 src/{utils => infra}/uri-handler.ts | 2 +- src/markdown/extend-markdownIt.ts | 2 +- src/{models => model}/blog-export.ts | 0 .../blog-export/export-post.ts | 4 +- src/{models => model}/blog-settings.ts | 0 .../clipboard-img.ts} | 0 src/{models => model}/config.ts | 0 src/{models => model}/error-response.ts | 0 .../img-upload-status.ts} | 4 +- src/{models => model}/ing-view.ts | 0 src/{models => model}/ing.ts | 0 src/{models => model}/page-model.ts | 0 src/{models => model}/post-category.ts | 0 src/{models => model}/post-cfg.ts | 0 src/{models => model}/post-edit-dto.ts | 0 src/{models => model}/post-list-state.ts | 0 src/{models => model}/post-tag.ts | 0 .../post-updated-response.ts | 0 src/{models => model}/post.ts | 0 src/{models => model}/site-category.ts | 0 src/{models => model}/token-info.ts | 0 src/{models => model}/webview-cmd.ts | 2 +- src/{models => model}/webview-msg.ts | 4 +- src/{models => model}/zzk-search-result.ts | 0 src/{services => service}/alert.ts | 0 .../blog-export-post.store.ts | 4 +- .../blog-export-records.store.ts | 4 +- src/{services => service}/blog-export.api.ts | 6 +- src/{services => service}/blog-settings.ts | 4 +- src/{services => service}/code-challenge.ts | 0 .../downloaded-export.store.ts | 4 +- src/{services => service}/global-ctx.ts | 2 +- src/{services/image.ts => service/img.ts} | 4 +- .../ing-list-webview-provider.ts | 22 ++--- src/{services => service}/ing.api.ts | 8 +- src/service/is-target-workspace.ts | 23 +++++ src/{services => service}/local-draft.ts | 0 .../mkd-img-extractor.ts | 12 +-- src/{services => service}/multi-step-input.ts | 0 src/{services => service}/oauth.api.ts | 12 +-- .../parse-webview-html.ts | 2 +- src/{services => service}/post-category.ts | 4 +- src/{services => service}/post-cfg-panel.ts | 16 +-- src/{services => service}/post-file-map.ts | 6 +- src/{services => service}/post-list-view.ts | 4 +- src/{services => service}/post-tag.ts | 4 +- .../post-title-sanitizer.ts | 2 +- src/{services => service}/post.ts | 22 ++--- .../search-post-by-title.ts | 2 +- src/{services => service}/settings.ts | 2 +- src/{services => service}/site-category.ts | 6 +- src/services/check-workspace.ts | 65 ------------- .../cmd-register.ts => setup/setup-cmd.ts} | 97 ++++++++++--------- src/{services => setup}/setup-ui.ts | 44 +-------- src/setup/setup-watch.ts | 37 +++++++ src/test/runTest.ts | 26 ----- src/test/suite/extension.test.ts | 15 --- src/test/suite/index.ts | 38 -------- .../converters.ts => tree-view/convert.ts} | 12 +-- .../model}/base-entry-tree-item.ts | 0 .../model}/base-tree-item-source.ts | 0 .../model}/blog-export/downloaded.ts | 18 ++-- .../model}/blog-export/index.ts | 6 +- .../model}/blog-export/parser.ts | 9 +- .../model}/blog-export/post.ts | 10 +- .../model}/blog-export/record-metadata.ts | 4 +- .../model}/blog-export/record.ts | 14 +-- .../model/category-list-tree-item.ts} | 2 +- .../model}/post-category-tree-item.ts | 4 +- .../model}/post-metadata.ts | 10 +- .../model}/post-search-result-entry.ts | 4 +- .../model}/post-tree-item.ts | 4 +- .../navi-view.ts | 0 .../provider}/account-view-data-provider.ts | 0 .../provider}/blog-export-provider.ts | 10 +- .../post-category-tree-data-provider.ts} | 34 +++---- .../provider}/post-data-provider.ts | 20 ++-- .../tree-view-register.ts} | 22 ++--- src/utils/throw-if-not-ok-response.ts | 44 --------- ui/global.d.ts | 2 +- ui/ing/App.tsx | 6 +- ui/ing/IngItem.tsx | 6 +- ui/ing/IngList.tsx | 2 +- ui/post-cfg/App.tsx | 12 +-- .../components/AccessPermissionSelector.tsx | 2 +- ...ategoriesSelect.tsx => CategorySelect.tsx} | 8 +- ui/post-cfg/components/ErrorResponse.tsx | 4 +- ui/post-cfg/components/InputSummary.tsx | 6 +- ...oriesSelect.tsx => NestCategorySelect.tsx} | 10 +- ui/post-cfg/components/PostForm.tsx | 22 ++--- ...sSelector.tsx => SiteCategorySelector.tsx} | 9 +- .../SiteHomeContributionOptionsSelector.tsx | 2 +- ui/post-cfg/components/TagsInput.tsx | 4 +- .../site-home-contribution-options.ts | 0 .../personal-category-store.ts} | 4 +- .../site-category-store.ts} | 2 +- .../{services => service}/tags-store.ts | 2 +- ui/tsconfig.json | 5 +- 180 files changed, 765 insertions(+), 904 deletions(-) rename src/{commands => cmd}/blog-export/create.ts (79%) rename src/{commands => cmd}/blog-export/delete.ts (90%) rename src/{commands => cmd}/blog-export/download.ts (88%) rename src/{commands => cmd}/blog-export/edit.ts (78%) rename src/{commands => cmd}/blog-export/index.ts (61%) rename src/{commands => cmd}/blog-export/open-local.ts (92%) rename src/{commands => cmd}/blog-export/refresh.ts (67%) rename src/{commands => cmd}/blog-export/view-post.ts (89%) rename src/{commands => cmd}/cmd-handler.ts (100%) rename src/{commands/extract-images.ts => cmd/extract-img.ts} (98%) rename src/{commands => cmd}/ing/comment-ing.ts (91%) create mode 100644 src/cmd/ing/ing-list-cmd-register.ts rename src/{commands/ing/goto-ing-list-page.ts => cmd/ing/ing-list-go-next-page.ts} (78%) rename src/{commands => cmd}/ing/publish-ing.ts (94%) rename src/{commands => cmd}/ing/refresh-ing-list.ts (52%) create mode 100644 src/cmd/ing/select-ing-type.ts rename src/{commands => cmd}/login.ts (100%) rename src/{commands => cmd}/open/open-cnb-home.ts (76%) rename src/{commands => cmd}/open/open-cnb-ing.ts (76%) rename src/{commands => cmd}/open/open-cnb-news.ts (76%) rename src/{commands => cmd}/open/open-cnb-q.ts (75%) create mode 100644 src/cmd/open/open-ing-site.ts rename src/{commands => cmd}/open/open-my-account-settings.ts (80%) rename src/{commands => cmd}/open/open-my-blog-console.ts (77%) rename src/{commands => cmd}/open/open-my-blog.ts (87%) rename src/{commands => cmd}/open/open-my-home-page.ts (90%) rename src/{commands => cmd}/open/open-post-in-blog-admin.ts (64%) rename src/{commands => cmd}/open/open-workspace.ts (79%) rename src/{commands => cmd}/pdf/export-pdf.ts (92%) rename src/{commands => cmd}/pdf/post-pdf-template-builder.ts (94%) rename src/{commands => cmd}/post-category/base-tree-view-cmd-handler.ts (83%) rename src/{commands/post-category/delete-selected-categories.ts => cmd/post-category/delete-selected-category.ts} (86%) rename src/{commands => cmd}/post-category/input-post-category.ts (96%) rename src/{commands => cmd}/post-category/new-post-category.ts (81%) create mode 100644 src/cmd/post-category/refresh-post-category-list.ts rename src/{commands => cmd}/post-category/update-post-category.ts (89%) rename src/{commands => cmd}/post-list/copy-link.ts (88%) rename src/{commands => cmd}/post-list/create-local-draft.ts (94%) rename src/{commands => cmd}/post-list/delete-post-to-local-file-map.ts (71%) rename src/{commands => cmd}/post-list/delete-post.ts (84%) rename src/{commands => cmd}/post-list/modify-post-settings.ts (66%) rename src/{commands => cmd}/post-list/open-post-file.ts (74%) rename src/{commands => cmd}/post-list/open-post-in-vscode.ts (91%) rename src/{commands => cmd}/post-list/refresh-post-list.ts (91%) rename src/{commands => cmd}/post-list/rename-post.ts (87%) rename src/{commands => cmd}/post-list/search.ts (88%) rename src/{commands => cmd}/post-list/upload-post.ts (90%) rename src/{commands => cmd}/pull-post-remote-updates.ts (85%) rename src/{commands => cmd}/reveal-local-post-file-in-os.ts (66%) rename src/{commands => cmd}/reveal-workspace-in-os.ts (59%) rename src/{commands => cmd}/set-workspace.ts (86%) rename src/{commands => cmd}/show-local-file-to-post-info.ts (91%) rename src/{commands/upload-image/upload-clipboard-image.ts => cmd/upload-img/upload-clipboard-img.ts} (68%) rename src/{commands/upload-image/upload-local-disk-image.ts => cmd/upload-img/upload-fs-img.ts} (85%) rename src/{commands/upload-image/upload-image-utils.ts => cmd/upload-img/upload-img-util.ts} (93%) rename src/{commands/upload-image/upload-image.ts => cmd/upload-img/upload-img.ts} (78%) rename src/{commands => cmd}/view-post-online.ts (68%) delete mode 100644 src/commands/ing/ing-list-cmd-register.ts delete mode 100644 src/commands/ing/open-ing-in-browser.ts delete mode 100644 src/commands/ing/select-ing-type.ts delete mode 100644 src/commands/post-category/refresh-post-categories-list.ts rename src/{utils => infra}/chromium-path-provider.ts (95%) rename src/{utils => infra}/cmd.ts (100%) rename src/{utils/ingStarToText.ts => infra/convert/ing-star-to-text.ts} (100%) rename src/{services/converter.ts => infra/convert/object-keys-to-camel-case.ts} (87%) rename src/{utils => infra}/fetch-client.ts (73%) rename src/{utils/format-image-link.ts => infra/fmt-img-link.ts} (100%) rename src/{utils/get-clipboard-image.ts => infra/get-clipboard-img.ts} (96%) rename src/{utils => infra}/http-client.ts (94%) rename src/{utils => infra}/input-post-settings.ts (96%) create mode 100644 src/infra/response-err.ts rename src/{utils => infra}/reveal-active-file.ts (73%) rename src/{utils => infra}/save-file-pending-changes.ts (100%) rename src/{utils => infra}/tree-view.ts (100%) rename src/{utils => infra}/typed-keys.ts (100%) rename src/{utils => infra}/untildify.test.ts (84%) rename src/{utils => infra}/untildify.ts (100%) rename src/{utils => infra}/uri-handler.ts (93%) rename src/{models => model}/blog-export.ts (100%) rename src/{models => model}/blog-export/export-post.ts (82%) rename src/{models => model}/blog-settings.ts (100%) rename src/{models/clipboard-image.ts => model/clipboard-img.ts} (100%) rename src/{models => model}/config.ts (100%) rename src/{models => model}/error-response.ts (100%) rename src/{models/image-upload-status.ts => model/img-upload-status.ts} (64%) rename src/{models => model}/ing-view.ts (100%) rename src/{models => model}/ing.ts (100%) rename src/{models => model}/page-model.ts (100%) rename src/{models => model}/post-category.ts (100%) rename src/{models => model}/post-cfg.ts (100%) rename src/{models => model}/post-edit-dto.ts (100%) rename src/{models => model}/post-list-state.ts (100%) rename src/{models => model}/post-tag.ts (100%) rename src/{models => model}/post-updated-response.ts (100%) rename src/{models => model}/post.ts (100%) rename src/{models => model}/site-category.ts (100%) rename src/{models => model}/token-info.ts (100%) rename src/{models => model}/webview-cmd.ts (96%) rename src/{models => model}/webview-msg.ts (93%) rename src/{models => model}/zzk-search-result.ts (100%) rename src/{services => service}/alert.ts (100%) rename src/{services => service}/blog-export-post.store.ts (96%) rename src/{services => service}/blog-export-records.store.ts (89%) rename src/{services => service}/blog-export.api.ts (91%) rename src/{services => service}/blog-settings.ts (92%) rename src/{services => service}/code-challenge.ts (100%) rename src/{services => service}/downloaded-export.store.ts (96%) rename src/{services => service}/global-ctx.ts (98%) rename src/{services/image.ts => service/img.ts} (95%) rename src/{services => service}/ing-list-webview-provider.ts (92%) rename src/{services => service}/ing.api.ts (96%) create mode 100644 src/service/is-target-workspace.ts rename src/{services => service}/local-draft.ts (100%) rename src/{services => service}/mkd-img-extractor.ts (95%) rename src/{services => service}/multi-step-input.ts (100%) rename src/{services => service}/oauth.api.ts (89%) rename src/{services => service}/parse-webview-html.ts (88%) rename src/{services => service}/post-category.ts (98%) rename src/{services => service}/post-cfg-panel.ts (95%) rename src/{services => service}/post-file-map.ts (89%) rename src/{services => service}/post-list-view.ts (69%) rename src/{services => service}/post-tag.ts (90%) rename src/{services => service}/post-title-sanitizer.ts (98%) rename src/{services => service}/post.ts (90%) rename src/{services => service}/search-post-by-title.ts (97%) rename src/{services => service}/settings.ts (99%) rename src/{services => service}/site-category.ts (78%) delete mode 100644 src/services/check-workspace.ts rename src/{commands/cmd-register.ts => setup/setup-cmd.ts} (52%) rename src/{services => setup}/setup-ui.ts (61%) create mode 100644 src/setup/setup-watch.ts delete mode 100644 src/test/runTest.ts delete mode 100644 src/test/suite/extension.test.ts delete mode 100644 src/test/suite/index.ts rename src/{tree-view-providers/converters.ts => tree-view/convert.ts} (88%) rename src/{tree-view-providers/models => tree-view/model}/base-entry-tree-item.ts (100%) rename src/{tree-view-providers/models => tree-view/model}/base-tree-item-source.ts (100%) rename src/{tree-view-providers/models => tree-view/model}/blog-export/downloaded.ts (83%) rename src/{tree-view-providers/models => tree-view/model}/blog-export/index.ts (66%) rename src/{tree-view-providers/models => tree-view/model}/blog-export/parser.ts (81%) rename src/{tree-view-providers/models => tree-view/model}/blog-export/post.ts (72%) rename src/{tree-view-providers/models => tree-view/model}/blog-export/record-metadata.ts (87%) rename src/{tree-view-providers/models => tree-view/model}/blog-export/record.ts (92%) rename src/{tree-view-providers/models/categories-list-tree-item.ts => tree-view/model/category-list-tree-item.ts} (87%) rename src/{tree-view-providers/models => tree-view/model}/post-category-tree-item.ts (80%) rename src/{tree-view-providers/models => tree-view/model}/post-metadata.ts (97%) rename src/{tree-view-providers/models => tree-view/model}/post-search-result-entry.ts (95%) rename src/{tree-view-providers/models => tree-view/model}/post-tree-item.ts (90%) rename src/{tree-view-providers => tree-view}/navi-view.ts (100%) rename src/{tree-view-providers => tree-view/provider}/account-view-data-provider.ts (100%) rename src/{tree-view-providers => tree-view/provider}/blog-export-provider.ts (95%) rename src/{tree-view-providers/post-categories-tree-data-provider.ts => tree-view/provider/post-category-tree-data-provider.ts} (81%) rename src/{tree-view-providers => tree-view/provider}/post-data-provider.ts (86%) rename src/{tree-view-providers/tree-view-registration.ts => tree-view/tree-view-register.ts} (79%) delete mode 100644 src/utils/throw-if-not-ok-response.ts rename ui/post-cfg/components/{CategoriesSelect.tsx => CategorySelect.tsx} (86%) rename ui/post-cfg/components/{NestCategoriesSelect.tsx => NestCategorySelect.tsx} (94%) rename ui/post-cfg/components/{SiteCategoriesSelector.tsx => SiteCategorySelector.tsx} (95%) rename ui/post-cfg/{models => model}/site-home-contribution-options.ts (100%) rename ui/post-cfg/{services/personal-categories-store.ts => service/personal-category-store.ts} (95%) rename ui/post-cfg/{services/site-categories-store.ts => service/site-category-store.ts} (75%) rename ui/post-cfg/{services => service}/tags-store.ts (80%) diff --git a/package.json b/package.json index edf30d14..afeecfdb 100644 --- a/package.json +++ b/package.json @@ -175,7 +175,7 @@ "enablement": "vscode-cnb.isAuthorized" }, { - "command": "vscode-cnb.upload-image", + "command": "vscode-cnb.upload-img", "title": "上传图片到博客园", "category": "Cnblogs", "icon": "$(vscode-cnb-image-upload)", @@ -188,7 +188,7 @@ "enablement": "vscode-cnb.isAuthorized" }, { - "command": "vscode-cnb.upload-local-disk-image", + "command": "vscode-cnb.upload-fs-img", "title": "上传本地图片到博客园", "category": "Cnblogs", "enablement": "vscode-cnb.isAuthorized" @@ -225,14 +225,14 @@ "enablement": "vscode-cnb.isAuthorized" }, { - "command": "vscode-cnb.delete-selected-post-categories", + "command": "vscode-cnb.delete-selected-post-category", "title": "删除", "icon": "$(trash)", "category": "Cnblogs Post Categories Management", "enablement": "vscode-cnb.isAuthorized && !vscode-cnb.postCategoriesList.isRefreshing" }, { - "command": "vscode-cnb.refresh-post-categories-list", + "command": "vscode-cnb.refresh-post-category-list", "title": "刷新", "icon": "$(refresh)", "category": "Cnblogs Post Categories Management", @@ -279,7 +279,7 @@ "enablement": "vscode-cnb.isAuthorized" }, { - "command": "vscode-cnb.extract-images", + "command": "vscode-cnb.extract-img", "title": "提取图片", "category": "Cnblogs", "enablement": "vscode-cnb.isAuthorized" @@ -616,8 +616,8 @@ "export-post-to-pdf": true, "copy-post-link": true, "upload-clipboard-image": true, - "upload-local-disk-image": true, - "extract-images": true, + "upload-fs-img": true, + "extract-img": true, "ing:publish-selection": false }, "properties": { @@ -662,12 +662,12 @@ "description": "上传剪贴板图片到博客园", "type": "boolean" }, - "upload-local-disk-image": { + "upload-fs-img": { "order": 8, "description": "上传本地图片到博客园", "type": "boolean" }, - "extract-images": { + "extract-img": { "order": 9, "description": "提取图片", "type": "boolean" @@ -741,7 +741,7 @@ "visibility": "collapsed" }, { - "id": "cnblogs-post-categories-list", + "id": "cnblogs-post-category-list", "name": "分类列表", "when": "vscode-cnb.isAuthorized", "visibility": "collapsed" @@ -813,11 +813,11 @@ { "command": "vscode-cnb.new-post-category", "group": "navigation@1", - "when": "view == cnblogs-post-categories-list" + "when": "view == cnblogs-post-category-list" }, { - "command": "vscode-cnb.refresh-post-categories-list", - "when": "view == cnblogs-post-categories-list", + "command": "vscode-cnb.refresh-post-category-list", + "when": "view == cnblogs-post-category-list", "group": "navigation@2" }, { @@ -900,11 +900,11 @@ "when": "false" }, { - "command": "vscode-cnb.delete-selected-post-categories", + "command": "vscode-cnb.delete-selected-post-category", "when": "false" }, { - "command": "vscode-cnb.refresh-post-categories-list", + "command": "vscode-cnb.refresh-post-category-list", "when": "false" }, { @@ -1064,7 +1064,7 @@ "group": "0@6" }, { - "command": "vscode-cnb.delete-selected-post-categories", + "command": "vscode-cnb.delete-selected-post-category", "when": "viewItem == cnb-post-category" }, { @@ -1073,7 +1073,7 @@ "group": "inline@1" }, { - "command": "vscode-cnb.delete-selected-post-categories", + "command": "vscode-cnb.delete-selected-post-category", "when": "viewItem == cnb-post-category", "group": "inline@2" }, @@ -1164,8 +1164,8 @@ "group": "cnblogs@6" }, { - "command": "vscode-cnb.upload-local-disk-image", - "when": "resourceLangId == markdown && config.cnblogsClient.menus.context.editor.upload-local-disk-image", + "command": "vscode-cnb.upload-fs-img", + "when": "resourceLangId == markdown && config.cnblogsClient.menus.context.editor.upload-fs-img", "group": "cnblogs@7" }, { @@ -1174,8 +1174,8 @@ "group": "cnblogs@8" }, { - "command": "vscode-cnb.extract-images", - "when": "resourceLangId == markdown && config.cnblogsClient.menus.context.editor.extract-images", + "command": "vscode-cnb.extract-img", + "when": "resourceLangId == markdown && config.cnblogsClient.menus.context.editor.extract-img", "group": "cnblogs@9" }, { @@ -1186,7 +1186,7 @@ ], "editor/title": [ { - "command": "vscode-cnb.upload-image", + "command": "vscode-cnb.upload-img", "when": "resourceLangId == markdown", "group": "navigation" }, @@ -1247,7 +1247,7 @@ "when": "editorTextFocus && resourceLangId == markdown" }, { - "command": "vscode-cnb.upload-local-disk-image", + "command": "vscode-cnb.upload-fs-img", "key": "ctrl+alt+f", "mac": "cmd+alt+f", "when": "editorTextFocus && resourceLangId == markdown" diff --git a/src/auth/account-info.ts b/src/auth/account-info.ts index a7316a22..b0ede0f9 100644 --- a/src/auth/account-info.ts +++ b/src/auth/account-info.ts @@ -1,4 +1,4 @@ -import { UserInfoSpec } from '@/services/oauth.api' +import { UserInfoSpec } from '@/service/oauth.api' import { trim } from 'lodash-es' import { AuthenticationSessionAccountInformation } from 'vscode' import { AuthProvider } from './auth-provider' diff --git a/src/auth/account-manager.ts b/src/auth/account-manager.ts index 06522faf..1d79f5e1 100644 --- a/src/auth/account-manager.ts +++ b/src/auth/account-manager.ts @@ -1,15 +1,15 @@ import { AccountInfo } from './account-info' -import { globalCtx } from '@/services/global-ctx' +import { globalCtx } from '@/service/global-ctx' import vscode, { authentication, AuthenticationGetSessionOptions, Disposable } from 'vscode' -import { accountViewDataProvider } from '@/tree-view-providers/account-view-data-provider' -import { postDataProvider } from '@/tree-view-providers/post-data-provider' -import { postCategoriesDataProvider } from '@/tree-view-providers/post-categories-tree-data-provider' -import { Oauth } from '@/services/oauth.api' +import { accountViewDataProvider } from '@/tree-view/provider/account-view-data-provider' +import { postDataProvider } from '@/tree-view/provider/post-data-provider' +import { postCategoryDataProvider } from '@/tree-view/provider/post-category-tree-data-provider' +import { Oauth } from '@/service/oauth.api' import { authProvider } from '@/auth/auth-provider' import { AuthSession } from '@/auth/auth-session' -import { BlogExportProvider } from '@/tree-view-providers/blog-export-provider' -import { Alert } from '@/services/alert' -import { execCmd } from '@/utils/cmd' +import { BlogExportProvider } from '@/tree-view/provider/blog-export-provider' +import { Alert } from '@/service/alert' +import { execCmd } from '@/infra/cmd' const isAuthorizedStorageKey = 'isAuthorized' @@ -26,7 +26,7 @@ class AccountManager extends vscode.Disposable { accountViewDataProvider.fireTreeDataChangedEvent() postDataProvider.fireTreeDataChangedEvent(undefined) - postCategoriesDataProvider.fireTreeDataChangedEvent() + postCategoryDataProvider.fireTreeDataChangedEvent() BlogExportProvider.optionalInstance?.refreshRecords({ force: false, clearCache: true }).catch(console.warn) }) diff --git a/src/auth/auth-provider.ts b/src/auth/auth-provider.ts index b00fda50..72888a3d 100644 --- a/src/auth/auth-provider.ts +++ b/src/auth/auth-provider.ts @@ -1,5 +1,5 @@ import { AuthSession } from '@/auth/auth-session' -import { genVerifyChallengePair } from '@/services/code-challenge' +import { genVerifyChallengePair } from '@/service/code-challenge' import { isArray, isUndefined } from 'lodash-es' import { authentication, @@ -14,12 +14,12 @@ import { Uri, window, } from 'vscode' -import { globalCtx } from '@/services/global-ctx' +import { globalCtx } from '@/service/global-ctx' import RandomString from 'randomstring' -import { Oauth } from '@/services/oauth.api' -import { extUriHandler } from '@/utils/uri-handler' +import { Oauth } from '@/service/oauth.api' +import { extUriHandler } from '@/infra/uri-handler' import { AccountInfo } from '@/auth/account-info' -import { TokenInfo } from '@/models/token-info' +import { TokenInfo } from '@/model/token-info' import { Optional } from 'utility-types' export class AuthProvider implements AuthenticationProvider, Disposable { diff --git a/src/commands/blog-export/create.ts b/src/cmd/blog-export/create.ts similarity index 79% rename from src/commands/blog-export/create.ts rename to src/cmd/blog-export/create.ts index 54f05abe..e864c01f 100644 --- a/src/commands/blog-export/create.ts +++ b/src/cmd/blog-export/create.ts @@ -1,7 +1,7 @@ -import { CmdHandler } from '@/commands/cmd-handler' -import { Alert } from '@/services/alert' -import { BlogExportApi } from '@/services/blog-export.api' -import { BlogExportProvider } from '@/tree-view-providers/blog-export-provider' +import { CmdHandler } from '@/cmd/cmd-handler' +import { Alert } from '@/service/alert' +import { BlogExportApi } from '@/service/blog-export.api' +import { BlogExportProvider } from '@/tree-view/provider/blog-export-provider' import { MessageItem, window } from 'vscode' export class CreateBlogExportCmdHandler implements CmdHandler { diff --git a/src/commands/blog-export/delete.ts b/src/cmd/blog-export/delete.ts similarity index 90% rename from src/commands/blog-export/delete.ts rename to src/cmd/blog-export/delete.ts index 4f7c2d04..18ff7c62 100644 --- a/src/commands/blog-export/delete.ts +++ b/src/cmd/blog-export/delete.ts @@ -1,10 +1,10 @@ -import { TreeViewCmdHandler } from '@/commands/cmd-handler' -import { DownloadedBlogExport } from '@/models/blog-export' -import { Alert } from '@/services/alert' -import { BlogExportApi } from '@/services/blog-export.api' -import { DownloadedExportStore } from '@/services/downloaded-export.store' -import { BlogExportProvider } from '@/tree-view-providers/blog-export-provider' -import { BlogExportRecordTreeItem, DownloadedExportTreeItem } from '@/tree-view-providers/models/blog-export' +import { TreeViewCmdHandler } from '@/cmd/cmd-handler' +import { DownloadedBlogExport } from '@/model/blog-export' +import { Alert } from '@/service/alert' +import { BlogExportApi } from '@/service/blog-export.api' +import { DownloadedExportStore } from '@/service/downloaded-export.store' +import { BlogExportProvider } from '@/tree-view/provider/blog-export-provider' +import { BlogExportRecordTreeItem, DownloadedExportTreeItem } from '@/tree-view/model/blog-export' import fs from 'fs' import path from 'path' import { promisify } from 'util' diff --git a/src/commands/blog-export/download.ts b/src/cmd/blog-export/download.ts similarity index 88% rename from src/commands/blog-export/download.ts rename to src/cmd/blog-export/download.ts index f6d6ca1d..58ce3040 100644 --- a/src/commands/blog-export/download.ts +++ b/src/cmd/blog-export/download.ts @@ -1,17 +1,17 @@ -import { TreeViewCmdHandler } from '@/commands/cmd-handler' -import { Alert } from '@/services/alert' -import { BlogExportApi } from '@/services/blog-export.api' -import { DownloadedExportStore } from '@/services/downloaded-export.store' -import { globalCtx } from '@/services/global-ctx' -import { Settings } from '@/services/settings' -import { BlogExportProvider } from '@/tree-view-providers/blog-export-provider' -import { BlogExportRecordTreeItem } from '@/tree-view-providers/models/blog-export' -import { extTreeViews } from '@/tree-view-providers/tree-view-registration' +import { TreeViewCmdHandler } from '@/cmd/cmd-handler' +import { Alert } from '@/service/alert' +import { BlogExportApi } from '@/service/blog-export.api' +import { DownloadedExportStore } from '@/service/downloaded-export.store' +import { globalCtx } from '@/service/global-ctx' +import { Settings } from '@/service/settings' +import { BlogExportProvider } from '@/tree-view/provider/blog-export-provider' +import { BlogExportRecordTreeItem } from '@/tree-view/model/blog-export' +import { extTreeViews } from '@/tree-view/tree-view-register' import fs from 'fs' import { Progress } from 'got' import path from 'path' import { promisify } from 'util' -import { execCmd } from '@/utils/cmd' +import { execCmd } from '@/infra/cmd' export class DownloadExportCmdHandler implements TreeViewCmdHandler { static readonly cmd = 'vscode-cnb.blog-export.download' diff --git a/src/commands/blog-export/edit.ts b/src/cmd/blog-export/edit.ts similarity index 78% rename from src/commands/blog-export/edit.ts rename to src/cmd/blog-export/edit.ts index 9be70b03..da8601eb 100644 --- a/src/commands/blog-export/edit.ts +++ b/src/cmd/blog-export/edit.ts @@ -1,8 +1,8 @@ -import { TreeViewCmdHandler } from '@/commands/cmd-handler' -import { openPostFile } from '@/commands/post-list/open-post-file' -import { Alert } from '@/services/alert' -import { Settings } from '@/services/settings' -import { ExportPostTreeItem } from '@/tree-view-providers/models/blog-export/post' +import { TreeViewCmdHandler } from '@/cmd/cmd-handler' +import { openPostFile } from '@/cmd/post-list/open-post-file' +import { Alert } from '@/service/alert' +import { Settings } from '@/service/settings' +import { ExportPostTreeItem } from '@/tree-view/model/blog-export/post' import fs from 'fs' import path from 'path' import sanitizeFileName from 'sanitize-filename' @@ -36,7 +36,7 @@ export class EditExportPostCmdHandler implements TreeViewCmdHandler { - const { ExportPostStore } = await import('@/services/blog-export-post.store') + const { ExportPostStore } = await import('@/service/blog-export-post.store') const store = new ExportPostStore(downloadedExport) return store.getBody(postId).finally(() => store.dispose()) } diff --git a/src/commands/cmd-handler.ts b/src/cmd/cmd-handler.ts similarity index 100% rename from src/commands/cmd-handler.ts rename to src/cmd/cmd-handler.ts diff --git a/src/commands/extract-images.ts b/src/cmd/extract-img.ts similarity index 98% rename from src/commands/extract-images.ts rename to src/cmd/extract-img.ts index c96ccb27..688c3f02 100644 --- a/src/commands/extract-images.ts +++ b/src/cmd/extract-img.ts @@ -1,6 +1,6 @@ import { MessageItem, MessageOptions, ProgressLocation, Range, Uri, window, workspace, WorkspaceEdit } from 'vscode' -import { ImageInfo, ImageSrc, MkdImgExtractor, newImageSrcFilter } from '@/services/mkd-img-extractor' -import { Alert } from '@/services/alert' +import { ImageInfo, ImageSrc, MkdImgExtractor, newImageSrcFilter } from '@/service/mkd-img-extractor' +import { Alert } from '@/service/alert' type ExtractOption = MessageItem & Partial<{ imageSrc: ImageSrc }> diff --git a/src/commands/ing/comment-ing.ts b/src/cmd/ing/comment-ing.ts similarity index 91% rename from src/commands/ing/comment-ing.ts rename to src/cmd/ing/comment-ing.ts index 6ba16b30..70ea73c6 100644 --- a/src/commands/ing/comment-ing.ts +++ b/src/cmd/ing/comment-ing.ts @@ -1,6 +1,6 @@ -import { CmdHandler } from '@/commands/cmd-handler' -import { IngApi } from '@/services/ing.api' -import { getIngListWebviewProvider } from '@/services/ing-list-webview-provider' +import { CmdHandler } from '@/cmd/cmd-handler' +import { IngApi } from '@/service/ing.api' +import { getIngListWebviewProvider } from '@/service/ing-list-webview-provider' import { ProgressLocation, window } from 'vscode' export class CommentIngCmdHandler implements CmdHandler { diff --git a/src/cmd/ing/ing-list-cmd-register.ts b/src/cmd/ing/ing-list-cmd-register.ts new file mode 100644 index 00000000..70677e0d --- /dev/null +++ b/src/cmd/ing/ing-list-cmd-register.ts @@ -0,0 +1,19 @@ +import { RefreshingList } from '@/cmd/ing/refresh-ing-list' +import { globalCtx } from '@/service/global-ctx' +import { GotoingListFirstPage, IngListGoNextPage, GotoingListPreviousPage } from '@/cmd/ing/ing-list-go-next-page' +import { regCmd } from '@/infra/cmd' +import { openIngSite } from '@/cmd/open/open-ing-site' +import { switchIngType } from "@/cmd/ing/select-ing-type"; + +export const regIngListCmds = () => { + const appName = globalCtx.extName + + return [ + regCmd(`${appName}.ing-list.refresh`, () => new RefreshingList().handle()), + regCmd(`${appName}.ing-list.next`, () => new IngListGoNextPage().handle()), + regCmd(`${appName}.ing-list.previous`, () => new GotoingListPreviousPage().handle()), + regCmd(`${appName}.ing-list.first`, () => new GotoingListFirstPage().handle()), + regCmd(`${appName}.ing-list.switch-type`, switchIngType), + regCmd(`${appName}.ing-list.open-in-browser`, openIngSite), + ] +} diff --git a/src/commands/ing/goto-ing-list-page.ts b/src/cmd/ing/ing-list-go-next-page.ts similarity index 78% rename from src/commands/ing/goto-ing-list-page.ts rename to src/cmd/ing/ing-list-go-next-page.ts index 6e729a8a..e723768c 100644 --- a/src/commands/ing/goto-ing-list-page.ts +++ b/src/cmd/ing/ing-list-go-next-page.ts @@ -1,7 +1,7 @@ -import { CmdHandler } from '@/commands/cmd-handler' -import { getIngListWebviewProvider } from 'src/services/ing-list-webview-provider' +import { CmdHandler } from '@/cmd/cmd-handler' +import { getIngListWebviewProvider } from '@/service/ing-list-webview-provider' -export class GotoingListNextPage implements CmdHandler { +export class IngListGoNextPage implements CmdHandler { handle(): Promise { const provider = getIngListWebviewProvider() const { pageIndex } = provider diff --git a/src/commands/ing/publish-ing.ts b/src/cmd/ing/publish-ing.ts similarity index 94% rename from src/commands/ing/publish-ing.ts rename to src/cmd/ing/publish-ing.ts index 59edfa3f..b41a3b6f 100644 --- a/src/commands/ing/publish-ing.ts +++ b/src/cmd/ing/publish-ing.ts @@ -1,11 +1,11 @@ -import { CmdHandler } from '@/commands/cmd-handler' -import { execCmd } from '@/utils/cmd' -import { IngPublishModel, IngType } from '@/models/ing' -import { Alert } from '@/services/alert' -import { globalCtx } from '@/services/global-ctx' -import { IngApi } from '@/services/ing.api' -import { getIngListWebviewProvider } from '@/services/ing-list-webview-provider' -import { InputStep, MultiStepInput, QuickPickParameters } from '@/services/multi-step-input' +import { CmdHandler } from '@/cmd/cmd-handler' +import { execCmd } from '@/infra/cmd' +import { IngPublishModel, IngType } from '@/model/ing' +import { Alert } from '@/service/alert' +import { globalCtx } from '@/service/global-ctx' +import { IngApi } from '@/service/ing.api' +import { getIngListWebviewProvider } from '@/service/ing-list-webview-provider' +import { InputStep, MultiStepInput, QuickPickParameters } from '@/service/multi-step-input' import { MessageOptions, ProgressLocation, QuickPickItem, Uri, window } from 'vscode' export class PublishIngCmdHandler implements CmdHandler { diff --git a/src/commands/ing/refresh-ing-list.ts b/src/cmd/ing/refresh-ing-list.ts similarity index 52% rename from src/commands/ing/refresh-ing-list.ts rename to src/cmd/ing/refresh-ing-list.ts index 9c3e3a3b..9ed2b022 100644 --- a/src/commands/ing/refresh-ing-list.ts +++ b/src/cmd/ing/refresh-ing-list.ts @@ -1,5 +1,5 @@ -import { CmdHandler } from '@/commands/cmd-handler' -import { getIngListWebviewProvider } from 'src/services/ing-list-webview-provider' +import { CmdHandler } from '@/cmd/cmd-handler' +import { getIngListWebviewProvider } from '@/service/ing-list-webview-provider' export class RefreshingList implements CmdHandler { handle(): Promise { diff --git a/src/cmd/ing/select-ing-type.ts b/src/cmd/ing/select-ing-type.ts new file mode 100644 index 00000000..7db4a49c --- /dev/null +++ b/src/cmd/ing/select-ing-type.ts @@ -0,0 +1,42 @@ +import { IngType, IngTypesMetadata } from '@/model/ing' +import { getIngListWebviewProvider } from '@/service/ing-list-webview-provider' +import { QuickPickItem, window } from 'vscode' + +export function switchIngType() { + const options: (QuickPickItem & { ingType: IngType })[] = IngTypesMetadata.map( + ([ingType, { displayName, description }]) => ({ + label: displayName, + ingType: ingType, + description: description, + picked: ingType === getIngListWebviewProvider().ingType, + }) + ) + const quickPick = window.createQuickPick<(typeof options)[0]>() + + quickPick.title = '选择闪存类型' + quickPick.items = options + quickPick.canSelectMany = false + quickPick.activeItems = options.filter(x => x.picked) + quickPick.selectedItems = quickPick.activeItems + quickPick.ignoreFocusOut = false + + const disposables = [quickPick] + + quickPick.onDidChangeSelection( + ([selectedItem]) => { + if (selectedItem) { + quickPick.hide() + return getIngListWebviewProvider().refreshingList({ + pageIndex: 1, + ingType: selectedItem.ingType, + }) + } + }, + undefined, + disposables + ) + quickPick.onDidHide(() => disposables.forEach(d => d.dispose()), undefined, disposables) + quickPick.show() + + return Promise.resolve() +} diff --git a/src/commands/login.ts b/src/cmd/login.ts similarity index 100% rename from src/commands/login.ts rename to src/cmd/login.ts diff --git a/src/commands/open/open-cnb-home.ts b/src/cmd/open/open-cnb-home.ts similarity index 76% rename from src/commands/open/open-cnb-home.ts rename to src/cmd/open/open-cnb-home.ts index 720fe346..dc028cbc 100644 --- a/src/commands/open/open-cnb-home.ts +++ b/src/cmd/open/open-cnb-home.ts @@ -1,4 +1,4 @@ -import { execCmd } from '@/utils/cmd' +import { execCmd } from '@/infra/cmd' import { Uri } from 'vscode' export const openCnbHome = () => execCmd('vscode.open', Uri.parse('https://www.cnblogs.com')) diff --git a/src/commands/open/open-cnb-ing.ts b/src/cmd/open/open-cnb-ing.ts similarity index 76% rename from src/commands/open/open-cnb-ing.ts rename to src/cmd/open/open-cnb-ing.ts index 4ab558ba..a8a04bba 100644 --- a/src/commands/open/open-cnb-ing.ts +++ b/src/cmd/open/open-cnb-ing.ts @@ -1,4 +1,4 @@ import { Uri } from 'vscode' -import { execCmd } from '@/utils/cmd' +import { execCmd } from '@/infra/cmd' export const openCnbIng = () => execCmd('vscode.open', Uri.parse('https://ing.cnblogs.com')) diff --git a/src/commands/open/open-cnb-news.ts b/src/cmd/open/open-cnb-news.ts similarity index 76% rename from src/commands/open/open-cnb-news.ts rename to src/cmd/open/open-cnb-news.ts index da0bdc34..14baf098 100644 --- a/src/commands/open/open-cnb-news.ts +++ b/src/cmd/open/open-cnb-news.ts @@ -1,4 +1,4 @@ -import { execCmd } from '@/utils/cmd' +import { execCmd } from '@/infra/cmd' import { Uri } from 'vscode' export const openCnbNews = () => execCmd('vscode.open', Uri.parse('https://news.cnblogs.com')) diff --git a/src/commands/open/open-cnb-q.ts b/src/cmd/open/open-cnb-q.ts similarity index 75% rename from src/commands/open/open-cnb-q.ts rename to src/cmd/open/open-cnb-q.ts index 0be3f4e1..3f2f8646 100644 --- a/src/commands/open/open-cnb-q.ts +++ b/src/cmd/open/open-cnb-q.ts @@ -1,4 +1,4 @@ -import { execCmd } from '@/utils/cmd' +import { execCmd } from '@/infra/cmd' import { Uri } from 'vscode' export const openCnbQ = () => execCmd('vscode.open', Uri.parse('https://q.cnblogs.com')) diff --git a/src/cmd/open/open-ing-site.ts b/src/cmd/open/open-ing-site.ts new file mode 100644 index 00000000..811d45b0 --- /dev/null +++ b/src/cmd/open/open-ing-site.ts @@ -0,0 +1,5 @@ +import { execCmd } from '@/infra/cmd' +import { globalCtx } from '@/service/global-ctx' +import { Uri } from 'vscode' + +export const openIngSite = () => execCmd('vscode.open', Uri.parse(globalCtx.config.ingSite)) diff --git a/src/commands/open/open-my-account-settings.ts b/src/cmd/open/open-my-account-settings.ts similarity index 80% rename from src/commands/open/open-my-account-settings.ts rename to src/cmd/open/open-my-account-settings.ts index fbfda00f..f93f113b 100644 --- a/src/commands/open/open-my-account-settings.ts +++ b/src/cmd/open/open-my-account-settings.ts @@ -1,5 +1,5 @@ import { Uri } from 'vscode' -import { execCmd } from '@/utils/cmd' +import { execCmd } from '@/infra/cmd' export const openMyAccountSettings = () => execCmd('vscode.open', Uri.parse('https://account.cnblogs.com/settings/account')) diff --git a/src/commands/open/open-my-blog-console.ts b/src/cmd/open/open-my-blog-console.ts similarity index 77% rename from src/commands/open/open-my-blog-console.ts rename to src/cmd/open/open-my-blog-console.ts index 1d2fd24a..9dfdda08 100644 --- a/src/commands/open/open-my-blog-console.ts +++ b/src/cmd/open/open-my-blog-console.ts @@ -1,4 +1,4 @@ import { Uri } from 'vscode' -import { execCmd } from '@/utils/cmd' +import { execCmd } from '@/infra/cmd' export const openMyWebBlogConsole = () => execCmd('vscode.open', Uri.parse('https://i.cnblogs.com')) diff --git a/src/commands/open/open-my-blog.ts b/src/cmd/open/open-my-blog.ts similarity index 87% rename from src/commands/open/open-my-blog.ts rename to src/cmd/open/open-my-blog.ts index 32e1b186..d3ac0e1c 100644 --- a/src/commands/open/open-my-blog.ts +++ b/src/cmd/open/open-my-blog.ts @@ -1,5 +1,5 @@ import { accountManager } from '@/auth/account-manager' -import { execCmd } from '@/utils/cmd' +import { execCmd } from '@/infra/cmd' import { Uri } from 'vscode' export const openMyBlog = () => { diff --git a/src/commands/open/open-my-home-page.ts b/src/cmd/open/open-my-home-page.ts similarity index 90% rename from src/commands/open/open-my-home-page.ts rename to src/cmd/open/open-my-home-page.ts index bd384b85..9fdc3a57 100644 --- a/src/commands/open/open-my-home-page.ts +++ b/src/cmd/open/open-my-home-page.ts @@ -1,5 +1,5 @@ import { accountManager } from '@/auth/account-manager' -import { execCmd } from '@/utils/cmd' +import { execCmd } from '@/infra/cmd' import { Uri } from 'vscode' export const openMyHomePage = () => { diff --git a/src/commands/open/open-post-in-blog-admin.ts b/src/cmd/open/open-post-in-blog-admin.ts similarity index 64% rename from src/commands/open/open-post-in-blog-admin.ts rename to src/cmd/open/open-post-in-blog-admin.ts index 32f3dba0..dec18cbf 100644 --- a/src/commands/open/open-post-in-blog-admin.ts +++ b/src/cmd/open/open-post-in-blog-admin.ts @@ -1,8 +1,8 @@ import { Uri } from 'vscode' -import { execCmd } from '@/utils/cmd' -import { Post } from '@/models/post' -import { PostFileMapManager } from '@/services/post-file-map' -import { PostTreeItem } from '@/tree-view-providers/models/post-tree-item' +import { execCmd } from '@/infra/cmd' +import { Post } from '@/model/post' +import { PostFileMapManager } from '@/service/post-file-map' +import { PostTreeItem } from '@/tree-view/model/post-tree-item' export const openPostInBlogAdmin = (item: Post | PostTreeItem | Uri) => { if (!item) return diff --git a/src/commands/open/open-workspace.ts b/src/cmd/open/open-workspace.ts similarity index 79% rename from src/commands/open/open-workspace.ts rename to src/cmd/open/open-workspace.ts index d2e032d9..8bb0357c 100644 --- a/src/commands/open/open-workspace.ts +++ b/src/cmd/open/open-workspace.ts @@ -1,7 +1,7 @@ import { MessageOptions } from 'vscode' -import { Settings } from '@/services/settings' -import { execCmd } from '@/utils/cmd' -import { Alert } from '@/services/alert' +import { Settings } from '@/service/settings' +import { execCmd } from '@/infra/cmd' +import { Alert } from '@/service/alert' export const openWorkspace = async () => { const uri = Settings.workspaceUri diff --git a/src/commands/pdf/export-pdf.ts b/src/cmd/pdf/export-pdf.ts similarity index 92% rename from src/commands/pdf/export-pdf.ts rename to src/cmd/pdf/export-pdf.ts index 82886a23..77f6f182 100644 --- a/src/commands/pdf/export-pdf.ts +++ b/src/cmd/pdf/export-pdf.ts @@ -3,17 +3,17 @@ import fs from 'fs' import path from 'path' import os from 'os' import { MessageOptions, Progress, ProgressLocation, Uri, window, workspace } from 'vscode' -import { Post } from '@/models/post' -import { PostFileMapManager } from '@/services/post-file-map' -import { PostService } from '@/services/post' -import { extTreeViews } from '@/tree-view-providers/tree-view-registration' -import { ChromiumPathProvider } from '@/utils/chromium-path-provider' -import { Settings } from '@/services/settings' +import { Post } from '@/model/post' +import { PostFileMapManager } from '@/service/post-file-map' +import { PostService } from '@/service/post' +import { extTreeViews } from '@/tree-view/tree-view-register' +import { ChromiumPathProvider } from '@/infra/chromium-path-provider' +import { Settings } from '@/service/settings' import { accountManager } from '@/auth/account-manager' -import { Alert } from '@/services/alert' -import { PostTreeItem } from '@/tree-view-providers/models/post-tree-item' -import { PostEditDto } from '@/models/post-edit-dto' -import { postPdfTemplateBuilder } from '@/commands/pdf/post-pdf-template-builder' +import { Alert } from '@/service/alert' +import { PostTreeItem } from '@/tree-view/model/post-tree-item' +import { PostEditDto } from '@/model/post-edit-dto' +import { postPdfTemplateBuilder } from '@/cmd/pdf/post-pdf-template-builder' const launchBrowser = async ( chromiumPath: string diff --git a/src/commands/pdf/post-pdf-template-builder.ts b/src/cmd/pdf/post-pdf-template-builder.ts similarity index 94% rename from src/commands/pdf/post-pdf-template-builder.ts rename to src/cmd/pdf/post-pdf-template-builder.ts index 9617222c..1dab1ab5 100644 --- a/src/commands/pdf/post-pdf-template-builder.ts +++ b/src/cmd/pdf/post-pdf-template-builder.ts @@ -1,10 +1,10 @@ -import { Post } from '@/models/post' -import { PostFileMapManager } from '@/services/post-file-map' +import { Post } from '@/model/post' +import { PostFileMapManager } from '@/service/post-file-map' import fs from 'fs' -import { BlogSettingsService } from '@/services/blog-settings' +import { BlogSettingsService } from '@/service/blog-settings' import { accountManager } from '@/auth/account-manager' -import { postCategoryService } from '@/services/post-category' -import { PostCategory } from '@/models/post-category' +import { postCategoryService } from '@/service/post-category' +import { PostCategory } from '@/model/post-category' import { markdownItFactory } from '@cnblogs/markdown-it-presets' export namespace postPdfTemplateBuilder { diff --git a/src/commands/post-category/base-tree-view-cmd-handler.ts b/src/cmd/post-category/base-tree-view-cmd-handler.ts similarity index 83% rename from src/commands/post-category/base-tree-view-cmd-handler.ts rename to src/cmd/post-category/base-tree-view-cmd-handler.ts index 342d5e16..83afbefe 100644 --- a/src/commands/post-category/base-tree-view-cmd-handler.ts +++ b/src/cmd/post-category/base-tree-view-cmd-handler.ts @@ -1,7 +1,7 @@ -import { PostCategory } from '@/models/post-category' -import { PostCategoriesListTreeItem } from '@/tree-view-providers/models/categories-list-tree-item' -import { PostCategoryTreeItem } from '@/tree-view-providers/models/post-category-tree-item' -import { extTreeViews } from '@/tree-view-providers/tree-view-registration' +import { PostCategory } from '@/model/post-category' +import { PostCategoriesListTreeItem } from '@/tree-view/model/category-list-tree-item' +import { PostCategoryTreeItem } from '@/tree-view/model/post-category-tree-item' +import { extTreeViews } from '@/tree-view/tree-view-register' import { MultiSelectableTreeViewCmdHandler, TreeViewCmdHandler } from '../cmd-handler' export abstract class BasePostCategoryTreeViewCmdHandler implements TreeViewCmdHandler { diff --git a/src/commands/post-category/delete-selected-categories.ts b/src/cmd/post-category/delete-selected-category.ts similarity index 86% rename from src/commands/post-category/delete-selected-categories.ts rename to src/cmd/post-category/delete-selected-category.ts index 9ea341df..58475cce 100644 --- a/src/commands/post-category/delete-selected-categories.ts +++ b/src/cmd/post-category/delete-selected-category.ts @@ -1,10 +1,10 @@ import { MessageOptions, ProgressLocation, window } from 'vscode' -import { PostCategory } from '@/models/post-category' -import { postCategoryService } from '@/services/post-category' -import { PostCategoriesListTreeItem } from '@/tree-view-providers/models/categories-list-tree-item' +import { PostCategory } from '@/model/post-category' +import { postCategoryService } from '@/service/post-category' +import { PostCategoriesListTreeItem } from '@/tree-view/model/category-list-tree-item' import { BaseMultiSelectablePostCategoryTreeViewCmdHandler } from './base-tree-view-cmd-handler' -import { refreshPostCategoriesList } from './refresh-post-categories-list' -import { Alert } from '@/services/alert' +import { Alert } from '@/service/alert' +import { refreshPostCategoryList } from '@/cmd/post-category/refresh-post-category-list' export class DeletePostCategoriesHandler extends BaseMultiSelectablePostCategoryTreeViewCmdHandler { constructor(input: PostCategoriesListTreeItem) { @@ -56,7 +56,7 @@ export class DeletePostCategoriesHandler extends BaseMultiSelectablePostCategory .join('\n'), } as MessageOptions) } - if (errs.length < selectedCategories.length) refreshPostCategoriesList() + if (errs.length < selectedCategories.length) refreshPostCategoryList() } ) } @@ -71,9 +71,8 @@ export class DeletePostCategoriesHandler extends BaseMultiSelectablePostCategory } as MessageOptions, ...options ) - if (clicked === options[0]) return true - return false + return clicked === options[0] } } diff --git a/src/commands/post-category/input-post-category.ts b/src/cmd/post-category/input-post-category.ts similarity index 96% rename from src/commands/post-category/input-post-category.ts rename to src/cmd/post-category/input-post-category.ts index 2dd10471..adee0e5e 100644 --- a/src/commands/post-category/input-post-category.ts +++ b/src/cmd/post-category/input-post-category.ts @@ -1,6 +1,6 @@ import { QuickPickItem } from 'vscode' -import { PostCategory, PostCategoryAddDto } from '@/models/post-category' -import { InputStep, MultiStepInput } from '@/services/multi-step-input' +import { PostCategory, PostCategoryAddDto } from '@/model/post-category' +import { InputStep, MultiStepInput } from '@/service/multi-step-input' class InputOption { title = '编辑分类' diff --git a/src/commands/post-category/new-post-category.ts b/src/cmd/post-category/new-post-category.ts similarity index 81% rename from src/commands/post-category/new-post-category.ts rename to src/cmd/post-category/new-post-category.ts index 7c8bb401..db01eece 100644 --- a/src/commands/post-category/new-post-category.ts +++ b/src/cmd/post-category/new-post-category.ts @@ -1,9 +1,9 @@ import { MessageOptions, ProgressLocation, window } from 'vscode' -import { postCategoryService } from '@/services/post-category' -import { extTreeViews } from '@/tree-view-providers/tree-view-registration' +import { postCategoryService } from '@/service/post-category' +import { extTreeViews } from '@/tree-view/tree-view-register' import { inputPostCategory } from './input-post-category' -import { refreshPostCategoriesList } from './refresh-post-categories-list' -import { Alert } from '@/services/alert' +import { refreshPostCategoryList } from './refresh-post-category-list' +import { Alert } from '@/service/alert' export const newPostCategory = async () => { const input = await inputPostCategory({ @@ -25,7 +25,7 @@ export const newPostCategory = async () => { p.report({ increment: 90, }) - refreshPostCategoriesList() + refreshPostCategoryList() const newCategory = (await postCategoryService.listCategories()).find(x => x.title === input.title) if (newCategory) await extTreeViews.postCategoriesList.reveal(newCategory) } catch (err) { diff --git a/src/cmd/post-category/refresh-post-category-list.ts b/src/cmd/post-category/refresh-post-category-list.ts new file mode 100644 index 00000000..1024869b --- /dev/null +++ b/src/cmd/post-category/refresh-post-category-list.ts @@ -0,0 +1,5 @@ +import { postCategoryDataProvider } from '@/tree-view/provider/post-category-tree-data-provider' + +export const refreshPostCategoryList = () => { + postCategoryDataProvider.refresh() +} diff --git a/src/commands/post-category/update-post-category.ts b/src/cmd/post-category/update-post-category.ts similarity index 89% rename from src/commands/post-category/update-post-category.ts rename to src/cmd/post-category/update-post-category.ts index 18c352fa..dea5853d 100644 --- a/src/commands/post-category/update-post-category.ts +++ b/src/cmd/post-category/update-post-category.ts @@ -1,10 +1,10 @@ import fs from 'fs' import { MessageOptions, ProgressLocation, window, Uri, workspace } from 'vscode' -import { PostCategory } from '@/models/post-category' -import { postCategoryService } from '@/services/post-category' +import { PostCategory } from '@/model/post-category' +import { postCategoryService } from '@/service/post-category' import { inputPostCategory } from './input-post-category' -import { refreshPostCategoriesList } from './refresh-post-categories-list' -import { Settings } from '@/services/settings' +import { refreshPostCategoryList } from './refresh-post-category-list' +import { Settings } from '@/service/settings' import { BasePostCategoryTreeViewCmdHandler } from './base-tree-view-cmd-handler' class UpdatePostCategoryTreeViewCmdHandler extends BasePostCategoryTreeViewCmdHandler { @@ -30,7 +30,7 @@ class UpdatePostCategoryTreeViewCmdHandler extends BasePostCategoryTreeViewCmdHa p.report({ increment: 10 }) try { await postCategoryService.updateCategory(updateDto) - refreshPostCategoriesList() + refreshPostCategoryList() // 如果选择了createLocalPostFileWithCategory模式且本地有该目录,则重命名该目录 const workspaceUri = Settings.workspaceUri const shouldCreateLocalPostFileWithCategory = Settings.createLocalPostFileWithCategory diff --git a/src/commands/post-list/copy-link.ts b/src/cmd/post-list/copy-link.ts similarity index 88% rename from src/commands/post-list/copy-link.ts rename to src/cmd/post-list/copy-link.ts index 1afdc0ff..bdfc2d0c 100644 --- a/src/commands/post-list/copy-link.ts +++ b/src/cmd/post-list/copy-link.ts @@ -1,9 +1,9 @@ -import { TreeViewCmdHandler } from '@/commands/cmd-handler' -import { Post } from '@/models/post' -import { Alert } from '@/services/alert' -import { PostFileMapManager } from '@/services/post-file-map' -import { PostService } from '@/services/post' -import { PostTreeItem } from '@/tree-view-providers/models/post-tree-item' +import { TreeViewCmdHandler } from '@/cmd/cmd-handler' +import { Post } from '@/model/post' +import { Alert } from '@/service/alert' +import { PostFileMapManager } from '@/service/post-file-map' +import { PostService } from '@/service/post' +import { PostTreeItem } from '@/tree-view/model/post-tree-item' import { env, MessageItem, Uri, window } from 'vscode' type LinkFormat = 'markdown' | 'raw' | 'id' diff --git a/src/commands/post-list/create-local-draft.ts b/src/cmd/post-list/create-local-draft.ts similarity index 94% rename from src/commands/post-list/create-local-draft.ts rename to src/cmd/post-list/create-local-draft.ts index 45f9d875..c4a93c9c 100644 --- a/src/commands/post-list/create-local-draft.ts +++ b/src/cmd/post-list/create-local-draft.ts @@ -1,8 +1,8 @@ import { homedir } from 'os' import path from 'path' import { Uri, window, workspace } from 'vscode' -import { Settings } from '@/services/settings' -import { revealActiveFileInExplorer } from '@/utils/reveal-active-file' +import { Settings } from '@/service/settings' +import { revealActiveFileInExplorer } from '@/infra/reveal-active-file' import { openPostFile } from './open-post-file' export const createLocalDraft = async () => { diff --git a/src/commands/post-list/delete-post-to-local-file-map.ts b/src/cmd/post-list/delete-post-to-local-file-map.ts similarity index 71% rename from src/commands/post-list/delete-post-to-local-file-map.ts rename to src/cmd/post-list/delete-post-to-local-file-map.ts index 21b900b8..2df95606 100644 --- a/src/commands/post-list/delete-post-to-local-file-map.ts +++ b/src/cmd/post-list/delete-post-to-local-file-map.ts @@ -1,10 +1,10 @@ -import { MessageOptions, window } from 'vscode' -import { Post } from '@/models/post' -import { PostFileMap, PostFileMapManager } from '@/services/post-file-map' -import { revealPostListItem } from '@/services/post-list-view' -import { PostTreeItem } from '@/tree-view-providers/models/post-tree-item' -import { extTreeViews } from '@/tree-view-providers/tree-view-registration' -import { Alert } from '@/services/alert' +import { MessageOptions } from 'vscode' +import { Post } from '@/model/post' +import { PostFileMap, PostFileMapManager } from '@/service/post-file-map' +import { revealPostListItem } from '@/service/post-list-view' +import { PostTreeItem } from '@/tree-view/model/post-tree-item' +import { extTreeViews } from '@/tree-view/tree-view-register' +import { Alert } from '@/service/alert' const confirm = async (postList: Post[]): Promise => { const options = ['确定'] diff --git a/src/commands/post-list/delete-post.ts b/src/cmd/post-list/delete-post.ts similarity index 84% rename from src/commands/post-list/delete-post.ts rename to src/cmd/post-list/delete-post.ts index cf4721b2..c7f90a53 100644 --- a/src/commands/post-list/delete-post.ts +++ b/src/cmd/post-list/delete-post.ts @@ -1,13 +1,13 @@ import { MessageOptions, ProgressLocation, Uri, window, workspace } from 'vscode' -import { Post } from '@/models/post' -import { Alert } from '@/services/alert' -import { PostService } from '@/services/post' -import { PostFileMap, PostFileMapManager } from '@/services/post-file-map' -import { postDataProvider } from '@/tree-view-providers/post-data-provider' -import { extTreeViews } from '@/tree-view-providers/tree-view-registration' +import { Post } from '@/model/post' +import { Alert } from '@/service/alert' +import { PostService } from '@/service/post' +import { PostFileMap, PostFileMapManager } from '@/service/post-file-map' +import { postDataProvider } from '@/tree-view/provider/post-data-provider' +import { extTreeViews } from '@/tree-view/tree-view-register' import { refreshPostList } from './refresh-post-list' -import { PostTreeItem } from '@/tree-view-providers/models/post-tree-item' -import { postCategoriesDataProvider } from '@/tree-view-providers/post-categories-tree-data-provider' +import { PostTreeItem } from '@/tree-view/model/post-tree-item' +import { postCategoryDataProvider } from '@/tree-view/provider/post-category-tree-data-provider' let isDeleting = false @@ -86,7 +86,7 @@ export const deleteSelectedPost = async (arg: unknown) => { maps: selectedPost.map(p => [p.id, '']), }) await refreshPostList().catch() - postCategoriesDataProvider.onPostUpdated({ + postCategoryDataProvider.onPostUpdated({ refreshPost: true, postIds: selectedPost.map(({ id }) => id), }) diff --git a/src/commands/post-list/modify-post-settings.ts b/src/cmd/post-list/modify-post-settings.ts similarity index 66% rename from src/commands/post-list/modify-post-settings.ts rename to src/cmd/post-list/modify-post-settings.ts index 645e7f8a..6e7a474b 100644 --- a/src/commands/post-list/modify-post-settings.ts +++ b/src/cmd/post-list/modify-post-settings.ts @@ -1,16 +1,16 @@ import { Uri } from 'vscode' -import { Post } from '@/models/post' -import { Alert } from '@/services/alert' -import { PostService } from '@/services/post' -import { PostFileMapManager } from '@/services/post-file-map' -import { revealPostListItem } from '@/services/post-list-view' -import { PostCfgPanel } from '@/services/post-cfg-panel' +import { Post } from '@/model/post' +import { Alert } from '@/service/alert' +import { PostService } from '@/service/post' +import { PostFileMapManager } from '@/service/post-file-map' +import { revealPostListItem } from '@/service/post-list-view' +import { PostCfgPanel } from '@/service/post-cfg-panel' import fs from 'fs' -import { LocalDraft } from '@/services/local-draft' -import { saveFilePendingChanges } from '@/utils/save-file-pending-changes' -import { postDataProvider } from '@/tree-view-providers/post-data-provider' -import { PostTreeItem } from '@/tree-view-providers/models/post-tree-item' -import { postCategoriesDataProvider } from '@/tree-view-providers/post-categories-tree-data-provider' +import { LocalDraft } from '@/service/local-draft' +import { saveFilePendingChanges } from '@/infra/save-file-pending-changes' +import { postDataProvider } from '@/tree-view/provider/post-data-provider' +import { PostTreeItem } from '@/tree-view/model/post-tree-item' +import { postCategoryDataProvider } from '@/tree-view/provider/post-category-tree-data-provider' export const modifyPostSettings = async (input: Post | PostTreeItem | Uri) => { let post: Post | undefined @@ -42,7 +42,7 @@ export const modifyPostSettings = async (input: Post | PostTreeItem | Uri) => { successCallback: ({ id }) => { Alert.info('博文已更新') postDataProvider.fireTreeDataChangedEvent(id) - postCategoriesDataProvider.onPostUpdated({ refreshPost: false, postIds: [id] }) + postCategoryDataProvider.onPostUpdated({ refreshPost: false, postIds: [id] }) }, beforeUpdate: async post => { if (localFilePath && fs.existsSync(localFilePath)) { diff --git a/src/commands/post-list/open-post-file.ts b/src/cmd/post-list/open-post-file.ts similarity index 74% rename from src/commands/post-list/open-post-file.ts rename to src/cmd/post-list/open-post-file.ts index 1f0e898f..7d6524f2 100644 --- a/src/commands/post-list/open-post-file.ts +++ b/src/cmd/post-list/open-post-file.ts @@ -1,8 +1,8 @@ import { TextDocumentShowOptions, Uri } from 'vscode' -import { execCmd } from '@/utils/cmd' -import { Post } from '@/models/post' -import { LocalDraft } from '@/services/local-draft' -import { PostFileMapManager } from '@/services/post-file-map' +import { execCmd } from '@/infra/cmd' +import { Post } from '@/model/post' +import { LocalDraft } from '@/service/local-draft' +import { PostFileMapManager } from '@/service/post-file-map' export const openPostFile = async (post: LocalDraft | Post | string, options?: TextDocumentShowOptions) => { let filePath = '' diff --git a/src/commands/post-list/open-post-in-vscode.ts b/src/cmd/post-list/open-post-in-vscode.ts similarity index 91% rename from src/commands/post-list/open-post-in-vscode.ts rename to src/cmd/post-list/open-post-in-vscode.ts index b32e82c4..45b91ccd 100644 --- a/src/commands/post-list/open-post-in-vscode.ts +++ b/src/cmd/post-list/open-post-in-vscode.ts @@ -1,14 +1,14 @@ import fs from 'fs' import path from 'path' import { FileSystemError, MessageOptions, Uri, workspace } from 'vscode' -import { Post } from '@/models/post' -import { Alert } from '@/services/alert' -import { PostService } from '@/services/post' -import { PostFileMapManager } from '@/services/post-file-map' -import { Settings } from '@/services/settings' +import { Post } from '@/model/post' +import { Alert } from '@/service/alert' +import { PostService } from '@/service/post' +import { PostFileMapManager } from '@/service/post-file-map' +import { Settings } from '@/service/settings' import { openPostFile } from './open-post-file' -import { PostTitleSanitizer } from '@/services/post-title-sanitizer' -import { postCategoryService } from '@/services/post-category' +import { PostTitleSanitizer } from '@/service/post-title-sanitizer' +import { postCategoryService } from '@/service/post-category' import sanitizeFileName from 'sanitize-filename' const buildLocalPostFileUri = async (post: Post, includePostId = false): Promise => { diff --git a/src/commands/post-list/refresh-post-list.ts b/src/cmd/post-list/refresh-post-list.ts similarity index 91% rename from src/commands/post-list/refresh-post-list.ts rename to src/cmd/post-list/refresh-post-list.ts index 993a1c40..64dbdf69 100644 --- a/src/commands/post-list/refresh-post-list.ts +++ b/src/cmd/post-list/refresh-post-list.ts @@ -1,11 +1,11 @@ -import { globalCtx } from '@/services/global-ctx' -import { PostService } from '@/services/post' -import vscode, { window } from 'vscode' -import { postDataProvider } from '@/tree-view-providers/post-data-provider' -import { Alert } from '@/services/alert' -import { PostListState } from '@/models/post-list-state' -import { extTreeViews } from '@/tree-view-providers/tree-view-registration' -import { execCmd } from '@/utils/cmd' +import { globalCtx } from '@/service/global-ctx' +import { PostService } from '@/service/post' +import { window } from 'vscode' +import { postDataProvider } from '@/tree-view/provider/post-data-provider' +import { Alert } from '@/service/alert' +import { PostListState } from '@/model/post-list-state' +import { extTreeViews } from '@/tree-view/tree-view-register' +import { execCmd } from '@/infra/cmd' let refreshTask: Promise | null = null diff --git a/src/commands/post-list/rename-post.ts b/src/cmd/post-list/rename-post.ts similarity index 87% rename from src/commands/post-list/rename-post.ts rename to src/cmd/post-list/rename-post.ts index 38b35dfa..ccc64dc5 100644 --- a/src/commands/post-list/rename-post.ts +++ b/src/cmd/post-list/rename-post.ts @@ -1,13 +1,13 @@ import { escapeRegExp } from 'lodash-es' import path from 'path' import { MessageOptions, ProgressLocation, Uri, window, workspace } from 'vscode' -import { Post } from '@/models/post' -import { PostService } from '@/services/post' -import { PostFileMapManager } from '@/services/post-file-map' -import { postDataProvider } from '@/tree-view-providers/post-data-provider' -import { revealPostListItem } from '@/services/post-list-view' -import { PostTreeItem } from '@/tree-view-providers/models/post-tree-item' -import { Alert } from '@/services/alert' +import { Post } from '@/model/post' +import { PostService } from '@/service/post' +import { PostFileMapManager } from '@/service/post-file-map' +import { postDataProvider } from '@/tree-view/provider/post-data-provider' +import { revealPostListItem } from '@/service/post-list-view' +import { PostTreeItem } from '@/tree-view/model/post-tree-item' +import { Alert } from '@/service/alert' const renameLinkedFile = async (post: Post): Promise => { const filePath = PostFileMapManager.getFilePath(post.id) diff --git a/src/commands/post-list/search.ts b/src/cmd/post-list/search.ts similarity index 88% rename from src/commands/post-list/search.ts rename to src/cmd/post-list/search.ts index 4d1eae7e..2ae294de 100644 --- a/src/commands/post-list/search.ts +++ b/src/cmd/post-list/search.ts @@ -1,5 +1,5 @@ import { window } from 'vscode' -import { postDataProvider } from '@/tree-view-providers/post-data-provider' +import { postDataProvider } from '@/tree-view/provider/post-data-provider' export const searchPost = async () => { const searchKey = await window.showInputBox({ diff --git a/src/commands/post-list/upload-post.ts b/src/cmd/post-list/upload-post.ts similarity index 90% rename from src/commands/post-list/upload-post.ts rename to src/cmd/post-list/upload-post.ts index b5741db6..71a5d6ce 100644 --- a/src/commands/post-list/upload-post.ts +++ b/src/cmd/post-list/upload-post.ts @@ -1,21 +1,21 @@ import { Uri, workspace, window, ProgressLocation, MessageOptions } from 'vscode' -import { Post } from '@/models/post' -import { LocalDraft } from '@/services/local-draft' -import { Alert } from '@/services/alert' -import { PostService } from '@/services/post' -import { PostFileMapManager } from '@/services/post-file-map' -import { postDataProvider } from '@/tree-view-providers/post-data-provider' +import { Post } from '@/model/post' +import { LocalDraft } from '@/service/local-draft' +import { Alert } from '@/service/alert' +import { PostService } from '@/service/post' +import { PostFileMapManager } from '@/service/post-file-map' +import { postDataProvider } from '@/tree-view/provider/post-data-provider' import { openPostInVscode } from './open-post-in-vscode' import { openPostFile } from './open-post-file' -import { searchPostByTitle } from '@/services/search-post-by-title' +import { searchPostByTitle } from '@/service/search-post-by-title' import * as path from 'path' import { refreshPostList } from './refresh-post-list' -import { PostEditDto } from '@/models/post-edit-dto' -import { PostCfgPanel } from '@/services/post-cfg-panel' -import { saveFilePendingChanges } from '@/utils/save-file-pending-changes' -import { extractImages } from '../extract-images' -import { Settings } from '@/services/settings' -import { PostTreeItem } from '@/tree-view-providers/models/post-tree-item' +import { PostEditDto } from '@/model/post-edit-dto' +import { PostCfgPanel } from '@/service/post-cfg-panel' +import { saveFilePendingChanges } from '@/infra/save-file-pending-changes' +import { extractImages } from '@/cmd/extract-img' +import { Settings } from '@/service/settings' +import { PostTreeItem } from '@/tree-view/model/post-tree-item' const parseFileUri = async (fileUri: Uri | undefined): Promise => { if (fileUri && fileUri.scheme !== 'file') { diff --git a/src/commands/pull-post-remote-updates.ts b/src/cmd/pull-post-remote-updates.ts similarity index 85% rename from src/commands/pull-post-remote-updates.ts rename to src/cmd/pull-post-remote-updates.ts index 66549030..14c03212 100644 --- a/src/commands/pull-post-remote-updates.ts +++ b/src/cmd/pull-post-remote-updates.ts @@ -1,16 +1,16 @@ import { MessageOptions, Uri, window, workspace } from 'vscode' -import { Post } from '@/models/post' -import { PostFileMapManager } from '@/services/post-file-map' +import { Post } from '@/model/post' +import { PostFileMapManager } from '@/service/post-file-map' import { openPostInVscode } from './post-list/open-post-in-vscode' import fs from 'fs' -import { PostService } from '@/services/post' -import { Alert } from '@/services/alert' +import { PostService } from '@/service/post' +import { Alert } from '@/service/alert' import path from 'path' -import { revealPostListItem } from '@/services/post-list-view' -import { PostTreeItem } from '@/tree-view-providers/models/post-tree-item' -import { Settings } from '@/services/settings' +import { revealPostListItem } from '@/service/post-list-view' +import { PostTreeItem } from '@/tree-view/model/post-tree-item' +import { Settings } from '@/service/settings' -const pullPostRemoteUpdates = async (input: Post | PostTreeItem | Uri | undefined | null): Promise => { +export async function pullPostRemoteUpdates(input: Post | PostTreeItem | Uri | undefined | null) { const ctxs: CmdCtx[] = [] let uri: Uri | undefined input = input instanceof PostTreeItem ? input.post : input @@ -36,8 +36,6 @@ const pullPostRemoteUpdates = async (input: Post | PostTreeItem | Uri | undefine void Alert.info(`本地文件${resolveFileNames(ctxs)}已更新`) } -export { pullPostRemoteUpdates } - type InputType = Post | Uri | undefined | null type CmdCtx = { postId: number; fileUri: Uri } diff --git a/src/commands/reveal-local-post-file-in-os.ts b/src/cmd/reveal-local-post-file-in-os.ts similarity index 66% rename from src/commands/reveal-local-post-file-in-os.ts rename to src/cmd/reveal-local-post-file-in-os.ts index e031ae48..3fc23734 100644 --- a/src/commands/reveal-local-post-file-in-os.ts +++ b/src/cmd/reveal-local-post-file-in-os.ts @@ -1,7 +1,7 @@ import { Uri } from 'vscode' -import { execCmd } from '@/utils/cmd' -import { Post } from '@/models/post' -import { PostFileMapManager } from '@/services/post-file-map' +import { execCmd } from '@/infra/cmd' +import { Post } from '@/model/post' +import { PostFileMapManager } from '@/service/post-file-map' export const revealLocalPostFileInOs = (post: Post) => { if (!post) return diff --git a/src/commands/reveal-workspace-in-os.ts b/src/cmd/reveal-workspace-in-os.ts similarity index 59% rename from src/commands/reveal-workspace-in-os.ts rename to src/cmd/reveal-workspace-in-os.ts index e9957454..6eb9a333 100644 --- a/src/commands/reveal-workspace-in-os.ts +++ b/src/cmd/reveal-workspace-in-os.ts @@ -1,5 +1,5 @@ import { commands } from 'vscode' -import { execCmd } from '@/utils/cmd' -import { Settings } from '@/services/settings' +import { execCmd } from '@/infra/cmd' +import { Settings } from '@/service/settings' export const revealWorkspaceInOs = () => execCmd('revealFileInOS', Settings.workspaceUri) diff --git a/src/commands/set-workspace.ts b/src/cmd/set-workspace.ts similarity index 86% rename from src/commands/set-workspace.ts rename to src/cmd/set-workspace.ts index 91d5870b..79de0a55 100644 --- a/src/commands/set-workspace.ts +++ b/src/cmd/set-workspace.ts @@ -1,6 +1,6 @@ import { window } from 'vscode' -import { Alert } from '@/services/alert' -import { Settings } from '@/services/settings' +import { Alert } from '@/service/alert' +import { Settings } from '@/service/settings' export const setWorkspace = async () => { const uris = diff --git a/src/commands/show-local-file-to-post-info.ts b/src/cmd/show-local-file-to-post-info.ts similarity index 91% rename from src/commands/show-local-file-to-post-info.ts rename to src/cmd/show-local-file-to-post-info.ts index 04bc5ad4..9f2691ae 100644 --- a/src/commands/show-local-file-to-post-info.ts +++ b/src/cmd/show-local-file-to-post-info.ts @@ -1,10 +1,10 @@ import path from 'path' import { MessageOptions, Uri, window } from 'vscode' -import { Alert } from '@/services/alert' -import { PostService } from '@/services/post' -import { postCategoryService } from '@/services/post-category' -import { PostFileMapManager } from '@/services/post-file-map' -import { searchPostByTitle } from '@/services/search-post-by-title' +import { Alert } from '@/service/alert' +import { PostService } from '@/service/post' +import { postCategoryService } from '@/service/post-category' +import { PostFileMapManager } from '@/service/post-file-map' +import { searchPostByTitle } from '@/service/search-post-by-title' import { viewPostOnline } from './view-post-online' import format from 'date-fns/format' diff --git a/src/commands/upload-image/upload-clipboard-image.ts b/src/cmd/upload-img/upload-clipboard-img.ts similarity index 68% rename from src/commands/upload-image/upload-clipboard-image.ts rename to src/cmd/upload-img/upload-clipboard-img.ts index edf168d2..720ee7b4 100644 --- a/src/commands/upload-image/upload-clipboard-image.ts +++ b/src/cmd/upload-img/upload-clipboard-img.ts @@ -1,22 +1,22 @@ import fs from 'fs' import { ProgressLocation, Uri, window, workspace } from 'vscode' -import { Alert } from '@/services/alert' -import { ImageService } from '@/services/image' -import getClipboardImage from '@/utils/get-clipboard-image' +import { Alert } from '@/service/alert' +import { ImgService } from '@/service/img' +import getClipboardImage from '@/infra/get-clipboard-img' const noImagePath = 'no image' export const uploadImageFromClipboard = async () => { const clipboardImage = await getClipboardImage() if (clipboardImage.imgPath === noImagePath) { - Alert.warn('剪贴板中没有找到图片') + void Alert.warn('剪贴板中没有找到图片') return } try { return await window.withProgress({ title: '正在上传图片', location: ProgressLocation.Notification }, p => { p.report({ increment: 10 }) - return ImageService.upload(fs.createReadStream(clipboardImage.imgPath)) + return ImgService.upload(fs.createReadStream(clipboardImage.imgPath)) }) } finally { if (!clipboardImage.shouldKeepAfterUploading) await workspace.fs.delete(Uri.file(clipboardImage.imgPath)) diff --git a/src/commands/upload-image/upload-local-disk-image.ts b/src/cmd/upload-img/upload-fs-img.ts similarity index 85% rename from src/commands/upload-image/upload-local-disk-image.ts rename to src/cmd/upload-img/upload-fs-img.ts index fb61f273..489b6bae 100644 --- a/src/commands/upload-image/upload-local-disk-image.ts +++ b/src/cmd/upload-img/upload-fs-img.ts @@ -1,8 +1,8 @@ import { ProgressLocation, window } from 'vscode' -import { ImageService } from '@/services/image' +import { ImgService } from '@/service/img' import fs from 'fs' -export const uploadLocalDiskImage = async () => { +export const uploadFsImage = async () => { const imageFileUri = ((await window.showOpenDialog({ title: '选择要上传的图片(图片最大不能超过20M)', canSelectMany: false, @@ -25,7 +25,7 @@ export const uploadLocalDiskImage = async () => { }) const readStream = fs.createReadStream(imageFilePath) try { - return await ImageService.upload(readStream) + return await ImgService.upload(readStream) } finally { p.report({ increment: 100, diff --git a/src/commands/upload-image/upload-image-utils.ts b/src/cmd/upload-img/upload-img-util.ts similarity index 93% rename from src/commands/upload-image/upload-image-utils.ts rename to src/cmd/upload-img/upload-img-util.ts index 2fa894d3..c526484c 100644 --- a/src/commands/upload-image/upload-image-utils.ts +++ b/src/cmd/upload-img/upload-img-util.ts @@ -1,6 +1,6 @@ import { env, MessageOptions, SnippetString, window } from 'vscode' -import { formatImageLink } from '@/utils/format-image-link' -import { Alert } from '@/services/alert' +import { formatImageLink } from '@/infra/fmt-img-link' +import { Alert } from '@/service/alert' /** * 显示上传成功对话框, 支持复制不同格式的图片链接 diff --git a/src/commands/upload-image/upload-image.ts b/src/cmd/upload-img/upload-img.ts similarity index 78% rename from src/commands/upload-image/upload-image.ts rename to src/cmd/upload-img/upload-img.ts index c8fa7d69..ab60fd7c 100644 --- a/src/commands/upload-image/upload-image.ts +++ b/src/cmd/upload-img/upload-img.ts @@ -1,8 +1,7 @@ -import { Alert } from '@/services/alert' -import { window } from 'vscode' -import { uploadImageFromClipboard } from './upload-clipboard-image' -import { insertImageLinkToActiveEditor, showUploadSuccessModel } from './upload-image-utils' -import { uploadLocalDiskImage } from './upload-local-disk-image' +import { Alert } from '@/service/alert' +import { uploadImageFromClipboard } from './upload-clipboard-img' +import { insertImageLinkToActiveEditor, showUploadSuccessModel } from './upload-img-util' +import { uploadFsImage } from './upload-fs-img' export const uploadImage = async (autoInsertToActiveEditor = true, from?: 'local' | 'clipboard') => { const options = ['本地图片文件', '剪贴板图片'] @@ -23,7 +22,7 @@ export const uploadImage = async (autoInsertToActiveEditor = true, from?: 'local switch (selected) { case 'local': case options[0]: - imageUrl = await uploadLocalDiskImage().catch(caughtFailedUpload) + imageUrl = await uploadFsImage().catch(caughtFailedUpload) break case 'clipboard': case options[1]: diff --git a/src/commands/view-post-online.ts b/src/cmd/view-post-online.ts similarity index 68% rename from src/commands/view-post-online.ts rename to src/cmd/view-post-online.ts index 3f179acb..8d66b8b6 100644 --- a/src/commands/view-post-online.ts +++ b/src/cmd/view-post-online.ts @@ -1,9 +1,9 @@ import { Uri, window } from 'vscode' -import { execCmd } from '@/utils/cmd' -import { Post } from '@/models/post' -import { PostService } from '@/services/post' -import { PostFileMapManager } from '@/services/post-file-map' -import { PostTreeItem } from '@/tree-view-providers/models/post-tree-item' +import { execCmd } from '@/infra/cmd' +import { Post } from '@/model/post' +import { PostService } from '@/service/post' +import { PostFileMapManager } from '@/service/post-file-map' +import { PostTreeItem } from '@/tree-view/model/post-tree-item' export const viewPostOnline = async (input?: Post | PostTreeItem | Uri) => { let post: Post | undefined = input instanceof Post ? input : input instanceof PostTreeItem ? input.post : undefined diff --git a/src/commands/ing/ing-list-cmd-register.ts b/src/commands/ing/ing-list-cmd-register.ts deleted file mode 100644 index be9f4388..00000000 --- a/src/commands/ing/ing-list-cmd-register.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { RefreshingList } from 'src/commands/ing/refresh-ing-list' -import { globalCtx } from 'src/services/global-ctx' -import { GotoingListFirstPage, GotoingListNextPage, GotoingListPreviousPage } from 'src/commands/ing/goto-ing-list-page' -import { SwitchIngType } from '@/commands/ing/select-ing-type' -import { OpenIngInBrowser } from '@/commands/ing/open-ing-in-browser' -import { regCmd } from '@/utils/cmd' - -export const regIngListCmds = () => { - const appName = globalCtx.extName - - return [ - regCmd(`${appName}.ing-list.refresh`, () => new RefreshingList().handle()), - regCmd(`${appName}.ing-list.next`, () => new GotoingListNextPage().handle()), - regCmd(`${appName}.ing-list.previous`, () => new GotoingListPreviousPage().handle()), - regCmd(`${appName}.ing-list.first`, () => new GotoingListFirstPage().handle()), - regCmd(`${appName}.ing-list.switch-type`, () => new SwitchIngType().handle()), - regCmd(`${appName}.ing-list.open-in-browser`, () => new OpenIngInBrowser().handle()), - ] -} diff --git a/src/commands/ing/open-ing-in-browser.ts b/src/commands/ing/open-ing-in-browser.ts deleted file mode 100644 index dadebabe..00000000 --- a/src/commands/ing/open-ing-in-browser.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { CmdHandler } from '@/commands/cmd-handler' -import { execCmd } from '@/utils/cmd' -import { globalCtx } from '@/services/global-ctx' -import { Uri } from 'vscode' - -export class OpenIngInBrowser implements CmdHandler { - async handle(): Promise { - await execCmd('vscode.open', Uri.parse(globalCtx.config.ingSite)) - } -} diff --git a/src/commands/ing/select-ing-type.ts b/src/commands/ing/select-ing-type.ts deleted file mode 100644 index 6c76feeb..00000000 --- a/src/commands/ing/select-ing-type.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { CmdHandler } from '@/commands/cmd-handler' -import { IngType, IngTypesMetadata } from '@/models/ing' -import { getIngListWebviewProvider } from '@/services/ing-list-webview-provider' -import { QuickPickItem, window } from 'vscode' - -export class SwitchIngType implements CmdHandler { - handle(): Promise { - const options: (QuickPickItem & { ingType: IngType })[] = IngTypesMetadata.map( - ([ingType, { displayName, description }]) => ({ - label: displayName, - ingType: ingType, - description: description, - picked: ingType === getIngListWebviewProvider().ingType, - }) - ) - const quickPick = window.createQuickPick<(typeof options)[0]>() - - quickPick.title = '选择闪存类型' - quickPick.items = options - quickPick.canSelectMany = false - quickPick.activeItems = options.filter(x => x.picked) - quickPick.selectedItems = quickPick.activeItems - quickPick.ignoreFocusOut = false - - const disposables = [quickPick] - - quickPick.onDidChangeSelection( - ([selectedItem]) => { - if (selectedItem) { - quickPick.hide() - return getIngListWebviewProvider().refreshingList({ - pageIndex: 1, - ingType: selectedItem.ingType, - }) - } - }, - undefined, - disposables - ) - quickPick.onDidHide(() => disposables.forEach(d => d.dispose()), undefined, disposables) - quickPick.show() - - return Promise.resolve() - } -} diff --git a/src/commands/post-category/refresh-post-categories-list.ts b/src/commands/post-category/refresh-post-categories-list.ts deleted file mode 100644 index f8a34643..00000000 --- a/src/commands/post-category/refresh-post-categories-list.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { postCategoriesDataProvider } from '@/tree-view-providers/post-categories-tree-data-provider' - -export const refreshPostCategoriesList = () => { - postCategoriesDataProvider.refresh() -} diff --git a/src/extension.ts b/src/extension.ts index 132506d2..1249e178 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -1,19 +1,15 @@ -import { setupExtTreeView } from '@/tree-view-providers/tree-view-registration' -import { setupExtCmd } from '@/commands/cmd-register' -import { globalCtx } from '@/services/global-ctx' -// The module 'vscode' contains the VS Code extensibility API -// Import the module and reference it with the alias vscode in your code below +import { setupExtTreeView } from '@/tree-view/tree-view-register' +import { setupExtCmd } from '@/setup/setup-cmd' +import { globalCtx } from '@/service/global-ctx' import { window, ExtensionContext } from 'vscode' import { accountManager } from '@/auth/account-manager' -import { watchCfgUpdate, watchWorkspaceFileUpdate, watchWorkspaceUpdate } from '@/services/check-workspace' -import { extUriHandler } from '@/utils/uri-handler' +import { setupWorkspaceWatch, setupCfgWatch, setupWorkspaceFileWatch } from '@/setup/setup-watch' +import { extUriHandler } from '@/infra/uri-handler' import { extendMarkdownIt } from '@/markdown/extend-markdownIt' -import { Settings } from '@/services/settings' -import { getIngListWebviewProvider } from '@/services/ing-list-webview-provider' -import { setupUi } from '@/services/setup-ui' +import { Settings } from '@/service/settings' +import { getIngListWebviewProvider } from '@/service/ing-list-webview-provider' +import { setupUi } from '@/setup/setup-ui' -// this method is called when your extension is activated -// your extension is activated the very first time the commands is executed export function activate(ctx: ExtensionContext) { globalCtx.extCtx = ctx @@ -23,13 +19,12 @@ export function activate(ctx: ExtensionContext) { setupExtTreeView() ctx.subscriptions.push( - window.registerWebviewViewProvider(getIngListWebviewProvider().viewId, getIngListWebviewProvider()) + window.registerWebviewViewProvider(getIngListWebviewProvider().viewId, getIngListWebviewProvider()), + setupCfgWatch(), + setupWorkspaceWatch(), + setupWorkspaceFileWatch() ) - watchCfgUpdate() - watchWorkspaceUpdate() - watchWorkspaceFileUpdate() - Settings.migrateEnablePublishSelectionToIng().catch(console.warn) window.registerUriHandler(extUriHandler) @@ -41,6 +36,6 @@ export function activate(ctx: ExtensionContext) { return { extendMarkdownIt } } -// this method is called when your extension is deactivated -// eslint-disable-next-line @typescript-eslint/no-empty-function -export function deactivate() {} +export function deactivate() { + return +} diff --git a/src/utils/chromium-path-provider.ts b/src/infra/chromium-path-provider.ts similarity index 95% rename from src/utils/chromium-path-provider.ts rename to src/infra/chromium-path-provider.ts index 516e5ea6..5c5165c5 100644 --- a/src/utils/chromium-path-provider.ts +++ b/src/infra/chromium-path-provider.ts @@ -2,11 +2,11 @@ import { window, ProgressLocation } from 'vscode' import fs from 'fs' import os from 'os' import path from 'path' -import { Alert } from '@/services/alert' +import { Alert } from '@/service/alert' // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-var-requires const download: (arg: Record) => Promise = require('download-chromium') -namespace ChromiumPathProvider { +export namespace ChromiumPathProvider { export const defaultChromiumPath = { osx: [`${os.homedir()}/Applications/Google Chrome.app`, '/Applications/Google Chrome.app'], win: ['C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe'], @@ -74,7 +74,7 @@ namespace ChromiumPathProvider { } } ) - if (chromiumPath) Alert.info(`Chromium已下载至${chromiumPath}`) + if (chromiumPath) void Alert.info(`Chromium已下载至${chromiumPath}`) return chromiumPath } @@ -84,5 +84,3 @@ namespace ChromiumPathProvider { [downloadFromInternetTitle, ChromiumPathProvider.downloadFromInternet], ] } - -export { ChromiumPathProvider } diff --git a/src/utils/cmd.ts b/src/infra/cmd.ts similarity index 100% rename from src/utils/cmd.ts rename to src/infra/cmd.ts diff --git a/src/utils/ingStarToText.ts b/src/infra/convert/ing-star-to-text.ts similarity index 100% rename from src/utils/ingStarToText.ts rename to src/infra/convert/ing-star-to-text.ts diff --git a/src/services/converter.ts b/src/infra/convert/object-keys-to-camel-case.ts similarity index 87% rename from src/services/converter.ts rename to src/infra/convert/object-keys-to-camel-case.ts index 797b9f1c..2c4cfae8 100644 --- a/src/services/converter.ts +++ b/src/infra/convert/object-keys-to-camel-case.ts @@ -1,4 +1,4 @@ -export const convertObjectKeysToCamelCase = (obj: T) => { +export const objectKeysToCamelCase = (obj: T) => { const anyObj = >obj const splitters = ['-', '_'] diff --git a/src/utils/fetch-client.ts b/src/infra/fetch-client.ts similarity index 73% rename from src/utils/fetch-client.ts rename to src/infra/fetch-client.ts index 730f4f89..9cebb748 100644 --- a/src/utils/fetch-client.ts +++ b/src/infra/fetch-client.ts @@ -1,4 +1,4 @@ -import httpClient from '@/utils/http-client' +import httpClient from '@/infra/http-client' import { createFetch } from 'got-fetch' const fetch = createFetch(httpClient) diff --git a/src/utils/format-image-link.ts b/src/infra/fmt-img-link.ts similarity index 100% rename from src/utils/format-image-link.ts rename to src/infra/fmt-img-link.ts diff --git a/src/utils/get-clipboard-image.ts b/src/infra/get-clipboard-img.ts similarity index 96% rename from src/utils/get-clipboard-image.ts rename to src/infra/get-clipboard-img.ts index 185cf668..fda337a4 100644 --- a/src/utils/get-clipboard-image.ts +++ b/src/infra/get-clipboard-img.ts @@ -5,9 +5,9 @@ import path from 'path' import fs from 'fs' import os from 'os' import isWsl from 'is-wsl' -import { globalCtx } from '@/services/global-ctx' -import { Alert } from '@/services/alert' -import { IClipboardImage } from '@/models/clipboard-image' +import { globalCtx } from '@/service/global-ctx' +import { Alert } from '@/service/alert' +import { IClipboardImage } from '@/model/clipboard-img' import format from 'date-fns/format' export type Platform = 'darwin' | 'win32' | 'win10' | 'linux' | 'wsl' diff --git a/src/utils/http-client.ts b/src/infra/http-client.ts similarity index 94% rename from src/utils/http-client.ts rename to src/infra/http-client.ts index a43343dc..4d31273d 100644 --- a/src/utils/http-client.ts +++ b/src/infra/http-client.ts @@ -1,7 +1,7 @@ import { accountManager } from '@/auth/account-manager' import got, { BeforeRequestHook } from 'got' import { isString } from 'lodash-es' -import { Oauth } from '@/services/oauth.api' +import { Oauth } from '@/service/oauth.api' const bearerTokenHook: BeforeRequestHook = async opt => { const { headers } = opt diff --git a/src/utils/input-post-settings.ts b/src/infra/input-post-settings.ts similarity index 96% rename from src/utils/input-post-settings.ts rename to src/infra/input-post-settings.ts index 4531e672..6b0ca0b6 100644 --- a/src/utils/input-post-settings.ts +++ b/src/infra/input-post-settings.ts @@ -1,9 +1,9 @@ import { QuickPickItem } from 'vscode' -import { AccessPermission, Post } from '@/models/post' -import { PostCategories, PostCategory } from '@/models/post-category' -import { Alert } from '@/services/alert' -import { InputFlowAction, InputStep, MultiStepInput, QuickPickParameters } from '@/services/multi-step-input' -import { postCategoryService } from '@/services/post-category' +import { AccessPermission, Post } from '@/model/post' +import { PostCategories, PostCategory } from '@/model/post-category' +import { Alert } from '@/service/alert' +import { InputFlowAction, InputStep, MultiStepInput, QuickPickParameters } from '@/service/multi-step-input' +import { postCategoryService } from '@/service/post-category' class CategoryPickItem implements QuickPickItem { label: string diff --git a/src/infra/response-err.ts b/src/infra/response-err.ts new file mode 100644 index 00000000..0752f7c0 --- /dev/null +++ b/src/infra/response-err.ts @@ -0,0 +1,50 @@ +import { GotFetchResponse } from 'got-fetch/out/lib/response' +import { Response as GotResponse } from 'got' +import { IErrorResponse, isErrorResponse } from '@/model/error-response' +import iconv from 'iconv-lite' + +export async function throwIfNotOkResponse(response: GotFetchResponse) { + if (response.ok) return + + const responseText = await response.text() + let responseJson: unknown + try { + responseJson = JSON.parse(responseText) + } catch { + // ignore + } + + if (isErrorResponse(responseJson)) { + throw Object.assign(responseJson, { statusCode: response.status } as IErrorResponse) + } else { + // eslint-disable-next-line no-throw-literal + throw { + errors: [`状态码: ${response.status}(${response.statusText})`, responseText], + type: -1, + statusCode: -1, + } as IErrorResponse + } +} + +export function throwIfNotOkGotResponse(response: GotResponse) { + if (response.ok) return + + const responseText = iconv.decode(response.rawBody, 'utf-8') + let responseJson: unknown + try { + responseJson = JSON.parse(responseText) + } catch { + // ignore + } + + if (isErrorResponse(responseJson)) { + throw Object.assign(responseJson, { statusCode: response.statusCode } as IErrorResponse) + } else { + // eslint-disable-next-line no-throw-literal + throw { + errors: [`状态码: ${response.statusCode}(${response.statusMessage})`, responseText], + type: -1, + statusCode: -1, + } as IErrorResponse + } +} diff --git a/src/utils/reveal-active-file.ts b/src/infra/reveal-active-file.ts similarity index 73% rename from src/utils/reveal-active-file.ts rename to src/infra/reveal-active-file.ts index e8772543..0d3eb6af 100644 --- a/src/utils/reveal-active-file.ts +++ b/src/infra/reveal-active-file.ts @@ -1,3 +1,3 @@ -import { execCmd } from '@/utils/cmd' +import { execCmd } from '@/infra/cmd' export const revealActiveFileInExplorer = () => execCmd('workbench.files.action.showActiveFileInExplorer') diff --git a/src/utils/save-file-pending-changes.ts b/src/infra/save-file-pending-changes.ts similarity index 100% rename from src/utils/save-file-pending-changes.ts rename to src/infra/save-file-pending-changes.ts diff --git a/src/utils/tree-view.ts b/src/infra/tree-view.ts similarity index 100% rename from src/utils/tree-view.ts rename to src/infra/tree-view.ts diff --git a/src/utils/typed-keys.ts b/src/infra/typed-keys.ts similarity index 100% rename from src/utils/typed-keys.ts rename to src/infra/typed-keys.ts diff --git a/src/utils/untildify.test.ts b/src/infra/untildify.test.ts similarity index 84% rename from src/utils/untildify.test.ts rename to src/infra/untildify.test.ts index 21000e9a..6e3dda49 100644 --- a/src/utils/untildify.test.ts +++ b/src/infra/untildify.test.ts @@ -1,4 +1,4 @@ -import { untildify } from '@/utils/untildify' +import { untildify } from '@/infra/untildify' import { homedir } from 'os' describe('untildify', () => { diff --git a/src/utils/untildify.ts b/src/infra/untildify.ts similarity index 100% rename from src/utils/untildify.ts rename to src/infra/untildify.ts diff --git a/src/utils/uri-handler.ts b/src/infra/uri-handler.ts similarity index 93% rename from src/utils/uri-handler.ts rename to src/infra/uri-handler.ts index 3a5acf46..4b98f5c8 100644 --- a/src/utils/uri-handler.ts +++ b/src/infra/uri-handler.ts @@ -1,5 +1,5 @@ import { Disposable, EventEmitter, ProviderResult, Uri, UriHandler, Event } from 'vscode' -import { openPostInVscode } from '@/commands/post-list/open-post-in-vscode' +import { openPostInVscode } from '@/cmd/post-list/open-post-in-vscode' class ExtUriHandler implements UriHandler, Disposable { private _uriEventEmitter?: EventEmitter diff --git a/src/markdown/extend-markdownIt.ts b/src/markdown/extend-markdownIt.ts index 11060c06..e9167dd8 100644 --- a/src/markdown/extend-markdownIt.ts +++ b/src/markdown/extend-markdownIt.ts @@ -1,4 +1,4 @@ -import { Settings } from '@/services/settings' +import { Settings } from '@/service/settings' import { HighlightCodeLinesPlugin, MultilineBlockquotePlugin } from '@cnblogs/markdown-it-presets' import type { MarkdownIt } from '@cnblogs/markdown-it-presets' diff --git a/src/models/blog-export.ts b/src/model/blog-export.ts similarity index 100% rename from src/models/blog-export.ts rename to src/model/blog-export.ts diff --git a/src/models/blog-export/export-post.ts b/src/model/blog-export/export-post.ts similarity index 82% rename from src/models/blog-export/export-post.ts rename to src/model/blog-export/export-post.ts index 83cc23f2..d7a72a1b 100644 --- a/src/models/blog-export/export-post.ts +++ b/src/model/blog-export/export-post.ts @@ -1,4 +1,4 @@ -import { Post } from '@/models/post' +import { Post } from '@/model/post' import { Model } from 'sequelize' export type PostType = 'BlogPost' | 'Message' @@ -13,4 +13,4 @@ export type ExportPost = Pick< export class ExportPostModel extends Model {} -export { Post } from '@/models/post' +export { Post } from '@/model/post' diff --git a/src/models/blog-settings.ts b/src/model/blog-settings.ts similarity index 100% rename from src/models/blog-settings.ts rename to src/model/blog-settings.ts diff --git a/src/models/clipboard-image.ts b/src/model/clipboard-img.ts similarity index 100% rename from src/models/clipboard-image.ts rename to src/model/clipboard-img.ts diff --git a/src/models/config.ts b/src/model/config.ts similarity index 100% rename from src/models/config.ts rename to src/model/config.ts diff --git a/src/models/error-response.ts b/src/model/error-response.ts similarity index 100% rename from src/models/error-response.ts rename to src/model/error-response.ts diff --git a/src/models/image-upload-status.ts b/src/model/img-upload-status.ts similarity index 64% rename from src/models/image-upload-status.ts rename to src/model/img-upload-status.ts index fb1986f8..1fa273ac 100644 --- a/src/models/image-upload-status.ts +++ b/src/model/img-upload-status.ts @@ -4,10 +4,10 @@ enum ImageUploadStatusId { failed, } -interface ImageUploadStatus { +interface ImgUploadStatus { id: ImageUploadStatusId imageUrl?: string errors?: string[] } -export { ImageUploadStatusId, ImageUploadStatus } +export { ImageUploadStatusId, ImgUploadStatus } diff --git a/src/models/ing-view.ts b/src/model/ing-view.ts similarity index 100% rename from src/models/ing-view.ts rename to src/model/ing-view.ts diff --git a/src/models/ing.ts b/src/model/ing.ts similarity index 100% rename from src/models/ing.ts rename to src/model/ing.ts diff --git a/src/models/page-model.ts b/src/model/page-model.ts similarity index 100% rename from src/models/page-model.ts rename to src/model/page-model.ts diff --git a/src/models/post-category.ts b/src/model/post-category.ts similarity index 100% rename from src/models/post-category.ts rename to src/model/post-category.ts diff --git a/src/models/post-cfg.ts b/src/model/post-cfg.ts similarity index 100% rename from src/models/post-cfg.ts rename to src/model/post-cfg.ts diff --git a/src/models/post-edit-dto.ts b/src/model/post-edit-dto.ts similarity index 100% rename from src/models/post-edit-dto.ts rename to src/model/post-edit-dto.ts diff --git a/src/models/post-list-state.ts b/src/model/post-list-state.ts similarity index 100% rename from src/models/post-list-state.ts rename to src/model/post-list-state.ts diff --git a/src/models/post-tag.ts b/src/model/post-tag.ts similarity index 100% rename from src/models/post-tag.ts rename to src/model/post-tag.ts diff --git a/src/models/post-updated-response.ts b/src/model/post-updated-response.ts similarity index 100% rename from src/models/post-updated-response.ts rename to src/model/post-updated-response.ts diff --git a/src/models/post.ts b/src/model/post.ts similarity index 100% rename from src/models/post.ts rename to src/model/post.ts diff --git a/src/models/site-category.ts b/src/model/site-category.ts similarity index 100% rename from src/models/site-category.ts rename to src/model/site-category.ts diff --git a/src/models/token-info.ts b/src/model/token-info.ts similarity index 100% rename from src/models/token-info.ts rename to src/model/token-info.ts diff --git a/src/models/webview-cmd.ts b/src/model/webview-cmd.ts similarity index 96% rename from src/models/webview-cmd.ts rename to src/model/webview-cmd.ts index fba945cf..f1efcc02 100644 --- a/src/models/webview-cmd.ts +++ b/src/model/webview-cmd.ts @@ -1,4 +1,4 @@ -import { PostCategories } from '@/models/post-category' +import { PostCategories } from '@/model/post-category' export namespace WebviewCmd { export enum UiCmd { diff --git a/src/models/webview-msg.ts b/src/model/webview-msg.ts similarity index 93% rename from src/models/webview-msg.ts rename to src/model/webview-msg.ts index 365f8ca0..49fd2b14 100644 --- a/src/models/webview-msg.ts +++ b/src/model/webview-msg.ts @@ -5,7 +5,7 @@ import { PostCategories } from './post-category' import { SiteCategories } from './site-category' import { PostTags } from './post-tag' import { IErrorResponse as ErrorResponse } from './error-response' -import { ImageUploadStatus } from './image-upload-status' +import { ImgUploadStatus } from './img-upload-status' export namespace webviewMessage { export interface Message { @@ -40,7 +40,7 @@ export namespace webviewMessage { export interface UpdateImageUpdateStatusMessage extends Message { imageId: string - status: ImageUploadStatus + status: ImgUploadStatus } export interface SetFluentIconBaseUrlMessage extends Message { diff --git a/src/models/zzk-search-result.ts b/src/model/zzk-search-result.ts similarity index 100% rename from src/models/zzk-search-result.ts rename to src/model/zzk-search-result.ts diff --git a/src/services/alert.ts b/src/service/alert.ts similarity index 100% rename from src/services/alert.ts rename to src/service/alert.ts diff --git a/src/services/blog-export-post.store.ts b/src/service/blog-export-post.store.ts similarity index 96% rename from src/services/blog-export-post.store.ts rename to src/service/blog-export-post.store.ts index 7921283a..ca8ac0ca 100644 --- a/src/services/blog-export-post.store.ts +++ b/src/service/blog-export-post.store.ts @@ -1,5 +1,5 @@ -import { DownloadedBlogExport } from '@/models/blog-export' -import { ExportPost, ExportPostModel } from '@/models/blog-export/export-post' +import { DownloadedBlogExport } from '@/model/blog-export' +import { ExportPost, ExportPostModel } from '@/model/blog-export/export-post' import { DataTypes, Op, Sequelize } from 'sequelize' import { Disposable } from 'vscode' import sqlite3 from 'sqlite3' diff --git a/src/services/blog-export-records.store.ts b/src/service/blog-export-records.store.ts similarity index 89% rename from src/services/blog-export-records.store.ts rename to src/service/blog-export-records.store.ts index b924213e..0a2831c3 100644 --- a/src/services/blog-export-records.store.ts +++ b/src/service/blog-export-records.store.ts @@ -1,5 +1,5 @@ -import { BlogExportRecordList } from '@/models/blog-export' -import { BlogExportApi } from '@/services/blog-export.api' +import { BlogExportRecordList } from '@/model/blog-export' +import { BlogExportApi } from '@/service/blog-export.api' export class BlogExportRecordsStore { private _cachedList: Promise | null = null diff --git a/src/services/blog-export.api.ts b/src/service/blog-export.api.ts similarity index 91% rename from src/services/blog-export.api.ts rename to src/service/blog-export.api.ts index c2850c16..1a25729c 100644 --- a/src/services/blog-export.api.ts +++ b/src/service/blog-export.api.ts @@ -1,6 +1,6 @@ -import { BlogExportRecord, BlogExportRecordList } from '@/models/blog-export' -import { globalCtx } from '@/services/global-ctx' -import got from '@/utils/http-client' +import { BlogExportRecord, BlogExportRecordList } from '@/model/blog-export' +import { globalCtx } from '@/service/global-ctx' +import got from '@/infra/http-client' const basePath = `${globalCtx.config.apiBaseUrl}/api/blogExports` const downloadOrigin = 'https://export.cnblogs.com' diff --git a/src/services/blog-settings.ts b/src/service/blog-settings.ts similarity index 92% rename from src/services/blog-settings.ts rename to src/service/blog-settings.ts index f97f73be..393ed855 100644 --- a/src/services/blog-settings.ts +++ b/src/service/blog-settings.ts @@ -1,5 +1,5 @@ -import fetch from '@/utils/fetch-client' -import { BlogSettings, BlogSiteDto, BlogSiteExtendDto } from '@/models/blog-settings' +import fetch from '@/infra/fetch-client' +import { BlogSettings, BlogSiteDto, BlogSiteExtendDto } from '@/model/blog-settings' import { globalCtx } from './global-ctx' let settingCache: BlogSettings | null = null diff --git a/src/services/code-challenge.ts b/src/service/code-challenge.ts similarity index 100% rename from src/services/code-challenge.ts rename to src/service/code-challenge.ts diff --git a/src/services/downloaded-export.store.ts b/src/service/downloaded-export.store.ts similarity index 96% rename from src/services/downloaded-export.store.ts rename to src/service/downloaded-export.store.ts index 555ce054..1d4f4fed 100644 --- a/src/services/downloaded-export.store.ts +++ b/src/service/downloaded-export.store.ts @@ -1,5 +1,5 @@ -import { DownloadedBlogExport } from '@/models/blog-export' -import { globalCtx } from '@/services/global-ctx' +import { DownloadedBlogExport } from '@/model/blog-export' +import { globalCtx } from '@/service/global-ctx' import { exists, existsSync } from 'fs' import { take } from 'lodash-es' import { promisify } from 'util' diff --git a/src/services/global-ctx.ts b/src/service/global-ctx.ts similarity index 98% rename from src/services/global-ctx.ts rename to src/service/global-ctx.ts index 8feaa24b..c9459a9e 100644 --- a/src/services/global-ctx.ts +++ b/src/service/global-ctx.ts @@ -1,5 +1,5 @@ import { env, ExtensionContext, Uri } from 'vscode' -import { defaultConfig, devConfig, IExtensionConfig, isDevEnv } from '@/models/config' +import { defaultConfig, devConfig, IExtensionConfig, isDevEnv } from '@/model/config' import path from 'path' export class GlobalCtx { diff --git a/src/services/image.ts b/src/service/img.ts similarity index 95% rename from src/services/image.ts rename to src/service/img.ts index 7ae7f424..78162048 100644 --- a/src/services/image.ts +++ b/src/service/img.ts @@ -1,10 +1,10 @@ import { globalCtx } from './global-ctx' import { Readable } from 'stream' import { isString, merge, pick } from 'lodash-es' -import httpClient from '@/utils/http-client' +import httpClient from '@/infra/http-client' import path from 'path' -export namespace ImageService { +export namespace ImgService { export async function upload< T extends Readable & { name?: string diff --git a/src/services/ing-list-webview-provider.ts b/src/service/ing-list-webview-provider.ts similarity index 92% rename from src/services/ing-list-webview-provider.ts rename to src/service/ing-list-webview-provider.ts index 03dddc52..1d2d9b11 100644 --- a/src/services/ing-list-webview-provider.ts +++ b/src/service/ing-list-webview-provider.ts @@ -1,4 +1,4 @@ -import { globalCtx } from 'src/services/global-ctx' +import { globalCtx } from '@/service/global-ctx' import { CancellationToken, Disposable, @@ -8,17 +8,17 @@ import { WebviewViewResolveContext, window, } from 'vscode' -import { parseWebviewHtml } from 'src/services/parse-webview-html' -import { IngWebviewHostCmd, IngWebviewUiCmd, WebviewCmd } from 'src/models/webview-cmd' -import { IngApi } from 'src/services/ing.api' -import { IngAppState } from 'src/models/ing-view' -import { IngType, IngTypesMetadata } from 'src/models/ing' +import { parseWebviewHtml } from '@/service/parse-webview-html' +import { IngWebviewHostCmd, IngWebviewUiCmd, WebviewCmd } from '@/model/webview-cmd' +import { IngApi } from '@/service/ing.api' +import { IngAppState } from '@/model/ing-view' +import { IngType, IngTypesMetadata } from '@/model/ing' import { isNumber } from 'lodash-es' -import { CommentIngCmdHandler } from '@/commands/ing/comment-ing' -import { execCmd } from '@/utils/cmd' -import { ingStarToText } from '@/utils/ingStarToText' -import { Settings } from '@/services/settings' -import { isDisableIngUserAvatar, isEnableTextIngStar } from '@/services/setup-ui' +import { CommentIngCmdHandler } from '@/cmd/ing/comment-ing' +import { execCmd } from '@/infra/cmd' +import { ingStarToText } from '@/infra/convert/ing-star-to-text' +import { Settings } from '@/service/settings' +import { isDisableIngUserAvatar, isEnableTextIngStar } from '@/setup/setup-ui' export class IngListWebviewProvider implements WebviewViewProvider { readonly viewId = `${globalCtx.extName}.ing-list-webview` diff --git a/src/services/ing.api.ts b/src/service/ing.api.ts similarity index 96% rename from src/services/ing.api.ts rename to src/service/ing.api.ts index 0c2b8843..5e1b08c2 100644 --- a/src/services/ing.api.ts +++ b/src/service/ing.api.ts @@ -1,7 +1,7 @@ -import { Ing, IngComment, IngPublishModel, IngType } from '@/models/ing' -import { Alert } from '@/services/alert' -import { globalCtx } from '@/services/global-ctx' -import fetch from '@/utils/fetch-client' +import { Ing, IngComment, IngPublishModel, IngType } from '@/model/ing' +import { Alert } from '@/service/alert' +import { globalCtx } from '@/service/global-ctx' +import fetch from '@/infra/fetch-client' import { URLSearchParams } from 'url' import { isArray, isObject } from 'lodash-es' diff --git a/src/service/is-target-workspace.ts b/src/service/is-target-workspace.ts new file mode 100644 index 00000000..344b856f --- /dev/null +++ b/src/service/is-target-workspace.ts @@ -0,0 +1,23 @@ +import os from 'os' +import { workspace } from 'vscode' +import { globalCtx } from './global-ctx' +import { execCmd } from '@/infra/cmd' +import { Settings } from './settings' + +const diskSymbolRegex = /^(\S{1,5}:)(.*)/ + +export const isTargetWorkspace = (): boolean => { + const folders = workspace.workspaceFolders + let currentFolder = folders?.length === 1 ? folders[0].uri.path : undefined + let targetFolder = Settings.workspaceUri.path + const platform = os.platform() + if (platform === 'win32' && targetFolder && currentFolder) { + const replacer = (sub: string, m0: string | null | undefined, m2: string | null | undefined) => + m0 && m2 ? m0.toLowerCase() + m2 : sub + currentFolder = currentFolder.replace(diskSymbolRegex, replacer) + targetFolder = targetFolder.replace(diskSymbolRegex, replacer) + } + const isTarget = !!currentFolder && currentFolder === targetFolder + void execCmd('setContext', `${globalCtx.extName}.isTargetWorkspace`, isTarget) + return isTarget +} diff --git a/src/services/local-draft.ts b/src/service/local-draft.ts similarity index 100% rename from src/services/local-draft.ts rename to src/service/local-draft.ts diff --git a/src/services/mkd-img-extractor.ts b/src/service/mkd-img-extractor.ts similarity index 95% rename from src/services/mkd-img-extractor.ts rename to src/service/mkd-img-extractor.ts index 035725d1..bd49b389 100644 --- a/src/services/mkd-img-extractor.ts +++ b/src/service/mkd-img-extractor.ts @@ -2,8 +2,8 @@ import path from 'path' import { isString } from 'lodash-es' import fs from 'fs' import { Uri, workspace } from 'vscode' -import { ImageService } from './image' -import { isErrorResponse } from '@/models/error-response' +import { ImgService } from '@/service/img' +import { isErrorResponse } from '@/model/error-response' import { promisify } from 'util' import { Readable } from 'stream' import { tmpdir } from 'os' @@ -28,8 +28,8 @@ export interface ImageInfo { const imgTagDataUrlImgPat = /()/g const imgTagUrlImgPat = /()/gi -const mkdDataUrlImgPat = /(!\[.*?\]\()(data:image\/.*?,[a-zA-Z0-9+/]*?=?=?)(\))/g -const mkdUrlImgPat = /(!\[.*?\]\()(.*?\.(?:png|jpg|jpeg|webp|svg|gif))(\))/gi +const mkdDataUrlImgPat = /(!\[.*?]\()(data:image\/.*?,[a-zA-Z0-9+/]*?=?=?)(\))/g +const mkdUrlImgPat = /(!\[.*?]\()(.*?\.(?:png|jpg|jpeg|webp|svg|gif))(\))/gi const cnblogsDomainRegExp = /\.cnblogs\.com\//gi @@ -115,7 +115,7 @@ export class MkdImgExtractor { const dstInfo = await (async () => { if (streamOrLink === undefined) return null try { - const newLink = isString(streamOrLink) ? streamOrLink : await ImageService.upload(streamOrLink) + const newLink = isString(streamOrLink) ? streamOrLink : await ImgService.upload(streamOrLink) return { ...srcInfo, @@ -175,7 +175,7 @@ export class MkdImgExtractor { private async resolveWebImg(url: string) { try { - return await ImageService.download(url) + return await ImgService.download(url) } catch (e) { // eslint-disable-next-line @typescript-eslint/restrict-template-expressions this._errors.push([url, `无法下载网络图片: ${e}`]) diff --git a/src/services/multi-step-input.ts b/src/service/multi-step-input.ts similarity index 100% rename from src/services/multi-step-input.ts rename to src/service/multi-step-input.ts diff --git a/src/services/oauth.api.ts b/src/service/oauth.api.ts similarity index 89% rename from src/services/oauth.api.ts rename to src/service/oauth.api.ts index 5e5fb59b..7ec3f875 100644 --- a/src/services/oauth.api.ts +++ b/src/service/oauth.api.ts @@ -1,12 +1,12 @@ /* eslint-disable @typescript-eslint/naming-convention */ -import { TokenInfo } from '@/models/token-info' +import { TokenInfo } from '@/model/token-info' import { AccountInfo } from '@/auth/account-info' -import { convertObjectKeysToCamelCase } from '@/services/converter' -import { globalCtx } from '@/services/global-ctx' -import fetch from '@/utils/fetch-client' -import got from '@/utils/http-client' +import { globalCtx } from '@/service/global-ctx' +import fetch from '@/infra/fetch-client' +import got from '@/infra/http-client' import { CancellationToken } from 'vscode' import { AbortController } from 'node-abort-controller' +import { objectKeysToCamelCase } from '@/infra/convert/object-keys-to-camel-case' export type UserInfoSpec = Pick & { readonly blog_id: string @@ -40,7 +40,7 @@ export namespace Oauth { }, }) - if (res.statusCode === 200) return convertObjectKeysToCamelCase(res.body) + if (res.statusCode === 200) return objectKeysToCamelCase(res.body) throw Error( `Failed to request token endpoint, ${res.statusCode}, ${res.statusMessage}, ${res.rawBody.toString()}` diff --git a/src/services/parse-webview-html.ts b/src/service/parse-webview-html.ts similarity index 88% rename from src/services/parse-webview-html.ts rename to src/service/parse-webview-html.ts index 229ed5f5..10058f34 100644 --- a/src/services/parse-webview-html.ts +++ b/src/service/parse-webview-html.ts @@ -1,5 +1,5 @@ import vscode from 'vscode' -import { globalCtx } from 'src/services/global-ctx' +import { globalCtx } from '@/service/global-ctx' export type WebviewEntryName = 'ing' | 'post-cfg' diff --git a/src/services/post-category.ts b/src/service/post-category.ts similarity index 98% rename from src/services/post-category.ts rename to src/service/post-category.ts index 2f67e1cd..158a818d 100644 --- a/src/services/post-category.ts +++ b/src/service/post-category.ts @@ -1,5 +1,5 @@ -import fetch from '@/utils/fetch-client' -import { PostCategories, PostCategory, PostCategoryAddDto } from '@/models/post-category' +import fetch from '@/infra/fetch-client' +import { PostCategories, PostCategory, PostCategoryAddDto } from '@/model/post-category' import { globalCtx } from './global-ctx' import { URLSearchParams } from 'url' diff --git a/src/services/post-cfg-panel.ts b/src/service/post-cfg-panel.ts similarity index 95% rename from src/services/post-cfg-panel.ts rename to src/service/post-cfg-panel.ts index b6b014ab..099fbeb5 100644 --- a/src/services/post-cfg-panel.ts +++ b/src/service/post-cfg-panel.ts @@ -1,18 +1,18 @@ import { cloneDeep } from 'lodash-es' import vscode, { Uri } from 'vscode' -import { Post } from '@/models/post' +import { Post } from '@/model/post' import { globalCtx } from './global-ctx' import { postCategoryService } from './post-category' import { siteCategoryService } from './site-category' import { PostTagService } from './post-tag' import { PostService } from './post' -import { isErrorResponse } from '@/models/error-response' -import { webviewMessage } from '@/models/webview-msg' -import { WebviewCommonCmd, WebviewCmd } from 'src/models/webview-cmd' -import { uploadImage } from '@/commands/upload-image/upload-image' -import { ImageUploadStatusId } from '@/models/image-upload-status' -import { openPostFile } from '@/commands/post-list/open-post-file' -import { parseWebviewHtml } from 'src/services/parse-webview-html' +import { isErrorResponse } from '@/model/error-response' +import { webviewMessage } from '@/model/webview-msg' +import { WebviewCommonCmd, WebviewCmd } from '@/model/webview-cmd' +import { uploadImage } from '@/cmd/upload-img/upload-img' +import { ImageUploadStatusId } from '@/model/img-upload-status' +import { openPostFile } from '@/cmd/post-list/open-post-file' +import { parseWebviewHtml } from '@/service/parse-webview-html' import path from 'path' const panels: Map = new Map() diff --git a/src/services/post-file-map.ts b/src/service/post-file-map.ts similarity index 89% rename from src/services/post-file-map.ts rename to src/service/post-file-map.ts index 97ae308f..228a982a 100644 --- a/src/services/post-file-map.ts +++ b/src/service/post-file-map.ts @@ -1,5 +1,5 @@ -import { postCategoriesDataProvider } from '@/tree-view-providers/post-categories-tree-data-provider' -import { postDataProvider } from '@/tree-view-providers/post-data-provider' +import { postCategoryDataProvider } from '@/tree-view/provider/post-category-tree-data-provider' +import { postDataProvider } from '@/tree-view/provider/post-data-provider' import { globalCtx } from './global-ctx' const validatePostFileMap = (map: PostFileMap) => map[0] >= 0 && !!map[1] @@ -41,7 +41,7 @@ export class PostFileMapManager { await globalCtx.storage.update(this.storageKey, maps.filter(validatePostFileMap)) if (emitEvent) { postDataProvider.fireTreeDataChangedEvent(postId) - postCategoriesDataProvider.onPostUpdated({ refreshPost: false, postIds: [postId] }) + postCategoryDataProvider.onPostUpdated({ refreshPost: false, postIds: [postId] }) } } diff --git a/src/services/post-list-view.ts b/src/service/post-list-view.ts similarity index 69% rename from src/services/post-list-view.ts rename to src/service/post-list-view.ts index 3f9646c7..a7b686f6 100644 --- a/src/services/post-list-view.ts +++ b/src/service/post-list-view.ts @@ -1,5 +1,5 @@ -import { Post } from '@/models/post' -import { extTreeViews } from '@/tree-view-providers/tree-view-registration' +import { Post } from '@/model/post' +import { extTreeViews } from '@/tree-view/tree-view-register' export const revealPostListItem = async ( post: Post, diff --git a/src/services/post-tag.ts b/src/service/post-tag.ts similarity index 90% rename from src/services/post-tag.ts rename to src/service/post-tag.ts index 6c46e856..958f4759 100644 --- a/src/services/post-tag.ts +++ b/src/service/post-tag.ts @@ -1,5 +1,5 @@ -import got from '@/utils/http-client' -import { PostTag } from '@/models/post-tag' +import got from '@/infra/http-client' +import { PostTag } from '@/model/post-tag' import { globalCtx } from './global-ctx' let cachedTags: PostTag[] | null = null diff --git a/src/services/post-title-sanitizer.ts b/src/service/post-title-sanitizer.ts similarity index 98% rename from src/services/post-title-sanitizer.ts rename to src/service/post-title-sanitizer.ts index 6a7693f5..cea14acc 100644 --- a/src/services/post-title-sanitizer.ts +++ b/src/service/post-title-sanitizer.ts @@ -1,6 +1,6 @@ import path from 'path' import sanitizeFilename from 'sanitize-filename' -import { Post } from '@/models/post' +import { Post } from '@/model/post' import { globalCtx } from './global-ctx' import { PostFileMapManager } from './post-file-map' diff --git a/src/services/post.ts b/src/service/post.ts similarity index 90% rename from src/services/post.ts rename to src/service/post.ts index 33511908..56196853 100644 --- a/src/services/post.ts +++ b/src/service/post.ts @@ -1,17 +1,17 @@ -import fetch from '@/utils/fetch-client' -import { Post } from '@/models/post' +import fetch from '@/infra/fetch-client' +import { Post } from '@/model/post' import { globalCtx } from './global-ctx' -import { PageModel } from '@/models/page-model' -import { PostListState } from '@/models/post-list-state' -import { PostEditDto } from '@/models/post-edit-dto' -import { PostUpdatedResponse } from '@/models/post-updated-response' -import { throwIfNotOkGotResponse } from '@/utils/throw-if-not-ok-response' -import { IErrorResponse } from '@/models/error-response' +import { PageModel } from '@/model/page-model' +import { PostListState } from '@/model/post-list-state' +import { PostEditDto } from '@/model/post-edit-dto' +import { PostUpdatedResponse } from '@/model/post-updated-response' +import { throwIfNotOkGotResponse } from '@/infra/response-err' +import { IErrorResponse } from '@/model/error-response' import { Alert } from './alert' import { PostFileMapManager } from './post-file-map' -import { ZzkSearchResult } from '@/models/zzk-search-result' -import got from '@/utils/http-client' -import httpClient from '@/utils/http-client' +import { ZzkSearchResult } from '@/model/zzk-search-result' +import got from '@/infra/http-client' +import httpClient from '@/infra/http-client' import iconv from 'iconv-lite' const defaultPageSize = 30 diff --git a/src/services/search-post-by-title.ts b/src/service/search-post-by-title.ts similarity index 97% rename from src/services/search-post-by-title.ts rename to src/service/search-post-by-title.ts index 6175ffbe..f081ed8d 100644 --- a/src/services/search-post-by-title.ts +++ b/src/service/search-post-by-title.ts @@ -1,5 +1,5 @@ import { QuickPickItem, window } from 'vscode' -import { Post } from '@/models/post' +import { Post } from '@/model/post' import { PostService } from './post' class PostPickItem implements QuickPickItem { diff --git a/src/services/settings.ts b/src/service/settings.ts similarity index 99% rename from src/services/settings.ts rename to src/service/settings.ts index 6ce3c903..d058510f 100644 --- a/src/services/settings.ts +++ b/src/service/settings.ts @@ -3,7 +3,7 @@ import fs from 'fs' import { ConfigurationTarget, Uri, workspace } from 'vscode' import { ImageSrc } from './mkd-img-extractor' import { isNumber } from 'lodash-es' -import { untildify } from '@/utils/untildify' +import { untildify } from '@/infra/untildify' export class Settings { static postListPageSizeKey = 'pageSize.postList' diff --git a/src/services/site-category.ts b/src/service/site-category.ts similarity index 78% rename from src/services/site-category.ts rename to src/service/site-category.ts index c053bf62..033b79cc 100644 --- a/src/services/site-category.ts +++ b/src/service/site-category.ts @@ -1,5 +1,5 @@ -import fetch from '@/utils/fetch-client' -import { SiteCategories, SiteCategory } from '@/models/site-category' +import fetch from '@/infra/fetch-client' +import { SiteCategories, SiteCategory } from '@/model/site-category' import { globalCtx } from './global-ctx' export namespace siteCategoryService { @@ -9,7 +9,7 @@ export namespace siteCategoryService { if (cached && !forceRefresh) return cached const response = await fetch(`${globalCtx.config.apiBaseUrl}/api/category/site`) - if (!response.ok) throw Error(`Failed to fetch post categories\n${response.status}\n${await response.text()}`) + if (!response.ok) throw Error(`Failed to fetch post category\n${response.status}\n${await response.text()}`) const categories = await response.json() cached = categories.map(c => Object.assign(new SiteCategory(), c)) diff --git a/src/services/check-workspace.ts b/src/services/check-workspace.ts deleted file mode 100644 index 05485675..00000000 --- a/src/services/check-workspace.ts +++ /dev/null @@ -1,65 +0,0 @@ -import os from 'os' -import { workspace } from 'vscode' -import { refreshPostCategoriesList } from '@/commands/post-category/refresh-post-categories-list' -import { refreshPostList } from '@/commands/post-list/refresh-post-list' -import { globalCtx } from './global-ctx' -import { PostFileMapManager } from './post-file-map' -import { execCmd } from '@/utils/cmd' -import { Settings } from './settings' -import { setupUi } from '@/services/setup-ui' - -const diskSymbolRegex = /^(\S{1,5}:)(.*)/ - -export const isTargetWorkspace = (): boolean => { - const folders = workspace.workspaceFolders - let currentFolder = folders?.length === 1 ? folders[0].uri.path : undefined - let targetFolder = Settings.workspaceUri.path - const platform = os.platform() - if (platform === 'win32' && targetFolder && currentFolder) { - const replacer = (sub: string, m0: string | null | undefined, m2: string | null | undefined) => - m0 && m2 ? m0.toLowerCase() + m2 : sub - currentFolder = currentFolder.replace(diskSymbolRegex, replacer) - targetFolder = targetFolder.replace(diskSymbolRegex, replacer) - } - const isTarget = !!currentFolder && currentFolder === targetFolder - void execCmd('setContext', `${globalCtx.extName}.isTargetWorkspace`, isTarget) - return isTarget -} - -export const watchCfgUpdate = () => { - globalCtx.extCtx.subscriptions.push( - workspace.onDidChangeConfiguration(ev => { - if (ev.affectsConfiguration(Settings.cfgPrefix)) isTargetWorkspace() - - if (ev.affectsConfiguration(`${Settings.iconThemePrefix}.${Settings.iconThemeKey}`)) - refreshPostCategoriesList() - - if (ev.affectsConfiguration(`${Settings.cfgPrefix}.${Settings.postListPageSizeKey}`)) - refreshPostList({ queue: true }).catch(() => undefined) - - if (ev.affectsConfiguration(`${Settings.cfgPrefix}.markdown`)) - execCmd('markdown.preview.refresh').then(undefined, () => undefined) - - if (ev.affectsConfiguration(`${Settings.cfgPrefix}.ui`)) setupUi(Settings.cfg) - }) - ) - isTargetWorkspace() -} - -export const watchWorkspaceUpdate = () => - void globalCtx.extCtx.subscriptions.push( - workspace.onDidChangeWorkspaceFolders(() => { - isTargetWorkspace() - }) - ) - -export const watchWorkspaceFileUpdate = () => - void globalCtx.extCtx.subscriptions.push( - workspace.onDidRenameFiles(e => { - for (const item of e.files) { - const { oldUri, newUri } = item - const postId = PostFileMapManager.getPostId(oldUri.fsPath) - if (postId !== undefined) void PostFileMapManager.updateOrCreate(postId, newUri.fsPath) - } - }) - ) diff --git a/src/commands/cmd-register.ts b/src/setup/setup-cmd.ts similarity index 52% rename from src/commands/cmd-register.ts rename to src/setup/setup-cmd.ts index 8faa1f21..2e4a1f20 100644 --- a/src/commands/cmd-register.ts +++ b/src/setup/setup-cmd.ts @@ -1,42 +1,47 @@ -import { openMyAccountSettings } from './open/open-my-account-settings' -import { openMyWebBlogConsole } from './open/open-my-blog-console' -import { openMyHomePage } from './open/open-my-home-page' -import { login, logout } from './login' -import { openMyBlog } from './open/open-my-blog' -import { globalCtx } from '@/services/global-ctx' -import { gotoNextPostList, gotoPreviousPostList, refreshPostList, seekPostList } from './post-list/refresh-post-list' -import { uploadPostFileToCnblogs, uploadPostToCnblogs } from './post-list/upload-post' -import { createLocalDraft } from './post-list/create-local-draft' -import { deleteSelectedPost } from './post-list/delete-post' -import { modifyPostSettings } from './post-list/modify-post-settings' -import { uploadImage } from './upload-image/upload-image' -import { revealLocalPostFileInOs } from './reveal-local-post-file-in-os' -import { showLocalFileToPostInfo } from './show-local-file-to-post-info' -import { newPostCategory } from './post-category/new-post-category' -import { refreshPostCategoriesList } from './post-category/refresh-post-categories-list' -import { handleUpdatePostCategory } from './post-category/update-post-category' -import { openPostInVscode } from './post-list/open-post-in-vscode' -import { deletePostToLocalFileMap } from './post-list/delete-post-to-local-file-map' -import { renamePost } from './post-list/rename-post' -import { openPostInBlogAdmin } from './open/open-post-in-blog-admin' -import { openWorkspace } from './open/open-workspace' -import { setWorkspace } from './set-workspace' -import { revealWorkspaceInOs } from './reveal-workspace-in-os' -import { viewPostOnline } from './view-post-online' -import { pullPostRemoteUpdates } from './pull-post-remote-updates' -import { extractImages } from './extract-images' -import { clearPostSearchResults, refreshPostSearchResults, searchPost } from './post-list/search' -import { handleDeletePostCategories } from './post-category/delete-selected-categories' -import { PublishIngCmdHandler } from '@/commands/ing/publish-ing' -import { regIngListCmds } from 'src/commands/ing/ing-list-cmd-register' -import { CopyPostLinkCmdHandler } from '@/commands/post-list/copy-link' -import { regBlogExportCmds } from '@/commands/blog-export' -import { regCmd } from '@/utils/cmd' -import { exportPostToPdf } from '@/commands/pdf/export-pdf' -import { openCnbHome } from '@/commands/open/open-cnb-home' -import { openCnbNews } from '@/commands/open/open-cnb-news' -import { openCnbQ } from '@/commands/open/open-cnb-q' -import { openCnbIng } from '@/commands/open/open-cnb-ing' +import { openMyAccountSettings } from '@/cmd/open/open-my-account-settings' +import { openMyWebBlogConsole } from '@/cmd/open/open-my-blog-console' +import { openMyHomePage } from '@/cmd/open/open-my-home-page' +import { login, logout } from '@/cmd/login' +import { openMyBlog } from '@/cmd/open/open-my-blog' +import { globalCtx } from '@/service/global-ctx' +import { + gotoNextPostList, + gotoPreviousPostList, + refreshPostList, + seekPostList, +} from '@/cmd/post-list/refresh-post-list' +import { uploadPostFileToCnblogs, uploadPostToCnblogs } from '@/cmd/post-list/upload-post' +import { createLocalDraft } from '@/cmd/post-list/create-local-draft' +import { deleteSelectedPost } from '@/cmd/post-list/delete-post' +import { modifyPostSettings } from '@/cmd/post-list/modify-post-settings' +import { uploadImage } from '@/cmd/upload-img/upload-img' +import { revealLocalPostFileInOs } from '@/cmd/reveal-local-post-file-in-os' +import { showLocalFileToPostInfo } from '@/cmd/show-local-file-to-post-info' +import { newPostCategory } from '@/cmd/post-category/new-post-category' +import { refreshPostCategoryList } from '@/cmd/post-category/refresh-post-category-list' +import { handleUpdatePostCategory } from '@/cmd/post-category/update-post-category' +import { openPostInVscode } from '@/cmd/post-list/open-post-in-vscode' +import { deletePostToLocalFileMap } from '@/cmd/post-list/delete-post-to-local-file-map' +import { renamePost } from '@/cmd/post-list/rename-post' +import { openPostInBlogAdmin } from '@/cmd/open/open-post-in-blog-admin' +import { openWorkspace } from '@/cmd/open/open-workspace' +import { setWorkspace } from '@/cmd/set-workspace' +import { revealWorkspaceInOs } from '@/cmd/reveal-workspace-in-os' +import { viewPostOnline } from '@/cmd/view-post-online' +import { pullPostRemoteUpdates } from '@/cmd/pull-post-remote-updates' +import { extractImages } from '@/cmd/extract-img' +import { clearPostSearchResults, refreshPostSearchResults, searchPost } from '@/cmd/post-list/search' +import { handleDeletePostCategories } from '@/cmd/post-category/delete-selected-category' +import { PublishIngCmdHandler } from '@/cmd/ing/publish-ing' +import { regIngListCmds } from '@/cmd/ing/ing-list-cmd-register' +import { CopyPostLinkCmdHandler } from '@/cmd/post-list/copy-link' +import { regBlogExportCmds } from '@/cmd/blog-export' +import { regCmd } from '@/infra/cmd' +import { exportPostToPdf } from '@/cmd/pdf/export-pdf' +import { openCnbHome } from '@/cmd/open/open-cnb-home' +import { openCnbNews } from '@/cmd/open/open-cnb-news' +import { openCnbQ } from '@/cmd/open/open-cnb-q' +import { openCnbIng } from '@/cmd/open/open-cnb-ing' function withPrefix(prefix: string) { return (rest: string) => `${prefix}${rest}` @@ -47,7 +52,7 @@ export function setupExtCmd() { const withAppName = withPrefix(globalCtx.extName) // TODO: simplify register - const disposables = [ + const tokens = [ regCmd(withAppName('.login'), login), regCmd(withAppName('.open-my-blog'), openMyBlog), regCmd(withAppName('.open-my-home-page'), openMyHomePage), @@ -66,13 +71,13 @@ export function setupExtCmd() { regCmd(withAppName('.upload-post-file-to-cnblogs'), uploadPostFileToCnblogs), regCmd(withAppName('.pull-post-remote-updates'), pullPostRemoteUpdates), regCmd(withAppName('.upload-clipboard-image'), () => uploadImage(true, 'clipboard')), - regCmd(withAppName('.upload-local-disk-image'), () => uploadImage(true, 'local')), - regCmd(withAppName('.upload-image'), () => uploadImage(true)), + regCmd(withAppName('.upload-fs-img'), () => uploadImage(true, 'local')), + regCmd(withAppName('.upload-img'), () => uploadImage(true)), regCmd(withAppName('.reveal-local-post-file-in-os'), revealLocalPostFileInOs), regCmd(withAppName('.show-post-to-local-file-info'), showLocalFileToPostInfo), regCmd(withAppName('.new-post-category'), newPostCategory), - regCmd(withAppName('.delete-selected-post-categories'), handleDeletePostCategories), - regCmd(withAppName('.refresh-post-categories-list'), refreshPostCategoriesList), + regCmd(withAppName('.delete-selected-post-category'), handleDeletePostCategories), + regCmd(withAppName('.refresh-post-category-list'), refreshPostCategoryList), regCmd(withAppName('.update-post-category'), handleUpdatePostCategory), regCmd(withAppName('.delete-post-to-local-file-map'), deletePostToLocalFileMap), regCmd(withAppName('.rename-post'), renamePost), @@ -82,7 +87,7 @@ export function setupExtCmd() { regCmd(withAppName('.reveal-workspace-in-os'), revealWorkspaceInOs), regCmd(withAppName('.view-post-online'), viewPostOnline), regCmd(withAppName('.export-post-to-pdf'), (input: unknown) => exportPostToPdf(input)), - regCmd(withAppName('.extract-images'), extractImages), + regCmd(withAppName('.extract-img'), extractImages), regCmd(withAppName('.search-post'), searchPost), regCmd(withAppName('.clear-post-search-results'), clearPostSearchResults), regCmd(withAppName('.refresh-post-search-results'), refreshPostSearchResults), @@ -98,5 +103,5 @@ export function setupExtCmd() { ...regBlogExportCmds(), ] - ctx.subscriptions.push(...disposables) + ctx.subscriptions.push(...tokens) } diff --git a/src/services/setup-ui.ts b/src/setup/setup-ui.ts similarity index 61% rename from src/services/setup-ui.ts rename to src/setup/setup-ui.ts index 3932f7b2..5f7289e8 100644 --- a/src/services/setup-ui.ts +++ b/src/setup/setup-ui.ts @@ -1,46 +1,6 @@ import { WorkspaceConfiguration as WorkspaceCfg } from 'vscode' -import { extTreeViews } from '@/tree-view-providers/tree-view-registration' -import { getIngListWebviewProvider } from '@/services/ing-list-webview-provider' - -/* -"cnblogsClient.ui.textIngStar": { - "order": 15, - "type": "boolean", - "scope": "application", - "default": false, - "markdownDescription": "符号化闪存表情" -}, -"cnblogsClient.ui.disableIngUserAvatar": { - "order": 16, - "type": "boolean", - "scope": "application", - "default": false, - "markdownDescription": "禁用闪存头像" -}, -"cnblogsClient.ui.treeViewTitleStyle": { - "order": 17, - "scope": "application", - "default": "normal", - "markdownDescription": "侧栏标题风格", - "enum": [ - "normal", - "short", - "short-english" - ], - "enumItemLabels": [ - "正常", - "简洁", - "英文简洁" - ] -}, -"cnblogsClient.ui.fakeExtIcon": { - "order": 18, - "type": "boolean", - "scope": "application", - "default": false, - "markdownDescription": "伪装扩展图标" -} -* */ +import { getIngListWebviewProvider } from '@/service/ing-list-webview-provider' +import { extTreeViews } from '@/tree-view/tree-view-register' export function setupUi(cfg: WorkspaceCfg) { void getIngListWebviewProvider().refreshingList() diff --git a/src/setup/setup-watch.ts b/src/setup/setup-watch.ts new file mode 100644 index 00000000..3c761cab --- /dev/null +++ b/src/setup/setup-watch.ts @@ -0,0 +1,37 @@ +import { workspace } from 'vscode' +import { isTargetWorkspace } from '@/service/is-target-workspace' +import { PostFileMapManager } from '@/service/post-file-map' +import { Settings } from '@/service/settings' +import { refreshPostCategoryList } from '@/cmd/post-category/refresh-post-category-list' +import { refreshPostList } from '@/cmd/post-list/refresh-post-list' +import { execCmd } from '@/infra/cmd' +import { setupUi } from '@/setup/setup-ui' + +export const setupCfgWatch = () => + workspace.onDidChangeConfiguration(ev => { + if (ev.affectsConfiguration(Settings.cfgPrefix)) isTargetWorkspace() + + if (ev.affectsConfiguration(`${Settings.iconThemePrefix}.${Settings.iconThemeKey}`)) refreshPostCategoryList() + + if (ev.affectsConfiguration(`${Settings.cfgPrefix}.${Settings.postListPageSizeKey}`)) + refreshPostList({ queue: true }).catch(() => undefined) + + if (ev.affectsConfiguration(`${Settings.cfgPrefix}.markdown`)) + execCmd('markdown.preview.refresh').then(undefined, () => undefined) + + if (ev.affectsConfiguration(`${Settings.cfgPrefix}.ui`)) setupUi(Settings.cfg) + }) + +export const setupWorkspaceWatch = () => + workspace.onDidChangeWorkspaceFolders(() => { + isTargetWorkspace() + }) + +export const setupWorkspaceFileWatch = () => + workspace.onDidRenameFiles(e => { + for (const item of e.files) { + const { oldUri, newUri } = item + const postId = PostFileMapManager.getPostId(oldUri.fsPath) + if (postId !== undefined) void PostFileMapManager.updateOrCreate(postId, newUri.fsPath) + } + }) diff --git a/src/test/runTest.ts b/src/test/runTest.ts deleted file mode 100644 index fdb1db43..00000000 --- a/src/test/runTest.ts +++ /dev/null @@ -1,26 +0,0 @@ -import path from 'path' - -import { runTests } from '@vscode/test-electron' - -async function main() { - try { - // The folder containing the Extension Manifest package.json - // Passed to `--extensionDevelopmentPath` - const extensionDevelopmentPath = path.resolve(__dirname, '../../') - - // The path to test runner - // Passed to --extensionTestsPath - const extensionTestsPath = path.resolve(__dirname, './suite/index') - - // Download VS Code, unzip it and run the integration test - await runTests({ - extensionDevelopmentPath, - extensionTestsPath, - }) - } catch (err) { - console.error('Failed to run tests') - process.exit(1) - } -} - -main() diff --git a/src/test/suite/extension.test.ts b/src/test/suite/extension.test.ts deleted file mode 100644 index 49ff70cd..00000000 --- a/src/test/suite/extension.test.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Alert } from '@/services/alert' -import assert from 'assert' - -// You can import and use all API from the 'vscode' module -// as well as import your extension to test it -// import * as myExtension from '../../extension'; - -suite('Extension Test Suite', () => { - Alert.info('Start all tests.') - - test('Sample test', () => { - assert.strictEqual(-1, [1, 2, 3].indexOf(5)) - assert.strictEqual(-1, [1, 2, 3].indexOf(0)) - }) -}) diff --git a/src/test/suite/index.ts b/src/test/suite/index.ts deleted file mode 100644 index 6947a966..00000000 --- a/src/test/suite/index.ts +++ /dev/null @@ -1,38 +0,0 @@ -import path from 'path' -import Mocha from 'mocha' -import glob from 'glob' - -export function run(): Promise { - // Create the mocha test - const mocha = new (Mocha as any)({ - ui: 'tdd', - color: true, - }) - - const testsRoot = path.resolve(__dirname, '..') - - return new Promise((c, e) => { - ;(glob as any)('**/**.test.js', { cwd: testsRoot }, (err: any, files: any) => { - if (err) { - return e(err) - } - - // Add files to the test suite - files.forEach((f: any) => mocha.addFile(path.resolve(testsRoot, f))) - - try { - // Run the mocha test - mocha.run((failures: any) => { - if (failures > 0) { - e(new Error(`${failures} tests failed.`)) - } else { - c() - } - }) - } catch (err) { - console.error(err) - e(err) - } - }) - }) -} diff --git a/src/tree-view-providers/converters.ts b/src/tree-view/convert.ts similarity index 88% rename from src/tree-view-providers/converters.ts rename to src/tree-view/convert.ts index 197ec4ec..6bd94e77 100644 --- a/src/tree-view-providers/converters.ts +++ b/src/tree-view/convert.ts @@ -1,12 +1,12 @@ import format from 'date-fns/format' import { homedir } from 'os' import { MarkdownString, ThemeIcon, TreeItem, TreeItemCollapsibleState, Uri } from 'vscode' -import { Post } from '@/models/post' -import { PostCategory } from '@/models/post-category' -import { globalCtx } from '@/services/global-ctx' -import { PostFileMapManager } from '@/services/post-file-map' -import { Settings } from '@/services/settings' -import { BaseTreeItemSource } from './models/base-tree-item-source' +import { Post } from '@/model/post' +import { PostCategory } from '@/model/post-category' +import { globalCtx } from '@/service/global-ctx' +import { PostFileMapManager } from '@/service/post-file-map' +import { Settings } from '@/service/settings' +import { BaseTreeItemSource } from '@/tree-view/model/base-tree-item-source' const contextValues = { post({ id }: Post) { diff --git a/src/tree-view-providers/models/base-entry-tree-item.ts b/src/tree-view/model/base-entry-tree-item.ts similarity index 100% rename from src/tree-view-providers/models/base-entry-tree-item.ts rename to src/tree-view/model/base-entry-tree-item.ts diff --git a/src/tree-view-providers/models/base-tree-item-source.ts b/src/tree-view/model/base-tree-item-source.ts similarity index 100% rename from src/tree-view-providers/models/base-tree-item-source.ts rename to src/tree-view/model/base-tree-item-source.ts diff --git a/src/tree-view-providers/models/blog-export/downloaded.ts b/src/tree-view/model/blog-export/downloaded.ts similarity index 83% rename from src/tree-view-providers/models/blog-export/downloaded.ts rename to src/tree-view/model/blog-export/downloaded.ts index ec861dd0..22afe1c2 100644 --- a/src/tree-view-providers/models/blog-export/downloaded.ts +++ b/src/tree-view/model/blog-export/downloaded.ts @@ -1,11 +1,11 @@ -import { DownloadedBlogExport } from '@/models/blog-export' -import { DownloadedExportStore } from '@/services/downloaded-export.store' -import { BaseEntryTreeItem } from '@/tree-view-providers/models/base-entry-tree-item' -import { BaseTreeItemSource } from '@/tree-view-providers/models/base-tree-item-source' -import { BlogExportTreeItem } from '@/tree-view-providers/models/blog-export' -import { parseDownloadedExports } from '@/tree-view-providers/models/blog-export/parser' -import { ExportPostTreeItem } from '@/tree-view-providers/models/blog-export/post' -import { PostTreeItem } from '@/tree-view-providers/models/post-tree-item' +import { DownloadedBlogExport } from '@/model/blog-export' +import { DownloadedExportStore } from '@/service/downloaded-export.store' +import { BaseEntryTreeItem } from '@/tree-view/model/base-entry-tree-item' +import { BaseTreeItemSource } from '@/tree-view/model/base-tree-item-source' +import { BlogExportTreeItem } from '@/tree-view/model/blog-export' +import { parseDownloadedExports } from '@/tree-view/model/blog-export/parser' +import { ExportPostTreeItem } from '@/tree-view/model/blog-export/post' +import { PostTreeItem } from '@/tree-view/model/post-tree-item' import path from 'path' import { ThemeIcon, TreeItem, TreeItemCollapsibleState } from 'vscode' @@ -39,7 +39,7 @@ export class ExportPostEntryTreeItem extends BaseTreeItemSource implements BaseE } getChildrenAsync: () => Promise = async () => { - const { ExportPostStore } = await import('@/services/blog-export-post.store') + const { ExportPostStore } = await import('@/service/blog-export-post.store') const { downloadedExport } = this const store = new ExportPostStore(downloadedExport) const postTreeItems: ExportPostTreeItem[] = await store.list().then( diff --git a/src/tree-view-providers/models/blog-export/index.ts b/src/tree-view/model/blog-export/index.ts similarity index 66% rename from src/tree-view-providers/models/blog-export/index.ts rename to src/tree-view/model/blog-export/index.ts index 79f55d76..4fa3edb0 100644 --- a/src/tree-view-providers/models/blog-export/index.ts +++ b/src/tree-view/model/blog-export/index.ts @@ -2,9 +2,9 @@ import { DownloadedExportChildTreeItem, DownloadedExportsEntryTreeItem, DownloadedExportTreeItem, -} from '@/tree-view-providers/models/blog-export/downloaded' -import { BlogExportRecordMetadata } from '@/tree-view-providers/models/blog-export/record-metadata' -import { BlogExportRecordTreeItem } from '@/tree-view-providers/models/blog-export/record' +} from '@/tree-view/model/blog-export/downloaded' +import { BlogExportRecordMetadata } from '@/tree-view/model/blog-export/record-metadata' +import { BlogExportRecordTreeItem } from '@/tree-view/model/blog-export/record' export * from './record-metadata' export * from './record' diff --git a/src/tree-view-providers/models/blog-export/parser.ts b/src/tree-view/model/blog-export/parser.ts similarity index 81% rename from src/tree-view-providers/models/blog-export/parser.ts rename to src/tree-view/model/blog-export/parser.ts index 91d88de7..94a2c2f5 100644 --- a/src/tree-view-providers/models/blog-export/parser.ts +++ b/src/tree-view/model/blog-export/parser.ts @@ -1,11 +1,8 @@ -import { BlogExportRecord, BlogExportStatus, DownloadedBlogExport } from '@/models/blog-export' +import { BlogExportRecord, BlogExportStatus, DownloadedBlogExport } from '@/model/blog-export' import { BlogExportRecordTreeItem } from './record' import { ThemeColor, ThemeIcon } from 'vscode' -import { - DownloadedExportsEntryTreeItem, - DownloadedExportTreeItem, -} from '@/tree-view-providers/models/blog-export/downloaded' -import { BlogExportProvider } from '@/tree-view-providers/blog-export-provider' +import { DownloadedExportsEntryTreeItem, DownloadedExportTreeItem } from '@/tree-view/model/blog-export/downloaded' +import { BlogExportProvider } from '@/tree-view/provider/blog-export-provider' export function parseStatusIcon(status: BlogExportStatus) { switch (status) { diff --git a/src/tree-view-providers/models/blog-export/post.ts b/src/tree-view/model/blog-export/post.ts similarity index 72% rename from src/tree-view-providers/models/blog-export/post.ts rename to src/tree-view/model/blog-export/post.ts index 300bc063..e8b60a96 100644 --- a/src/tree-view-providers/models/blog-export/post.ts +++ b/src/tree-view/model/blog-export/post.ts @@ -1,8 +1,8 @@ -import { ViewPostCmdHandler } from '@/commands/blog-export/view-post' -import type { ExportPost } from '@/models/blog-export/export-post' -import { Settings } from '@/services/settings' -import { BaseTreeItemSource } from '@/tree-view-providers/models/base-tree-item-source' -import { ExportPostEntryTreeItem } from '@/tree-view-providers/models/blog-export' +import { ViewPostCmdHandler } from '@/cmd/blog-export/view-post' +import type { ExportPost } from '@/model/blog-export/export-post' +import { Settings } from '@/service/settings' +import { BaseTreeItemSource } from '@/tree-view/model/base-tree-item-source' +import { ExportPostEntryTreeItem } from '@/tree-view/model/blog-export' import { ThemeIcon, TreeItem, TreeItemCollapsibleState, Uri } from 'vscode' export class ExportPostTreeItem extends BaseTreeItemSource { diff --git a/src/tree-view-providers/models/blog-export/record-metadata.ts b/src/tree-view/model/blog-export/record-metadata.ts similarity index 87% rename from src/tree-view-providers/models/blog-export/record-metadata.ts rename to src/tree-view/model/blog-export/record-metadata.ts index 8477a600..3b237848 100644 --- a/src/tree-view-providers/models/blog-export/record-metadata.ts +++ b/src/tree-view/model/blog-export/record-metadata.ts @@ -1,5 +1,5 @@ -import { BaseTreeItemSource } from '@/tree-view-providers/models/base-tree-item-source' -import { BlogExportRecordTreeItem } from '@/tree-view-providers/models/blog-export/record' +import { BaseTreeItemSource } from '@/tree-view/model/base-tree-item-source' +import { BlogExportRecordTreeItem } from '@/tree-view/model/blog-export/record' import { TreeItem, TreeItemCollapsibleState } from 'vscode' export class BlogExportRecordMetadata extends BaseTreeItemSource { diff --git a/src/tree-view-providers/models/blog-export/record.ts b/src/tree-view/model/blog-export/record.ts similarity index 92% rename from src/tree-view-providers/models/blog-export/record.ts rename to src/tree-view/model/blog-export/record.ts index 40ea70d3..05c85b8c 100644 --- a/src/tree-view-providers/models/blog-export/record.ts +++ b/src/tree-view/model/blog-export/record.ts @@ -1,17 +1,17 @@ -import { BlogExportRecord, BlogExportStatus, blogExportStatusNameMap } from '@/models/blog-export' -import { BaseEntryTreeItem } from '@/tree-view-providers/models/base-entry-tree-item' -import { BaseTreeItemSource } from '@/tree-view-providers/models/base-tree-item-source' +import { BlogExportRecord, BlogExportStatus, blogExportStatusNameMap } from '@/model/blog-export' +import { BaseEntryTreeItem } from '@/tree-view/model/base-entry-tree-item' +import { BaseTreeItemSource } from '@/tree-view/model/base-tree-item-source' import { BlogExportRecordMetadata } from './record-metadata' import { parseStatusIcon } from './parser' import { TreeItem, TreeItemCollapsibleState, ThemeIcon } from 'vscode' import format from 'date-fns/format' import parseISO from 'date-fns/parseISO' -import { DownloadedExportStore } from '@/services/downloaded-export.store' -import { BlogExportTreeItem, DownloadedExportTreeItem } from '@/tree-view-providers/models/blog-export' +import { DownloadedExportStore } from '@/service/downloaded-export.store' +import { BlogExportTreeItem, DownloadedExportTreeItem } from '@/tree-view/model/blog-export' import os from 'os' import { escapeRegExp } from 'lodash-es' -import { BlogExportProvider } from '@/tree-view-providers/blog-export-provider' -import { BlogExportApi } from '@/services/blog-export.api' +import { BlogExportProvider } from '@/tree-view/provider/blog-export-provider' +import { BlogExportApi } from '@/service/blog-export.api' export class BlogExportRecordTreeItem extends BaseTreeItemSource implements BaseEntryTreeItem { static readonly contextValue = 'cnblogs-export-record' diff --git a/src/tree-view-providers/models/categories-list-tree-item.ts b/src/tree-view/model/category-list-tree-item.ts similarity index 87% rename from src/tree-view-providers/models/categories-list-tree-item.ts rename to src/tree-view/model/category-list-tree-item.ts index 39b64830..0d260f83 100644 --- a/src/tree-view-providers/models/categories-list-tree-item.ts +++ b/src/tree-view/model/category-list-tree-item.ts @@ -1,4 +1,4 @@ -import { PostCategory } from '@/models/post-category' +import { PostCategory } from '@/model/post-category' import { PostCategoryTreeItem } from './post-category-tree-item' import { PostEntryMetadata, PostMetadata, PostTagMetadata } from './post-metadata' import { PostTreeItem } from './post-tree-item' diff --git a/src/tree-view-providers/models/post-category-tree-item.ts b/src/tree-view/model/post-category-tree-item.ts similarity index 80% rename from src/tree-view-providers/models/post-category-tree-item.ts rename to src/tree-view/model/post-category-tree-item.ts index a0010e4d..e0708250 100644 --- a/src/tree-view-providers/models/post-category-tree-item.ts +++ b/src/tree-view/model/post-category-tree-item.ts @@ -1,6 +1,6 @@ import { TreeItem } from 'vscode' -import { PostCategory } from '@/models/post-category' -import { toTreeItem } from '../converters' +import { PostCategory } from '@/model/post-category' +import { toTreeItem } from '@/tree-view/convert' import { BaseTreeItemSource } from './base-tree-item-source' import { PostTreeItem } from './post-tree-item' diff --git a/src/tree-view-providers/models/post-metadata.ts b/src/tree-view/model/post-metadata.ts similarity index 97% rename from src/tree-view-providers/models/post-metadata.ts rename to src/tree-view/model/post-metadata.ts index 1493ea68..136f4d1b 100644 --- a/src/tree-view-providers/models/post-metadata.ts +++ b/src/tree-view/model/post-metadata.ts @@ -4,14 +4,14 @@ import format from 'date-fns/format' import formatDistanceStrict from 'date-fns/formatDistanceStrict' import zhCN from 'date-fns/locale/zh-CN' import { TreeItem, TreeItemCollapsibleState, ThemeIcon } from 'vscode' -import { AccessPermission, Post, formatAccessPermission } from '@/models/post' -import { PostEditDto } from '@/models/post-edit-dto' -import { postCategoryService } from '@/services/post-category' -import { PostService } from '@/services/post' +import { AccessPermission, Post, formatAccessPermission } from '@/model/post' +import { PostEditDto } from '@/model/post-edit-dto' +import { postCategoryService } from '@/service/post-category' +import { PostService } from '@/service/post' import { BaseEntryTreeItem } from './base-entry-tree-item' import { BaseTreeItemSource } from './base-tree-item-source' import { PostTreeItem } from './post-tree-item' -import { PostCategory } from '@/models/post-category' +import { PostCategory } from '@/model/post-category' export enum RootPostMetadataType { categoryEntry = 'categoryEntry', diff --git a/src/tree-view-providers/models/post-search-result-entry.ts b/src/tree-view/model/post-search-result-entry.ts similarity index 95% rename from src/tree-view-providers/models/post-search-result-entry.ts rename to src/tree-view/model/post-search-result-entry.ts index 52cf7f0d..56286aee 100644 --- a/src/tree-view-providers/models/post-search-result-entry.ts +++ b/src/tree-view/model/post-search-result-entry.ts @@ -1,6 +1,6 @@ import { ThemeIcon, TreeItem, TreeItemCollapsibleState } from 'vscode' -import { Post } from '@/models/post' -import { ZzkSearchResult } from '@/models/zzk-search-result' +import { Post } from '@/model/post' +import { ZzkSearchResult } from '@/model/zzk-search-result' import { BaseEntryTreeItem } from './base-entry-tree-item' import { BaseTreeItemSource } from './base-tree-item-source' import { PostTreeItem } from './post-tree-item' diff --git a/src/tree-view-providers/models/post-tree-item.ts b/src/tree-view/model/post-tree-item.ts similarity index 90% rename from src/tree-view-providers/models/post-tree-item.ts rename to src/tree-view/model/post-tree-item.ts index 76848158..82a72417 100644 --- a/src/tree-view-providers/models/post-tree-item.ts +++ b/src/tree-view/model/post-tree-item.ts @@ -1,6 +1,6 @@ import { TreeItem, TreeItemCollapsibleState } from 'vscode' -import { Post } from '@/models/post' -import { toTreeItem } from '../converters' +import { Post } from '@/model/post' +import { toTreeItem } from '@/tree-view/convert' import { BaseTreeItemSource } from './base-tree-item-source' export class PostTreeItem extends BaseTreeItemSource { diff --git a/src/tree-view-providers/navi-view.ts b/src/tree-view/navi-view.ts similarity index 100% rename from src/tree-view-providers/navi-view.ts rename to src/tree-view/navi-view.ts diff --git a/src/tree-view-providers/account-view-data-provider.ts b/src/tree-view/provider/account-view-data-provider.ts similarity index 100% rename from src/tree-view-providers/account-view-data-provider.ts rename to src/tree-view/provider/account-view-data-provider.ts diff --git a/src/tree-view-providers/blog-export-provider.ts b/src/tree-view/provider/blog-export-provider.ts similarity index 95% rename from src/tree-view-providers/blog-export-provider.ts rename to src/tree-view/provider/blog-export-provider.ts index a928b09a..bb298718 100644 --- a/src/tree-view-providers/blog-export-provider.ts +++ b/src/tree-view/provider/blog-export-provider.ts @@ -1,19 +1,19 @@ -import { BlogExportRecordsStore } from '@/services/blog-export-records.store' +import { BlogExportRecordsStore } from '@/service/blog-export-records.store' import { BlogExportRecordTreeItem, BlogExportRecordMetadata, BlogExportTreeItem, parseBlogExportRecords, -} from './models/blog-export' +} from '@/tree-view/model/blog-export' import { DownloadedExportMetadata, DownloadedExportsEntryTreeItem, DownloadedExportTreeItem, ExportPostEntryTreeItem, -} from './models/blog-export/downloaded' +} from '@/tree-view/model/blog-export' import { Event, EventEmitter, ProviderResult, TreeDataProvider, TreeItem } from 'vscode' -import { Alert } from '@/services/alert' -import { BlogExportRecord } from '@/models/blog-export' +import { Alert } from '@/service/alert' +import { BlogExportRecord } from '@/model/blog-export' export class BlogExportProvider implements TreeDataProvider { private static _instance: BlogExportProvider | null = null diff --git a/src/tree-view-providers/post-categories-tree-data-provider.ts b/src/tree-view/provider/post-category-tree-data-provider.ts similarity index 81% rename from src/tree-view-providers/post-categories-tree-data-provider.ts rename to src/tree-view/provider/post-category-tree-data-provider.ts index 4558979d..87d00352 100644 --- a/src/tree-view-providers/post-categories-tree-data-provider.ts +++ b/src/tree-view/provider/post-category-tree-data-provider.ts @@ -1,19 +1,19 @@ import { flattenDepth, take } from 'lodash-es' import { EventEmitter, ProviderResult, TreeDataProvider, TreeItem } from 'vscode' -import { PostCategories } from '@/models/post-category' -import { globalCtx } from '@/services/global-ctx' -import { postCategoryService } from '@/services/post-category' -import { PostService } from '@/services/post' -import { toTreeItem } from './converters' -import { PostCategoriesListTreeItem } from './models/categories-list-tree-item' -import { PostCategoryTreeItem } from './models/post-category-tree-item' -import { PostEntryMetadata, PostMetadata, RootPostMetadataType } from './models/post-metadata' -import { PostTreeItem } from './models/post-tree-item' -import { Alert } from '@/services/alert' -import { execCmd } from '@/utils/cmd' - -export class PostCategoriesTreeDataProvider implements TreeDataProvider { - private static _instance: PostCategoriesTreeDataProvider | null = null +import { PostCategories } from '@/model/post-category' +import { globalCtx } from '@/service/global-ctx' +import { postCategoryService } from '@/service/post-category' +import { PostService } from '@/service/post' +import { toTreeItem } from '@/tree-view/convert' +import { PostCategoriesListTreeItem } from '@/tree-view/model/category-list-tree-item' +import { PostCategoryTreeItem } from '@/tree-view/model/post-category-tree-item' +import { PostEntryMetadata, PostMetadata, RootPostMetadataType } from '@/tree-view/model/post-metadata' +import { PostTreeItem } from '@/tree-view/model/post-tree-item' +import { Alert } from '@/service/alert' +import { execCmd } from '@/infra/cmd' + +export class PostCategoryTreeDataProvider implements TreeDataProvider { + private static _instance: PostCategoryTreeDataProvider | null = null private _treeDataChanged = new EventEmitter() private _isRefreshing = false private _roots: PostCategoryTreeItem[] | null = null @@ -21,7 +21,7 @@ export class PostCategoriesTreeDataProvider implements TreeDataProvidere).message}`) + void Alert.err(`获取博文分类失败: ${(e).message}`) } finally { await this.setIsRefreshing(false) } @@ -144,4 +144,4 @@ export class PostCategoriesTreeDataProvider implements TreeDataProvider @@ -35,8 +35,8 @@ export function setupExtTreeView() { treeDataProvider: postDataProvider, canSelectMany: true, }) - _views.postCategoriesList = regTreeView('cnblogs-post-categories-list', { - treeDataProvider: postCategoriesDataProvider, + _views.postCategoriesList = regTreeView('cnblogs-post-category-list', { + treeDataProvider: postCategoryDataProvider, canSelectMany: true, }) _views.blogExport = regTreeView('vscode-cnb.blog-export', { diff --git a/src/utils/throw-if-not-ok-response.ts b/src/utils/throw-if-not-ok-response.ts deleted file mode 100644 index 6237cf0b..00000000 --- a/src/utils/throw-if-not-ok-response.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { GotFetchResponse } from 'got-fetch/out/lib/response' -import { Response as GotResponse } from 'got' -import { IErrorResponse, isErrorResponse } from '@/models/error-response' -import iconv from 'iconv-lite' - -const throwIfNotOkResponse = async (response: GotFetchResponse) => { - if (!response.ok) { - const responseText = await response.text() - let responseJson: unknown - try { - responseJson = JSON.parse(responseText) - } catch { - // ignore - } - throw isErrorResponse(responseJson) - ? Object.assign(responseJson, { statusCode: response.status } as IErrorResponse) - : ({ - errors: [`状态码: ${response.status}(${response.statusText})`, responseText], - type: -1, - statusCode: -1, - } as IErrorResponse) - } -} - -const throwIfNotOkGotResponse = (response: GotResponse) => { - if (!response.ok) { - const responseText = iconv.decode(response.rawBody, 'utf-8') - let responseJson: unknown - try { - responseJson = JSON.parse(responseText) - } catch { - // ignore - } - throw isErrorResponse(responseJson) - ? Object.assign(responseJson, { statusCode: response.statusCode } as IErrorResponse) - : ({ - errors: [`状态码: ${response.statusCode}(${response.statusMessage})`, responseText], - type: -1, - statusCode: -1, - } as IErrorResponse) - } -} - -export { throwIfNotOkResponse, throwIfNotOkGotResponse } diff --git a/ui/global.d.ts b/ui/global.d.ts index 0d884e6a..1e24e4ed 100644 --- a/ui/global.d.ts +++ b/ui/global.d.ts @@ -1,4 +1,4 @@ -type WebviewCommonCmd = import('@models/webview-cmd').WebviewCommonCmd +type WebviewCommonCmd = import('@/model/webview-cmd').WebviewCommonCmd declare interface VsCodeApi { postMessage = WebviewCommonCmd<{}>>(message: Object | T): any diff --git a/ui/ing/App.tsx b/ui/ing/App.tsx index c3dfa32d..ca328fe6 100644 --- a/ui/ing/App.tsx +++ b/ui/ing/App.tsx @@ -1,9 +1,9 @@ import React, { Component, ReactNode } from 'react' -import { IngWebviewUiCmd, WebviewCmd } from '@models/webview-cmd' +import { IngWebviewUiCmd, WebviewCmd } from '@/model/webview-cmd' import { IngList } from 'ing/IngList' import { getVsCodeApiSingleton } from 'share/vscode-api' -import { IngAppState } from '@models/ing-view' -import { Ing, IngComment } from '@models/ing' +import { IngAppState } from '@/model/ing-view' +import { Ing, IngComment } from '@/model/ing' import { activeThemeProvider } from 'share/active-theme-provider' import { ThemeProvider } from '@fluentui/react/lib/Theme' import { Spinner, Stack } from '@fluentui/react' diff --git a/ui/ing/IngItem.tsx b/ui/ing/IngItem.tsx index a1639f97..e4f1575b 100644 --- a/ui/ing/IngItem.tsx +++ b/ui/ing/IngItem.tsx @@ -1,12 +1,12 @@ import React, { Component } from 'react' -import { Ing, IngComment, IngSendFromType } from '@models/ing' -import { IngItemState } from '@models/ing-view' +import { Ing, IngComment, IngSendFromType } from '@/model/ing' +import { IngItemState } from '@/model/ing-view' import { take } from 'lodash-es' import { ActivityItem, IPersonaProps, Link, Text } from '@fluentui/react' import { format, formatDistanceStrict } from 'date-fns' import { zhCN } from 'date-fns/locale' import { getVsCodeApiSingleton } from 'share/vscode-api' -import { IngWebviewHostCmd, WebviewCmd } from '@models/webview-cmd' +import { IngWebviewHostCmd, WebviewCmd } from '@/model/webview-cmd' interface IngItemProps { ing: Ing diff --git a/ui/ing/IngList.tsx b/ui/ing/IngList.tsx index ad35cfd3..312b9db8 100644 --- a/ui/ing/IngList.tsx +++ b/ui/ing/IngList.tsx @@ -1,5 +1,5 @@ import React, { Component } from 'react' -import { Ing, IngComment } from '@models/ing' +import { Ing, IngComment } from '@/model/ing' import { IngItem } from 'ing/IngItem' import { Stack } from '@fluentui/react' diff --git a/ui/post-cfg/App.tsx b/ui/post-cfg/App.tsx index 38a41562..d4da6a65 100644 --- a/ui/post-cfg/App.tsx +++ b/ui/post-cfg/App.tsx @@ -2,12 +2,12 @@ import React, { Component } from 'react' import { ThemeProvider } from '@fluentui/react/lib/Theme' import { Theme, PartialTheme, Stack, Breadcrumb, IBreadcrumbItem, Spinner, initializeIcons } from '@fluentui/react' import { PostForm } from './components/PostForm' -import { Post } from '@models/post' -import { personalCategoriesStore } from './services/personal-categories-store' -import { siteCategoriesStore } from './services/site-categories-store' -import { tagsStore } from './services/tags-store' -import { webviewMessage } from '@models/webview-msg' -import { WebviewCmd } from '@models/webview-cmd' +import { Post } from '@/model/post' +import { personalCategoriesStore } from './service/personal-category-store' +import { siteCategoriesStore } from './service/site-category-store' +import { tagsStore } from './service/tags-store' +import { webviewMessage } from '@/model/webview-msg' +import { WebviewCmd } from '@/model/webview-cmd' import { PostFormContextProvider } from './components/PostFormContextProvider' import { activeThemeProvider } from 'share/active-theme-provider' import { darkTheme, lightTheme } from 'share/theme' diff --git a/ui/post-cfg/components/AccessPermissionSelector.tsx b/ui/post-cfg/components/AccessPermissionSelector.tsx index c1ef18a5..c3f84394 100644 --- a/ui/post-cfg/components/AccessPermissionSelector.tsx +++ b/ui/post-cfg/components/AccessPermissionSelector.tsx @@ -1,5 +1,5 @@ import { ChoiceGroup, IChoiceGroupOption, Label, Stack } from '@fluentui/react' -import { AccessPermission, formatAccessPermission } from '@models/post' +import { AccessPermission, formatAccessPermission } from '@/model/post' import React from 'react' export interface IAccessPermissionSelectorProps { diff --git a/ui/post-cfg/components/CategoriesSelect.tsx b/ui/post-cfg/components/CategorySelect.tsx similarity index 86% rename from ui/post-cfg/components/CategoriesSelect.tsx rename to ui/post-cfg/components/CategorySelect.tsx index 76caafe5..1c11f2c6 100644 --- a/ui/post-cfg/components/CategoriesSelect.tsx +++ b/ui/post-cfg/components/CategorySelect.tsx @@ -1,7 +1,7 @@ import { Checkbox, Stack } from '@fluentui/react' -import { PostCategories } from '@models/post-category' +import { PostCategories } from '@/model/post-category' import { Component } from 'react' -import { personalCategoriesStore } from '../services/personal-categories-store' +import { personalCategoriesStore } from '../service/personal-category-store' interface CategoriesSelectorProps { categoryIds: number[] | undefined @@ -13,7 +13,7 @@ interface CategoriesSelectorState { categoryIds: number[] } -class CategoriesSelect extends Component { +class CategorySelect extends Component { constructor(props: CategoriesSelectorProps) { super(props) this.state = { categories: personalCategoriesStore.get(), categoryIds: props.categoryIds ?? [] } @@ -53,4 +53,4 @@ class CategoriesSelect extends Component { @@ -81,12 +81,12 @@ export default class NestCategoriesSelect extends React.Component< {this.checkIsExpanded(c) ? ( - + > ) : ( <> )} diff --git a/ui/post-cfg/components/PostForm.tsx b/ui/post-cfg/components/PostForm.tsx index 446c9349..5f49903a 100644 --- a/ui/post-cfg/components/PostForm.tsx +++ b/ui/post-cfg/components/PostForm.tsx @@ -1,25 +1,25 @@ import { DefaultButton, PrimaryButton } from '@fluentui/react/lib/Button' import { Stack } from '@fluentui/react/lib/Stack' import React from 'react' -import { CategoriesSelect } from './CategoriesSelect' +import { CategorySelect } from './CategorySelect' import { SiteHomeContributionOptionsSelector } from './SiteHomeContributionOptionsSelector' -import { PostCfg } from '@models/post-cfg' -import { Post } from '@models/post' +import { PostCfg } from '@/model/post-cfg' +import { Post } from '@/model/post' import { Label, Spinner } from '@fluentui/react' -import { SiteCategoriesSelector } from './SiteCategoriesSelector' +import { SiteCategorySelector } from './SiteCategorySelector' import { TagsInput } from './TagsInput' import { CommonOptions } from './CommonOptions' import { AccessPermissionSelector } from './AccessPermissionSelector' import { PasswordInput } from './PasswordInput' import { getVsCodeApiSingleton } from '../../share/vscode-api' import { ErrorResponse } from './ErrorResponse' -import { WebviewCmd } from '@models/webview-cmd' -import { webviewMessage } from '@models/webview-msg' +import { WebviewCmd } from '@/model/webview-cmd' +import { webviewMessage } from '@/model/webview-msg' import { InputSummary } from './InputSummary' import { IPostFormContext, PostFormContext } from './PostFormContext' import PostEntryNameInput from './PostEntryNameInput' import PostTitleInput from 'post-cfg/components/PostTitleInput' -import NestCategoriesSelect from 'post-cfg/components/NestCategoriesSelect' +import NestCategorySelect from './NestCategorySelect' export interface IPostFormProps { post?: Post @@ -59,12 +59,12 @@ export class PostForm extends React.Component { {this.props.useNestCategoriesSelect ? ( - this.setState({ categoryIds })} selected={this.state.categoryIds ?? []} - > + > ) : ( - this.setState({ categoryIds })} categoryIds={this.state.categoryIds ?? []} /> @@ -119,7 +119,7 @@ export class PostForm extends React.Component { inSiteCandidate={this.state.inSiteCandidate} inSiteHome={this.state.inSiteHome} /> - this.setState({ siteCategoryId: categoryId })} /> diff --git a/ui/post-cfg/components/SiteCategoriesSelector.tsx b/ui/post-cfg/components/SiteCategorySelector.tsx similarity index 95% rename from ui/post-cfg/components/SiteCategoriesSelector.tsx rename to ui/post-cfg/components/SiteCategorySelector.tsx index 3dd681ed..393d3715 100644 --- a/ui/post-cfg/components/SiteCategoriesSelector.tsx +++ b/ui/post-cfg/components/SiteCategorySelector.tsx @@ -1,7 +1,7 @@ import { ActionButton, Checkbox, Label, Stack } from '@fluentui/react' -import { SiteCategories } from '@models/site-category' +import { SiteCategories } from '@/model/site-category' import React from 'react' -import { siteCategoriesStore } from '../services/site-categories-store' +import { siteCategoriesStore } from '../service/site-category-store' export interface ISiteCategoriesSelectorProps { categoryIds?: number[] @@ -15,10 +15,7 @@ export interface ISiteCategoriesSelectorState { categoryExpandState: { [key: number]: boolean | undefined } } -export class SiteCategoriesSelector extends React.Component< - ISiteCategoriesSelectorProps, - ISiteCategoriesSelectorState -> { +export class SiteCategorySelector extends React.Component { constructor(props: ISiteCategoriesSelectorProps) { super(props) diff --git a/ui/post-cfg/components/SiteHomeContributionOptionsSelector.tsx b/ui/post-cfg/components/SiteHomeContributionOptionsSelector.tsx index 3edc75f1..565d0abb 100644 --- a/ui/post-cfg/components/SiteHomeContributionOptionsSelector.tsx +++ b/ui/post-cfg/components/SiteHomeContributionOptionsSelector.tsx @@ -1,5 +1,5 @@ import React from 'react' -import { SiteHomeContributionOptions as ISiteHomeContributionOptions } from '../models/site-home-contribution-options' +import { SiteHomeContributionOptions as ISiteHomeContributionOptions } from '../model/site-home-contribution-options' import { Text } from '@fluentui/react/lib/Text' import { Stack } from '@fluentui/react/lib/Stack' import { ActionButton, Checkbox, Label } from '@fluentui/react' diff --git a/ui/post-cfg/components/TagsInput.tsx b/ui/post-cfg/components/TagsInput.tsx index d158fb01..3d3ecde0 100644 --- a/ui/post-cfg/components/TagsInput.tsx +++ b/ui/post-cfg/components/TagsInput.tsx @@ -11,8 +11,8 @@ import { Text, } from '@fluentui/react' import React from 'react' -import { tagsStore } from '../services/tags-store' -import { PostTags, PostTag } from '@models/post-tag' +import { tagsStore } from '../service/tags-store' +import { PostTags, PostTag } from '@/model/post-tag' export interface ITagsInputProps { selectedTagNames?: string[] diff --git a/ui/post-cfg/models/site-home-contribution-options.ts b/ui/post-cfg/model/site-home-contribution-options.ts similarity index 100% rename from ui/post-cfg/models/site-home-contribution-options.ts rename to ui/post-cfg/model/site-home-contribution-options.ts diff --git a/ui/post-cfg/services/personal-categories-store.ts b/ui/post-cfg/service/personal-category-store.ts similarity index 95% rename from ui/post-cfg/services/personal-categories-store.ts rename to ui/post-cfg/service/personal-category-store.ts index c22cf8d0..d4cd3e2e 100644 --- a/ui/post-cfg/services/personal-categories-store.ts +++ b/ui/post-cfg/service/personal-category-store.ts @@ -1,5 +1,5 @@ -import { PostCategories } from '@/models/post-category' -import { WebviewCommonCmd, WebviewCmd } from '@models/webview-cmd' +import { PostCategories } from '@/model/post-category' +import { WebviewCommonCmd, WebviewCmd } from '@/model/webview-cmd' import { getVsCodeApiSingleton } from 'share/vscode-api' let children: Map diff --git a/ui/post-cfg/services/site-categories-store.ts b/ui/post-cfg/service/site-category-store.ts similarity index 75% rename from ui/post-cfg/services/site-categories-store.ts rename to ui/post-cfg/service/site-category-store.ts index 480e8468..2d89bb9c 100644 --- a/ui/post-cfg/services/site-categories-store.ts +++ b/ui/post-cfg/service/site-category-store.ts @@ -1,4 +1,4 @@ -import { SiteCategories } from '@models/site-category' +import { SiteCategories } from '../../../src/model/site-category' export namespace siteCategoriesStore { let items: SiteCategories = [] diff --git a/ui/post-cfg/services/tags-store.ts b/ui/post-cfg/service/tags-store.ts similarity index 80% rename from ui/post-cfg/services/tags-store.ts rename to ui/post-cfg/service/tags-store.ts index 99a75fef..71e45909 100644 --- a/ui/post-cfg/services/tags-store.ts +++ b/ui/post-cfg/service/tags-store.ts @@ -1,4 +1,4 @@ -import { PostTag } from '@models/post-tag' +import { PostTag } from '@/model/post-tag' export namespace tagsStore { let tags: PostTag[] = [] diff --git a/ui/tsconfig.json b/ui/tsconfig.json index 92e097ad..f29341d5 100644 --- a/ui/tsconfig.json +++ b/ui/tsconfig.json @@ -13,12 +13,11 @@ "strictPropertyInitialization": true, "baseUrl": ".", "paths": { - "@models/*": ["../src/models/*"], - "@/models/*": ["../src/models/*"] + "@/model/*": ["../src/model/*"] }, "lib": ["DOM", "ES2020"], "strictBindCallApply": true }, - "include": ["./**/*.ts", "./**/*.tsx", "./**/*.jsx", "./**/*.js", "*.mjs", "../src/models/*.ts"], + "include": ["./**/*.ts", "./**/*.tsx", "./**/*.jsx", "./**/*.js", "*.mjs", "../src/model/*.ts"], "exclude": ["./dist"] } From e0738ba2510f300896ead98387461bd378e44ff2 Mon Sep 17 00:00:00 2001 From: Thaumy Date: Tue, 25 Jul 2023 15:27:43 +0800 Subject: [PATCH 026/157] refactor: simplify code --- src/cmd/extract-img.ts | 28 +++++------ src/cmd/ing/ing-list-cmd-register.ts | 2 +- src/cmd/post-list/upload-post.ts | 6 +-- src/cmd/upload-img/upload-clipboard-img.ts | 2 +- src/cmd/upload-img/upload-img-util.ts | 20 ++++---- src/cmd/upload-img/upload-img.ts | 4 +- src/infra/fmt-img-link.ts | 4 +- src/infra/get-clipboard-img.ts | 6 +-- src/model/clipboard-img.ts | 4 +- src/model/img-upload-status.ts | 8 ++-- src/service/mkd-img-extractor.ts | 56 +++++++++++----------- src/service/post-cfg-panel.ts | 8 ++-- src/service/settings.ts | 12 ++--- src/setup/setup-cmd.ts | 4 +- ui/post-cfg/components/InputSummary.tsx | 6 +-- 15 files changed, 84 insertions(+), 86 deletions(-) diff --git a/src/cmd/extract-img.ts b/src/cmd/extract-img.ts index 688c3f02..2d687545 100644 --- a/src/cmd/extract-img.ts +++ b/src/cmd/extract-img.ts @@ -1,10 +1,10 @@ import { MessageItem, MessageOptions, ProgressLocation, Range, Uri, window, workspace, WorkspaceEdit } from 'vscode' -import { ImageInfo, ImageSrc, MkdImgExtractor, newImageSrcFilter } from '@/service/mkd-img-extractor' +import { ImgInfo, ImgSrc, MkdImgExtractor, newImgSrcFilter } from '@/service/mkd-img-extractor' import { Alert } from '@/service/alert' -type ExtractOption = MessageItem & Partial<{ imageSrc: ImageSrc }> +type ExtractOption = MessageItem & Partial<{ imageSrc: ImgSrc }> -export async function extractImages(arg: unknown, inputImageSrc?: ImageSrc) { +export async function extractImg(arg: unknown, inputImgSrc?: ImgSrc) { if (!(arg instanceof Uri && arg.scheme === 'file')) return const editor = window.visibleTextEditors.find(x => x.document.fileName === arg.fsPath) @@ -18,26 +18,26 @@ export async function extractImages(arg: unknown, inputImageSrc?: ImageSrc) { const images = extractor.findImages() if (images.length <= 0) { - if (inputImageSrc !== undefined) void Alert.info('没有找到可以提取的图片') + if (inputImgSrc !== undefined) void Alert.info('没有找到可以提取的图片') return } - const webImgCount = images.filter(newImageSrcFilter(ImageSrc.web)).length - const dataUrlImgCount = images.filter(newImageSrcFilter(ImageSrc.dataUrl)).length - const fsImgCount = images.filter(newImageSrcFilter(ImageSrc.fs)).length + const webImgCount = images.filter(newImgSrcFilter(ImgSrc.web)).length + const dataUrlImgCount = images.filter(newImgSrcFilter(ImgSrc.dataUrl)).length + const fsImgCount = images.filter(newImgSrcFilter(ImgSrc.fs)).length const displayOptions: ExtractOption[] = [ - { title: '提取全部', imageSrc: ImageSrc.any }, - { title: '提取网络图片', imageSrc: ImageSrc.web }, - { title: '提取 Data Url 图片', imageSrc: ImageSrc.dataUrl }, - { title: '提取本地图片', imageSrc: ImageSrc.fs }, + { title: '提取全部', imageSrc: ImgSrc.any }, + { title: '提取网络图片', imageSrc: ImgSrc.web }, + { title: '提取 Data Url 图片', imageSrc: ImgSrc.dataUrl }, + { title: '提取本地图片', imageSrc: ImgSrc.fs }, { title: '取消', imageSrc: undefined, isCloseAffordance: true }, ] let selectedSrc - if (inputImageSrc !== undefined) { - selectedSrc = displayOptions.find(ent => ent.imageSrc === inputImageSrc)?.imageSrc + if (inputImgSrc !== undefined) { + selectedSrc = displayOptions.find(ent => ent.imageSrc === inputImgSrc)?.imageSrc } else { // if src is not specified: const selectedOption = await Alert.info( @@ -87,7 +87,7 @@ export async function extractImages(arg: unknown, inputImageSrc?: ImageSrc) { const range = new Range(posL, posR) // just for ts type inferring - const ret: [Range, ImageInfo] = [range, dst] + const ret: [Range, ImgInfo] = [range, dst] return ret }) .reduce((we, [range, dst]) => { diff --git a/src/cmd/ing/ing-list-cmd-register.ts b/src/cmd/ing/ing-list-cmd-register.ts index 70677e0d..da395cc5 100644 --- a/src/cmd/ing/ing-list-cmd-register.ts +++ b/src/cmd/ing/ing-list-cmd-register.ts @@ -3,7 +3,7 @@ import { globalCtx } from '@/service/global-ctx' import { GotoingListFirstPage, IngListGoNextPage, GotoingListPreviousPage } from '@/cmd/ing/ing-list-go-next-page' import { regCmd } from '@/infra/cmd' import { openIngSite } from '@/cmd/open/open-ing-site' -import { switchIngType } from "@/cmd/ing/select-ing-type"; +import { switchIngType } from '@/cmd/ing/select-ing-type' export const regIngListCmds = () => { const appName = globalCtx.extName diff --git a/src/cmd/post-list/upload-post.ts b/src/cmd/post-list/upload-post.ts index 71a5d6ce..2806f90b 100644 --- a/src/cmd/post-list/upload-post.ts +++ b/src/cmd/post-list/upload-post.ts @@ -13,7 +13,7 @@ import { refreshPostList } from './refresh-post-list' import { PostEditDto } from '@/model/post-edit-dto' import { PostCfgPanel } from '@/service/post-cfg-panel' import { saveFilePendingChanges } from '@/infra/save-file-pending-changes' -import { extractImages } from '@/cmd/extract-img' +import { extractImg } from '@/cmd/extract-img' import { Settings } from '@/service/settings' import { PostTreeItem } from '@/tree-view/model/post-tree-item' @@ -116,7 +116,7 @@ export const saveLocalDraftToCnblogs = async (localDraft: LocalDraft) => { return false } if (Settings.autoExtractImgSrc !== undefined) - await extractImages(localDraft.filePathUri, Settings.autoExtractImgSrc).catch(console.warn) + await extractImg(localDraft.filePathUri, Settings.autoExtractImgSrc).catch(console.warn) postToSave.postBody = await localDraft.readAllText() return true @@ -139,7 +139,7 @@ export const uploadPostToCnblogs = async (input: Post | PostTreeItem | PostEditD if (!localFilePath) return Alert.warn('本地无该博文的编辑记录') if (Settings.autoExtractImgSrc !== undefined) - await extractImages(Uri.file(localFilePath), Settings.autoExtractImgSrc).catch(console.warn) + await extractImg(Uri.file(localFilePath), Settings.autoExtractImgSrc).catch(console.warn) await saveFilePendingChanges(localFilePath) post.postBody = (await workspace.fs.readFile(Uri.file(localFilePath))).toString() diff --git a/src/cmd/upload-img/upload-clipboard-img.ts b/src/cmd/upload-img/upload-clipboard-img.ts index 720ee7b4..ba21d245 100644 --- a/src/cmd/upload-img/upload-clipboard-img.ts +++ b/src/cmd/upload-img/upload-clipboard-img.ts @@ -9,7 +9,7 @@ const noImagePath = 'no image' export const uploadImageFromClipboard = async () => { const clipboardImage = await getClipboardImage() if (clipboardImage.imgPath === noImagePath) { - void Alert.warn('剪贴板中没有找到图片') + void Alert.warn('剪贴板中没有找到图片') return } diff --git a/src/cmd/upload-img/upload-img-util.ts b/src/cmd/upload-img/upload-img-util.ts index c526484c..3d5acbc1 100644 --- a/src/cmd/upload-img/upload-img-util.ts +++ b/src/cmd/upload-img/upload-img-util.ts @@ -1,14 +1,13 @@ import { env, MessageOptions, SnippetString, window } from 'vscode' -import { formatImageLink } from '@/infra/fmt-img-link' +import { fmtImgLink } from '@/infra/fmt-img-link' import { Alert } from '@/service/alert' /** * 显示上传成功对话框, 支持复制不同格式的图片链接 * * @param {string} imgLink - * @returns {*} {Promise} */ -export const showUploadSuccessModel = async (imgLink: string): Promise => { +export async function showUploadSuccessModel(imgLink: string) { const copyOptions = ['复制链接', '复制链接(markdown)', '复制链接(html)'] const option = await Alert.info( '上传图片成功', @@ -18,25 +17,26 @@ export const showUploadSuccessModel = async (imgLink: string): Promise => } as MessageOptions, ...copyOptions ) - let formattedImageLink = '' + + let newImgLink switch (option) { case copyOptions[0]: - formattedImageLink = imgLink + newImgLink = imgLink break case copyOptions[1]: - formattedImageLink = formatImageLink(imgLink, 'markdown') + newImgLink = fmtImgLink(imgLink, 'markdown') break case copyOptions[2]: - formattedImageLink = formatImageLink(imgLink, 'html') + newImgLink = fmtImgLink(imgLink, 'html') break } - if (formattedImageLink) await env.clipboard.writeText(formattedImageLink) + if (newImgLink) await env.clipboard.writeText(newImgLink) } -export const insertImageLinkToActiveEditor = async (imageLink: string): Promise => { +export const insertImgLinkToActiveEditor = async (imgLink: string): Promise => { const activeEditor = window.activeTextEditor if (activeEditor) { - await activeEditor.insertSnippet(new SnippetString(formatImageLink(imageLink, 'markdown'))) + await activeEditor.insertSnippet(new SnippetString(fmtImgLink(imgLink, 'markdown'))) return true } diff --git a/src/cmd/upload-img/upload-img.ts b/src/cmd/upload-img/upload-img.ts index ab60fd7c..63f174e4 100644 --- a/src/cmd/upload-img/upload-img.ts +++ b/src/cmd/upload-img/upload-img.ts @@ -1,6 +1,6 @@ import { Alert } from '@/service/alert' import { uploadImageFromClipboard } from './upload-clipboard-img' -import { insertImageLinkToActiveEditor, showUploadSuccessModel } from './upload-img-util' +import { insertImgLinkToActiveEditor, showUploadSuccessModel } from './upload-img-util' import { uploadFsImage } from './upload-fs-img' export const uploadImage = async (autoInsertToActiveEditor = true, from?: 'local' | 'clipboard') => { @@ -33,7 +33,7 @@ export const uploadImage = async (autoInsertToActiveEditor = true, from?: 'local } if (imageUrl && autoInsertToActiveEditor) - if (!(await insertImageLinkToActiveEditor(imageUrl))) await showUploadSuccessModel(imageUrl) + if (!(await insertImgLinkToActiveEditor(imageUrl))) await showUploadSuccessModel(imageUrl) return imageUrl } diff --git a/src/infra/fmt-img-link.ts b/src/infra/fmt-img-link.ts index 387b2213..bac0c00f 100644 --- a/src/infra/fmt-img-link.ts +++ b/src/infra/fmt-img-link.ts @@ -1,10 +1,10 @@ -export const formatImageLink = (link: string, format: 'html' | 'markdown' | 'raw'): string => { +export function fmtImgLink(link: string, format: 'html' | 'markdown' | 'raw') { if (!link) return '' let formatted = link switch (format) { case 'html': - formatted = `` + formatted = `image` break case 'markdown': formatted = `![img](${link})` diff --git a/src/infra/get-clipboard-img.ts b/src/infra/get-clipboard-img.ts index fda337a4..338b1ddd 100644 --- a/src/infra/get-clipboard-img.ts +++ b/src/infra/get-clipboard-img.ts @@ -7,7 +7,7 @@ import os from 'os' import isWsl from 'is-wsl' import { globalCtx } from '@/service/global-ctx' import { Alert } from '@/service/alert' -import { IClipboardImage } from '@/model/clipboard-img' +import { IClipboardImg } from '@/model/clipboard-img' import format from 'date-fns/format' export type Platform = 'darwin' | 'win32' | 'win10' | 'linux' | 'wsl' @@ -57,12 +57,12 @@ const platform2ScriptFilename: { wsl: 'wsl.sh', } -const getClipboardImage = (): Promise => { +const getClipboardImage = (): Promise => { const imagePath = path.join( globalCtx.extCtx?.asAbsolutePath('./') ?? '', `${format(new Date(), 'yyyyMMddHHmmss')}.png` ) - return new Promise((resolve, reject): void => { + return new Promise((resolve, reject): void => { const platform = getCurrentPlatform() const scriptPath = path.join(__dirname, platform2ScriptFilename[platform]) // If the script does not exist yet, we need to write the content to the script file diff --git a/src/model/clipboard-img.ts b/src/model/clipboard-img.ts index 75c44465..a73f9b13 100644 --- a/src/model/clipboard-img.ts +++ b/src/model/clipboard-img.ts @@ -1,7 +1,7 @@ -export interface IClipboardImage { +export interface IClipboardImg { imgPath: string /** - * if the path is generate by the extension -> false + * if the path is generated by the extension -> false * if the path is a real file path in system -> true */ shouldKeepAfterUploading: boolean diff --git a/src/model/img-upload-status.ts b/src/model/img-upload-status.ts index 1fa273ac..ba6ba551 100644 --- a/src/model/img-upload-status.ts +++ b/src/model/img-upload-status.ts @@ -1,13 +1,11 @@ -enum ImageUploadStatusId { +export enum ImgUploadStatusId { uploading, uploaded, failed, } -interface ImgUploadStatus { - id: ImageUploadStatusId +export type ImgUploadStatus = { + id: ImgUploadStatusId imageUrl?: string errors?: string[] } - -export { ImageUploadStatusId, ImgUploadStatus } diff --git a/src/service/mkd-img-extractor.ts b/src/service/mkd-img-extractor.ts index bd49b389..e0b6e2a5 100644 --- a/src/service/mkd-img-extractor.ts +++ b/src/service/mkd-img-extractor.ts @@ -13,7 +13,7 @@ export const enum DataType { url, } -export interface ImageInfo { +export interface ImgInfo { startOffset: number data: string dataType: DataType @@ -33,29 +33,29 @@ const mkdUrlImgPat = /(!\[.*?]\()(.*?\.(?:png|jpg|jpeg|webp|svg|gif))(\))/gi const cnblogsDomainRegExp = /\.cnblogs\.com\//gi -export const enum ImageSrc { +export const enum ImgSrc { web, dataUrl, fs, any, } -export const newImageSrcFilter = (type: ImageSrc) => { - const isWebImage = (imgInfo: ImageInfo) => imgInfo.dataType === DataType.url && /https?:\/\//.test(imgInfo.data) - const isFsImage = (imgInfo: ImageInfo) => imgInfo.dataType === DataType.url && !isWebImage(imgInfo) - const isDataUrlImage = (imgInfo: ImageInfo) => imgInfo.dataType === DataType.dataUrl +export const newImgSrcFilter = (type: ImgSrc) => { + const isWebImg = (imgInfo: ImgInfo) => imgInfo.dataType === DataType.url && /https?:\/\//.test(imgInfo.data) + const isFsImg = (imgInfo: ImgInfo) => imgInfo.dataType === DataType.url && !isWebImg(imgInfo) + const isDataUrlImg = (imgInfo: ImgInfo) => imgInfo.dataType === DataType.dataUrl // eslint-disable-next-line @typescript-eslint/no-unused-vars - const isAnyImage = (_: ImageInfo) => true + const isAnyImg = (_: ImgInfo) => true switch (type) { - case ImageSrc.web: - return isWebImage - case ImageSrc.fs: - return isFsImage - case ImageSrc.dataUrl: - return isDataUrlImage - case ImageSrc.any: - return isAnyImage + case ImgSrc.web: + return isWebImg + case ImgSrc.fs: + return isFsImg + case ImgSrc.dataUrl: + return isDataUrlImg + case ImgSrc.any: + return isAnyImg } } @@ -66,16 +66,16 @@ enum ExtractorSt { } export class MkdImgExtractor { - private _imageSrc = ImageSrc.any + private _imageSrc = ImgSrc.any private _status = ExtractorSt.pending - private _errors: [imageLink: string, msg: string][] = [] - private _images: ImageInfo[] | null | undefined = null + private _errors: [imgLink: string, msg: string][] = [] + private _images: ImgInfo[] | null | undefined = null private readonly _workspaceDirs: string[] | undefined constructor( private readonly markdown: string, private readonly targetFileUri: Uri, - public onProgress?: (index: number, images: ImageInfo[]) => void + public onProgress?: (index: number, images: ImgInfo[]) => void ) { this._workspaceDirs = workspace.workspaceFolders?.map(({ uri: { fsPath } }) => fsPath) } @@ -96,7 +96,7 @@ export class MkdImgExtractor { return this._errors } - async extract(): Promise<[src: ImageInfo, dst: ImageInfo | null][]> { + async extract(): Promise<[src: ImgInfo, dst: ImgInfo | null][]> { this._status = ExtractorSt.extracting const srcInfoArr = this.findImages() @@ -136,11 +136,11 @@ export class MkdImgExtractor { return result } - findImages(): ImageInfo[] { + findImages(): ImgInfo[] { const acc = () => { const imgTagUrlImgMatchGroups = Array.from(this.markdown.matchAll(imgTagUrlImgPat)) const mkdUrlImgMatchGroups = Array.from(this.markdown.matchAll(mkdUrlImgPat)) - const urlImgInfo = imgTagUrlImgMatchGroups.concat(mkdUrlImgMatchGroups).map(mg => ({ + const urlImgInfo = imgTagUrlImgMatchGroups.concat(mkdUrlImgMatchGroups).map(mg => ({ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion startOffset: mg.index!, dataType: DataType.url, @@ -151,7 +151,7 @@ export class MkdImgExtractor { const imgTagDataUrlImgMatchGroups = Array.from(this.markdown.matchAll(imgTagDataUrlImgPat)) const mkdDataUrlImgMatchGroups = Array.from(this.markdown.matchAll(mkdDataUrlImgPat)) - const dataUrlImgInfo = imgTagDataUrlImgMatchGroups.concat(mkdDataUrlImgMatchGroups).map(mg => ({ + const dataUrlImgInfo = imgTagDataUrlImgMatchGroups.concat(mkdDataUrlImgMatchGroups).map(mg => ({ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion startOffset: mg.index!, dataType: DataType.dataUrl, @@ -170,7 +170,7 @@ export class MkdImgExtractor { this._images ??= acc() // apply settings - return this._images.filter(x => newImageSrcFilter(this._imageSrc)(x)) + return this._images.filter(x => newImgSrcFilter(this._imageSrc)(x)) } private async resolveWebImg(url: string) { @@ -229,16 +229,16 @@ export class MkdImgExtractor { return fs.createReadStream(path) } - private async resolveImgInfo(info: ImageInfo): Promise { + private async resolveImgInfo(info: ImgInfo): Promise { // for web img // eslint-disable-next-line no-return-await - if (newImageSrcFilter(ImageSrc.web)(info)) return await this.resolveWebImg(info.data) + if (newImgSrcFilter(ImgSrc.web)(info)) return await this.resolveWebImg(info.data) // for fs img // eslint-disable-next-line no-return-await - if (newImageSrcFilter(ImageSrc.fs)(info)) return await this.resolveFsImg(info.data) + if (newImgSrcFilter(ImgSrc.fs)(info)) return await this.resolveFsImg(info.data) // for data url img - if (newImageSrcFilter(ImageSrc.dataUrl)(info)) return this.resolveDataUrlImg(info.data) + if (newImgSrcFilter(ImgSrc.dataUrl)(info)) return this.resolveDataUrlImg(info.data) } } diff --git a/src/service/post-cfg-panel.ts b/src/service/post-cfg-panel.ts index 099fbeb5..2c63de7e 100644 --- a/src/service/post-cfg-panel.ts +++ b/src/service/post-cfg-panel.ts @@ -10,7 +10,7 @@ import { isErrorResponse } from '@/model/error-response' import { webviewMessage } from '@/model/webview-msg' import { WebviewCommonCmd, WebviewCmd } from '@/model/webview-cmd' import { uploadImage } from '@/cmd/upload-img/upload-img' -import { ImageUploadStatusId } from '@/model/img-upload-status' +import { ImgUploadStatusId } from '@/model/img-upload-status' import { openPostFile } from '@/cmd/post-list/open-post-file' import { parseWebviewHtml } from '@/service/parse-webview-html' import path from 'path' @@ -122,7 +122,7 @@ export namespace PostCfgPanel { await webview.postMessage({ command: WebviewCmd.UiCmd.updateImageUploadStatus, status: { - id: ImageUploadStatusId.uploading, + id: ImgUploadStatusId.uploading, }, imageId: message.imageId, } as webviewMessage.UpdateImageUpdateStatusMessage) @@ -132,7 +132,7 @@ export namespace PostCfgPanel { command: WebviewCmd.UiCmd.updateImageUploadStatus, status: { imageUrl, - id: ImageUploadStatusId.uploaded, + id: ImgUploadStatusId.uploaded, }, imageId: message.imageId, } as webviewMessage.UpdateImageUpdateStatusMessage) @@ -141,7 +141,7 @@ export namespace PostCfgPanel { await webview.postMessage({ command: WebviewCmd.UiCmd.updateImageUploadStatus, status: { - id: ImageUploadStatusId.failed, + id: ImgUploadStatusId.failed, errors: err.errors, }, imageId: message.imageId, diff --git a/src/service/settings.ts b/src/service/settings.ts index d058510f..48a1354c 100644 --- a/src/service/settings.ts +++ b/src/service/settings.ts @@ -1,7 +1,7 @@ import os, { homedir } from 'os' import fs from 'fs' import { ConfigurationTarget, Uri, workspace } from 'vscode' -import { ImageSrc } from './mkd-img-extractor' +import { ImgSrc } from './mkd-img-extractor' import { isNumber } from 'lodash-es' import { untildify } from '@/infra/untildify' @@ -65,14 +65,14 @@ export class Settings { return Settings.cfg.get('createLocalPostFileWithCategory') ?? false } - static get autoExtractImgSrc(): ImageSrc | undefined { + static get autoExtractImgSrc(): ImgSrc | undefined { const cfg = Settings.cfg.get<'disable' | 'web' | 'dataUrl' | 'fs' | 'any'>('autoExtractImages') if (cfg === 'disable') return - if (cfg === 'fs') return ImageSrc.fs - if (cfg === 'dataUrl') return ImageSrc.dataUrl - if (cfg === 'web') return ImageSrc.web - if (cfg === 'any') return ImageSrc.any + if (cfg === 'fs') return ImgSrc.fs + if (cfg === 'dataUrl') return ImgSrc.dataUrl + if (cfg === 'web') return ImgSrc.web + if (cfg === 'any') return ImgSrc.any } static get postListPageSize() { diff --git a/src/setup/setup-cmd.ts b/src/setup/setup-cmd.ts index 2e4a1f20..5e4b2fe9 100644 --- a/src/setup/setup-cmd.ts +++ b/src/setup/setup-cmd.ts @@ -29,7 +29,7 @@ import { setWorkspace } from '@/cmd/set-workspace' import { revealWorkspaceInOs } from '@/cmd/reveal-workspace-in-os' import { viewPostOnline } from '@/cmd/view-post-online' import { pullPostRemoteUpdates } from '@/cmd/pull-post-remote-updates' -import { extractImages } from '@/cmd/extract-img' +import { extractImg } from '@/cmd/extract-img' import { clearPostSearchResults, refreshPostSearchResults, searchPost } from '@/cmd/post-list/search' import { handleDeletePostCategories } from '@/cmd/post-category/delete-selected-category' import { PublishIngCmdHandler } from '@/cmd/ing/publish-ing' @@ -87,7 +87,7 @@ export function setupExtCmd() { regCmd(withAppName('.reveal-workspace-in-os'), revealWorkspaceInOs), regCmd(withAppName('.view-post-online'), viewPostOnline), regCmd(withAppName('.export-post-to-pdf'), (input: unknown) => exportPostToPdf(input)), - regCmd(withAppName('.extract-img'), extractImages), + regCmd(withAppName('.extract-img'), extractImg), regCmd(withAppName('.search-post'), searchPost), regCmd(withAppName('.clear-post-search-results'), clearPostSearchResults), regCmd(withAppName('.refresh-post-search-results'), refreshPostSearchResults), diff --git a/ui/post-cfg/components/InputSummary.tsx b/ui/post-cfg/components/InputSummary.tsx index 5c9c6211..f854f4d5 100644 --- a/ui/post-cfg/components/InputSummary.tsx +++ b/ui/post-cfg/components/InputSummary.tsx @@ -1,5 +1,5 @@ import { ActionButton, Label, MessageBar, MessageBarType, Stack, TextField, Text } from '@fluentui/react' -import { ImageUploadStatusId } from '@/model/img-upload-status' +import { ImgUploadStatusId } from '@/model/img-upload-status' import { WebviewCmd } from '@/model/webview-cmd' import { webviewMessage } from '@/model/webview-msg' import React from 'react' @@ -109,8 +109,8 @@ export class InputSummary extends React.Component Date: Tue, 25 Jul 2023 17:21:12 +0800 Subject: [PATCH 027/157] refactor: simplify code --- README.md | 2 +- package.json | 88 +++++----- src/auth/account-manager.ts | 2 +- src/auth/auth-provider.ts | 2 +- src/cmd/blog-export/create.ts | 32 ++-- src/cmd/blog-export/delete.ts | 141 +++++++-------- src/cmd/blog-export/download.ts | 163 +++++++++--------- src/cmd/blog-export/edit.ts | 57 +++--- src/cmd/blog-export/index.ts | 23 --- src/cmd/blog-export/open-local.ts | 98 +++++------ src/cmd/blog-export/refresh.ts | 20 +-- src/cmd/blog-export/view-post.ts | 97 +++++------ src/cmd/ing/ing-list-cmd-register.ts | 19 -- src/cmd/ing/ing-list-go-next-page.ts | 25 --- src/cmd/ing/publish-ing.ts | 7 +- src/cmd/ing/refresh-ing-list.ts | 7 +- src/cmd/ing/switch-ing-list-page.ts | 18 ++ src/cmd/login.ts | 5 - src/cmd/open/open-ing-site.ts | 2 +- ...settings.ts => open-my-account-setting.ts} | 2 +- src/cmd/open/open-workspace.ts | 4 +- src/cmd/pdf/export-pdf.ts | 6 +- src/cmd/pdf/post-pdf-template-builder.ts | 4 +- src/cmd/post-category/update-post-category.ts | 6 +- src/cmd/post-list/create-local-draft.ts | 6 +- ...ost-settings.ts => modify-post-setting.ts} | 2 +- src/cmd/post-list/open-post-in-vscode.ts | 8 +- src/cmd/post-list/refresh-post-list.ts | 15 +- src/cmd/post-list/upload-post.ts | 20 +-- ...-remote-updates.ts => pull-remote-post.ts} | 22 +-- src/cmd/reveal-workspace-in-os.ts | 5 +- src/cmd/set-workspace.ts | 8 +- src/cmd/upload-img/upload-clipboard-img.ts | 2 +- src/cmd/upload-img/upload-img.ts | 6 +- src/{service/settings.ts => ctx/ext-cfg.ts} | 49 +++--- src/{service => ctx}/global-ctx.ts | 0 src/extension.ts | 8 +- src/infra/get-clipboard-img.ts | 2 +- ...post-settings.ts => input-post-setting.ts} | 18 +- src/markdown/extend-markdownIt.ts | 6 +- .../{blog-settings.ts => blog-setting.ts} | 2 +- src/model/webview-cmd.ts | 2 +- src/service/blog-export.api.ts | 2 +- .../{blog-settings.ts => blog-setting.ts} | 12 +- src/service/downloaded-export.store.ts | 2 +- src/service/img.ts | 2 +- src/service/ing-list-webview-provider.ts | 8 +- src/service/ing.api.ts | 2 +- src/service/is-target-workspace.ts | 6 +- src/service/oauth.api.ts | 2 +- src/service/parse-webview-html.ts | 2 +- src/service/post-category.ts | 2 +- src/service/post-cfg-panel.ts | 8 +- src/service/post-file-map.ts | 2 +- src/service/post-tag.ts | 2 +- src/service/post-title-sanitizer.ts | 2 +- src/service/post.ts | 2 +- src/service/site-category.ts | 2 +- src/setup/setup-cmd.ts | 115 +++++++----- src/setup/setup-watch.ts | 12 +- src/tree-view/convert.ts | 8 +- src/tree-view/model/blog-export/post.ts | 8 +- .../provider/account-view-data-provider.ts | 2 +- .../post-category-tree-data-provider.ts | 2 +- src/tree-view/provider/post-data-provider.ts | 4 +- src/tree-view/tree-view-register.ts | 2 +- ui/post-cfg/components/InputSummary.tsx | 2 +- 67 files changed, 561 insertions(+), 663 deletions(-) delete mode 100644 src/cmd/blog-export/index.ts delete mode 100644 src/cmd/ing/ing-list-cmd-register.ts delete mode 100644 src/cmd/ing/ing-list-go-next-page.ts create mode 100644 src/cmd/ing/switch-ing-list-page.ts delete mode 100644 src/cmd/login.ts rename src/cmd/open/{open-my-account-settings.ts => open-my-account-setting.ts} (78%) rename src/cmd/post-list/{modify-post-settings.ts => modify-post-setting.ts} (96%) rename src/cmd/{pull-post-remote-updates.ts => pull-remote-post.ts} (81%) rename src/{service/settings.ts => ctx/ext-cfg.ts} (61%) rename src/{service => ctx}/global-ctx.ts (100%) rename src/infra/{input-post-settings.ts => input-post-setting.ts} (93%) rename src/model/{blog-settings.ts => blog-setting.ts} (95%) rename src/service/{blog-settings.ts => blog-setting.ts} (57%) diff --git a/README.md b/README.md index ce088101..31a12d92 100644 --- a/README.md +++ b/README.md @@ -154,7 +154,7 @@ 也可以在编辑器中选中一段文本或代码,然后鼠标右键唤起上下文菜单,可以将选中的内容发到闪存; > PS: 上下文菜单的"将选中内容发到闪存"功能默认处于禁用,您可以在 VSCode 设置中启用此功能 -> demo-settings-enable-publish-selection-to-ing +> demo-settings-enable-publish-select-to-ing diff --git a/package.json b/package.json index afeecfdb..f234cf2c 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ "onCommand:vscode-cnb.open-workspace", "onCommand:vscode-cnb.login", "onCommand:vscode-cnb.logout", - "onCommand:vscode-cnb.ing-publish-selection" + "onCommand:vscode-cnb.ing-publish-select" ], "main": "./dist/extension.js", "contributes": { @@ -168,7 +168,7 @@ "category": "Cnblogs Local Draft" }, { - "command": "vscode-cnb.modify-post-settings", + "command": "vscode-cnb.modify-post-setting", "title": "博文设置", "icon": "$(gear)", "category": "Cnblogs Post List", @@ -199,14 +199,14 @@ "category": "Cnblogs" }, { - "command": "vscode-cnb.upload-post-file-to-cnblogs", + "command": "vscode-cnb.upload-post-file", "title": "上传到博客园", "icon": "$(vscode-cnb-cloud-upload)", "enablement": "vscode-cnb.isAuthorized", "category": "Cnblogs" }, { - "command": "vscode-cnb.pull-post-remote-updates", + "command": "vscode-cnb.pull-remote-post", "title": "拉取博文", "category": "Cnblogs", "enablement": "vscode-cnb.isAuthorized", @@ -313,7 +313,7 @@ "icon": "$(add)" }, { - "command": "vscode-cnb.ing.publish-selection", + "command": "vscode-cnb.ing.publish-select", "title": "将选中内容发到闪存", "category": "Cnblogs", "enablement": "vscode-cnb.isAuthorized && editorHasSelection == true && isInDiffEditor == false && isInEmbeddedEditor == false" @@ -366,7 +366,7 @@ "enablement": "vscode-cnb.isAuthorized" }, { - "command": "vscode-cnb.blog-export.refresh-records", + "command": "vscode-cnb.blog-export.refresh-record", "title": "刷新博客备份记录", "category": "Cnblogs", "icon": "$(refresh)", @@ -550,9 +550,9 @@ "type": "object", "additionalProperties": false, "default": { - "upload-post-file-to-cnblogs": true, - "pull-post-remote-updates": true, - "modify-post-settings": true, + "upload-post-file": true, + "pull-remote-post": true, + "modify-post-setting": true, "show-post-to-local-file-info": true, "open-post-in-blog-admin": true, "export-post-to-pdf": true, @@ -560,19 +560,19 @@ }, "markdownDescription": "控制要在资源管理器右键菜单中显示的命令", "properties": { - "upload-post-file-to-cnblogs": { + "upload-post-file": { "description": "上传到博客园", "type": "boolean", "order": 0, "default": true }, - "pull-post-remote-updates": { + "pull-remote-post": { "description": "拉取博文", "type": "boolean", "order": 1, "default": true }, - "modify-post-settings": { + "modify-post-setting": { "description": "博文设置", "type": "boolean", "order": 2, @@ -608,9 +608,9 @@ "order": 14, "type": "object", "default": { - "upload-post-file-to-cnblogs": true, - "pull-post-remote-updates": true, - "modify-post-settings": true, + "upload-post-file": true, + "pull-remote-post": true, + "modify-post-setting": true, "show-post-to-local-file-info": true, "open-post-in-blog-admin": true, "export-post-to-pdf": true, @@ -618,20 +618,20 @@ "upload-clipboard-image": true, "upload-fs-img": true, "extract-img": true, - "ing:publish-selection": false + "ing:publish-select": false }, "properties": { - "upload-post-file-to-cnblogs": { + "upload-post-file": { "order": 0, "description": "上传到博客园", "type": "boolean" }, - "pull-post-remote-updates": { + "pull-remote-post": { "order": 1, "description": "拉取博文", "type": "boolean" }, - "modify-post-settings": { + "modify-post-setting": { "order": 2, "description": "博文设置", "type": "boolean" @@ -672,7 +672,7 @@ "description": "提取图片", "type": "boolean" }, - "ing:publish-selection": { + "ing:publish-select": { "order": 10, "description": "将选中内容发到闪存", "type": "boolean" @@ -861,7 +861,7 @@ "group": "navigation@1" }, { - "command": "vscode-cnb.blog-export.refresh-records", + "command": "vscode-cnb.blog-export.refresh-record", "when": "view == vscode-cnb.blog-export", "group": "navigation@2" } @@ -876,7 +876,7 @@ "when": "false" }, { - "command": "vscode-cnb.modify-post-settings", + "command": "vscode-cnb.modify-post-setting", "when": "false" }, { @@ -884,7 +884,7 @@ "when": "false" }, { - "command": "vscode-cnb.upload-post-file-to-cnblogs", + "command": "vscode-cnb.upload-post-file", "when": "true" }, { @@ -944,7 +944,7 @@ "when": "false" }, { - "command": "vscode-cnb.ing.publish-selection", + "command": "vscode-cnb.ing.publish-select", "when": "false" }, { @@ -972,7 +972,7 @@ "when": "false" }, { - "command": "vscode-cnb.blog-export.refresh-records", + "command": "vscode-cnb.blog-export.refresh-record", "when": "false" }, { @@ -995,12 +995,12 @@ "when": "viewItem == cnb-post-cached" }, { - "command": "vscode-cnb.pull-post-remote-updates", + "command": "vscode-cnb.pull-remote-post", "group": "inline@2", "when": "viewItem == cnb-post-cached" }, { - "command": "vscode-cnb.modify-post-settings", + "command": "vscode-cnb.modify-post-setting", "group": "inline@3", "when": "viewItem =~ /^cnb-post/ && viewItem != cnb-post-category" }, @@ -1019,7 +1019,7 @@ "group": "1@2" }, { - "command": "vscode-cnb.modify-post-settings", + "command": "vscode-cnb.modify-post-setting", "when": "viewItem =~ /^cnb-post/ && viewItem != cnb-post-category", "group": "1@1" }, @@ -1039,7 +1039,7 @@ "when": "viewItem == cnb-post-cached" }, { - "command": "vscode-cnb.pull-post-remote-updates", + "command": "vscode-cnb.pull-remote-post", "group": "0@2", "when": "viewItem == cnb-post-cached" }, @@ -1139,18 +1139,18 @@ "group": "cnblogs@1" }, { - "command": "vscode-cnb.upload-post-file-to-cnblogs", - "when": "resourceLangId == markdown && config.cnblogsClient.menus.context.editor.upload-post-file-to-cnblogs", + "command": "vscode-cnb.upload-post-file", + "when": "resourceLangId == markdown && config.cnblogsClient.menus.context.editor.upload-post-file", "group": "cnblogs@2" }, { - "command": "vscode-cnb.pull-post-remote-updates", - "when": "resourceLangId == markdown && config.cnblogsClient.menus.context.editor.pull-post-remote-updates", + "command": "vscode-cnb.pull-remote-post", + "when": "resourceLangId == markdown && config.cnblogsClient.menus.context.editor.pull-remote-post", "group": "cnblogs@3" }, { - "command": "vscode-cnb.modify-post-settings", - "when": "resourceLangId == markdown && config.cnblogsClient.menus.context.editor.modify-post-settings", + "command": "vscode-cnb.modify-post-setting", + "when": "resourceLangId == markdown && config.cnblogsClient.menus.context.editor.modify-post-setting", "group": "cnblogs@4" }, { @@ -1179,9 +1179,9 @@ "group": "cnblogs@9" }, { - "command": "vscode-cnb.ing.publish-selection", + "command": "vscode-cnb.ing.publish-select", "group": "cnblogs@10", - "when": "config.cnblogsClient.menus.context.editor.ing:publish-selection" + "when": "config.cnblogsClient.menus.context.editor.ing:publish-select" } ], "editor/title": [ @@ -1191,7 +1191,7 @@ "group": "navigation" }, { - "command": "vscode-cnb.upload-post-file-to-cnblogs", + "command": "vscode-cnb.upload-post-file", "when": "resourceLangId == markdown", "group": "navigation" } @@ -1203,18 +1203,18 @@ "group": "cnblogs@1" }, { - "command": "vscode-cnb.upload-post-file-to-cnblogs", - "when": "resourceLangId == markdown && config.cnblogsClient.menus.context.explorer.upload-post-file-to-cnblogs", + "command": "vscode-cnb.upload-post-file", + "when": "resourceLangId == markdown && config.cnblogsClient.menus.context.explorer.upload-post-file", "group": "cnblogs@2" }, { - "command": "vscode-cnb.pull-post-remote-updates", - "when": "resourceLangId == markdown && config.cnblogsClient.menus.context.explorer.pull-post-remote-updates", + "command": "vscode-cnb.pull-remote-post", + "when": "resourceLangId == markdown && config.cnblogsClient.menus.context.explorer.pull-remote-post", "group": "cnblogs@3" }, { - "command": "vscode-cnb.modify-post-settings", - "when": "resourceLangId == markdown && config.cnblogsClient.menus.context.explorer.modify-post-settings", + "command": "vscode-cnb.modify-post-setting", + "when": "resourceLangId == markdown && config.cnblogsClient.menus.context.explorer.modify-post-setting", "group": "cnblogs@4" }, { diff --git a/src/auth/account-manager.ts b/src/auth/account-manager.ts index 1d79f5e1..2bc8cd5c 100644 --- a/src/auth/account-manager.ts +++ b/src/auth/account-manager.ts @@ -1,5 +1,5 @@ import { AccountInfo } from './account-info' -import { globalCtx } from '@/service/global-ctx' +import { globalCtx } from '@/ctx/global-ctx' import vscode, { authentication, AuthenticationGetSessionOptions, Disposable } from 'vscode' import { accountViewDataProvider } from '@/tree-view/provider/account-view-data-provider' import { postDataProvider } from '@/tree-view/provider/post-data-provider' diff --git a/src/auth/auth-provider.ts b/src/auth/auth-provider.ts index 72888a3d..3806f039 100644 --- a/src/auth/auth-provider.ts +++ b/src/auth/auth-provider.ts @@ -14,7 +14,7 @@ import { Uri, window, } from 'vscode' -import { globalCtx } from '@/service/global-ctx' +import { globalCtx } from '@/ctx/global-ctx' import RandomString from 'randomstring' import { Oauth } from '@/service/oauth.api' import { extUriHandler } from '@/infra/uri-handler' diff --git a/src/cmd/blog-export/create.ts b/src/cmd/blog-export/create.ts index e864c01f..4971bf55 100644 --- a/src/cmd/blog-export/create.ts +++ b/src/cmd/blog-export/create.ts @@ -1,27 +1,21 @@ -import { CmdHandler } from '@/cmd/cmd-handler' import { Alert } from '@/service/alert' import { BlogExportApi } from '@/service/blog-export.api' import { BlogExportProvider } from '@/tree-view/provider/blog-export-provider' -import { MessageItem, window } from 'vscode' +import { MessageItem } from 'vscode' -export class CreateBlogExportCmdHandler implements CmdHandler { - static readonly cmd = 'vscode-cnb.blog-export.create' +export async function createBlogExport() { + if (!(await confirm())) return - async handle(): Promise { - if (!(await this.confirm())) return + const isOk = await BlogExportApi.create().catch((e: unknown) => { + Alert.httpErr(typeof e === 'object' && e ? e : {}, { message: '创建博客备份失败' }) + return false + }) - if ( - (await BlogExportApi.create().catch((e: unknown) => { - Alert.httpErr(typeof e === 'object' && e ? e : {}, { message: '创建博客备份失败' }) - return false - })) !== false - ) - await BlogExportProvider.optionalInstance?.refreshRecords() - } + if (isOk) await BlogExportProvider.optionalInstance?.refreshRecords() +} - private async confirm(): Promise { - const items: MessageItem[] = [{ title: '确定', isCloseAffordance: false }] - const result = await Alert.info('确定要创建备份吗?', { modal: true, detail: '一天可以创建一次备份' }, ...items) - return result != null - } +async function confirm() { + const items: MessageItem[] = [{ title: '确定', isCloseAffordance: false }] + const result = await Alert.info('确定要创建备份吗?', { modal: true, detail: '一天可以创建一次备份' }, ...items) + return result != null } diff --git a/src/cmd/blog-export/delete.ts b/src/cmd/blog-export/delete.ts index 18ff7c62..12cd2fb3 100644 --- a/src/cmd/blog-export/delete.ts +++ b/src/cmd/blog-export/delete.ts @@ -1,4 +1,3 @@ -import { TreeViewCmdHandler } from '@/cmd/cmd-handler' import { DownloadedBlogExport } from '@/model/blog-export' import { Alert } from '@/service/alert' import { BlogExportApi } from '@/service/blog-export.api' @@ -8,94 +7,76 @@ import { BlogExportRecordTreeItem, DownloadedExportTreeItem } from '@/tree-view/ import fs from 'fs' import path from 'path' import { promisify } from 'util' -import { MessageItem, window } from 'vscode' +import { window } from 'vscode' -export class DeleteCmdHandler implements TreeViewCmdHandler { - static readonly cmd = 'vscode-cnb.blog-export.delete' - - constructor(public input: unknown) {} - - parseInput(): DownloadedExportTreeItem | BlogExportRecordTreeItem | null | undefined { - return this.input instanceof DownloadedExportTreeItem || this.input instanceof BlogExportRecordTreeItem - ? this.input - : null - } +function parseInput(input: unknown): DownloadedExportTreeItem | BlogExportRecordTreeItem | null | undefined { + return input instanceof DownloadedExportTreeItem || input instanceof BlogExportRecordTreeItem ? input : null +} - async handle(): Promise { - const input = this.parseInput() - if (input instanceof DownloadedExportTreeItem) await this.deleteDownloadedExportItem(input) - if (input instanceof BlogExportRecordTreeItem) await this.deleteExportRecordItem(input) - } +export async function deleteBlogExport(input: unknown): Promise { + const parsedInput = parseInput(input) + if (parsedInput instanceof DownloadedExportTreeItem) await deleteDownloadedExportItem(parsedInput) + if (parsedInput instanceof BlogExportRecordTreeItem) await deleteExportRecordItem(parsedInput) +} - private confirm( - itemName: string, - hasLocalFile = true, - detail: string | undefined | null = '数据可能无法恢复, 请谨慎操作!' - ): Thenable { - const options: (MessageItem & { - result: ReturnType extends Thenable ? R : never - })[] = [ - { title: '确定' + (hasLocalFile ? '(保留本地文件)' : ''), result: { shouldDeleteLocal: false } }, - ...(hasLocalFile ? [{ title: '确定(同时删除本地文件)', result: { shouldDeleteLocal: true } }] : []), - ] - return window - .showInformationMessage( - `确定要删除 ${itemName} 吗?`, - { modal: true, detail: detail ? detail : undefined }, - ...options - ) - .then( - x => x?.result, - () => undefined - ) - } +function confirm( + itemName: string, + hasLocalFile = true, + detail: string | undefined | null = '数据可能无法恢复, 请谨慎操作!' +): Thenable { + const options = [ + { title: '确定' + (hasLocalFile ? '(保留本地文件)' : ''), result: { shouldDeleteLocal: false } }, + ...(hasLocalFile ? [{ title: '确定(同时删除本地文件)', result: { shouldDeleteLocal: true } }] : []), + ] + return window + .showInformationMessage( + `确定要删除 ${itemName} 吗?`, + { modal: true, detail: detail ? detail : undefined }, + ...options + ) + .then( + x => x?.result, + () => undefined + ) +} - private async deleteDownloadedExportItem( - item: DownloadedExportTreeItem, - { hasConfirmed = false } = {} - ): Promise { - const result = hasConfirmed - ? { shouldDeleteLocal: true } - : await this.confirm( - `博客备份-${path.basename(item.downloadedExport.filePath)}`, - false, - '删除后备份文件无法恢复' - ) - if (result == null) return +async function deleteDownloadedExportItem( + item: DownloadedExportTreeItem, + { hasConfirmed = false } = {} +): Promise { + const result = hasConfirmed + ? { shouldDeleteLocal: true } + : await confirm(`博客备份-${path.basename(item.downloadedExport.filePath)}`, false, '删除后备份文件无法恢复') + if (result == null) return - await this.removeDownloadedBlogExport(item.downloadedExport, { shouldDeleteLocal: true }) + await removeDownloadedBlogExport(item.downloadedExport, { shouldDeleteLocal: true }) - await BlogExportProvider.optionalInstance?.refreshRecords({ force: false }) - await BlogExportProvider.optionalInstance?.refreshDownloadedExports() - } + await BlogExportProvider.optionalInstance?.refreshRecords({ force: false }) + await BlogExportProvider.optionalInstance?.refreshDownloadedExports() +} - private async deleteExportRecordItem(item: BlogExportRecordTreeItem) { - const { record } = item - const downloaded = await DownloadedExportStore.findById(record.id) +async function deleteExportRecordItem(item: BlogExportRecordTreeItem) { + const { record } = item + const downloaded = await DownloadedExportStore.findById(record.id) - const confirmResult = await this.confirm( - `云端博客备份-${record.fileName}`, - downloaded != null, - '删除后备份无法恢复' - ) - if (confirmResult == null) return + const confirmResult = await confirm(`云端博客备份-${record.fileName}`, downloaded != null, '删除后备份无法恢复') + if (confirmResult == null) return - const { shouldDeleteLocal } = confirmResult - const hasDeleted = await BlogExportApi.del(record.id) - .then(() => true) - .catch((e: unknown) => { - Alert.httpErr(typeof e === 'object' && e != null ? e : {}) - return false - }) - if (hasDeleted) if (downloaded) await this.removeDownloadedBlogExport(downloaded, { shouldDeleteLocal }) + const { shouldDeleteLocal } = confirmResult + const hasDeleted = await BlogExportApi.del(record.id) + .then(() => true) + .catch((e: unknown) => { + Alert.httpErr(typeof e === 'object' && e != null ? e : {}) + return false + }) + if (hasDeleted) if (downloaded) await removeDownloadedBlogExport(downloaded, { shouldDeleteLocal }) - await BlogExportProvider.optionalInstance?.refreshRecords() - } + await BlogExportProvider.optionalInstance?.refreshRecords() +} - private async removeDownloadedBlogExport(downloaded: DownloadedBlogExport, { shouldDeleteLocal = false }) { - await DownloadedExportStore.remove(downloaded, { shouldRemoveExportRecordMap: shouldDeleteLocal }).catch( - console.warn - ) - if (shouldDeleteLocal) await promisify(fs.rm)(downloaded.filePath).catch(console.warn) - } +async function removeDownloadedBlogExport(downloaded: DownloadedBlogExport, { shouldDeleteLocal = false }) { + await DownloadedExportStore.remove(downloaded, { shouldRemoveExportRecordMap: shouldDeleteLocal }).catch( + console.warn + ) + if (shouldDeleteLocal) await promisify(fs.rm)(downloaded.filePath).catch(console.warn) } diff --git a/src/cmd/blog-export/download.ts b/src/cmd/blog-export/download.ts index 58ce3040..0c5fcce1 100644 --- a/src/cmd/blog-export/download.ts +++ b/src/cmd/blog-export/download.ts @@ -1,9 +1,8 @@ -import { TreeViewCmdHandler } from '@/cmd/cmd-handler' import { Alert } from '@/service/alert' import { BlogExportApi } from '@/service/blog-export.api' import { DownloadedExportStore } from '@/service/downloaded-export.store' -import { globalCtx } from '@/service/global-ctx' -import { Settings } from '@/service/settings' +import { globalCtx } from '@/ctx/global-ctx' +import { ExtCfg } from '@/ctx/ext-cfg' import { BlogExportProvider } from '@/tree-view/provider/blog-export-provider' import { BlogExportRecordTreeItem } from '@/tree-view/model/blog-export' import { extTreeViews } from '@/tree-view/tree-view-register' @@ -13,98 +12,92 @@ import path from 'path' import { promisify } from 'util' import { execCmd } from '@/infra/cmd' -export class DownloadExportCmdHandler implements TreeViewCmdHandler { - static readonly cmd = 'vscode-cnb.blog-export.download' - - constructor(public readonly input: unknown) {} +function parseInput(input: unknown): BlogExportRecordTreeItem | null | undefined { + return input instanceof BlogExportRecordTreeItem ? input : null +} - parseInput(): BlogExportRecordTreeItem | null | undefined { - return this.input instanceof BlogExportRecordTreeItem ? this.input : null - } +export async function downloadBlogExport(input: unknown) { + const treeItem = parseInput(input) + if (treeItem == null) return + const { + record: { id: exportId, blogId }, + } = treeItem - async handle(): Promise { - const treeItem = this.parseInput() - if (treeItem == null) return - const { - record: { id: exportId, blogId }, - } = treeItem + if (blogId < 0 || exportId <= 0) return - if (blogId < 0 || exportId <= 0) return + const targetDir = path.join(ExtCfg.workspaceUri.fsPath, '博客备份') + await promisify(fs.mkdir)(targetDir, { recursive: true }) + const nonZipFilePath = path.join(targetDir, treeItem.record.fileName) + const zipFilePath = nonZipFilePath + '.zip' + const downloadStream = BlogExportApi.download(blogId, exportId) + const isFileExist = await promisify(fs.exists)(zipFilePath) - const targetDir = path.join(Settings.workspaceUri.fsPath, '博客备份') - await promisify(fs.mkdir)(targetDir, { recursive: true }) - const nonZipFilePath = path.join(targetDir, treeItem.record.fileName) - const zipFilePath = nonZipFilePath + '.zip' - const downloadStream = BlogExportApi.download(blogId, exportId) - const isFileExist = await promisify(fs.exists)(zipFilePath) + extTreeViews.blogExport.reveal(treeItem, { expand: true }).then(undefined, console.warn) - extTreeViews.blogExport.reveal(treeItem, { expand: true }).then(undefined, console.warn) + const { optionalInstance: blogExportProvider } = BlogExportProvider + await setIsDownloading(true) - const { optionalInstance: blogExportProvider } = BlogExportProvider - await this.setIsDownloading(true) + const onError = (msg?: string | null) => { + if (msg) Alert.warn(msg) + if (!isFileExist) fs.rmSync(zipFilePath) + blogExportProvider?.refreshItem(treeItem) + setIsDownloading(false).then(undefined, console.warn) + } - const onError = (msg?: string | null) => { - if (msg) Alert.warn(msg) - if (!isFileExist) fs.rmSync(zipFilePath) + downloadStream + .on('downloadProgress', ({ transferred, total, percent }: Progress) => { + const percentage = Math.round(percent * 100) + treeItem.reportDownloadingProgress({ percentage, transferred, total: total ?? transferred }) blogExportProvider?.refreshItem(treeItem) - this.setIsDownloading(false).then(undefined, console.warn) - } + }) + .on('error', e => { + treeItem.reportDownloadingProgress(null) + onError('下载博客备份失败' + ', ' + e.toString()) + }) + .on('response', () => { + const statusCode = downloadStream.response?.statusCode + if (statusCode != null && statusCode >= 200 && statusCode < 300) { + treeItem.reportDownloadingProgress({ percentage: 0 }) - downloadStream - .on('downloadProgress', ({ transferred, total, percent }: Progress) => { - const percentage = Math.round(percent * 100) - treeItem.reportDownloadingProgress({ percentage, transferred, total: total ?? transferred }) blogExportProvider?.refreshItem(treeItem) - }) - .on('error', e => { - treeItem.reportDownloadingProgress(null) - onError('下载博客备份失败' + ', ' + e.toString()) - }) - .on('response', () => { - const statusCode = downloadStream.response?.statusCode - if (statusCode != null && statusCode >= 200 && statusCode < 300) { - treeItem.reportDownloadingProgress({ percentage: 0 }) + downloadStream.pipe( + fs + .createWriteStream(zipFilePath) + .on('error', error => { + onError(`写入文件 ${zipFilePath} 时发生异常, ${error.message}`) + }) + .on('finish', () => { + treeItem.reportDownloadingProgress({ percentage: 100, message: '解压中' }) + blogExportProvider?.refreshItem(treeItem) - blogExportProvider?.refreshItem(treeItem) - downloadStream.pipe( - fs - .createWriteStream(zipFilePath) - .on('error', error => { - onError(`写入文件 ${zipFilePath} 时发生异常, ${error.message}`) - }) - .on('finish', () => { - treeItem.reportDownloadingProgress({ percentage: 100, message: '解压中' }) - blogExportProvider?.refreshItem(treeItem) - - import('adm-zip') - // eslint-disable-next-line @typescript-eslint/naming-convention - .then(({ default: AdmZip }) => { - const entry = new AdmZip(zipFilePath) - return promisify(entry.extractAllToAsync.bind(entry))( - targetDir, - true, - undefined - ).then(() => promisify(fs.rm)(zipFilePath)) - }) - .then(() => { - DownloadedExportStore.add(nonZipFilePath, exportId) - .then(() => treeItem.reportDownloadingProgress(null)) - .then(() => blogExportProvider?.refreshItem(treeItem)) - .then(() => blogExportProvider?.refreshDownloadedExports()) - .catch(console.warn) - }, console.warn) - .finally(() => { - this.setIsDownloading(false).then(undefined, console.warn) - }) - }) - ) - } else { - this.setIsDownloading(false).then(undefined, console.warn) - } - }) - } + import('adm-zip') + // eslint-disable-next-line @typescript-eslint/naming-convention + .then(({ default: AdmZip }) => { + const entry = new AdmZip(zipFilePath) + return promisify(entry.extractAllToAsync.bind(entry))( + targetDir, + true, + undefined + ).then(() => promisify(fs.rm)(zipFilePath)) + }) + .then(() => { + DownloadedExportStore.add(nonZipFilePath, exportId) + .then(() => treeItem.reportDownloadingProgress(null)) + .then(() => blogExportProvider?.refreshItem(treeItem)) + .then(() => blogExportProvider?.refreshDownloadedExports()) + .catch(console.warn) + }, console.warn) + .finally(() => { + setIsDownloading(false).then(undefined, console.warn) + }) + }) + ) + } else { + setIsDownloading(false).then(undefined, console.warn) + } + }) +} - private setIsDownloading(value: boolean) { - return execCmd('setContext', `${globalCtx.extName}.blog-export.downloading`, value || undefined) - } +function setIsDownloading(value: boolean) { + return execCmd('setContext', `${globalCtx.extName}.blog-export.downloading`, value || undefined) } diff --git a/src/cmd/blog-export/edit.ts b/src/cmd/blog-export/edit.ts index da8601eb..d196bef3 100644 --- a/src/cmd/blog-export/edit.ts +++ b/src/cmd/blog-export/edit.ts @@ -1,47 +1,40 @@ -import { TreeViewCmdHandler } from '@/cmd/cmd-handler' import { openPostFile } from '@/cmd/post-list/open-post-file' import { Alert } from '@/service/alert' -import { Settings } from '@/service/settings' +import { ExtCfg } from '@/ctx/ext-cfg' import { ExportPostTreeItem } from '@/tree-view/model/blog-export/post' import fs from 'fs' import path from 'path' import sanitizeFileName from 'sanitize-filename' import { promisify } from 'util' -export class EditExportPostCmdHandler implements TreeViewCmdHandler { - static readonly cmd = 'vscode-cnb.blog-export.edit' - - constructor(public readonly input: unknown) {} - - parseInput(): ExportPostTreeItem | null | undefined { - return this.input instanceof ExportPostTreeItem ? this.input : null - } +function parseInput(input: unknown): ExportPostTreeItem | null | undefined { + return input instanceof ExportPostTreeItem ? input : null +} - async handle(): Promise { - const target = this.parseInput() - if (!target) return void Alert.warn('不支持的参数输入') +export async function editExportPost(input: unknown): Promise { + const target = parseInput(input) + if (!target) return void Alert.warn('不支持的参数输入') - const { - post: { title, isMarkdown, id: postId }, - parent: { - downloadedExport: { filePath: backupFilePath }, - downloadedExport, - }, - } = target + const { + post: { title, isMarkdown, id: postId }, + parent: { + downloadedExport: { filePath: backupFilePath }, + downloadedExport, + }, + } = target - const fileName = sanitizeFileName(title) - const extName = isMarkdown ? 'md' : 'html' - const dirname = Settings.workspaceUri.fsPath - const backupName = path.parse(backupFilePath).name - fs.mkdirSync(dirname, { recursive: true }) - const fullPath = path.join(`${dirname}`, `${fileName}.博客备份-${backupName}-${postId}.${extName}`) + const fileName = sanitizeFileName(title) + const extName = isMarkdown ? 'md' : 'html' + const dirname = ExtCfg.workspaceUri.fsPath + const backupName = path.parse(backupFilePath).name + fs.mkdirSync(dirname, { recursive: true }) + const fullPath = path.join(`${dirname}`, `${fileName}.博客备份-${backupName}-${postId}.${extName}`) - const { ExportPostStore } = await import('@/service/blog-export-post.store') - const store = new ExportPostStore(downloadedExport) - await promisify(fs.writeFile)(fullPath, await store.getBody(postId)) + const { ExportPostStore } = await import('@/service/blog-export-post.store') + const store = new ExportPostStore(downloadedExport) + await promisify(fs.writeFile)(fullPath, await store.getBody(postId)) - store.dispose() + store.dispose() - return openPostFile(fullPath, {}) - } + return openPostFile(fullPath, {}) } diff --git a/src/cmd/blog-export/index.ts b/src/cmd/blog-export/index.ts deleted file mode 100644 index 2bbddc1e..00000000 --- a/src/cmd/blog-export/index.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { RefreshExportRecordsCmdHandler } from './refresh' -import { globalCtx } from '@/service/global-ctx' -import { OpenLocalExportCmdHandler } from '@/cmd/blog-export/open-local' -import { EditExportPostCmdHandler } from '@/cmd/blog-export/edit' -import { CreateBlogExportCmdHandler } from '@/cmd/blog-export/create' -import { DownloadExportCmdHandler } from '@/cmd/blog-export/download' -import { ViewPostCmdHandler } from '@/cmd/blog-export/view-post' -import { DeleteCmdHandler } from '@/cmd/blog-export/delete' -import { regCmd } from '@/infra/cmd' - -export function regBlogExportCmds() { - const { extName } = globalCtx - - return [ - regCmd(`${extName}.blog-export.refresh-records`, () => new RefreshExportRecordsCmdHandler().handle()), - regCmd(OpenLocalExportCmdHandler.cmd, () => new OpenLocalExportCmdHandler().handle()), - regCmd(EditExportPostCmdHandler.cmd, input => new EditExportPostCmdHandler(input).handle()), - regCmd(CreateBlogExportCmdHandler.cmd, () => new CreateBlogExportCmdHandler().handle()), - regCmd(DownloadExportCmdHandler.cmd, input => new DownloadExportCmdHandler(input).handle()), - regCmd(ViewPostCmdHandler.cmd, input => new ViewPostCmdHandler(input).handle()), - regCmd(DeleteCmdHandler.cmd, input => new DeleteCmdHandler(input).handle()), - ] -} diff --git a/src/cmd/blog-export/open-local.ts b/src/cmd/blog-export/open-local.ts index 975f1504..b80a3e36 100644 --- a/src/cmd/blog-export/open-local.ts +++ b/src/cmd/blog-export/open-local.ts @@ -9,62 +9,58 @@ import { BlogExportProvider } from '@/tree-view/provider/blog-export-provider' const defaultOptions = { confirmUnzip: true } -export class OpenLocalExportCmdHandler implements CmdHandler { - static readonly cmd = `vscode-cnb.blog-export.open-local-export` +export async function openLocalExport(opts: Partial = defaultOptions) { + let isConfirmedToUnzip = opts?.confirmUnzip === true ? true : defaultOptions.confirmUnzip - async handle(opts: Partial = defaultOptions): Promise { - let isConfirmedToUnzip = opts?.confirmUnzip === true ? true : defaultOptions.confirmUnzip + const [fileUri] = + (await window.showOpenDialog({ + canSelectFolders: false, + canSelectMany: false, + filters: { + // eslint-disable-next-line @typescript-eslint/naming-convention + Sqlite: ['db', 'zip'], + // eslint-disable-next-line @typescript-eslint/naming-convention + // ZipSqlite: ['zip'], + }, + })) ?? [] + if (fileUri == null) return + const filePath = fileUri.fsPath + if (filePath.endsWith('.zip') && !filePath.endsWith('.db.zip')) return void Alert.warn('不支持的博客备份文件') - const [fileUri] = - (await window.showOpenDialog({ - canSelectFolders: false, - canSelectMany: false, - filters: { - // eslint-disable-next-line @typescript-eslint/naming-convention - Sqlite: ['db', 'zip'], - // eslint-disable-next-line @typescript-eslint/naming-convention - // ZipSqlite: ['zip'], - }, - })) ?? [] - if (fileUri == null) return - const filePath = fileUri.fsPath - if (filePath.endsWith('.zip') && !filePath.endsWith('.db.zip')) return void Alert.warn('不支持的博客备份文件') + const fileName = path.basename(filePath.replace(/\.db(\.zip)?$/, '')) + const dirname = path.dirname(filePath) + let dbFilePath = filePath + isConfirmedToUnzip = filePath.endsWith('.db.zip') + // if (!confirmUnzip && fileUri.fsPath.endsWith('db.zip')) { + // const options: (MessageItem & { confirmed: boolean })[] = [{ title: '确定', confirmed: true }]; + // const selected = await Alert.info( + // '浏览博客备份需要解决, 确定要解压吗?', + // { modal: true }, + // ...options + // ); - const fileName = path.basename(filePath.replace(/\.db(\.zip)?$/, '')) - const dirname = path.dirname(filePath) - let dbFilePath = filePath - isConfirmedToUnzip = filePath.endsWith('.db.zip') - // if (!confirmUnzip && fileUri.fsPath.endsWith('db.zip')) { - // const options: (MessageItem & { confirmed: boolean })[] = [{ title: '确定', confirmed: true }]; - // const selected = await Alert.info( - // '浏览博客备份需要解决, 确定要解压吗?', - // { modal: true }, - // ...options - // ); + // confirmUnzip = selected?.confirmed === true; + // } - // confirmUnzip = selected?.confirmed === true; - // } - - if (isConfirmedToUnzip) { - // eslint-disable-next-line @typescript-eslint/naming-convention - const AdmZip = (await import('adm-zip')).default - const zip = new AdmZip(filePath) - zip.extractEntryTo(`${fileName}.db`, dirname, false, true) - dbFilePath = path.join(dirname, `${fileName}.db`) - } - const dbFileName = path.basename(dbFilePath) + if (isConfirmedToUnzip) { + // eslint-disable-next-line @typescript-eslint/naming-convention + const AdmZip = (await import('adm-zip')).default + const zip = new AdmZip(filePath) + zip.extractEntryTo(`${fileName}.db`, dirname, false, true) + dbFilePath = path.join(dirname, `${fileName}.db`) + } + const dbFileName = path.basename(dbFilePath) - const isExist = await promisify(fs.exists)(dbFilePath) - if (!isExist) return void Alert.warn('文件不存在') + const isExist = await promisify(fs.exists)(dbFilePath) + if (!isExist) return void Alert.warn('文件不存在') - const treeProvider = BlogExportProvider.optionalInstance - const dbFileSize = (await promisify(fs.stat)(dbFilePath)).size - const exportRecord = await treeProvider?.store - .list() - .then(x => x.items.find(i => i.fileName === dbFileName && i.fileBytes === dbFileSize)) - await DownloadedExportStore.add(dbFilePath, exportRecord?.id) + const treeProvider = BlogExportProvider.optionalInstance + const dbFileSize = (await promisify(fs.stat)(dbFilePath)).size + const exportRecord = await treeProvider?.store + .list() + .then(x => x.items.find(i => i.fileName === dbFileName && i.fileBytes === dbFileSize)) + await DownloadedExportStore.add(dbFilePath, exportRecord?.id) - if (exportRecord) await treeProvider?.refreshRecords({ force: false }) - else await treeProvider?.refreshDownloadedExports() - } + if (exportRecord) await treeProvider?.refreshRecords({ force: false }) + else await treeProvider?.refreshDownloadedExports() } diff --git a/src/cmd/blog-export/refresh.ts b/src/cmd/blog-export/refresh.ts index b17d317e..03f32e1e 100644 --- a/src/cmd/blog-export/refresh.ts +++ b/src/cmd/blog-export/refresh.ts @@ -1,19 +1,15 @@ -import { CmdHandler } from '@/cmd/cmd-handler' import { execCmd } from '@/infra/cmd' -import { globalCtx } from '@/service/global-ctx' +import { globalCtx } from '@/ctx/global-ctx' import { BlogExportProvider } from '@/tree-view/provider/blog-export-provider' -import { commands } from 'vscode' -export class RefreshExportRecordsCmdHandler implements CmdHandler { - async handle(): Promise { - await this.setIsRefreshing(true) +export async function refreshExportRecord() { + await setIsRefreshing(true) - await BlogExportProvider.instance.refreshRecords() + await BlogExportProvider.instance.refreshRecords() - await this.setIsRefreshing(false) - } + await setIsRefreshing(false) +} - private setIsRefreshing(value: boolean) { - return execCmd('setContext', `${globalCtx.extName}.blog-export.records.isRefreshing`, value || undefined) - } +function setIsRefreshing(value: boolean) { + return execCmd('setContext', `${globalCtx.extName}.blog-export.records.isRefreshing`, value || undefined) } diff --git a/src/cmd/blog-export/view-post.ts b/src/cmd/blog-export/view-post.ts index c5a8a11d..61c42719 100644 --- a/src/cmd/blog-export/view-post.ts +++ b/src/cmd/blog-export/view-post.ts @@ -1,70 +1,59 @@ -import { TreeViewCmdHandler } from '@/cmd/cmd-handler' import { DownloadedBlogExport } from '@/model/blog-export' import { ExportPost } from '@/model/blog-export/export-post' import { ExportPostTreeItem } from '@/tree-view/model/blog-export/post' import { URLSearchParams } from 'url' import { languages, TextDocumentContentProvider, Uri, window, workspace } from 'vscode' -export class ViewPostCmdHandler implements TreeViewCmdHandler { - static readonly cmd = 'vscode-cnb.blog-export.view-post' - static readonly schema = 'vscode-cnb.blog-export.post' +const schema = 'vscode-cnb.blog-export.post' - constructor(public input: unknown) {} - - parseInput(): ExportPostTreeItem | null | undefined { - return this.input instanceof ExportPostTreeItem ? this.input : null - } - - async handle(): Promise { - const input = this.parseInput() - if (input == null) return - const { - parent: { downloadedExport }, - post, - } = input - if (downloadedExport == null) return +function parseInput(input: unknown): ExportPostTreeItem | null | undefined { + return input instanceof ExportPostTreeItem ? input : null +} - await this.provide(downloadedExport, post) - } +export async function viewPostBlogExport(input: unknown) { + const parsedInput = parseInput(input) + if (parsedInput == null || parsedInput.parent.downloadedExport == null) return - private async provide(downloadedExport: DownloadedBlogExport, { id: postId, title, isMarkdown }: ExportPost) { - const schema = `${ViewPostCmdHandler.schema}-${postId}` + await provide(parsedInput.parent.downloadedExport, parsedInput.post) +} - const matchedEditor = window.visibleTextEditors.find(({ document }) => { - if (document.uri.scheme === schema && !document.isClosed) { - const query = new URLSearchParams(document.uri.query) - const parsedId = Number.parseInt(query.get('postId') ?? '-1') - if (parsedId > 0 && parsedId === postId) return true - } +async function provide(downloadedExport: DownloadedBlogExport, { id: postId, title, isMarkdown }: ExportPost) { + const schemaWithId = `${schema}-${postId}` - return false - }) - if (matchedEditor) { - await window.showTextDocument(matchedEditor.document, { preview: false, preserveFocus: true }) - return + const matchedEditor = window.visibleTextEditors.find(({ document }) => { + if (document.uri.scheme === schemaWithId && !document.isClosed) { + const query = new URLSearchParams(document.uri.query) + const parsedId = Number.parseInt(query.get('postId') ?? '-1') + if (parsedId > 0 && parsedId === postId) return true } - const disposable = workspace.registerTextDocumentContentProvider( - schema, - new (class implements TextDocumentContentProvider { - async provideTextDocumentContent(): Promise { - const { ExportPostStore } = await import('@/service/blog-export-post.store') - const store = new ExportPostStore(downloadedExport) - return store.getBody(postId).finally(() => store.dispose()) - } - })() - ) - - const document = await workspace - .openTextDocument(Uri.parse(`${schema}:(只读) ${title}.${isMarkdown ? 'md' : 'html'}?postId=${postId}`)) - .then(x => x, console.warn) - if (document) { - await window.showTextDocument(document).then(undefined, console.warn) - await languages - .setTextDocumentLanguage(document, isMarkdown ? 'markdown' : 'html') - .then(undefined, console.warn) - } + return false + }) + if (matchedEditor) { + await window.showTextDocument(matchedEditor.document, { preview: false, preserveFocus: true }) + return + } - disposable.dispose() + const disposable = workspace.registerTextDocumentContentProvider( + schemaWithId, + new (class implements TextDocumentContentProvider { + async provideTextDocumentContent(): Promise { + const { ExportPostStore } = await import('@/service/blog-export-post.store') + const store = new ExportPostStore(downloadedExport) + return store.getBody(postId).finally(() => store.dispose()) + } + })() + ) + + const document = await workspace + .openTextDocument(Uri.parse(`${schemaWithId}:(只读) ${title}.${isMarkdown ? 'md' : 'html'}?postId=${postId}`)) + .then(x => x, console.warn) + if (document) { + await window.showTextDocument(document).then(undefined, console.warn) + await languages + .setTextDocumentLanguage(document, isMarkdown ? 'markdown' : 'html') + .then(undefined, console.warn) } + + disposable.dispose() } diff --git a/src/cmd/ing/ing-list-cmd-register.ts b/src/cmd/ing/ing-list-cmd-register.ts deleted file mode 100644 index da395cc5..00000000 --- a/src/cmd/ing/ing-list-cmd-register.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { RefreshingList } from '@/cmd/ing/refresh-ing-list' -import { globalCtx } from '@/service/global-ctx' -import { GotoingListFirstPage, IngListGoNextPage, GotoingListPreviousPage } from '@/cmd/ing/ing-list-go-next-page' -import { regCmd } from '@/infra/cmd' -import { openIngSite } from '@/cmd/open/open-ing-site' -import { switchIngType } from '@/cmd/ing/select-ing-type' - -export const regIngListCmds = () => { - const appName = globalCtx.extName - - return [ - regCmd(`${appName}.ing-list.refresh`, () => new RefreshingList().handle()), - regCmd(`${appName}.ing-list.next`, () => new IngListGoNextPage().handle()), - regCmd(`${appName}.ing-list.previous`, () => new GotoingListPreviousPage().handle()), - regCmd(`${appName}.ing-list.first`, () => new GotoingListFirstPage().handle()), - regCmd(`${appName}.ing-list.switch-type`, switchIngType), - regCmd(`${appName}.ing-list.open-in-browser`, openIngSite), - ] -} diff --git a/src/cmd/ing/ing-list-go-next-page.ts b/src/cmd/ing/ing-list-go-next-page.ts deleted file mode 100644 index e723768c..00000000 --- a/src/cmd/ing/ing-list-go-next-page.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { CmdHandler } from '@/cmd/cmd-handler' -import { getIngListWebviewProvider } from '@/service/ing-list-webview-provider' - -export class IngListGoNextPage implements CmdHandler { - handle(): Promise { - const provider = getIngListWebviewProvider() - const { pageIndex } = provider - return provider.refreshingList({ pageIndex: pageIndex + 1 }) - } -} - -export class GotoingListPreviousPage implements CmdHandler { - handle(): Promise { - const provider = getIngListWebviewProvider() - const { pageIndex } = provider - if (pageIndex > 1) return provider.refreshingList({ pageIndex: pageIndex - 1 }) - return Promise.resolve() - } -} - -export class GotoingListFirstPage implements CmdHandler { - handle(): Promise { - return getIngListWebviewProvider().refreshingList({ pageIndex: 1 }) - } -} diff --git a/src/cmd/ing/publish-ing.ts b/src/cmd/ing/publish-ing.ts index b41a3b6f..8f392cdb 100644 --- a/src/cmd/ing/publish-ing.ts +++ b/src/cmd/ing/publish-ing.ts @@ -2,14 +2,13 @@ import { CmdHandler } from '@/cmd/cmd-handler' import { execCmd } from '@/infra/cmd' import { IngPublishModel, IngType } from '@/model/ing' import { Alert } from '@/service/alert' -import { globalCtx } from '@/service/global-ctx' +import { globalCtx } from '@/ctx/global-ctx' import { IngApi } from '@/service/ing.api' import { getIngListWebviewProvider } from '@/service/ing-list-webview-provider' import { InputStep, MultiStepInput, QuickPickParameters } from '@/service/multi-step-input' import { MessageOptions, ProgressLocation, QuickPickItem, Uri, window } from 'vscode' export class PublishIngCmdHandler implements CmdHandler { - readonly maxLength = 0 readonly operation = '发布闪存' readonly editingText = '编辑闪存' readonly inputStep: Record<'content' | 'access' | 'tags', InputStep> = { @@ -73,7 +72,7 @@ export class PublishIngCmdHandler implements CmdHandler { inputIsPrivate = false currentStep = 0 - constructor(public readonly contentSource: 'selection' | 'input' = 'selection') {} + constructor(public readonly contentSource: 'select' | 'input' = 'select') {} private get formattedIngContent() { return `${this.inputTags.map(x => `[${x}]`).join('')}${this.inputContent}` @@ -98,7 +97,7 @@ export class PublishIngCmdHandler implements CmdHandler { private getContent(): Promise { switch (this.contentSource) { - case 'selection': + case 'select': return this.getContentFromSelection() case 'input': return this.acquireInputContent() diff --git a/src/cmd/ing/refresh-ing-list.ts b/src/cmd/ing/refresh-ing-list.ts index 9ed2b022..5c036188 100644 --- a/src/cmd/ing/refresh-ing-list.ts +++ b/src/cmd/ing/refresh-ing-list.ts @@ -1,8 +1,3 @@ -import { CmdHandler } from '@/cmd/cmd-handler' import { getIngListWebviewProvider } from '@/service/ing-list-webview-provider' -export class RefreshingList implements CmdHandler { - handle(): Promise { - return getIngListWebviewProvider().refreshingList() - } -} +export const refreshIngList = () => getIngListWebviewProvider().refreshingList() diff --git a/src/cmd/ing/switch-ing-list-page.ts b/src/cmd/ing/switch-ing-list-page.ts new file mode 100644 index 00000000..bf0d1774 --- /dev/null +++ b/src/cmd/ing/switch-ing-list-page.ts @@ -0,0 +1,18 @@ +import { getIngListWebviewProvider } from '@/service/ing-list-webview-provider' + +export function goIngListNextPage() { + const provider = getIngListWebviewProvider() + const { pageIndex } = provider + return provider.refreshingList({ pageIndex: pageIndex + 1 }) +} + +export function goIngListPrevPage() { + const provider = getIngListWebviewProvider() + const { pageIndex } = provider + if (pageIndex > 1) return provider.refreshingList({ pageIndex: pageIndex - 1 }) + return Promise.resolve() +} + +export function goIngList1stPage(): Promise { + return getIngListWebviewProvider().refreshingList({ pageIndex: 1 }) +} diff --git a/src/cmd/login.ts b/src/cmd/login.ts deleted file mode 100644 index 204c3352..00000000 --- a/src/cmd/login.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { accountManager } from '@/auth/account-manager' - -export const login = () => accountManager.login() - -export const logout = () => accountManager.logout() diff --git a/src/cmd/open/open-ing-site.ts b/src/cmd/open/open-ing-site.ts index 811d45b0..79e15b3c 100644 --- a/src/cmd/open/open-ing-site.ts +++ b/src/cmd/open/open-ing-site.ts @@ -1,5 +1,5 @@ import { execCmd } from '@/infra/cmd' -import { globalCtx } from '@/service/global-ctx' +import { globalCtx } from '@/ctx/global-ctx' import { Uri } from 'vscode' export const openIngSite = () => execCmd('vscode.open', Uri.parse(globalCtx.config.ingSite)) diff --git a/src/cmd/open/open-my-account-settings.ts b/src/cmd/open/open-my-account-setting.ts similarity index 78% rename from src/cmd/open/open-my-account-settings.ts rename to src/cmd/open/open-my-account-setting.ts index f93f113b..29a64aa0 100644 --- a/src/cmd/open/open-my-account-settings.ts +++ b/src/cmd/open/open-my-account-setting.ts @@ -1,5 +1,5 @@ import { Uri } from 'vscode' import { execCmd } from '@/infra/cmd' -export const openMyAccountSettings = () => +export const openMyAccountSetting = () => execCmd('vscode.open', Uri.parse('https://account.cnblogs.com/settings/account')) diff --git a/src/cmd/open/open-workspace.ts b/src/cmd/open/open-workspace.ts index 8bb0357c..3c4fd831 100644 --- a/src/cmd/open/open-workspace.ts +++ b/src/cmd/open/open-workspace.ts @@ -1,10 +1,10 @@ import { MessageOptions } from 'vscode' -import { Settings } from '@/service/settings' +import { ExtCfg } from '@/ctx/ext-cfg' import { execCmd } from '@/infra/cmd' import { Alert } from '@/service/alert' export const openWorkspace = async () => { - const uri = Settings.workspaceUri + const uri = ExtCfg.workspaceUri const { fsPath } = uri const options = ['在当前窗口中打开', '在新窗口中打开'] const input = await Alert.info(`即将打开 ${fsPath}`, { modal: true } as MessageOptions, ...options) diff --git a/src/cmd/pdf/export-pdf.ts b/src/cmd/pdf/export-pdf.ts index 77f6f182..c1112b06 100644 --- a/src/cmd/pdf/export-pdf.ts +++ b/src/cmd/pdf/export-pdf.ts @@ -8,7 +8,7 @@ import { PostFileMapManager } from '@/service/post-file-map' import { PostService } from '@/service/post' import { extTreeViews } from '@/tree-view/tree-view-register' import { ChromiumPathProvider } from '@/infra/chromium-path-provider' -import { Settings } from '@/service/settings' +import { ExtCfg } from '@/ctx/ext-cfg' import { accountManager } from '@/auth/account-manager' import { Alert } from '@/service/alert' import { PostTreeItem } from '@/tree-view/model/post-tree-item' @@ -98,7 +98,7 @@ const writePdfToFile = (dir: Uri, post: Post, buffer: Buffer) => }) const retrieveChromiumPath = async (): Promise => { - let path: string | undefined = ChromiumPathProvider.lookupExecutableFromMacApp(Settings.chromiumPath) + let path: string | undefined = ChromiumPathProvider.lookupExecutableFromMacApp(ExtCfg.chromiumPath) if (path && fs.existsSync(path)) return path const platform = os.platform() @@ -125,7 +125,7 @@ const retrieveChromiumPath = async (): Promise => { path = op ? await op[1]() : undefined } - if (path !== undefined && path !== Settings.chromiumPath) await Settings.setChromiumPath(path) + if (path !== undefined && path !== ExtCfg.chromiumPath) await ExtCfg.setChromiumPath(path) return path } diff --git a/src/cmd/pdf/post-pdf-template-builder.ts b/src/cmd/pdf/post-pdf-template-builder.ts index 1dab1ab5..09673bf4 100644 --- a/src/cmd/pdf/post-pdf-template-builder.ts +++ b/src/cmd/pdf/post-pdf-template-builder.ts @@ -1,7 +1,7 @@ import { Post } from '@/model/post' import { PostFileMapManager } from '@/service/post-file-map' import fs from 'fs' -import { BlogSettingsService } from '@/service/blog-settings' +import { BlogSettingService } from '@/service/blog-setting' import { accountManager } from '@/auth/account-manager' import { postCategoryService } from '@/service/post-category' import { PostCategory } from '@/model/post-category' @@ -61,7 +61,7 @@ export namespace postPdfTemplateBuilder { codeHighlightTheme, enableCodeLineNumber: isCodeLineNumberEnabled, blogId, - } = await BlogSettingsService.getBlogSettings() + } = await BlogSettingService.getBlogSetting() const { userId } = accountManager.currentUser return ` diff --git a/src/cmd/post-category/update-post-category.ts b/src/cmd/post-category/update-post-category.ts index dea5853d..471a46ad 100644 --- a/src/cmd/post-category/update-post-category.ts +++ b/src/cmd/post-category/update-post-category.ts @@ -4,7 +4,7 @@ import { PostCategory } from '@/model/post-category' import { postCategoryService } from '@/service/post-category' import { inputPostCategory } from './input-post-category' import { refreshPostCategoryList } from './refresh-post-category-list' -import { Settings } from '@/service/settings' +import { ExtCfg } from '@/ctx/ext-cfg' import { BasePostCategoryTreeViewCmdHandler } from './base-tree-view-cmd-handler' class UpdatePostCategoryTreeViewCmdHandler extends BasePostCategoryTreeViewCmdHandler { @@ -32,8 +32,8 @@ class UpdatePostCategoryTreeViewCmdHandler extends BasePostCategoryTreeViewCmdHa await postCategoryService.updateCategory(updateDto) refreshPostCategoryList() // 如果选择了createLocalPostFileWithCategory模式且本地有该目录,则重命名该目录 - const workspaceUri = Settings.workspaceUri - const shouldCreateLocalPostFileWithCategory = Settings.createLocalPostFileWithCategory + const workspaceUri = ExtCfg.workspaceUri + const shouldCreateLocalPostFileWithCategory = ExtCfg.createLocalPostFileWithCategory const uri = Uri.joinPath(workspaceUri, category.title).fsPath const isFileExist = fs.existsSync(uri) if (shouldCreateLocalPostFileWithCategory && isFileExist) { diff --git a/src/cmd/post-list/create-local-draft.ts b/src/cmd/post-list/create-local-draft.ts index c4a93c9c..1f998051 100644 --- a/src/cmd/post-list/create-local-draft.ts +++ b/src/cmd/post-list/create-local-draft.ts @@ -1,14 +1,14 @@ import { homedir } from 'os' import path from 'path' import { Uri, window, workspace } from 'vscode' -import { Settings } from '@/service/settings' +import { ExtCfg } from '@/ctx/ext-cfg' import { revealActiveFileInExplorer } from '@/infra/reveal-active-file' import { openPostFile } from './open-post-file' export const createLocalDraft = async () => { let title = await window.showInputBox({ placeHolder: '请输入标题', - prompt: `文件将会保存到 ${Settings.workspaceUri.fsPath.replace(homedir(), '~')} 目录下`, + prompt: `文件将会保存到 ${ExtCfg.workspaceUri.fsPath.replace(homedir(), '~')} 目录下`, title: '新建本地草稿', validateInput: input => { if (!input) return '标题不能为空' @@ -18,7 +18,7 @@ export const createLocalDraft = async () => { }) if (!title) return - const { fsPath: workspacePath } = Settings.workspaceUri + const { fsPath: workspacePath } = ExtCfg.workspaceUri title = ['.md', '.html'].some(ext => title && title.endsWith(ext)) ? title : `${title}${title.endsWith('.') ? '' : '.'}md` diff --git a/src/cmd/post-list/modify-post-settings.ts b/src/cmd/post-list/modify-post-setting.ts similarity index 96% rename from src/cmd/post-list/modify-post-settings.ts rename to src/cmd/post-list/modify-post-setting.ts index 6e7a474b..0fbddfe7 100644 --- a/src/cmd/post-list/modify-post-settings.ts +++ b/src/cmd/post-list/modify-post-setting.ts @@ -12,7 +12,7 @@ import { postDataProvider } from '@/tree-view/provider/post-data-provider' import { PostTreeItem } from '@/tree-view/model/post-tree-item' import { postCategoryDataProvider } from '@/tree-view/provider/post-category-tree-data-provider' -export const modifyPostSettings = async (input: Post | PostTreeItem | Uri) => { +export const modifyPostSetting = async (input: Post | PostTreeItem | Uri) => { let post: Post | undefined let postId = -1 input = input instanceof PostTreeItem ? input.post : input diff --git a/src/cmd/post-list/open-post-in-vscode.ts b/src/cmd/post-list/open-post-in-vscode.ts index 45b91ccd..757a19e5 100644 --- a/src/cmd/post-list/open-post-in-vscode.ts +++ b/src/cmd/post-list/open-post-in-vscode.ts @@ -5,15 +5,15 @@ import { Post } from '@/model/post' import { Alert } from '@/service/alert' import { PostService } from '@/service/post' import { PostFileMapManager } from '@/service/post-file-map' -import { Settings } from '@/service/settings' +import { ExtCfg } from '@/ctx/ext-cfg' import { openPostFile } from './open-post-file' import { PostTitleSanitizer } from '@/service/post-title-sanitizer' import { postCategoryService } from '@/service/post-category' import sanitizeFileName from 'sanitize-filename' const buildLocalPostFileUri = async (post: Post, includePostId = false): Promise => { - const workspaceUri = Settings.workspaceUri - const shouldCreateLocalPostFileWithCategory = Settings.createLocalPostFileWithCategory + const workspaceUri = ExtCfg.workspaceUri + const shouldCreateLocalPostFileWithCategory = ExtCfg.createLocalPostFileWithCategory const ext = `.${post.isMarkdown ? 'md' : 'html'}` const postIdSegment = includePostId ? `.${post.id}` : '' const { text: postTitle } = await PostTitleSanitizer.sanitize(post) @@ -56,7 +56,7 @@ export const openPostInVscode = async (postId: number, forceUpdateLocalPostFile const post = postEditDto.post - const workspaceUri = Settings.workspaceUri + const workspaceUri = ExtCfg.workspaceUri await createDirectoryIfNotExist(workspaceUri) let fileUri = mappedPostFilePath ? Uri.file(mappedPostFilePath) : await buildLocalPostFileUri(post) diff --git a/src/cmd/post-list/refresh-post-list.ts b/src/cmd/post-list/refresh-post-list.ts index 64dbdf69..25511ab9 100644 --- a/src/cmd/post-list/refresh-post-list.ts +++ b/src/cmd/post-list/refresh-post-list.ts @@ -1,4 +1,4 @@ -import { globalCtx } from '@/service/global-ctx' +import { globalCtx } from '@/ctx/global-ctx' import { PostService } from '@/service/post' import { window } from 'vscode' import { postDataProvider } from '@/tree-view/provider/post-data-provider' @@ -40,7 +40,6 @@ export const refreshPostList = async ({ queue = false } = {}): Promise .then(() => true) } }) - // TODO: impl `always` fn .then(ok => postDataProvider.refreshSearch().then(() => ok)) .then(ok => setRefreshing(false).then(() => ok)) .catch(() => false) @@ -50,13 +49,9 @@ export const refreshPostList = async ({ queue = false } = {}): Promise return refreshTask } -export const gotoNextPostList = async () => { - await gotoPage(c => c + 1) -} +export const goNextPostList = () => goPage(i => i + 1) -export const gotoPreviousPostList = async () => { - await gotoPage(c => c - 1) -} +export const goPrevPostList = () => goPage(i => i - 1) export const seekPostList = async () => { const input = await window.showInputBox({ @@ -74,7 +69,7 @@ export const seekPostList = async () => { }, }) const pageIndex = Number.parseInt(input ?? '-1') - if (pageIndex > 0 && !isNaN(pageIndex)) await gotoPage(() => pageIndex) + if (pageIndex > 0 && !isNaN(pageIndex)) await goPage(() => pageIndex) } let isRefreshing = false @@ -95,7 +90,7 @@ const alertRefreshing = () => { void Alert.info('正在刷新, 请勿重复操作') } -const gotoPage = async (pageIndex: (currentIndex: number) => number) => { +const goPage = async (pageIndex: (currentIndex: number) => number) => { if (isRefreshing) { alertRefreshing() return diff --git a/src/cmd/post-list/upload-post.ts b/src/cmd/post-list/upload-post.ts index 2806f90b..e27bf440 100644 --- a/src/cmd/post-list/upload-post.ts +++ b/src/cmd/post-list/upload-post.ts @@ -14,7 +14,7 @@ import { PostEditDto } from '@/model/post-edit-dto' import { PostCfgPanel } from '@/service/post-cfg-panel' import { saveFilePendingChanges } from '@/infra/save-file-pending-changes' import { extractImg } from '@/cmd/extract-img' -import { Settings } from '@/service/settings' +import { ExtCfg } from '@/ctx/ext-cfg' import { PostTreeItem } from '@/tree-view/model/post-tree-item' const parseFileUri = async (fileUri: Uri | undefined): Promise => { @@ -34,14 +34,14 @@ const parseFileUri = async (fileUri: Uri | undefined): Promise return fileUri } -export const uploadPostFileToCnblogs = async (fileUri: Uri | undefined) => { +export const uploadPostFile = async (fileUri: Uri | undefined) => { fileUri = await parseFileUri(fileUri) if (!fileUri) return const { fsPath: filePath } = fileUri const postId = PostFileMapManager.getPostId(filePath) if (postId && postId >= 0) { - await uploadPostToCnblogs(await PostService.fetchPostEditDto(postId)) + await uploadPost(await PostService.fetchPostEditDto(postId)) } else { const options = [`新建博文`, `关联已有博文`] const selected = await Alert.info( @@ -67,7 +67,7 @@ export const uploadPostFileToCnblogs = async (fileUri: Uri | undefined) => { if (!fileContent) await workspace.fs.writeFile(fileUri, Buffer.from(postEditDto.post.postBody)) - await uploadPostToCnblogs(postEditDto.post) + await uploadPost(postEditDto.post) } } } @@ -115,8 +115,8 @@ export const saveLocalDraftToCnblogs = async (localDraft: LocalDraft) => { void Alert.warn('本地文件已删除, 无法新建博文') return false } - if (Settings.autoExtractImgSrc !== undefined) - await extractImg(localDraft.filePathUri, Settings.autoExtractImgSrc).catch(console.warn) + if (ExtCfg.autoExtractImgSrc !== undefined) + await extractImg(localDraft.filePathUri, ExtCfg.autoExtractImgSrc).catch(console.warn) postToSave.postBody = await localDraft.readAllText() return true @@ -124,7 +124,7 @@ export const saveLocalDraftToCnblogs = async (localDraft: LocalDraft) => { }) } -export const uploadPostToCnblogs = async (input: Post | PostTreeItem | PostEditDto | undefined) => { +export const uploadPost = async (input: Post | PostTreeItem | PostEditDto | undefined) => { input = input instanceof PostTreeItem ? input.post : input const post = input instanceof PostEditDto @@ -138,8 +138,8 @@ export const uploadPostToCnblogs = async (input: Post | PostTreeItem | PostEditD const localFilePath = PostFileMapManager.getFilePath(postId) if (!localFilePath) return Alert.warn('本地无该博文的编辑记录') - if (Settings.autoExtractImgSrc !== undefined) - await extractImg(Uri.file(localFilePath), Settings.autoExtractImgSrc).catch(console.warn) + if (ExtCfg.autoExtractImgSrc !== undefined) + await extractImg(Uri.file(localFilePath), ExtCfg.autoExtractImgSrc).catch(console.warn) await saveFilePendingChanges(localFilePath) post.postBody = (await workspace.fs.readFile(Uri.file(localFilePath))).toString() @@ -147,7 +147,7 @@ export const uploadPostToCnblogs = async (input: Post | PostTreeItem | PostEditD if (!validatePost(post)) return false - if (Settings.showConfirmMsgWhenUploadPost) { + if (ExtCfg.showConfirmMsgWhenUploadPost) { const answer = await Alert.warn( '确认上传吗?', { diff --git a/src/cmd/pull-post-remote-updates.ts b/src/cmd/pull-remote-post.ts similarity index 81% rename from src/cmd/pull-post-remote-updates.ts rename to src/cmd/pull-remote-post.ts index 14c03212..7da1852d 100644 --- a/src/cmd/pull-post-remote-updates.ts +++ b/src/cmd/pull-remote-post.ts @@ -8,32 +8,32 @@ import { Alert } from '@/service/alert' import path from 'path' import { revealPostListItem } from '@/service/post-list-view' import { PostTreeItem } from '@/tree-view/model/post-tree-item' -import { Settings } from '@/service/settings' +import { ExtCfg } from '@/ctx/ext-cfg' -export async function pullPostRemoteUpdates(input: Post | PostTreeItem | Uri | undefined | null) { - const ctxs: CmdCtx[] = [] +export async function pullRemotePost(input: Post | PostTreeItem | Uri | undefined | null) { + const ctxList: CmdCtx[] = [] let uri: Uri | undefined input = input instanceof PostTreeItem ? input.post : input - if (parsePostInput(input) && input.id > 0) await handlePostInput(input, ctxs) - else if ((uri = parseUriInput(input))) await handleUriInput(uri, ctxs) + if (parsePostInput(input) && input.id > 0) await handlePostInput(input, ctxList) + else if ((uri = parseUriInput(input))) await handleUriInput(uri, ctxList) - if (Settings.showConfirmMsgWhenPullPost) { + if (ExtCfg.showConfirmMsgWhenPullPost) { const answer = await Alert.warn( '确认要拉取远程博文吗?', { modal: true, - detail: `本地文件 ${resolveFileNames(ctxs)} 将被覆盖, 请谨慎操作!(此消息可在设置中关闭)`, + detail: `本地文件 ${resolveFileNames(ctxList)} 将被覆盖, 请谨慎操作!(此消息可在设置中关闭)`, } as MessageOptions, '确认' ) if (answer !== '确认') return } - if (ctxs.length <= 0) return + if (ctxList.length <= 0) return - await update(ctxs) + await update(ctxList) - void Alert.info(`本地文件${resolveFileNames(ctxs)}已更新`) + void Alert.info(`本地文件${resolveFileNames(ctxList)}已更新`) } type InputType = Post | Uri | undefined | null @@ -86,4 +86,4 @@ const update = async (contexts: CmdCtx[]) => { } } -const resolveFileNames = (ctxs: CmdCtx[]) => `"${ctxs.map(x => path.basename(x.fileUri.fsPath)).join('", ')}"` +const resolveFileNames = (ctxList: CmdCtx[]) => `"${ctxList.map(x => path.basename(x.fileUri.fsPath)).join('", ')}"` diff --git a/src/cmd/reveal-workspace-in-os.ts b/src/cmd/reveal-workspace-in-os.ts index 6eb9a333..d4aa155b 100644 --- a/src/cmd/reveal-workspace-in-os.ts +++ b/src/cmd/reveal-workspace-in-os.ts @@ -1,5 +1,4 @@ -import { commands } from 'vscode' import { execCmd } from '@/infra/cmd' -import { Settings } from '@/service/settings' +import { ExtCfg } from '@/ctx/ext-cfg' -export const revealWorkspaceInOs = () => execCmd('revealFileInOS', Settings.workspaceUri) +export const revealWorkspaceInOs = () => execCmd('revealFileInOS', ExtCfg.workspaceUri) diff --git a/src/cmd/set-workspace.ts b/src/cmd/set-workspace.ts index 79de0a55..f9394da9 100644 --- a/src/cmd/set-workspace.ts +++ b/src/cmd/set-workspace.ts @@ -1,6 +1,6 @@ import { window } from 'vscode' import { Alert } from '@/service/alert' -import { Settings } from '@/service/settings' +import { ExtCfg } from '@/ctx/ext-cfg' export const setWorkspace = async () => { const uris = @@ -9,13 +9,13 @@ export const setWorkspace = async () => { canSelectFolders: true, canSelectFiles: false, canSelectMany: false, - defaultUri: Settings.workspaceUri, + defaultUri: ExtCfg.workspaceUri, })) ?? [] const firstUri = uris[0] if (firstUri === undefined) return - await Settings.setWorkspaceUri(firstUri) - void Alert.info(`工作空间成功修改为: "${Settings.workspaceUri.fsPath}"`) + await ExtCfg.setWorkspaceUri(firstUri) + void Alert.info(`工作空间成功修改为: "${ExtCfg.workspaceUri.fsPath}"`) } diff --git a/src/cmd/upload-img/upload-clipboard-img.ts b/src/cmd/upload-img/upload-clipboard-img.ts index ba21d245..70410b28 100644 --- a/src/cmd/upload-img/upload-clipboard-img.ts +++ b/src/cmd/upload-img/upload-clipboard-img.ts @@ -6,7 +6,7 @@ import getClipboardImage from '@/infra/get-clipboard-img' const noImagePath = 'no image' -export const uploadImageFromClipboard = async () => { +export const uploadImgFromClipboard = async () => { const clipboardImage = await getClipboardImage() if (clipboardImage.imgPath === noImagePath) { void Alert.warn('剪贴板中没有找到图片') diff --git a/src/cmd/upload-img/upload-img.ts b/src/cmd/upload-img/upload-img.ts index 63f174e4..c5f5dcc9 100644 --- a/src/cmd/upload-img/upload-img.ts +++ b/src/cmd/upload-img/upload-img.ts @@ -1,9 +1,9 @@ import { Alert } from '@/service/alert' -import { uploadImageFromClipboard } from './upload-clipboard-img' +import { uploadImgFromClipboard } from './upload-clipboard-img' import { insertImgLinkToActiveEditor, showUploadSuccessModel } from './upload-img-util' import { uploadFsImage } from './upload-fs-img' -export const uploadImage = async (autoInsertToActiveEditor = true, from?: 'local' | 'clipboard') => { +export const uploadImg = async (autoInsertToActiveEditor = true, from?: 'local' | 'clipboard') => { const options = ['本地图片文件', '剪贴板图片'] const selected = !from ? await Alert.info( @@ -26,7 +26,7 @@ export const uploadImage = async (autoInsertToActiveEditor = true, from?: 'local break case 'clipboard': case options[1]: - imageUrl = await uploadImageFromClipboard().catch(caughtFailedUpload) + imageUrl = await uploadImgFromClipboard().catch(caughtFailedUpload) break default: break diff --git a/src/service/settings.ts b/src/ctx/ext-cfg.ts similarity index 61% rename from src/service/settings.ts rename to src/ctx/ext-cfg.ts index 48a1354c..4fc19c13 100644 --- a/src/service/settings.ts +++ b/src/ctx/ext-cfg.ts @@ -1,11 +1,11 @@ import os, { homedir } from 'os' import fs from 'fs' import { ConfigurationTarget, Uri, workspace } from 'vscode' -import { ImgSrc } from './mkd-img-extractor' +import { ImgSrc } from '@/service/mkd-img-extractor' import { isNumber } from 'lodash-es' import { untildify } from '@/infra/untildify' -export class Settings { +export class ExtCfg { static postListPageSizeKey = 'pageSize.postList' static cfgPrefix = `cnblogsClient` static iconThemePrefix = 'workbench' @@ -30,16 +30,15 @@ export class Settings { } static get iconTheme() { - return workspace.getConfiguration(Settings.iconThemePrefix).get(Settings.iconThemeKey) + return workspace.getConfiguration(ExtCfg.iconThemePrefix).get(ExtCfg.iconThemeKey) } static get cfg() { - return workspace.getConfiguration(Settings.cfgPrefix) + return workspace.getConfiguration(ExtCfg.cfgPrefix) } static get platformCfg() { - if (this.platformPrefix != null) - return workspace.getConfiguration(`${Settings.cfgPrefix}.${this.platformPrefix}`) + if (this.platformPrefix != null) return workspace.getConfiguration(`${ExtCfg.cfgPrefix}.${this.platformPrefix}`) return null } @@ -53,20 +52,20 @@ export class Settings { if (legacy) return legacy - const workspace = this.platformCfg?.get(Settings.workspaceUriKey) + const workspace = this.platformCfg?.get(ExtCfg.workspaceUriKey) return workspace ? Uri.file(untildify(workspace)) : this._defaultWorkspaceUri } static get chromiumPath(): string { - return this.platformCfg?.get(Settings.chromiumPathKey) ?? '' + return this.platformCfg?.get(ExtCfg.chromiumPathKey) ?? '' } static get createLocalPostFileWithCategory(): boolean { - return Settings.cfg.get('createLocalPostFileWithCategory') ?? false + return ExtCfg.cfg.get('createLocalPostFileWithCategory') ?? false } static get autoExtractImgSrc(): ImgSrc | undefined { - const cfg = Settings.cfg.get<'disable' | 'web' | 'dataUrl' | 'fs' | 'any'>('autoExtractImages') + const cfg = ExtCfg.cfg.get<'disable' | 'web' | 'dataUrl' | 'fs' | 'any'>('autoExtractImages') if (cfg === 'disable') return if (cfg === 'fs') return ImgSrc.fs @@ -76,32 +75,32 @@ export class Settings { } static get postListPageSize() { - const size = Settings.cfg.get(Settings.postListPageSizeKey) + const size = ExtCfg.cfg.get(ExtCfg.postListPageSizeKey) return isNumber(size) ? size : 30 } static get showConfirmMsgWhenUploadPost() { - return Settings.cfg.get('markdown.showConfirmMsgWhenUploadPost') ?? true + return ExtCfg.cfg.get('markdown.showConfirmMsgWhenUploadPost') ?? true } static get showConfirmMsgWhenPullPost() { - return Settings.cfg.get('markdown.showConfirmMsgWhenPullPost') ?? true + return ExtCfg.cfg.get('markdown.showConfirmMsgWhenPullPost') ?? true } static get enableMarkdownEnhancement() { - return Settings.cfg.get('markdown.enableEnhancement') ?? true + return ExtCfg.cfg.get('markdown.enableEnhancement') ?? true } static get enableMarkdownFenceBlockquote() { - return Settings.cfg.get('markdown.enableFenceQuote') ?? true + return ExtCfg.cfg.get('markdown.enableFenceQuote') ?? true } static get enableMarkdownHighlightCodeLines() { - return Settings.cfg.get('markdown.enableHighlightCodeLines') + return ExtCfg.cfg.get('markdown.enableHighlightCodeLines') } private static get legacyWorkspaceUri() { - const path = this.platformCfg?.get(Settings.workspaceUriKey)?.replace('~', os.homedir()) + const path = this.platformCfg?.get(ExtCfg.workspaceUriKey)?.replace('~', os.homedir()) if (path === undefined) return undefined @@ -113,33 +112,33 @@ export class Settings { if (!fs.existsSync(uri.fsPath)) throw Error(`Path not exist: ${uri.fsPath}`) - await this.platformCfg?.update(Settings.workspaceUriKey, uri.fsPath, ConfigurationTarget.Global) + await this.platformCfg?.update(ExtCfg.workspaceUriKey, uri.fsPath, ConfigurationTarget.Global) } static async setChromiumPath(value: string) { - await this.platformCfg?.update(Settings.chromiumPathKey, value, ConfigurationTarget.Global) + await this.platformCfg?.update(ExtCfg.chromiumPathKey, value, ConfigurationTarget.Global) } static async setCreateLocalPostFileWithCategory(value: boolean) { - await Settings.cfg.update('createLocalPostFileWithCategory', value, ConfigurationTarget.Global) + await ExtCfg.cfg.update('createLocalPostFileWithCategory', value, ConfigurationTarget.Global) } static async migrateEnablePublishSelectionToIng() { const oldKey = 'ing.enablePublishSelectionToIng' - const enablePublishSelectionToIng = Settings.cfg.get(oldKey) + const enablePublishSelectionToIng = ExtCfg.cfg.get(oldKey) if (enablePublishSelectionToIng === true) { - const isOk = await Settings.cfg - .update('menus.context.editor', { 'ing:publish-selection': true }, ConfigurationTarget.Global) + const isOk = await ExtCfg.cfg + .update('menus.context.editor', { 'ing:publish-select': true }, ConfigurationTarget.Global) .then( () => true, () => false ) - if (isOk) await Settings.cfg.update(oldKey, undefined, ConfigurationTarget.Global) + if (isOk) await ExtCfg.cfg.update(oldKey, undefined, ConfigurationTarget.Global) } } private static removeLegacyWorkspaceUri() { - return Settings.cfg.update(Settings.workspaceUriKey, undefined, ConfigurationTarget.Global) + return ExtCfg.cfg.update(ExtCfg.workspaceUriKey, undefined, ConfigurationTarget.Global) } } diff --git a/src/service/global-ctx.ts b/src/ctx/global-ctx.ts similarity index 100% rename from src/service/global-ctx.ts rename to src/ctx/global-ctx.ts diff --git a/src/extension.ts b/src/extension.ts index 1249e178..6707e5d2 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -1,12 +1,12 @@ import { setupExtTreeView } from '@/tree-view/tree-view-register' import { setupExtCmd } from '@/setup/setup-cmd' -import { globalCtx } from '@/service/global-ctx' +import { globalCtx } from '@/ctx/global-ctx' import { window, ExtensionContext } from 'vscode' import { accountManager } from '@/auth/account-manager' import { setupWorkspaceWatch, setupCfgWatch, setupWorkspaceFileWatch } from '@/setup/setup-watch' import { extUriHandler } from '@/infra/uri-handler' import { extendMarkdownIt } from '@/markdown/extend-markdownIt' -import { Settings } from '@/service/settings' +import { ExtCfg } from '@/ctx/ext-cfg' import { getIngListWebviewProvider } from '@/service/ing-list-webview-provider' import { setupUi } from '@/setup/setup-ui' @@ -25,13 +25,13 @@ export function activate(ctx: ExtensionContext) { setupWorkspaceFileWatch() ) - Settings.migrateEnablePublishSelectionToIng().catch(console.warn) + ExtCfg.migrateEnablePublishSelectionToIng().catch(console.warn) window.registerUriHandler(extUriHandler) void accountManager.updateAuthStatus() - setupUi(Settings.cfg) + setupUi(ExtCfg.cfg) return { extendMarkdownIt } } diff --git a/src/infra/get-clipboard-img.ts b/src/infra/get-clipboard-img.ts index 338b1ddd..d854157e 100644 --- a/src/infra/get-clipboard-img.ts +++ b/src/infra/get-clipboard-img.ts @@ -5,7 +5,7 @@ import path from 'path' import fs from 'fs' import os from 'os' import isWsl from 'is-wsl' -import { globalCtx } from '@/service/global-ctx' +import { globalCtx } from '@/ctx/global-ctx' import { Alert } from '@/service/alert' import { IClipboardImg } from '@/model/clipboard-img' import format from 'date-fns/format' diff --git a/src/infra/input-post-settings.ts b/src/infra/input-post-setting.ts similarity index 93% rename from src/infra/input-post-settings.ts rename to src/infra/input-post-setting.ts index 6b0ca0b6..0aec21ed 100644 --- a/src/infra/input-post-settings.ts +++ b/src/infra/input-post-setting.ts @@ -34,10 +34,10 @@ class AccessPermissionPickItem implements QuickPickItem { constructor(public id: AccessPermission, public label: string) {} } -type PostSettingsType = 'categoryIds' | 'tags' | 'description' | 'password' | 'accessPermission' | 'isPublished' -type PostSettingsDto = Pick +type PostSettingType = 'categoryIds' | 'tags' | 'description' | 'password' | 'accessPermission' | 'isPublished' +type PostSettingDto = Pick -const defaultSteps: PostSettingsType[] = [ +const defaultSteps: PostSettingType[] = [ 'accessPermission', 'description', 'categoryIds', @@ -48,11 +48,11 @@ const defaultSteps: PostSettingsType[] = [ const parseTagNames = (value: string) => value.split(/[,,]/).filter(({ length }) => length > 0) -export const inputPostSettings = ( +export const inputPostSetting = ( postTitle: string, - source: PostSettingsDto, - steps: PostSettingsType[] = [] -): Promise => { + source: PostSettingDto, + steps: PostSettingType[] = [] +): Promise => { steps = steps?.length > 0 ? steps : defaultSteps const configuredPost = Object.assign({}, source) const state = { @@ -60,10 +60,10 @@ export const inputPostSettings = ( totalSteps: steps.length, step: 1, } - let map: [PostSettingsType, (input: MultiStepInput) => Promise][] = [] + let map: [PostSettingType, (input: MultiStepInput) => Promise][] = [] const calculateNextStep = (): undefined | InputStep => state.step > steps.length ? undefined : map.find(x => x[0] === steps[state.step - 1])?.[1] - const calculateStepNumber = (type: PostSettingsType) => { + const calculateStepNumber = (type: PostSettingType) => { state.step = steps.findIndex(x => x === type) + 1 } diff --git a/src/markdown/extend-markdownIt.ts b/src/markdown/extend-markdownIt.ts index e9167dd8..73e63599 100644 --- a/src/markdown/extend-markdownIt.ts +++ b/src/markdown/extend-markdownIt.ts @@ -1,12 +1,12 @@ -import { Settings } from '@/service/settings' +import { ExtCfg } from '@/ctx/ext-cfg' import { HighlightCodeLinesPlugin, MultilineBlockquotePlugin } from '@cnblogs/markdown-it-presets' import type { MarkdownIt } from '@cnblogs/markdown-it-presets' export const extendMarkdownIt = (md: MarkdownIt) => md .use(MultilineBlockquotePlugin, { - enable: () => Settings.enableMarkdownEnhancement && Settings.enableMarkdownFenceBlockquote, + enable: () => ExtCfg.enableMarkdownEnhancement && ExtCfg.enableMarkdownFenceBlockquote, }) .use(HighlightCodeLinesPlugin, { - enable: () => Settings.enableMarkdownEnhancement && Settings.enableMarkdownHighlightCodeLines, + enable: () => ExtCfg.enableMarkdownEnhancement && ExtCfg.enableMarkdownHighlightCodeLines, }) diff --git a/src/model/blog-settings.ts b/src/model/blog-setting.ts similarity index 95% rename from src/model/blog-settings.ts rename to src/model/blog-setting.ts index 9ccc008d..1fb0d3a2 100644 --- a/src/model/blog-settings.ts +++ b/src/model/blog-setting.ts @@ -1,4 +1,4 @@ -export class BlogSettings implements BlogSiteDto, BlogSiteExtendDto { +export class BlogSetting implements BlogSiteDto, BlogSiteExtendDto { blogId = -1 blogNews = '' secondaryCss = '' diff --git a/src/model/webview-cmd.ts b/src/model/webview-cmd.ts index f1efcc02..0f4042b5 100644 --- a/src/model/webview-cmd.ts +++ b/src/model/webview-cmd.ts @@ -14,7 +14,7 @@ export namespace WebviewCmd { export enum ExtCmd { uploadPost = 'uploadPost', disposePanel = 'disposePanel', - uploadImage = 'uploadImage', + uploadImg = 'uploadImg', refreshPost = 'refreshPost', getChildCategories = 'getChildCategories', } diff --git a/src/service/blog-export.api.ts b/src/service/blog-export.api.ts index 1a25729c..e0d33c68 100644 --- a/src/service/blog-export.api.ts +++ b/src/service/blog-export.api.ts @@ -1,5 +1,5 @@ import { BlogExportRecord, BlogExportRecordList } from '@/model/blog-export' -import { globalCtx } from '@/service/global-ctx' +import { globalCtx } from '@/ctx/global-ctx' import got from '@/infra/http-client' const basePath = `${globalCtx.config.apiBaseUrl}/api/blogExports` diff --git a/src/service/blog-settings.ts b/src/service/blog-setting.ts similarity index 57% rename from src/service/blog-settings.ts rename to src/service/blog-setting.ts index 393ed855..ae0da26a 100644 --- a/src/service/blog-settings.ts +++ b/src/service/blog-setting.ts @@ -1,11 +1,11 @@ import fetch from '@/infra/fetch-client' -import { BlogSettings, BlogSiteDto, BlogSiteExtendDto } from '@/model/blog-settings' -import { globalCtx } from './global-ctx' +import { BlogSetting, BlogSiteDto, BlogSiteExtendDto } from '@/model/blog-setting' +import { globalCtx } from '@/ctx/global-ctx' -let settingCache: BlogSettings | null = null +let settingCache: BlogSetting | null = null -export namespace BlogSettingsService { - export async function getBlogSettings(refresh = false) { +export namespace BlogSettingService { + export async function getBlogSetting(refresh = false) { if (settingCache != null && !refresh) return settingCache const url = `${globalCtx.config.apiBaseUrl}/api/settings` @@ -14,7 +14,7 @@ export namespace BlogSettingsService { const data = (await res.json()) as { blogSite: BlogSiteDto; extend: BlogSiteExtendDto } - settingCache ??= new BlogSettings(data.blogSite, data.extend) + settingCache ??= new BlogSetting(data.blogSite, data.extend) return settingCache } diff --git a/src/service/downloaded-export.store.ts b/src/service/downloaded-export.store.ts index 1d4f4fed..6b03fc96 100644 --- a/src/service/downloaded-export.store.ts +++ b/src/service/downloaded-export.store.ts @@ -1,5 +1,5 @@ import { DownloadedBlogExport } from '@/model/blog-export' -import { globalCtx } from '@/service/global-ctx' +import { globalCtx } from '@/ctx/global-ctx' import { exists, existsSync } from 'fs' import { take } from 'lodash-es' import { promisify } from 'util' diff --git a/src/service/img.ts b/src/service/img.ts index 78162048..a09795e5 100644 --- a/src/service/img.ts +++ b/src/service/img.ts @@ -1,4 +1,4 @@ -import { globalCtx } from './global-ctx' +import { globalCtx } from '@/ctx/global-ctx' import { Readable } from 'stream' import { isString, merge, pick } from 'lodash-es' import httpClient from '@/infra/http-client' diff --git a/src/service/ing-list-webview-provider.ts b/src/service/ing-list-webview-provider.ts index 1d2d9b11..7fe832f5 100644 --- a/src/service/ing-list-webview-provider.ts +++ b/src/service/ing-list-webview-provider.ts @@ -1,4 +1,4 @@ -import { globalCtx } from '@/service/global-ctx' +import { globalCtx } from '@/ctx/global-ctx' import { CancellationToken, Disposable, @@ -17,7 +17,7 @@ import { isNumber } from 'lodash-es' import { CommentIngCmdHandler } from '@/cmd/ing/comment-ing' import { execCmd } from '@/infra/cmd' import { ingStarToText } from '@/infra/convert/ing-star-to-text' -import { Settings } from '@/service/settings' +import { ExtCfg } from '@/ctx/ext-cfg' import { isDisableIngUserAvatar, isEnableTextIngStar } from '@/setup/setup-ui' export class IngListWebviewProvider implements WebviewViewProvider { @@ -91,8 +91,8 @@ export class IngListWebviewProvider implements WebviewViewProvider { pageSize: 30, }) const ingList = rawIngList.map(ing => { - if (isDisableIngUserAvatar(Settings.cfg)) ing.userIconUrl = '' - if (isEnableTextIngStar(Settings.cfg)) ing.icons = ingStarToText(ing.icons) + if (isDisableIngUserAvatar(ExtCfg.cfg)) ing.userIconUrl = '' + if (isEnableTextIngStar(ExtCfg.cfg)) ing.icons = ingStarToText(ing.icons) return ing }) const comments = await IngApi.listComments(...ingList.map(x => x.id)) diff --git a/src/service/ing.api.ts b/src/service/ing.api.ts index 5e1b08c2..208e1dd6 100644 --- a/src/service/ing.api.ts +++ b/src/service/ing.api.ts @@ -1,6 +1,6 @@ import { Ing, IngComment, IngPublishModel, IngType } from '@/model/ing' import { Alert } from '@/service/alert' -import { globalCtx } from '@/service/global-ctx' +import { globalCtx } from '@/ctx/global-ctx' import fetch from '@/infra/fetch-client' import { URLSearchParams } from 'url' import { isArray, isObject } from 'lodash-es' diff --git a/src/service/is-target-workspace.ts b/src/service/is-target-workspace.ts index 344b856f..f2dfc5ea 100644 --- a/src/service/is-target-workspace.ts +++ b/src/service/is-target-workspace.ts @@ -1,15 +1,15 @@ import os from 'os' import { workspace } from 'vscode' -import { globalCtx } from './global-ctx' +import { globalCtx } from '@/ctx/global-ctx' import { execCmd } from '@/infra/cmd' -import { Settings } from './settings' +import { ExtCfg } from '@/ctx/ext-cfg' const diskSymbolRegex = /^(\S{1,5}:)(.*)/ export const isTargetWorkspace = (): boolean => { const folders = workspace.workspaceFolders let currentFolder = folders?.length === 1 ? folders[0].uri.path : undefined - let targetFolder = Settings.workspaceUri.path + let targetFolder = ExtCfg.workspaceUri.path const platform = os.platform() if (platform === 'win32' && targetFolder && currentFolder) { const replacer = (sub: string, m0: string | null | undefined, m2: string | null | undefined) => diff --git a/src/service/oauth.api.ts b/src/service/oauth.api.ts index 7ec3f875..462dc432 100644 --- a/src/service/oauth.api.ts +++ b/src/service/oauth.api.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/naming-convention */ import { TokenInfo } from '@/model/token-info' import { AccountInfo } from '@/auth/account-info' -import { globalCtx } from '@/service/global-ctx' +import { globalCtx } from '@/ctx/global-ctx' import fetch from '@/infra/fetch-client' import got from '@/infra/http-client' import { CancellationToken } from 'vscode' diff --git a/src/service/parse-webview-html.ts b/src/service/parse-webview-html.ts index 10058f34..e6871159 100644 --- a/src/service/parse-webview-html.ts +++ b/src/service/parse-webview-html.ts @@ -1,5 +1,5 @@ import vscode from 'vscode' -import { globalCtx } from '@/service/global-ctx' +import { globalCtx } from '@/ctx/global-ctx' export type WebviewEntryName = 'ing' | 'post-cfg' diff --git a/src/service/post-category.ts b/src/service/post-category.ts index 158a818d..ab9a3722 100644 --- a/src/service/post-category.ts +++ b/src/service/post-category.ts @@ -1,6 +1,6 @@ import fetch from '@/infra/fetch-client' import { PostCategories, PostCategory, PostCategoryAddDto } from '@/model/post-category' -import { globalCtx } from './global-ctx' +import { globalCtx } from '@/ctx/global-ctx' import { URLSearchParams } from 'url' export class PostCategoryService { diff --git a/src/service/post-cfg-panel.ts b/src/service/post-cfg-panel.ts index 2c63de7e..59aa9ff1 100644 --- a/src/service/post-cfg-panel.ts +++ b/src/service/post-cfg-panel.ts @@ -1,7 +1,7 @@ import { cloneDeep } from 'lodash-es' import vscode, { Uri } from 'vscode' import { Post } from '@/model/post' -import { globalCtx } from './global-ctx' +import { globalCtx } from '@/ctx/global-ctx' import { postCategoryService } from './post-category' import { siteCategoryService } from './site-category' import { PostTagService } from './post-tag' @@ -9,7 +9,7 @@ import { PostService } from './post' import { isErrorResponse } from '@/model/error-response' import { webviewMessage } from '@/model/webview-msg' import { WebviewCommonCmd, WebviewCmd } from '@/model/webview-cmd' -import { uploadImage } from '@/cmd/upload-img/upload-img' +import { uploadImg } from '@/cmd/upload-img/upload-img' import { ImgUploadStatusId } from '@/model/img-upload-status' import { openPostFile } from '@/cmd/post-list/open-post-file' import { parseWebviewHtml } from '@/service/parse-webview-html' @@ -127,7 +127,7 @@ export namespace PostCfgPanel { imageId: message.imageId, } as webviewMessage.UpdateImageUpdateStatusMessage) try { - const imageUrl = await uploadImage(false) + const imageUrl = await uploadImg(false) await webview.postMessage({ command: WebviewCmd.UiCmd.updateImageUploadStatus, status: { @@ -202,7 +202,7 @@ export namespace PostCfgPanel { case WebviewCmd.ExtCmd.disposePanel: panel?.dispose() break - case WebviewCmd.ExtCmd.uploadImage: + case WebviewCmd.ExtCmd.uploadImg: await onUploadImageCmd(panel, message) break case WebviewCmd.ExtCmd.getChildCategories: diff --git a/src/service/post-file-map.ts b/src/service/post-file-map.ts index 228a982a..bcfb8c83 100644 --- a/src/service/post-file-map.ts +++ b/src/service/post-file-map.ts @@ -1,6 +1,6 @@ import { postCategoryDataProvider } from '@/tree-view/provider/post-category-tree-data-provider' import { postDataProvider } from '@/tree-view/provider/post-data-provider' -import { globalCtx } from './global-ctx' +import { globalCtx } from '@/ctx/global-ctx' const validatePostFileMap = (map: PostFileMap) => map[0] >= 0 && !!map[1] diff --git a/src/service/post-tag.ts b/src/service/post-tag.ts index 958f4759..49c92244 100644 --- a/src/service/post-tag.ts +++ b/src/service/post-tag.ts @@ -1,6 +1,6 @@ import got from '@/infra/http-client' import { PostTag } from '@/model/post-tag' -import { globalCtx } from './global-ctx' +import { globalCtx } from '@/ctx/global-ctx' let cachedTags: PostTag[] | null = null diff --git a/src/service/post-title-sanitizer.ts b/src/service/post-title-sanitizer.ts index cea14acc..4fae2a7d 100644 --- a/src/service/post-title-sanitizer.ts +++ b/src/service/post-title-sanitizer.ts @@ -1,7 +1,7 @@ import path from 'path' import sanitizeFilename from 'sanitize-filename' import { Post } from '@/model/post' -import { globalCtx } from './global-ctx' +import { globalCtx } from '@/ctx/global-ctx' import { PostFileMapManager } from './post-file-map' type InvalidPostFileNameMap = [postId: number, invalidName: string | undefined | null] diff --git a/src/service/post.ts b/src/service/post.ts index 56196853..d2da8ea7 100644 --- a/src/service/post.ts +++ b/src/service/post.ts @@ -1,6 +1,6 @@ import fetch from '@/infra/fetch-client' import { Post } from '@/model/post' -import { globalCtx } from './global-ctx' +import { globalCtx } from '@/ctx/global-ctx' import { PageModel } from '@/model/page-model' import { PostListState } from '@/model/post-list-state' import { PostEditDto } from '@/model/post-edit-dto' diff --git a/src/service/site-category.ts b/src/service/site-category.ts index 033b79cc..fd782023 100644 --- a/src/service/site-category.ts +++ b/src/service/site-category.ts @@ -1,6 +1,6 @@ import fetch from '@/infra/fetch-client' import { SiteCategories, SiteCategory } from '@/model/site-category' -import { globalCtx } from './global-ctx' +import { globalCtx } from '@/ctx/global-ctx' export namespace siteCategoryService { let cached: SiteCategories | null = null diff --git a/src/setup/setup-cmd.ts b/src/setup/setup-cmd.ts index 5e4b2fe9..7d9490e2 100644 --- a/src/setup/setup-cmd.ts +++ b/src/setup/setup-cmd.ts @@ -1,20 +1,18 @@ -import { openMyAccountSettings } from '@/cmd/open/open-my-account-settings' +import { openIngSite } from '@/cmd/open/open-ing-site' +import { switchIngType } from '@/cmd/ing/select-ing-type' +import { refreshIngList } from '@/cmd/ing/refresh-ing-list' +import { goIngList1stPage, goIngListNextPage, goIngListPrevPage } from '@/cmd/ing/switch-ing-list-page' +import { openMyAccountSetting } from '@/cmd/open/open-my-account-setting' import { openMyWebBlogConsole } from '@/cmd/open/open-my-blog-console' import { openMyHomePage } from '@/cmd/open/open-my-home-page' -import { login, logout } from '@/cmd/login' import { openMyBlog } from '@/cmd/open/open-my-blog' -import { globalCtx } from '@/service/global-ctx' -import { - gotoNextPostList, - gotoPreviousPostList, - refreshPostList, - seekPostList, -} from '@/cmd/post-list/refresh-post-list' -import { uploadPostFileToCnblogs, uploadPostToCnblogs } from '@/cmd/post-list/upload-post' +import { globalCtx } from '@/ctx/global-ctx' +import { goNextPostList, goPrevPostList, refreshPostList, seekPostList } from '@/cmd/post-list/refresh-post-list' +import { uploadPostFile, uploadPost } from '@/cmd/post-list/upload-post' import { createLocalDraft } from '@/cmd/post-list/create-local-draft' import { deleteSelectedPost } from '@/cmd/post-list/delete-post' -import { modifyPostSettings } from '@/cmd/post-list/modify-post-settings' -import { uploadImage } from '@/cmd/upload-img/upload-img' +import { modifyPostSetting } from '@/cmd/post-list/modify-post-setting' +import { uploadImg } from '@/cmd/upload-img/upload-img' import { revealLocalPostFileInOs } from '@/cmd/reveal-local-post-file-in-os' import { showLocalFileToPostInfo } from '@/cmd/show-local-file-to-post-info' import { newPostCategory } from '@/cmd/post-category/new-post-category' @@ -28,20 +26,26 @@ import { openWorkspace } from '@/cmd/open/open-workspace' import { setWorkspace } from '@/cmd/set-workspace' import { revealWorkspaceInOs } from '@/cmd/reveal-workspace-in-os' import { viewPostOnline } from '@/cmd/view-post-online' -import { pullPostRemoteUpdates } from '@/cmd/pull-post-remote-updates' +import { pullRemotePost } from '@/cmd/pull-remote-post' import { extractImg } from '@/cmd/extract-img' import { clearPostSearchResults, refreshPostSearchResults, searchPost } from '@/cmd/post-list/search' import { handleDeletePostCategories } from '@/cmd/post-category/delete-selected-category' import { PublishIngCmdHandler } from '@/cmd/ing/publish-ing' -import { regIngListCmds } from '@/cmd/ing/ing-list-cmd-register' import { CopyPostLinkCmdHandler } from '@/cmd/post-list/copy-link' -import { regBlogExportCmds } from '@/cmd/blog-export' import { regCmd } from '@/infra/cmd' import { exportPostToPdf } from '@/cmd/pdf/export-pdf' import { openCnbHome } from '@/cmd/open/open-cnb-home' import { openCnbNews } from '@/cmd/open/open-cnb-news' import { openCnbQ } from '@/cmd/open/open-cnb-q' import { openCnbIng } from '@/cmd/open/open-cnb-ing' +import { editExportPost } from '@/cmd/blog-export/edit' +import { createBlogExport } from '@/cmd/blog-export/create' +import { downloadBlogExport } from '@/cmd/blog-export/download' +import { viewPostBlogExport } from '@/cmd/blog-export/view-post' +import { deleteBlogExport } from '@/cmd/blog-export/delete' +import { openLocalExport } from '@/cmd/blog-export/open-local' +import { refreshExportRecord } from '@/cmd/blog-export/refresh' +import { accountManager } from '@/auth/account-manager' function withPrefix(prefix: string) { return (rest: string) => `${prefix}${rest}` @@ -51,56 +55,75 @@ export function setupExtCmd() { const ctx = globalCtx.extCtx const withAppName = withPrefix(globalCtx.extName) - // TODO: simplify register const tokens = [ - regCmd(withAppName('.login'), login), - regCmd(withAppName('.open-my-blog'), openMyBlog), - regCmd(withAppName('.open-my-home-page'), openMyHomePage), - regCmd(withAppName('.open-my-blog-console'), openMyWebBlogConsole), - regCmd(withAppName('.open-my-account-settings'), openMyAccountSettings), - regCmd(withAppName('.logout'), logout), + // auth + regCmd(withAppName('.login'), () => accountManager.login()), + regCmd(withAppName('.logout'), () => accountManager.logout()), + // post-list regCmd(withAppName('.refresh-post-list'), refreshPostList), - regCmd(withAppName('.previous-post-list'), gotoPreviousPostList), + regCmd(withAppName('.prev-post-list'), goPrevPostList), + regCmd(withAppName('.next-post-list'), goNextPostList), regCmd(withAppName('.seek-post-list'), seekPostList), - regCmd(withAppName('.next-post-list'), gotoNextPostList), - regCmd(withAppName('.edit-post'), openPostInVscode), - regCmd(withAppName('.upload-post'), uploadPostToCnblogs), - regCmd(withAppName('.modify-post-settings'), modifyPostSettings), + // post + regCmd(withAppName('.upload-post'), uploadPost), regCmd(withAppName('.delete-post'), deleteSelectedPost), + regCmd(withAppName('.edit-post'), openPostInVscode), + regCmd(withAppName('.search-post'), searchPost), + regCmd(withAppName('.rename-post'), renamePost), + regCmd(withAppName('.modify-post-setting'), modifyPostSetting), regCmd(withAppName('.create-local-draft'), createLocalDraft), - regCmd(withAppName('.upload-post-file-to-cnblogs'), uploadPostFileToCnblogs), - regCmd(withAppName('.pull-post-remote-updates'), pullPostRemoteUpdates), - regCmd(withAppName('.upload-clipboard-image'), () => uploadImage(true, 'clipboard')), - regCmd(withAppName('.upload-fs-img'), () => uploadImage(true, 'local')), - regCmd(withAppName('.upload-img'), () => uploadImage(true)), + regCmd(withAppName('.upload-post-file'), uploadPostFile), + regCmd(withAppName('.pull-remote-post'), pullRemotePost), + regCmd(withAppName('.open-post-in-blog-admin'), openPostInBlogAdmin), + regCmd(withAppName('.delete-post-to-local-file-map'), deletePostToLocalFileMap), + regCmd(withAppName('.view-post-online'), viewPostOnline), + regCmd(withAppName('.export-post-to-pdf'), exportPostToPdf), + regCmd(withAppName('.clear-post-search-results'), clearPostSearchResults), + regCmd(withAppName('.refresh-post-search-results'), refreshPostSearchResults), + regCmd(withAppName('.copy-post-link'), input => new CopyPostLinkCmdHandler(input).handle()), regCmd(withAppName('.reveal-local-post-file-in-os'), revealLocalPostFileInOs), regCmd(withAppName('.show-post-to-local-file-info'), showLocalFileToPostInfo), + // img + regCmd(withAppName('.extract-img'), extractImg), + regCmd(withAppName('.upload-img'), () => uploadImg(true)), + regCmd(withAppName('.upload-fs-img'), () => uploadImg(true, 'local')), + regCmd(withAppName('.upload-clipboard-image'), () => uploadImg(true, 'clipboard')), + // post category regCmd(withAppName('.new-post-category'), newPostCategory), regCmd(withAppName('.delete-selected-post-category'), handleDeletePostCategories), regCmd(withAppName('.refresh-post-category-list'), refreshPostCategoryList), regCmd(withAppName('.update-post-category'), handleUpdatePostCategory), - regCmd(withAppName('.delete-post-to-local-file-map'), deletePostToLocalFileMap), - regCmd(withAppName('.rename-post'), renamePost), - regCmd(withAppName('.open-post-in-blog-admin'), openPostInBlogAdmin), + // workspace regCmd(withAppName('.open-workspace'), openWorkspace), regCmd(withAppName('.set-workspace'), setWorkspace), regCmd(withAppName('.reveal-workspace-in-os'), revealWorkspaceInOs), - regCmd(withAppName('.view-post-online'), viewPostOnline), - regCmd(withAppName('.export-post-to-pdf'), (input: unknown) => exportPostToPdf(input)), - regCmd(withAppName('.extract-img'), extractImg), - regCmd(withAppName('.search-post'), searchPost), - regCmd(withAppName('.clear-post-search-results'), clearPostSearchResults), - regCmd(withAppName('.refresh-post-search-results'), refreshPostSearchResults), - regCmd(withAppName('.copy-post-link'), input => new CopyPostLinkCmdHandler(input).handle()), + // ing regCmd(withAppName('.ing.publish'), () => new PublishIngCmdHandler('input').handle()), - regCmd(withAppName('.ing.publish-selection'), () => new PublishIngCmdHandler('selection').handle()), + regCmd(withAppName('.ing.publish-select'), () => new PublishIngCmdHandler('select').handle()), + // open in browser regCmd(withAppName('.open-cnb-home'), openCnbHome), regCmd(withAppName('.open-cnb-news'), openCnbNews), regCmd(withAppName('.open-cnb-q'), openCnbQ), regCmd(withAppName('.open-cnb-ing'), openCnbIng), - - ...regIngListCmds(), - ...regBlogExportCmds(), + regCmd(withAppName('.open-my-blog'), openMyBlog), + regCmd(withAppName('.open-my-home-page'), openMyHomePage), + regCmd(withAppName('.open-my-blog-console'), openMyWebBlogConsole), + regCmd(withAppName('.open-my-account-setting'), openMyAccountSetting), + // ing list + regCmd(withAppName('.ing-list.refresh'), refreshIngList), + regCmd(withAppName('.ing-list.next'), goIngListNextPage), + regCmd(withAppName('.ing-list.previous'), goIngListPrevPage), + regCmd(withAppName('.ing-list.first'), goIngList1stPage), + regCmd(withAppName('.ing-list.switch-type'), switchIngType), + regCmd(withAppName('.ing-list.open-in-browser'), openIngSite), + // blog export + regCmd(withAppName('.blog-export.refresh-record'), refreshExportRecord), + regCmd(withAppName('.blog-export.open-local-export'), openLocalExport), + regCmd(withAppName('.blog-export.edit'), editExportPost), + regCmd(withAppName('.blog-export.create'), createBlogExport), + regCmd(withAppName('.blog-export.download'), downloadBlogExport), + regCmd(withAppName('.blog-export.view-post'), viewPostBlogExport), + regCmd(withAppName('.blog-export.delete'), deleteBlogExport), ] ctx.subscriptions.push(...tokens) diff --git a/src/setup/setup-watch.ts b/src/setup/setup-watch.ts index 3c761cab..1b4e4648 100644 --- a/src/setup/setup-watch.ts +++ b/src/setup/setup-watch.ts @@ -1,7 +1,7 @@ import { workspace } from 'vscode' import { isTargetWorkspace } from '@/service/is-target-workspace' import { PostFileMapManager } from '@/service/post-file-map' -import { Settings } from '@/service/settings' +import { ExtCfg } from '@/ctx/ext-cfg' import { refreshPostCategoryList } from '@/cmd/post-category/refresh-post-category-list' import { refreshPostList } from '@/cmd/post-list/refresh-post-list' import { execCmd } from '@/infra/cmd' @@ -9,17 +9,17 @@ import { setupUi } from '@/setup/setup-ui' export const setupCfgWatch = () => workspace.onDidChangeConfiguration(ev => { - if (ev.affectsConfiguration(Settings.cfgPrefix)) isTargetWorkspace() + if (ev.affectsConfiguration(ExtCfg.cfgPrefix)) isTargetWorkspace() - if (ev.affectsConfiguration(`${Settings.iconThemePrefix}.${Settings.iconThemeKey}`)) refreshPostCategoryList() + if (ev.affectsConfiguration(`${ExtCfg.iconThemePrefix}.${ExtCfg.iconThemeKey}`)) refreshPostCategoryList() - if (ev.affectsConfiguration(`${Settings.cfgPrefix}.${Settings.postListPageSizeKey}`)) + if (ev.affectsConfiguration(`${ExtCfg.cfgPrefix}.${ExtCfg.postListPageSizeKey}`)) refreshPostList({ queue: true }).catch(() => undefined) - if (ev.affectsConfiguration(`${Settings.cfgPrefix}.markdown`)) + if (ev.affectsConfiguration(`${ExtCfg.cfgPrefix}.markdown`)) execCmd('markdown.preview.refresh').then(undefined, () => undefined) - if (ev.affectsConfiguration(`${Settings.cfgPrefix}.ui`)) setupUi(Settings.cfg) + if (ev.affectsConfiguration(`${ExtCfg.cfgPrefix}.ui`)) setupUi(ExtCfg.cfg) }) export const setupWorkspaceWatch = () => diff --git a/src/tree-view/convert.ts b/src/tree-view/convert.ts index 6bd94e77..27e6fd71 100644 --- a/src/tree-view/convert.ts +++ b/src/tree-view/convert.ts @@ -3,9 +3,9 @@ import { homedir } from 'os' import { MarkdownString, ThemeIcon, TreeItem, TreeItemCollapsibleState, Uri } from 'vscode' import { Post } from '@/model/post' import { PostCategory } from '@/model/post-category' -import { globalCtx } from '@/service/global-ctx' +import { globalCtx } from '@/ctx/global-ctx' import { PostFileMapManager } from '@/service/post-file-map' -import { Settings } from '@/service/settings' +import { ExtCfg } from '@/ctx/ext-cfg' import { BaseTreeItemSource } from '@/tree-view/model/base-tree-item-source' const contextValues = { @@ -15,7 +15,7 @@ const contextValues = { } const categoryIcon = () => { - const iconTheme = Settings.iconTheme + const iconTheme = ExtCfg.iconTheme let iconId = 'folder' switch (iconTheme) { case 'vs-seti': @@ -46,7 +46,7 @@ const postConverter: Converter = obj => { contextValue: contextValues.post(obj), iconPath: new ThemeIcon(obj.isMarkdown ? 'markdown' : 'file-code'), description: localPath ? localPathForDesc : '', - resourceUri: Uri.joinPath(Settings.workspaceUri, obj.title + (obj.isMarkdown ? '.md' : '.html')), + resourceUri: Uri.joinPath(ExtCfg.workspaceUri, obj.title + (obj.isMarkdown ? '.md' : '.html')), }) } diff --git a/src/tree-view/model/blog-export/post.ts b/src/tree-view/model/blog-export/post.ts index e8b60a96..db5c309d 100644 --- a/src/tree-view/model/blog-export/post.ts +++ b/src/tree-view/model/blog-export/post.ts @@ -1,9 +1,9 @@ -import { ViewPostCmdHandler } from '@/cmd/blog-export/view-post' import type { ExportPost } from '@/model/blog-export/export-post' -import { Settings } from '@/service/settings' +import { ExtCfg } from '@/ctx/ext-cfg' import { BaseTreeItemSource } from '@/tree-view/model/base-tree-item-source' import { ExportPostEntryTreeItem } from '@/tree-view/model/blog-export' import { ThemeIcon, TreeItem, TreeItemCollapsibleState, Uri } from 'vscode' +import { globalCtx } from '@/ctx/global-ctx' export class ExportPostTreeItem extends BaseTreeItemSource { readonly contextValue = 'cnblogs-export-post' @@ -24,10 +24,10 @@ export class ExportPostTreeItem extends BaseTreeItemSource { collapsibleState: TreeItemCollapsibleState.None, command: { title: '查看博文', - command: ViewPostCmdHandler.cmd, + command: `${globalCtx.extName}.blog-export.view-post`, arguments: [this], }, - resourceUri: Uri.joinPath(Settings.workspaceUri, title + (isMarkdown ? '.md' : '.html')), + resourceUri: Uri.joinPath(ExtCfg.workspaceUri, title + (isMarkdown ? '.md' : '.html')), contextValue, } } diff --git a/src/tree-view/provider/account-view-data-provider.ts b/src/tree-view/provider/account-view-data-provider.ts index 7ddc2c01..93179cba 100644 --- a/src/tree-view/provider/account-view-data-provider.ts +++ b/src/tree-view/provider/account-view-data-provider.ts @@ -31,7 +31,7 @@ export class AccountViewDataProvider implements TreeDataProvider { label: '账户设置', command: { title: '打开账户设置', - command: 'vscode-cnb.open-my-account-settings', + command: 'vscode-cnb.open-my-account-setting', }, iconPath: new ThemeIcon('gear'), }, diff --git a/src/tree-view/provider/post-category-tree-data-provider.ts b/src/tree-view/provider/post-category-tree-data-provider.ts index 87d00352..6d7cfbaf 100644 --- a/src/tree-view/provider/post-category-tree-data-provider.ts +++ b/src/tree-view/provider/post-category-tree-data-provider.ts @@ -1,7 +1,7 @@ import { flattenDepth, take } from 'lodash-es' import { EventEmitter, ProviderResult, TreeDataProvider, TreeItem } from 'vscode' import { PostCategories } from '@/model/post-category' -import { globalCtx } from '@/service/global-ctx' +import { globalCtx } from '@/ctx/global-ctx' import { postCategoryService } from '@/service/post-category' import { PostService } from '@/service/post' import { toTreeItem } from '@/tree-view/convert' diff --git a/src/tree-view/provider/post-data-provider.ts b/src/tree-view/provider/post-data-provider.ts index a29915c9..c7918b14 100644 --- a/src/tree-view/provider/post-data-provider.ts +++ b/src/tree-view/provider/post-data-provider.ts @@ -4,7 +4,7 @@ import { Post } from '@/model/post' import { PageModel } from '@/model/page-model' import { Alert } from '@/service/alert' import { PostService } from '@/service/post' -import { Settings } from '@/service/settings' +import { ExtCfg } from '@/ctx/ext-cfg' import { toTreeItem } from '@/tree-view/convert' import { PostEntryMetadata, PostMetadata } from '@/tree-view/model/post-metadata' import { PostSearchResultEntry } from '@/tree-view/model/post-search-result-entry' @@ -63,7 +63,7 @@ export class PostDataProvider implements TreeDataProvider { async loadPost(): Promise | null> { const { pageIndex } = PostService.getPostListState() ?? {} - const pageSize = Settings.postListPageSize + const pageSize = ExtCfg.postListPageSize this._pagedPost = await PostService.fetchPostList({ pageIndex, pageSize }).catch(e => { if (e instanceof Error) Alert.err(e.message) diff --git a/src/tree-view/tree-view-register.ts b/src/tree-view/tree-view-register.ts index 9c90ed67..0c7a8830 100644 --- a/src/tree-view/tree-view-register.ts +++ b/src/tree-view/tree-view-register.ts @@ -1,4 +1,4 @@ -import { globalCtx } from '@/service/global-ctx' +import { globalCtx } from '@/ctx/global-ctx' import { TreeView, TreeItem } from 'vscode' import { accountViewDataProvider } from './provider/account-view-data-provider' import { PostListTreeItem, postDataProvider } from './provider/post-data-provider' diff --git a/ui/post-cfg/components/InputSummary.tsx b/ui/post-cfg/components/InputSummary.tsx index f854f4d5..29905606 100644 --- a/ui/post-cfg/components/InputSummary.tsx +++ b/ui/post-cfg/components/InputSummary.tsx @@ -121,7 +121,7 @@ export class InputSummary extends React.Component Date: Tue, 25 Jul 2023 18:23:38 +0800 Subject: [PATCH 028/157] chore: move alert to infra --- src/auth/account-manager.ts | 2 +- src/cmd/blog-export/create.ts | 2 +- src/cmd/blog-export/delete.ts | 2 +- src/cmd/blog-export/download.ts | 2 +- src/cmd/blog-export/edit.ts | 2 +- src/cmd/blog-export/open-local.ts | 2 +- src/cmd/extract-img.ts | 2 +- src/cmd/ing/publish-ing.ts | 2 +- src/cmd/open/open-workspace.ts | 2 +- src/cmd/pdf/export-pdf.ts | 2 +- src/cmd/post-category/delete-selected-category.ts | 2 +- src/cmd/post-category/new-post-category.ts | 2 +- src/cmd/post-list/copy-link.ts | 2 +- src/cmd/post-list/delete-post-to-local-file-map.ts | 2 +- src/cmd/post-list/delete-post.ts | 2 +- src/cmd/post-list/modify-post-setting.ts | 2 +- src/cmd/post-list/open-post-in-vscode.ts | 2 +- src/cmd/post-list/refresh-post-list.ts | 2 +- src/cmd/post-list/rename-post.ts | 2 +- src/cmd/post-list/upload-post.ts | 2 +- src/cmd/pull-remote-post.ts | 2 +- src/cmd/set-workspace.ts | 2 +- src/cmd/show-local-file-to-post-info.ts | 2 +- src/cmd/upload-img/upload-clipboard-img.ts | 2 +- src/cmd/upload-img/upload-img-util.ts | 2 +- src/cmd/upload-img/upload-img.ts | 2 +- src/{service => infra}/alert.ts | 5 +++++ src/infra/chromium-path-provider.ts | 2 +- src/infra/get-clipboard-img.ts | 2 +- src/infra/input-post-setting.ts | 2 +- src/service/ing.api.ts | 2 +- src/service/post.ts | 2 +- src/tree-view/provider/blog-export-provider.ts | 2 +- src/tree-view/provider/post-category-tree-data-provider.ts | 2 +- src/tree-view/provider/post-data-provider.ts | 2 +- 35 files changed, 39 insertions(+), 34 deletions(-) rename src/{service => infra}/alert.ts (93%) diff --git a/src/auth/account-manager.ts b/src/auth/account-manager.ts index 2bc8cd5c..6f2953bb 100644 --- a/src/auth/account-manager.ts +++ b/src/auth/account-manager.ts @@ -8,7 +8,7 @@ import { Oauth } from '@/service/oauth.api' import { authProvider } from '@/auth/auth-provider' import { AuthSession } from '@/auth/auth-session' import { BlogExportProvider } from '@/tree-view/provider/blog-export-provider' -import { Alert } from '@/service/alert' +import { Alert } from '@/infra/alert' import { execCmd } from '@/infra/cmd' const isAuthorizedStorageKey = 'isAuthorized' diff --git a/src/cmd/blog-export/create.ts b/src/cmd/blog-export/create.ts index 4971bf55..5ca1d283 100644 --- a/src/cmd/blog-export/create.ts +++ b/src/cmd/blog-export/create.ts @@ -1,4 +1,4 @@ -import { Alert } from '@/service/alert' +import { Alert } from '@/infra/alert' import { BlogExportApi } from '@/service/blog-export.api' import { BlogExportProvider } from '@/tree-view/provider/blog-export-provider' import { MessageItem } from 'vscode' diff --git a/src/cmd/blog-export/delete.ts b/src/cmd/blog-export/delete.ts index 12cd2fb3..afdff961 100644 --- a/src/cmd/blog-export/delete.ts +++ b/src/cmd/blog-export/delete.ts @@ -1,5 +1,5 @@ import { DownloadedBlogExport } from '@/model/blog-export' -import { Alert } from '@/service/alert' +import { Alert } from '@/infra/alert' import { BlogExportApi } from '@/service/blog-export.api' import { DownloadedExportStore } from '@/service/downloaded-export.store' import { BlogExportProvider } from '@/tree-view/provider/blog-export-provider' diff --git a/src/cmd/blog-export/download.ts b/src/cmd/blog-export/download.ts index 0c5fcce1..aac7fe74 100644 --- a/src/cmd/blog-export/download.ts +++ b/src/cmd/blog-export/download.ts @@ -1,4 +1,4 @@ -import { Alert } from '@/service/alert' +import { Alert } from '@/infra/alert' import { BlogExportApi } from '@/service/blog-export.api' import { DownloadedExportStore } from '@/service/downloaded-export.store' import { globalCtx } from '@/ctx/global-ctx' diff --git a/src/cmd/blog-export/edit.ts b/src/cmd/blog-export/edit.ts index d196bef3..40a1d80e 100644 --- a/src/cmd/blog-export/edit.ts +++ b/src/cmd/blog-export/edit.ts @@ -1,5 +1,5 @@ import { openPostFile } from '@/cmd/post-list/open-post-file' -import { Alert } from '@/service/alert' +import { Alert } from '@/infra/alert' import { ExtCfg } from '@/ctx/ext-cfg' import { ExportPostTreeItem } from '@/tree-view/model/blog-export/post' import fs from 'fs' diff --git a/src/cmd/blog-export/open-local.ts b/src/cmd/blog-export/open-local.ts index b80a3e36..9404e5bc 100644 --- a/src/cmd/blog-export/open-local.ts +++ b/src/cmd/blog-export/open-local.ts @@ -3,7 +3,7 @@ import { window } from 'vscode' import path from 'path' import fs from 'fs' import { promisify } from 'util' -import { Alert } from '@/service/alert' +import { Alert } from '@/infra/alert' import { DownloadedExportStore } from '@/service/downloaded-export.store' import { BlogExportProvider } from '@/tree-view/provider/blog-export-provider' diff --git a/src/cmd/extract-img.ts b/src/cmd/extract-img.ts index 2d687545..076382a6 100644 --- a/src/cmd/extract-img.ts +++ b/src/cmd/extract-img.ts @@ -1,6 +1,6 @@ import { MessageItem, MessageOptions, ProgressLocation, Range, Uri, window, workspace, WorkspaceEdit } from 'vscode' import { ImgInfo, ImgSrc, MkdImgExtractor, newImgSrcFilter } from '@/service/mkd-img-extractor' -import { Alert } from '@/service/alert' +import { Alert } from '@/infra/alert' type ExtractOption = MessageItem & Partial<{ imageSrc: ImgSrc }> diff --git a/src/cmd/ing/publish-ing.ts b/src/cmd/ing/publish-ing.ts index 8f392cdb..9e496d24 100644 --- a/src/cmd/ing/publish-ing.ts +++ b/src/cmd/ing/publish-ing.ts @@ -1,7 +1,7 @@ import { CmdHandler } from '@/cmd/cmd-handler' import { execCmd } from '@/infra/cmd' import { IngPublishModel, IngType } from '@/model/ing' -import { Alert } from '@/service/alert' +import { Alert } from '@/infra/alert' import { globalCtx } from '@/ctx/global-ctx' import { IngApi } from '@/service/ing.api' import { getIngListWebviewProvider } from '@/service/ing-list-webview-provider' diff --git a/src/cmd/open/open-workspace.ts b/src/cmd/open/open-workspace.ts index 3c4fd831..20dbe3b1 100644 --- a/src/cmd/open/open-workspace.ts +++ b/src/cmd/open/open-workspace.ts @@ -1,7 +1,7 @@ import { MessageOptions } from 'vscode' import { ExtCfg } from '@/ctx/ext-cfg' import { execCmd } from '@/infra/cmd' -import { Alert } from '@/service/alert' +import { Alert } from '@/infra/alert' export const openWorkspace = async () => { const uri = ExtCfg.workspaceUri diff --git a/src/cmd/pdf/export-pdf.ts b/src/cmd/pdf/export-pdf.ts index c1112b06..f34b0be1 100644 --- a/src/cmd/pdf/export-pdf.ts +++ b/src/cmd/pdf/export-pdf.ts @@ -10,7 +10,7 @@ import { extTreeViews } from '@/tree-view/tree-view-register' import { ChromiumPathProvider } from '@/infra/chromium-path-provider' import { ExtCfg } from '@/ctx/ext-cfg' import { accountManager } from '@/auth/account-manager' -import { Alert } from '@/service/alert' +import { Alert } from '@/infra/alert' import { PostTreeItem } from '@/tree-view/model/post-tree-item' import { PostEditDto } from '@/model/post-edit-dto' import { postPdfTemplateBuilder } from '@/cmd/pdf/post-pdf-template-builder' diff --git a/src/cmd/post-category/delete-selected-category.ts b/src/cmd/post-category/delete-selected-category.ts index 58475cce..29e432a5 100644 --- a/src/cmd/post-category/delete-selected-category.ts +++ b/src/cmd/post-category/delete-selected-category.ts @@ -3,7 +3,7 @@ import { PostCategory } from '@/model/post-category' import { postCategoryService } from '@/service/post-category' import { PostCategoriesListTreeItem } from '@/tree-view/model/category-list-tree-item' import { BaseMultiSelectablePostCategoryTreeViewCmdHandler } from './base-tree-view-cmd-handler' -import { Alert } from '@/service/alert' +import { Alert } from '@/infra/alert' import { refreshPostCategoryList } from '@/cmd/post-category/refresh-post-category-list' export class DeletePostCategoriesHandler extends BaseMultiSelectablePostCategoryTreeViewCmdHandler { diff --git a/src/cmd/post-category/new-post-category.ts b/src/cmd/post-category/new-post-category.ts index db01eece..53614160 100644 --- a/src/cmd/post-category/new-post-category.ts +++ b/src/cmd/post-category/new-post-category.ts @@ -3,7 +3,7 @@ import { postCategoryService } from '@/service/post-category' import { extTreeViews } from '@/tree-view/tree-view-register' import { inputPostCategory } from './input-post-category' import { refreshPostCategoryList } from './refresh-post-category-list' -import { Alert } from '@/service/alert' +import { Alert } from '@/infra/alert' export const newPostCategory = async () => { const input = await inputPostCategory({ diff --git a/src/cmd/post-list/copy-link.ts b/src/cmd/post-list/copy-link.ts index bdfc2d0c..da1e8f11 100644 --- a/src/cmd/post-list/copy-link.ts +++ b/src/cmd/post-list/copy-link.ts @@ -1,6 +1,6 @@ import { TreeViewCmdHandler } from '@/cmd/cmd-handler' import { Post } from '@/model/post' -import { Alert } from '@/service/alert' +import { Alert } from '@/infra/alert' import { PostFileMapManager } from '@/service/post-file-map' import { PostService } from '@/service/post' import { PostTreeItem } from '@/tree-view/model/post-tree-item' diff --git a/src/cmd/post-list/delete-post-to-local-file-map.ts b/src/cmd/post-list/delete-post-to-local-file-map.ts index 2df95606..221571a4 100644 --- a/src/cmd/post-list/delete-post-to-local-file-map.ts +++ b/src/cmd/post-list/delete-post-to-local-file-map.ts @@ -4,7 +4,7 @@ import { PostFileMap, PostFileMapManager } from '@/service/post-file-map' import { revealPostListItem } from '@/service/post-list-view' import { PostTreeItem } from '@/tree-view/model/post-tree-item' import { extTreeViews } from '@/tree-view/tree-view-register' -import { Alert } from '@/service/alert' +import { Alert } from '@/infra/alert' const confirm = async (postList: Post[]): Promise => { const options = ['确定'] diff --git a/src/cmd/post-list/delete-post.ts b/src/cmd/post-list/delete-post.ts index c7f90a53..04f8496b 100644 --- a/src/cmd/post-list/delete-post.ts +++ b/src/cmd/post-list/delete-post.ts @@ -1,6 +1,6 @@ import { MessageOptions, ProgressLocation, Uri, window, workspace } from 'vscode' import { Post } from '@/model/post' -import { Alert } from '@/service/alert' +import { Alert } from '@/infra/alert' import { PostService } from '@/service/post' import { PostFileMap, PostFileMapManager } from '@/service/post-file-map' import { postDataProvider } from '@/tree-view/provider/post-data-provider' diff --git a/src/cmd/post-list/modify-post-setting.ts b/src/cmd/post-list/modify-post-setting.ts index 0fbddfe7..a234b684 100644 --- a/src/cmd/post-list/modify-post-setting.ts +++ b/src/cmd/post-list/modify-post-setting.ts @@ -1,6 +1,6 @@ import { Uri } from 'vscode' import { Post } from '@/model/post' -import { Alert } from '@/service/alert' +import { Alert } from '@/infra/alert' import { PostService } from '@/service/post' import { PostFileMapManager } from '@/service/post-file-map' import { revealPostListItem } from '@/service/post-list-view' diff --git a/src/cmd/post-list/open-post-in-vscode.ts b/src/cmd/post-list/open-post-in-vscode.ts index 757a19e5..8583b9d1 100644 --- a/src/cmd/post-list/open-post-in-vscode.ts +++ b/src/cmd/post-list/open-post-in-vscode.ts @@ -2,7 +2,7 @@ import fs from 'fs' import path from 'path' import { FileSystemError, MessageOptions, Uri, workspace } from 'vscode' import { Post } from '@/model/post' -import { Alert } from '@/service/alert' +import { Alert } from '@/infra/alert' import { PostService } from '@/service/post' import { PostFileMapManager } from '@/service/post-file-map' import { ExtCfg } from '@/ctx/ext-cfg' diff --git a/src/cmd/post-list/refresh-post-list.ts b/src/cmd/post-list/refresh-post-list.ts index 25511ab9..2393ba10 100644 --- a/src/cmd/post-list/refresh-post-list.ts +++ b/src/cmd/post-list/refresh-post-list.ts @@ -2,7 +2,7 @@ import { globalCtx } from '@/ctx/global-ctx' import { PostService } from '@/service/post' import { window } from 'vscode' import { postDataProvider } from '@/tree-view/provider/post-data-provider' -import { Alert } from '@/service/alert' +import { Alert } from '@/infra/alert' import { PostListState } from '@/model/post-list-state' import { extTreeViews } from '@/tree-view/tree-view-register' import { execCmd } from '@/infra/cmd' diff --git a/src/cmd/post-list/rename-post.ts b/src/cmd/post-list/rename-post.ts index ccc64dc5..6146c16f 100644 --- a/src/cmd/post-list/rename-post.ts +++ b/src/cmd/post-list/rename-post.ts @@ -7,7 +7,7 @@ import { PostFileMapManager } from '@/service/post-file-map' import { postDataProvider } from '@/tree-view/provider/post-data-provider' import { revealPostListItem } from '@/service/post-list-view' import { PostTreeItem } from '@/tree-view/model/post-tree-item' -import { Alert } from '@/service/alert' +import { Alert } from '@/infra/alert' const renameLinkedFile = async (post: Post): Promise => { const filePath = PostFileMapManager.getFilePath(post.id) diff --git a/src/cmd/post-list/upload-post.ts b/src/cmd/post-list/upload-post.ts index e27bf440..2a1915e0 100644 --- a/src/cmd/post-list/upload-post.ts +++ b/src/cmd/post-list/upload-post.ts @@ -1,7 +1,7 @@ import { Uri, workspace, window, ProgressLocation, MessageOptions } from 'vscode' import { Post } from '@/model/post' import { LocalDraft } from '@/service/local-draft' -import { Alert } from '@/service/alert' +import { Alert } from '@/infra/alert' import { PostService } from '@/service/post' import { PostFileMapManager } from '@/service/post-file-map' import { postDataProvider } from '@/tree-view/provider/post-data-provider' diff --git a/src/cmd/pull-remote-post.ts b/src/cmd/pull-remote-post.ts index 7da1852d..8607e5a2 100644 --- a/src/cmd/pull-remote-post.ts +++ b/src/cmd/pull-remote-post.ts @@ -4,7 +4,7 @@ import { PostFileMapManager } from '@/service/post-file-map' import { openPostInVscode } from './post-list/open-post-in-vscode' import fs from 'fs' import { PostService } from '@/service/post' -import { Alert } from '@/service/alert' +import { Alert } from '@/infra/alert' import path from 'path' import { revealPostListItem } from '@/service/post-list-view' import { PostTreeItem } from '@/tree-view/model/post-tree-item' diff --git a/src/cmd/set-workspace.ts b/src/cmd/set-workspace.ts index f9394da9..ac9dc3d8 100644 --- a/src/cmd/set-workspace.ts +++ b/src/cmd/set-workspace.ts @@ -1,5 +1,5 @@ import { window } from 'vscode' -import { Alert } from '@/service/alert' +import { Alert } from '@/infra/alert' import { ExtCfg } from '@/ctx/ext-cfg' export const setWorkspace = async () => { diff --git a/src/cmd/show-local-file-to-post-info.ts b/src/cmd/show-local-file-to-post-info.ts index 9f2691ae..f76d64b6 100644 --- a/src/cmd/show-local-file-to-post-info.ts +++ b/src/cmd/show-local-file-to-post-info.ts @@ -1,6 +1,6 @@ import path from 'path' import { MessageOptions, Uri, window } from 'vscode' -import { Alert } from '@/service/alert' +import { Alert } from '@/infra/alert' import { PostService } from '@/service/post' import { postCategoryService } from '@/service/post-category' import { PostFileMapManager } from '@/service/post-file-map' diff --git a/src/cmd/upload-img/upload-clipboard-img.ts b/src/cmd/upload-img/upload-clipboard-img.ts index 70410b28..c893807c 100644 --- a/src/cmd/upload-img/upload-clipboard-img.ts +++ b/src/cmd/upload-img/upload-clipboard-img.ts @@ -1,6 +1,6 @@ import fs from 'fs' import { ProgressLocation, Uri, window, workspace } from 'vscode' -import { Alert } from '@/service/alert' +import { Alert } from '@/infra/alert' import { ImgService } from '@/service/img' import getClipboardImage from '@/infra/get-clipboard-img' diff --git a/src/cmd/upload-img/upload-img-util.ts b/src/cmd/upload-img/upload-img-util.ts index 3d5acbc1..cbb8820e 100644 --- a/src/cmd/upload-img/upload-img-util.ts +++ b/src/cmd/upload-img/upload-img-util.ts @@ -1,6 +1,6 @@ import { env, MessageOptions, SnippetString, window } from 'vscode' import { fmtImgLink } from '@/infra/fmt-img-link' -import { Alert } from '@/service/alert' +import { Alert } from '@/infra/alert' /** * 显示上传成功对话框, 支持复制不同格式的图片链接 diff --git a/src/cmd/upload-img/upload-img.ts b/src/cmd/upload-img/upload-img.ts index c5f5dcc9..6452befa 100644 --- a/src/cmd/upload-img/upload-img.ts +++ b/src/cmd/upload-img/upload-img.ts @@ -1,4 +1,4 @@ -import { Alert } from '@/service/alert' +import { Alert } from '@/infra/alert' import { uploadImgFromClipboard } from './upload-clipboard-img' import { insertImgLinkToActiveEditor, showUploadSuccessModel } from './upload-img-util' import { uploadFsImage } from './upload-fs-img' diff --git a/src/service/alert.ts b/src/infra/alert.ts similarity index 93% rename from src/service/alert.ts rename to src/infra/alert.ts index 31f31ecb..5df36f5a 100644 --- a/src/service/alert.ts +++ b/src/infra/alert.ts @@ -3,6 +3,7 @@ import { isArray } from 'lodash-es' import path from 'path' import vscode, { Uri } from 'vscode' import { window } from 'vscode' +import { isDevEnv } from '@/model/config' export namespace Alert { export const err = window.showErrorMessage @@ -11,6 +12,10 @@ export namespace Alert { export const warn = window.showWarningMessage + export function dev(log: string) { + if (isDevEnv()) console.log(log) + } + export function httpErr(httpError: Partial, { message = '' } = {}) { const body = httpError.response?.body as | { errors: (string | unknown)[] | undefined | unknown } diff --git a/src/infra/chromium-path-provider.ts b/src/infra/chromium-path-provider.ts index 5c5165c5..6947752b 100644 --- a/src/infra/chromium-path-provider.ts +++ b/src/infra/chromium-path-provider.ts @@ -2,7 +2,7 @@ import { window, ProgressLocation } from 'vscode' import fs from 'fs' import os from 'os' import path from 'path' -import { Alert } from '@/service/alert' +import { Alert } from '@/infra/alert' // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-var-requires const download: (arg: Record) => Promise = require('download-chromium') diff --git a/src/infra/get-clipboard-img.ts b/src/infra/get-clipboard-img.ts index d854157e..47b84c74 100644 --- a/src/infra/get-clipboard-img.ts +++ b/src/infra/get-clipboard-img.ts @@ -6,7 +6,7 @@ import fs from 'fs' import os from 'os' import isWsl from 'is-wsl' import { globalCtx } from '@/ctx/global-ctx' -import { Alert } from '@/service/alert' +import { Alert } from '@/infra/alert' import { IClipboardImg } from '@/model/clipboard-img' import format from 'date-fns/format' diff --git a/src/infra/input-post-setting.ts b/src/infra/input-post-setting.ts index 0aec21ed..fadafad2 100644 --- a/src/infra/input-post-setting.ts +++ b/src/infra/input-post-setting.ts @@ -1,7 +1,7 @@ import { QuickPickItem } from 'vscode' import { AccessPermission, Post } from '@/model/post' import { PostCategories, PostCategory } from '@/model/post-category' -import { Alert } from '@/service/alert' +import { Alert } from '@/infra/alert' import { InputFlowAction, InputStep, MultiStepInput, QuickPickParameters } from '@/service/multi-step-input' import { postCategoryService } from '@/service/post-category' diff --git a/src/service/ing.api.ts b/src/service/ing.api.ts index 208e1dd6..0fa4389c 100644 --- a/src/service/ing.api.ts +++ b/src/service/ing.api.ts @@ -1,5 +1,5 @@ import { Ing, IngComment, IngPublishModel, IngType } from '@/model/ing' -import { Alert } from '@/service/alert' +import { Alert } from '@/infra/alert' import { globalCtx } from '@/ctx/global-ctx' import fetch from '@/infra/fetch-client' import { URLSearchParams } from 'url' diff --git a/src/service/post.ts b/src/service/post.ts index d2da8ea7..731b634f 100644 --- a/src/service/post.ts +++ b/src/service/post.ts @@ -7,7 +7,7 @@ import { PostEditDto } from '@/model/post-edit-dto' import { PostUpdatedResponse } from '@/model/post-updated-response' import { throwIfNotOkGotResponse } from '@/infra/response-err' import { IErrorResponse } from '@/model/error-response' -import { Alert } from './alert' +import { Alert } from '@/infra/alert' import { PostFileMapManager } from './post-file-map' import { ZzkSearchResult } from '@/model/zzk-search-result' import got from '@/infra/http-client' diff --git a/src/tree-view/provider/blog-export-provider.ts b/src/tree-view/provider/blog-export-provider.ts index bb298718..8c6ed006 100644 --- a/src/tree-view/provider/blog-export-provider.ts +++ b/src/tree-view/provider/blog-export-provider.ts @@ -12,7 +12,7 @@ import { ExportPostEntryTreeItem, } from '@/tree-view/model/blog-export' import { Event, EventEmitter, ProviderResult, TreeDataProvider, TreeItem } from 'vscode' -import { Alert } from '@/service/alert' +import { Alert } from '@/infra/alert' import { BlogExportRecord } from '@/model/blog-export' export class BlogExportProvider implements TreeDataProvider { diff --git a/src/tree-view/provider/post-category-tree-data-provider.ts b/src/tree-view/provider/post-category-tree-data-provider.ts index 6d7cfbaf..056f180b 100644 --- a/src/tree-view/provider/post-category-tree-data-provider.ts +++ b/src/tree-view/provider/post-category-tree-data-provider.ts @@ -9,7 +9,7 @@ import { PostCategoriesListTreeItem } from '@/tree-view/model/category-list-tree import { PostCategoryTreeItem } from '@/tree-view/model/post-category-tree-item' import { PostEntryMetadata, PostMetadata, RootPostMetadataType } from '@/tree-view/model/post-metadata' import { PostTreeItem } from '@/tree-view/model/post-tree-item' -import { Alert } from '@/service/alert' +import { Alert } from '@/infra/alert' import { execCmd } from '@/infra/cmd' export class PostCategoryTreeDataProvider implements TreeDataProvider { diff --git a/src/tree-view/provider/post-data-provider.ts b/src/tree-view/provider/post-data-provider.ts index c7918b14..591cccca 100644 --- a/src/tree-view/provider/post-data-provider.ts +++ b/src/tree-view/provider/post-data-provider.ts @@ -2,7 +2,7 @@ import { EventEmitter, ProviderResult, TreeDataProvider, TreeItem } from 'vscode import { refreshPostList } from '@/cmd/post-list/refresh-post-list' import { Post } from '@/model/post' import { PageModel } from '@/model/page-model' -import { Alert } from '@/service/alert' +import { Alert } from '@/infra/alert' import { PostService } from '@/service/post' import { ExtCfg } from '@/ctx/ext-cfg' import { toTreeItem } from '@/tree-view/convert' From 8f32966921b96734e546de890965e7338592173e Mon Sep 17 00:00:00 2001 From: Thaumy Date: Wed, 26 Jul 2023 00:09:20 +0800 Subject: [PATCH 029/157] refactor: split ext cfg --- package.json | 15 +- src/cmd/blog-export/download.ts | 4 +- src/cmd/blog-export/edit.ts | 4 +- src/cmd/open/open-workspace.ts | 10 +- src/cmd/pdf/export-pdf.ts | 6 +- src/cmd/post-category/update-post-category.ts | 7 +- src/cmd/post-list/create-local-draft.ts | 6 +- src/cmd/post-list/open-post-in-vscode.ts | 9 +- src/cmd/post-list/upload-post.ts | 14 +- src/cmd/pull-remote-post.ts | 4 +- src/cmd/reveal-workspace-in-os.ts | 4 +- src/cmd/set-workspace.ts | 8 +- src/ctx/cfg/chromium.ts | 14 ++ src/ctx/cfg/icon-theme.ts | 7 + src/ctx/cfg/markdown.ts | 38 +++++ src/ctx/cfg/platform.ts | 20 +++ src/ctx/cfg/post-category.ts | 13 ++ src/ctx/cfg/post-list.ts | 7 + src/ctx/cfg/ui.ts | 33 ++++ src/ctx/cfg/workspace.ts | 22 +++ src/ctx/ext-cfg.ts | 144 ------------------ src/ctx/local-state.ts | 7 + src/extension.ts | 6 +- src/markdown/extend-markdownIt.ts | 6 +- src/service/ing-list-webview-provider.ts | 7 +- src/service/is-target-workspace.ts | 4 +- src/setup/setup-ui.ts | 19 --- src/setup/setup-watch.ts | 12 +- src/tree-view/convert.ts | 7 +- src/tree-view/model/blog-export/post.ts | 4 +- src/tree-view/provider/post-data-provider.ts | 8 +- 31 files changed, 238 insertions(+), 231 deletions(-) create mode 100644 src/ctx/cfg/chromium.ts create mode 100644 src/ctx/cfg/icon-theme.ts create mode 100644 src/ctx/cfg/markdown.ts create mode 100644 src/ctx/cfg/platform.ts create mode 100644 src/ctx/cfg/post-category.ts create mode 100644 src/ctx/cfg/post-list.ts create mode 100644 src/ctx/cfg/ui.ts create mode 100644 src/ctx/cfg/workspace.ts delete mode 100644 src/ctx/ext-cfg.ts create mode 100644 src/ctx/local-state.ts diff --git a/package.json b/package.json index f234cf2c..181adb3d 100644 --- a/package.json +++ b/package.json @@ -466,7 +466,7 @@ "type": "boolean", "markdownDescription": "创建本地博文时, 是否根据博文分类保存到对应的文件夹中" }, - "cnblogsClient.autoExtractImages": { + "cnblogsClient.markdown.autoExtractImages": { "order": 6, "default": "disable", "scope": "application", @@ -689,15 +689,22 @@ "default": false, "markdownDescription": "闪存星文本化" }, - "cnblogsClient.ui.disableIngUserAvatar": { + "cnblogsClient.ui.textIngEmoji": { "order": 16, "type": "boolean", "scope": "application", "default": false, + "markdownDescription": "闪存 Emoji 文本化" + }, + "cnblogsClient.ui.disableIngUserAvatar": { + "order": 17, + "type": "boolean", + "scope": "application", + "default": false, "markdownDescription": "禁用闪存用户头像" }, "cnblogsClient.ui.treeViewTitleStyle": { - "order": 17, + "order": 18, "scope": "application", "default": "normal", "markdownDescription": "侧栏标题风格", @@ -1273,7 +1280,7 @@ }, { "view": "vscode-cnb-workspace", - "contents": "[在 VSCode 中打开工作空间](command:vscode-cnb.open-workspace)", + "contents": "[在 Code 中打开工作空间](command:vscode-cnb.open-workspace)", "when": "!vscode-cnb.isTargetWorkspace" }, { diff --git a/src/cmd/blog-export/download.ts b/src/cmd/blog-export/download.ts index aac7fe74..bd6fe19e 100644 --- a/src/cmd/blog-export/download.ts +++ b/src/cmd/blog-export/download.ts @@ -2,7 +2,6 @@ import { Alert } from '@/infra/alert' import { BlogExportApi } from '@/service/blog-export.api' import { DownloadedExportStore } from '@/service/downloaded-export.store' import { globalCtx } from '@/ctx/global-ctx' -import { ExtCfg } from '@/ctx/ext-cfg' import { BlogExportProvider } from '@/tree-view/provider/blog-export-provider' import { BlogExportRecordTreeItem } from '@/tree-view/model/blog-export' import { extTreeViews } from '@/tree-view/tree-view-register' @@ -11,6 +10,7 @@ import { Progress } from 'got' import path from 'path' import { promisify } from 'util' import { execCmd } from '@/infra/cmd' +import { WorkspaceCfg } from '@/ctx/cfg/workspace' function parseInput(input: unknown): BlogExportRecordTreeItem | null | undefined { return input instanceof BlogExportRecordTreeItem ? input : null @@ -25,7 +25,7 @@ export async function downloadBlogExport(input: unknown) { if (blogId < 0 || exportId <= 0) return - const targetDir = path.join(ExtCfg.workspaceUri.fsPath, '博客备份') + const targetDir = path.join(WorkspaceCfg.getWorkspaceUri().fsPath, '博客备份') await promisify(fs.mkdir)(targetDir, { recursive: true }) const nonZipFilePath = path.join(targetDir, treeItem.record.fileName) const zipFilePath = nonZipFilePath + '.zip' diff --git a/src/cmd/blog-export/edit.ts b/src/cmd/blog-export/edit.ts index 40a1d80e..39a41d8a 100644 --- a/src/cmd/blog-export/edit.ts +++ b/src/cmd/blog-export/edit.ts @@ -1,11 +1,11 @@ import { openPostFile } from '@/cmd/post-list/open-post-file' import { Alert } from '@/infra/alert' -import { ExtCfg } from '@/ctx/ext-cfg' import { ExportPostTreeItem } from '@/tree-view/model/blog-export/post' import fs from 'fs' import path from 'path' import sanitizeFileName from 'sanitize-filename' import { promisify } from 'util' +import { WorkspaceCfg } from '@/ctx/cfg/workspace' function parseInput(input: unknown): ExportPostTreeItem | null | undefined { return input instanceof ExportPostTreeItem ? input : null @@ -25,7 +25,7 @@ export async function editExportPost(input: unknown): Promise { const fileName = sanitizeFileName(title) const extName = isMarkdown ? 'md' : 'html' - const dirname = ExtCfg.workspaceUri.fsPath + const dirname = WorkspaceCfg.getWorkspaceUri().fsPath const backupName = path.parse(backupFilePath).name fs.mkdirSync(dirname, { recursive: true }) const fullPath = path.join(`${dirname}`, `${fileName}.博客备份-${backupName}-${postId}.${extName}`) diff --git a/src/cmd/open/open-workspace.ts b/src/cmd/open/open-workspace.ts index 20dbe3b1..6ca777bc 100644 --- a/src/cmd/open/open-workspace.ts +++ b/src/cmd/open/open-workspace.ts @@ -1,14 +1,14 @@ import { MessageOptions } from 'vscode' -import { ExtCfg } from '@/ctx/ext-cfg' import { execCmd } from '@/infra/cmd' import { Alert } from '@/infra/alert' +import { WorkspaceCfg } from '@/ctx/cfg/workspace' export const openWorkspace = async () => { - const uri = ExtCfg.workspaceUri - const { fsPath } = uri + const uri = WorkspaceCfg.getWorkspaceUri() const options = ['在当前窗口中打开', '在新窗口中打开'] - const input = await Alert.info(`即将打开 ${fsPath}`, { modal: true } as MessageOptions, ...options) - if (!input) return + const msg = `即将打开 ${uri.fsPath}` + const input = await Alert.info(msg, { modal: true } as MessageOptions, ...options) + if (input === undefined) return const shouldOpenInNewWindow = input === options[1] diff --git a/src/cmd/pdf/export-pdf.ts b/src/cmd/pdf/export-pdf.ts index f34b0be1..4f49037e 100644 --- a/src/cmd/pdf/export-pdf.ts +++ b/src/cmd/pdf/export-pdf.ts @@ -8,12 +8,12 @@ import { PostFileMapManager } from '@/service/post-file-map' import { PostService } from '@/service/post' import { extTreeViews } from '@/tree-view/tree-view-register' import { ChromiumPathProvider } from '@/infra/chromium-path-provider' -import { ExtCfg } from '@/ctx/ext-cfg' import { accountManager } from '@/auth/account-manager' import { Alert } from '@/infra/alert' import { PostTreeItem } from '@/tree-view/model/post-tree-item' import { PostEditDto } from '@/model/post-edit-dto' import { postPdfTemplateBuilder } from '@/cmd/pdf/post-pdf-template-builder' +import { ChromiumCfg } from '@/ctx/cfg/chromium' const launchBrowser = async ( chromiumPath: string @@ -98,7 +98,7 @@ const writePdfToFile = (dir: Uri, post: Post, buffer: Buffer) => }) const retrieveChromiumPath = async (): Promise => { - let path: string | undefined = ChromiumPathProvider.lookupExecutableFromMacApp(ExtCfg.chromiumPath) + let path: string | undefined = ChromiumPathProvider.lookupExecutableFromMacApp(ChromiumCfg.getChromiumPath()) if (path && fs.existsSync(path)) return path const platform = os.platform() @@ -125,7 +125,7 @@ const retrieveChromiumPath = async (): Promise => { path = op ? await op[1]() : undefined } - if (path !== undefined && path !== ExtCfg.chromiumPath) await ExtCfg.setChromiumPath(path) + if (path !== undefined && path !== ChromiumCfg.getChromiumPath()) await ChromiumCfg.setChromiumPath(path) return path } diff --git a/src/cmd/post-category/update-post-category.ts b/src/cmd/post-category/update-post-category.ts index 471a46ad..6081b448 100644 --- a/src/cmd/post-category/update-post-category.ts +++ b/src/cmd/post-category/update-post-category.ts @@ -4,8 +4,9 @@ import { PostCategory } from '@/model/post-category' import { postCategoryService } from '@/service/post-category' import { inputPostCategory } from './input-post-category' import { refreshPostCategoryList } from './refresh-post-category-list' -import { ExtCfg } from '@/ctx/ext-cfg' import { BasePostCategoryTreeViewCmdHandler } from './base-tree-view-cmd-handler' +import { PostCategoryCfg } from '@/ctx/cfg/post-category' +import { WorkspaceCfg } from '@/ctx/cfg/workspace' class UpdatePostCategoryTreeViewCmdHandler extends BasePostCategoryTreeViewCmdHandler { async handle(): Promise { @@ -32,8 +33,8 @@ class UpdatePostCategoryTreeViewCmdHandler extends BasePostCategoryTreeViewCmdHa await postCategoryService.updateCategory(updateDto) refreshPostCategoryList() // 如果选择了createLocalPostFileWithCategory模式且本地有该目录,则重命名该目录 - const workspaceUri = ExtCfg.workspaceUri - const shouldCreateLocalPostFileWithCategory = ExtCfg.createLocalPostFileWithCategory + const workspaceUri = WorkspaceCfg.getWorkspaceUri() + const shouldCreateLocalPostFileWithCategory = PostCategoryCfg.isCreateLocalPostFileWithCategory() const uri = Uri.joinPath(workspaceUri, category.title).fsPath const isFileExist = fs.existsSync(uri) if (shouldCreateLocalPostFileWithCategory && isFileExist) { diff --git a/src/cmd/post-list/create-local-draft.ts b/src/cmd/post-list/create-local-draft.ts index 1f998051..ea082409 100644 --- a/src/cmd/post-list/create-local-draft.ts +++ b/src/cmd/post-list/create-local-draft.ts @@ -1,14 +1,14 @@ import { homedir } from 'os' import path from 'path' import { Uri, window, workspace } from 'vscode' -import { ExtCfg } from '@/ctx/ext-cfg' import { revealActiveFileInExplorer } from '@/infra/reveal-active-file' import { openPostFile } from './open-post-file' +import { WorkspaceCfg } from '@/ctx/cfg/workspace' export const createLocalDraft = async () => { let title = await window.showInputBox({ placeHolder: '请输入标题', - prompt: `文件将会保存到 ${ExtCfg.workspaceUri.fsPath.replace(homedir(), '~')} 目录下`, + prompt: `文件将会保存到 ${WorkspaceCfg.getWorkspaceUri().fsPath.replace(homedir(), '~')} 目录下`, title: '新建本地草稿', validateInput: input => { if (!input) return '标题不能为空' @@ -18,7 +18,7 @@ export const createLocalDraft = async () => { }) if (!title) return - const { fsPath: workspacePath } = ExtCfg.workspaceUri + const { fsPath: workspacePath } = WorkspaceCfg.getWorkspaceUri() title = ['.md', '.html'].some(ext => title && title.endsWith(ext)) ? title : `${title}${title.endsWith('.') ? '' : '.'}md` diff --git a/src/cmd/post-list/open-post-in-vscode.ts b/src/cmd/post-list/open-post-in-vscode.ts index 8583b9d1..94f382a5 100644 --- a/src/cmd/post-list/open-post-in-vscode.ts +++ b/src/cmd/post-list/open-post-in-vscode.ts @@ -5,15 +5,16 @@ import { Post } from '@/model/post' import { Alert } from '@/infra/alert' import { PostService } from '@/service/post' import { PostFileMapManager } from '@/service/post-file-map' -import { ExtCfg } from '@/ctx/ext-cfg' import { openPostFile } from './open-post-file' import { PostTitleSanitizer } from '@/service/post-title-sanitizer' import { postCategoryService } from '@/service/post-category' import sanitizeFileName from 'sanitize-filename' +import { WorkspaceCfg } from '@/ctx/cfg/workspace' +import { PostCategoryCfg } from '@/ctx/cfg/post-category' const buildLocalPostFileUri = async (post: Post, includePostId = false): Promise => { - const workspaceUri = ExtCfg.workspaceUri - const shouldCreateLocalPostFileWithCategory = ExtCfg.createLocalPostFileWithCategory + const workspaceUri = WorkspaceCfg.getWorkspaceUri() + const shouldCreateLocalPostFileWithCategory = PostCategoryCfg.isCreateLocalPostFileWithCategory() const ext = `.${post.isMarkdown ? 'md' : 'html'}` const postIdSegment = includePostId ? `.${post.id}` : '' const { text: postTitle } = await PostTitleSanitizer.sanitize(post) @@ -56,7 +57,7 @@ export const openPostInVscode = async (postId: number, forceUpdateLocalPostFile const post = postEditDto.post - const workspaceUri = ExtCfg.workspaceUri + const workspaceUri = WorkspaceCfg.getWorkspaceUri() await createDirectoryIfNotExist(workspaceUri) let fileUri = mappedPostFilePath ? Uri.file(mappedPostFilePath) : await buildLocalPostFileUri(post) diff --git a/src/cmd/post-list/upload-post.ts b/src/cmd/post-list/upload-post.ts index 2a1915e0..0fea1f4b 100644 --- a/src/cmd/post-list/upload-post.ts +++ b/src/cmd/post-list/upload-post.ts @@ -14,8 +14,8 @@ import { PostEditDto } from '@/model/post-edit-dto' import { PostCfgPanel } from '@/service/post-cfg-panel' import { saveFilePendingChanges } from '@/infra/save-file-pending-changes' import { extractImg } from '@/cmd/extract-img' -import { ExtCfg } from '@/ctx/ext-cfg' import { PostTreeItem } from '@/tree-view/model/post-tree-item' +import { MarkdownCfg } from '@/ctx/cfg/markdown' const parseFileUri = async (fileUri: Uri | undefined): Promise => { if (fileUri && fileUri.scheme !== 'file') { @@ -115,8 +115,9 @@ export const saveLocalDraftToCnblogs = async (localDraft: LocalDraft) => { void Alert.warn('本地文件已删除, 无法新建博文') return false } - if (ExtCfg.autoExtractImgSrc !== undefined) - await extractImg(localDraft.filePathUri, ExtCfg.autoExtractImgSrc).catch(console.warn) + const autoExtractImgSrc = MarkdownCfg.getAutoExtractImgSrc() + if (autoExtractImgSrc !== undefined) + await extractImg(localDraft.filePathUri, autoExtractImgSrc).catch(console.warn) postToSave.postBody = await localDraft.readAllText() return true @@ -138,8 +139,9 @@ export const uploadPost = async (input: Post | PostTreeItem | PostEditDto | unde const localFilePath = PostFileMapManager.getFilePath(postId) if (!localFilePath) return Alert.warn('本地无该博文的编辑记录') - if (ExtCfg.autoExtractImgSrc !== undefined) - await extractImg(Uri.file(localFilePath), ExtCfg.autoExtractImgSrc).catch(console.warn) + const autoExtractImgSrc = MarkdownCfg.getAutoExtractImgSrc() + if (autoExtractImgSrc !== undefined) + await extractImg(Uri.file(localFilePath), autoExtractImgSrc).catch(console.warn) await saveFilePendingChanges(localFilePath) post.postBody = (await workspace.fs.readFile(Uri.file(localFilePath))).toString() @@ -147,7 +149,7 @@ export const uploadPost = async (input: Post | PostTreeItem | PostEditDto | unde if (!validatePost(post)) return false - if (ExtCfg.showConfirmMsgWhenUploadPost) { + if (MarkdownCfg.isShowConfirmMsgWhenUploadPost()) { const answer = await Alert.warn( '确认上传吗?', { diff --git a/src/cmd/pull-remote-post.ts b/src/cmd/pull-remote-post.ts index 8607e5a2..ad585a7b 100644 --- a/src/cmd/pull-remote-post.ts +++ b/src/cmd/pull-remote-post.ts @@ -8,7 +8,7 @@ import { Alert } from '@/infra/alert' import path from 'path' import { revealPostListItem } from '@/service/post-list-view' import { PostTreeItem } from '@/tree-view/model/post-tree-item' -import { ExtCfg } from '@/ctx/ext-cfg' +import { MarkdownCfg } from '@/ctx/cfg/markdown' export async function pullRemotePost(input: Post | PostTreeItem | Uri | undefined | null) { const ctxList: CmdCtx[] = [] @@ -17,7 +17,7 @@ export async function pullRemotePost(input: Post | PostTreeItem | Uri | undefine if (parsePostInput(input) && input.id > 0) await handlePostInput(input, ctxList) else if ((uri = parseUriInput(input))) await handleUriInput(uri, ctxList) - if (ExtCfg.showConfirmMsgWhenPullPost) { + if (MarkdownCfg.isShowConfirmMsgWhenPullPost()) { const answer = await Alert.warn( '确认要拉取远程博文吗?', { diff --git a/src/cmd/reveal-workspace-in-os.ts b/src/cmd/reveal-workspace-in-os.ts index d4aa155b..372f5c30 100644 --- a/src/cmd/reveal-workspace-in-os.ts +++ b/src/cmd/reveal-workspace-in-os.ts @@ -1,4 +1,4 @@ import { execCmd } from '@/infra/cmd' -import { ExtCfg } from '@/ctx/ext-cfg' +import { WorkspaceCfg } from '@/ctx/cfg/workspace' -export const revealWorkspaceInOs = () => execCmd('revealFileInOS', ExtCfg.workspaceUri) +export const revealWorkspaceInOs = () => execCmd('revealFileInOS', WorkspaceCfg.getWorkspaceUri()) diff --git a/src/cmd/set-workspace.ts b/src/cmd/set-workspace.ts index ac9dc3d8..eafe71a9 100644 --- a/src/cmd/set-workspace.ts +++ b/src/cmd/set-workspace.ts @@ -1,6 +1,6 @@ import { window } from 'vscode' import { Alert } from '@/infra/alert' -import { ExtCfg } from '@/ctx/ext-cfg' +import { WorkspaceCfg } from '@/ctx/cfg/workspace' export const setWorkspace = async () => { const uris = @@ -9,13 +9,13 @@ export const setWorkspace = async () => { canSelectFolders: true, canSelectFiles: false, canSelectMany: false, - defaultUri: ExtCfg.workspaceUri, + defaultUri: WorkspaceCfg.getWorkspaceUri(), })) ?? [] const firstUri = uris[0] if (firstUri === undefined) return - await ExtCfg.setWorkspaceUri(firstUri) - void Alert.info(`工作空间成功修改为: "${ExtCfg.workspaceUri.fsPath}"`) + await WorkspaceCfg.setWorkspaceUri(firstUri) + void Alert.info(`工作空间成功修改为: "${WorkspaceCfg.getWorkspaceUri().fsPath}"`) } diff --git a/src/ctx/cfg/chromium.ts b/src/ctx/cfg/chromium.ts new file mode 100644 index 00000000..7ed55b19 --- /dev/null +++ b/src/ctx/cfg/chromium.ts @@ -0,0 +1,14 @@ +import { PlatformCfg } from '@/ctx/cfg/platform' +import getPlatformCfg = PlatformCfg.getPlatformCfg +import { ConfigurationTarget } from 'vscode' + +export namespace ChromiumCfg { + export function getChromiumPath(): string { + return getPlatformCfg().get('chromiumPath') ?? '' + } + + export function setChromiumPath(path: string) { + const cfgTarget = ConfigurationTarget.Global + return getPlatformCfg().update('chromiumPath', path, cfgTarget) + } +} diff --git a/src/ctx/cfg/icon-theme.ts b/src/ctx/cfg/icon-theme.ts new file mode 100644 index 00000000..3cb6227b --- /dev/null +++ b/src/ctx/cfg/icon-theme.ts @@ -0,0 +1,7 @@ +import { workspace } from 'vscode' + +export namespace IconThemeCfg { + export function getIconTheme(): string { + return workspace.getConfiguration('workbench').get('iconTheme') ?? 'unknown' + } +} diff --git a/src/ctx/cfg/markdown.ts b/src/ctx/cfg/markdown.ts new file mode 100644 index 00000000..8a313736 --- /dev/null +++ b/src/ctx/cfg/markdown.ts @@ -0,0 +1,38 @@ +import { LocalState } from '@/ctx/local-state' +import getExtCfg = LocalState.getExtCfg +import { ImgSrc } from '@/service/mkd-img-extractor' + +export namespace MarkdownCfg { + const cfgGet = (key: string) => getExtCfg().get(`markdown.${key}`) + + export function isShowConfirmMsgWhenUploadPost(): boolean { + return cfgGet('showConfirmMsgWhenUploadPost') ?? true + } + + export function isShowConfirmMsgWhenPullPost(): boolean { + return cfgGet('showConfirmMsgWhenPullPost') ?? true + } + + export function isEnableMarkdownEnhancement(): boolean { + return cfgGet('enableEnhancement') ?? true + } + + export function isEnableMarkdownFenceBlockquote(): boolean { + return cfgGet('enableFenceQuote') ?? true + } + + export function isEnableMarkdownHighlightCodeLines(): boolean { + return cfgGet('enableHighlightCodeLines') ?? true + } + + export function getAutoExtractImgSrc(): ImgSrc | undefined { + type T = 'disable' | 'web' | 'dataUrl' | 'fs' | 'any' + const cfg = cfgGet('autoExtractImages') ?? 'disable' + + if (cfg === 'disable') return + if (cfg === 'fs') return ImgSrc.fs + if (cfg === 'dataUrl') return ImgSrc.dataUrl + if (cfg === 'web') return ImgSrc.web + if (cfg === 'any') return ImgSrc.any + } +} diff --git a/src/ctx/cfg/platform.ts b/src/ctx/cfg/platform.ts new file mode 100644 index 00000000..53dc39d7 --- /dev/null +++ b/src/ctx/cfg/platform.ts @@ -0,0 +1,20 @@ +import os from 'os' +import { workspace } from 'vscode' + +function getPlatformPrefix() { + const osName = os.platform() + + if (osName === 'darwin') return 'macos' + if (osName === 'win32') return 'windows' + if (osName === 'linux') return 'linux' + + // fallback to win + return 'windows' +} + +export namespace PlatformCfg { + export function getPlatformCfg() { + const entry = `cnblogsClient.${getPlatformPrefix()}` + return workspace.getConfiguration(entry) + } +} diff --git a/src/ctx/cfg/post-category.ts b/src/ctx/cfg/post-category.ts new file mode 100644 index 00000000..e8178daa --- /dev/null +++ b/src/ctx/cfg/post-category.ts @@ -0,0 +1,13 @@ +import { LocalState } from '@/ctx/local-state' +import { ConfigurationTarget } from 'vscode' + +export namespace PostCategoryCfg { + export function isCreateLocalPostFileWithCategory(): boolean { + return LocalState.getExtCfg().get('createLocalPostFileWithCategory') ?? false + } + + export function setCreateLocalPostFileWithCategory(val: boolean) { + const cfgTarget = ConfigurationTarget.Global + return LocalState.getExtCfg().update('createLocalPostFileWithCategory', val, cfgTarget) + } +} diff --git a/src/ctx/cfg/post-list.ts b/src/ctx/cfg/post-list.ts new file mode 100644 index 00000000..55984f18 --- /dev/null +++ b/src/ctx/cfg/post-list.ts @@ -0,0 +1,7 @@ +import { LocalState } from '@/ctx/local-state' + +export namespace PostListCfg { + export function getPostListPageSize() { + return LocalState.getExtCfg().get('pageSize.postList') ?? 30 + } +} diff --git a/src/ctx/cfg/ui.ts b/src/ctx/cfg/ui.ts new file mode 100644 index 00000000..7a86aeb2 --- /dev/null +++ b/src/ctx/cfg/ui.ts @@ -0,0 +1,33 @@ +import { LocalState } from '@/ctx/local-state' +import getExtCfg = LocalState.getExtCfg + +export namespace UiCfg { + const cfgGet = (key: string) => getExtCfg().get(`ui.${key}`) + + export function isEnableTextIngStar() { + return cfgGet('textIngStar') ?? false + } + + export function isEnableTextIngEmoji() { + return cfgGet('textIngEmoji') ?? false + } + + export function isDisableIngUserAvatar() { + return cfgGet('disableIngUserAvatar') ?? false + } +} + +/* +// TODO: waiting for VSC API support +"cnblogsClient.ui.fakeExtIcon": { + "order": 18, + "type": "boolean", + "scope": "application", + "default": false, + "markdownDescription": "伪装扩展图标" +} +export function applyFakeExtIcon(cfg: WorkspaceCfg) { + const isEnable = cfg.get('ui.fakeExtIcon') + console.log(isEnable) +} +*/ diff --git a/src/ctx/cfg/workspace.ts b/src/ctx/cfg/workspace.ts new file mode 100644 index 00000000..b21e3a32 --- /dev/null +++ b/src/ctx/cfg/workspace.ts @@ -0,0 +1,22 @@ +import { PlatformCfg } from '@/ctx/cfg/platform' +import getPlatformCfg = PlatformCfg.getPlatformCfg +import os from 'os' +import fs from 'fs' +import { ConfigurationTarget, Uri } from 'vscode' + +export namespace WorkspaceCfg { + export function getWorkspaceUri() { + const path = getPlatformCfg().get('workspace') ?? '~/Documents/Cnblogs' + const absPath = path.replace('~', os.homedir()) + + return Uri.file(absPath) + } + + export function setWorkspaceUri(uri: Uri) { + const fsPath = uri.fsPath + if (fs.existsSync(fsPath) || uri.scheme !== 'file') throw Error('Invalid Uri') + + const cfgTarget = ConfigurationTarget.Global + return getPlatformCfg()?.update('workspace', fsPath, cfgTarget) + } +} diff --git a/src/ctx/ext-cfg.ts b/src/ctx/ext-cfg.ts deleted file mode 100644 index 4fc19c13..00000000 --- a/src/ctx/ext-cfg.ts +++ /dev/null @@ -1,144 +0,0 @@ -import os, { homedir } from 'os' -import fs from 'fs' -import { ConfigurationTarget, Uri, workspace } from 'vscode' -import { ImgSrc } from '@/service/mkd-img-extractor' -import { isNumber } from 'lodash-es' -import { untildify } from '@/infra/untildify' - -export class ExtCfg { - static postListPageSizeKey = 'pageSize.postList' - static cfgPrefix = `cnblogsClient` - static iconThemePrefix = 'workbench' - static iconThemeKey = 'iconTheme' - static chromiumPathKey = 'chromiumPath' - static workspaceUriKey = 'workspace' - - private static readonly _defaultWorkspaceUri = Uri.joinPath(Uri.file(homedir()), 'Documents', 'Cnblogs') - private static _adaptLegacyWorkspaceTask?: Thenable | null - - static get platformPrefix() { - switch (os.platform()) { - case 'darwin': - return 'macos' - case 'win32': - return 'windows' - case 'linux': - return 'linux' - default: - return null - } - } - - static get iconTheme() { - return workspace.getConfiguration(ExtCfg.iconThemePrefix).get(ExtCfg.iconThemeKey) - } - - static get cfg() { - return workspace.getConfiguration(ExtCfg.cfgPrefix) - } - - static get platformCfg() { - if (this.platformPrefix != null) return workspace.getConfiguration(`${ExtCfg.cfgPrefix}.${this.platformPrefix}`) - return null - } - - static get workspaceUri(): Uri { - const legacy = this.legacyWorkspaceUri - - this._adaptLegacyWorkspaceTask ??= this.removeLegacyWorkspaceUri().then( - () => (legacy ? this.setWorkspaceUri(legacy) : Promise.resolve()), - () => undefined - ) - - if (legacy) return legacy - - const workspace = this.platformCfg?.get(ExtCfg.workspaceUriKey) - return workspace ? Uri.file(untildify(workspace)) : this._defaultWorkspaceUri - } - - static get chromiumPath(): string { - return this.platformCfg?.get(ExtCfg.chromiumPathKey) ?? '' - } - - static get createLocalPostFileWithCategory(): boolean { - return ExtCfg.cfg.get('createLocalPostFileWithCategory') ?? false - } - - static get autoExtractImgSrc(): ImgSrc | undefined { - const cfg = ExtCfg.cfg.get<'disable' | 'web' | 'dataUrl' | 'fs' | 'any'>('autoExtractImages') - - if (cfg === 'disable') return - if (cfg === 'fs') return ImgSrc.fs - if (cfg === 'dataUrl') return ImgSrc.dataUrl - if (cfg === 'web') return ImgSrc.web - if (cfg === 'any') return ImgSrc.any - } - - static get postListPageSize() { - const size = ExtCfg.cfg.get(ExtCfg.postListPageSizeKey) - return isNumber(size) ? size : 30 - } - - static get showConfirmMsgWhenUploadPost() { - return ExtCfg.cfg.get('markdown.showConfirmMsgWhenUploadPost') ?? true - } - - static get showConfirmMsgWhenPullPost() { - return ExtCfg.cfg.get('markdown.showConfirmMsgWhenPullPost') ?? true - } - - static get enableMarkdownEnhancement() { - return ExtCfg.cfg.get('markdown.enableEnhancement') ?? true - } - - static get enableMarkdownFenceBlockquote() { - return ExtCfg.cfg.get('markdown.enableFenceQuote') ?? true - } - - static get enableMarkdownHighlightCodeLines() { - return ExtCfg.cfg.get('markdown.enableHighlightCodeLines') - } - - private static get legacyWorkspaceUri() { - const path = this.platformCfg?.get(ExtCfg.workspaceUriKey)?.replace('~', os.homedir()) - - if (path === undefined) return undefined - - return Uri.file(path) - } - - static async setWorkspaceUri(uri: Uri) { - if (!uri.fsPath || uri.scheme !== 'file') throw Error('Invalid URI') - - if (!fs.existsSync(uri.fsPath)) throw Error(`Path not exist: ${uri.fsPath}`) - - await this.platformCfg?.update(ExtCfg.workspaceUriKey, uri.fsPath, ConfigurationTarget.Global) - } - - static async setChromiumPath(value: string) { - await this.platformCfg?.update(ExtCfg.chromiumPathKey, value, ConfigurationTarget.Global) - } - - static async setCreateLocalPostFileWithCategory(value: boolean) { - await ExtCfg.cfg.update('createLocalPostFileWithCategory', value, ConfigurationTarget.Global) - } - - static async migrateEnablePublishSelectionToIng() { - const oldKey = 'ing.enablePublishSelectionToIng' - const enablePublishSelectionToIng = ExtCfg.cfg.get(oldKey) - if (enablePublishSelectionToIng === true) { - const isOk = await ExtCfg.cfg - .update('menus.context.editor', { 'ing:publish-select': true }, ConfigurationTarget.Global) - .then( - () => true, - () => false - ) - - if (isOk) await ExtCfg.cfg.update(oldKey, undefined, ConfigurationTarget.Global) - } - } - - private static removeLegacyWorkspaceUri() { - return ExtCfg.cfg.update(ExtCfg.workspaceUriKey, undefined, ConfigurationTarget.Global) - } -} diff --git a/src/ctx/local-state.ts b/src/ctx/local-state.ts new file mode 100644 index 00000000..15d76ba3 --- /dev/null +++ b/src/ctx/local-state.ts @@ -0,0 +1,7 @@ +import { workspace } from 'vscode' + +export namespace LocalState { + export function getExtCfg() { + return workspace.getConfiguration('cnblogsClient') + } +} diff --git a/src/extension.ts b/src/extension.ts index 6707e5d2..85e0ed74 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -6,9 +6,9 @@ import { accountManager } from '@/auth/account-manager' import { setupWorkspaceWatch, setupCfgWatch, setupWorkspaceFileWatch } from '@/setup/setup-watch' import { extUriHandler } from '@/infra/uri-handler' import { extendMarkdownIt } from '@/markdown/extend-markdownIt' -import { ExtCfg } from '@/ctx/ext-cfg' import { getIngListWebviewProvider } from '@/service/ing-list-webview-provider' import { setupUi } from '@/setup/setup-ui' +import { LocalState } from '@/ctx/local-state' export function activate(ctx: ExtensionContext) { globalCtx.extCtx = ctx @@ -25,13 +25,11 @@ export function activate(ctx: ExtensionContext) { setupWorkspaceFileWatch() ) - ExtCfg.migrateEnablePublishSelectionToIng().catch(console.warn) - window.registerUriHandler(extUriHandler) void accountManager.updateAuthStatus() - setupUi(ExtCfg.cfg) + setupUi(LocalState.getExtCfg()) return { extendMarkdownIt } } diff --git a/src/markdown/extend-markdownIt.ts b/src/markdown/extend-markdownIt.ts index 73e63599..0794ff03 100644 --- a/src/markdown/extend-markdownIt.ts +++ b/src/markdown/extend-markdownIt.ts @@ -1,12 +1,12 @@ -import { ExtCfg } from '@/ctx/ext-cfg' import { HighlightCodeLinesPlugin, MultilineBlockquotePlugin } from '@cnblogs/markdown-it-presets' import type { MarkdownIt } from '@cnblogs/markdown-it-presets' +import { MarkdownCfg } from '@/ctx/cfg/markdown' export const extendMarkdownIt = (md: MarkdownIt) => md .use(MultilineBlockquotePlugin, { - enable: () => ExtCfg.enableMarkdownEnhancement && ExtCfg.enableMarkdownFenceBlockquote, + enable: () => MarkdownCfg.isEnableMarkdownEnhancement() && MarkdownCfg.isEnableMarkdownFenceBlockquote(), }) .use(HighlightCodeLinesPlugin, { - enable: () => ExtCfg.enableMarkdownEnhancement && ExtCfg.enableMarkdownHighlightCodeLines, + enable: () => MarkdownCfg.isEnableMarkdownEnhancement() && MarkdownCfg.isEnableMarkdownHighlightCodeLines(), }) diff --git a/src/service/ing-list-webview-provider.ts b/src/service/ing-list-webview-provider.ts index 7fe832f5..ab5b2067 100644 --- a/src/service/ing-list-webview-provider.ts +++ b/src/service/ing-list-webview-provider.ts @@ -17,8 +17,7 @@ import { isNumber } from 'lodash-es' import { CommentIngCmdHandler } from '@/cmd/ing/comment-ing' import { execCmd } from '@/infra/cmd' import { ingStarToText } from '@/infra/convert/ing-star-to-text' -import { ExtCfg } from '@/ctx/ext-cfg' -import { isDisableIngUserAvatar, isEnableTextIngStar } from '@/setup/setup-ui' +import { UiCfg } from '@/ctx/cfg/ui' export class IngListWebviewProvider implements WebviewViewProvider { readonly viewId = `${globalCtx.extName}.ing-list-webview` @@ -91,8 +90,8 @@ export class IngListWebviewProvider implements WebviewViewProvider { pageSize: 30, }) const ingList = rawIngList.map(ing => { - if (isDisableIngUserAvatar(ExtCfg.cfg)) ing.userIconUrl = '' - if (isEnableTextIngStar(ExtCfg.cfg)) ing.icons = ingStarToText(ing.icons) + if (UiCfg.isDisableIngUserAvatar()) ing.userIconUrl = '' + if (UiCfg.isEnableTextIngStar()) ing.icons = ingStarToText(ing.icons) return ing }) const comments = await IngApi.listComments(...ingList.map(x => x.id)) diff --git a/src/service/is-target-workspace.ts b/src/service/is-target-workspace.ts index f2dfc5ea..f0778c58 100644 --- a/src/service/is-target-workspace.ts +++ b/src/service/is-target-workspace.ts @@ -2,14 +2,14 @@ import os from 'os' import { workspace } from 'vscode' import { globalCtx } from '@/ctx/global-ctx' import { execCmd } from '@/infra/cmd' -import { ExtCfg } from '@/ctx/ext-cfg' +import { WorkspaceCfg } from '@/ctx/cfg/workspace' const diskSymbolRegex = /^(\S{1,5}:)(.*)/ export const isTargetWorkspace = (): boolean => { const folders = workspace.workspaceFolders let currentFolder = folders?.length === 1 ? folders[0].uri.path : undefined - let targetFolder = ExtCfg.workspaceUri.path + let targetFolder = WorkspaceCfg.getWorkspaceUri().path const platform = os.platform() if (platform === 'win32' && targetFolder && currentFolder) { const replacer = (sub: string, m0: string | null | undefined, m2: string | null | undefined) => diff --git a/src/setup/setup-ui.ts b/src/setup/setup-ui.ts index 5f7289e8..2dbaa684 100644 --- a/src/setup/setup-ui.ts +++ b/src/setup/setup-ui.ts @@ -7,10 +7,6 @@ export function setupUi(cfg: WorkspaceCfg) { applyTreeViewTitleStyle(cfg) } -export const isEnableTextIngStar = (cfg: WorkspaceCfg) => cfg.get('ui.textIngStar') - -export const isDisableIngUserAvatar = (cfg: WorkspaceCfg) => cfg.get('ui.disableIngUserAvatar') - export function applyTreeViewTitleStyle(cfg: WorkspaceCfg) { type Enum = 'normal' | 'short' const option = cfg.get('ui.treeViewTitleStyle') @@ -33,18 +29,3 @@ export function applyTreeViewTitleStyle(cfg: WorkspaceCfg) { return } } - -/* -// TODO: Wait for VSC API support -"cnblogsClient.ui.fakeExtIcon": { - "order": 18, - "type": "boolean", - "scope": "application", - "default": false, - "markdownDescription": "伪装扩展图标" -} -export function applyFakeExtIcon(cfg: WorkspaceCfg) { - const isEnable = cfg.get('ui.fakeExtIcon') - console.log(isEnable) -} -*/ diff --git a/src/setup/setup-watch.ts b/src/setup/setup-watch.ts index 1b4e4648..e7f5aca2 100644 --- a/src/setup/setup-watch.ts +++ b/src/setup/setup-watch.ts @@ -1,25 +1,25 @@ import { workspace } from 'vscode' import { isTargetWorkspace } from '@/service/is-target-workspace' import { PostFileMapManager } from '@/service/post-file-map' -import { ExtCfg } from '@/ctx/ext-cfg' import { refreshPostCategoryList } from '@/cmd/post-category/refresh-post-category-list' import { refreshPostList } from '@/cmd/post-list/refresh-post-list' import { execCmd } from '@/infra/cmd' import { setupUi } from '@/setup/setup-ui' +import { LocalState } from '@/ctx/local-state' export const setupCfgWatch = () => workspace.onDidChangeConfiguration(ev => { - if (ev.affectsConfiguration(ExtCfg.cfgPrefix)) isTargetWorkspace() + if (ev.affectsConfiguration('cnblogsConfig')) isTargetWorkspace() - if (ev.affectsConfiguration(`${ExtCfg.iconThemePrefix}.${ExtCfg.iconThemeKey}`)) refreshPostCategoryList() + if (ev.affectsConfiguration('workbench.iconTheme')) refreshPostCategoryList() - if (ev.affectsConfiguration(`${ExtCfg.cfgPrefix}.${ExtCfg.postListPageSizeKey}`)) + if (ev.affectsConfiguration('cnblogsConfig.pageSize.postList')) refreshPostList({ queue: true }).catch(() => undefined) - if (ev.affectsConfiguration(`${ExtCfg.cfgPrefix}.markdown`)) + if (ev.affectsConfiguration('cnblogsConfig.markdown')) execCmd('markdown.preview.refresh').then(undefined, () => undefined) - if (ev.affectsConfiguration(`${ExtCfg.cfgPrefix}.ui`)) setupUi(ExtCfg.cfg) + if (ev.affectsConfiguration('cnblogsConfig.ui')) setupUi(LocalState.getExtCfg()) }) export const setupWorkspaceWatch = () => diff --git a/src/tree-view/convert.ts b/src/tree-view/convert.ts index 27e6fd71..7296c564 100644 --- a/src/tree-view/convert.ts +++ b/src/tree-view/convert.ts @@ -5,8 +5,9 @@ import { Post } from '@/model/post' import { PostCategory } from '@/model/post-category' import { globalCtx } from '@/ctx/global-ctx' import { PostFileMapManager } from '@/service/post-file-map' -import { ExtCfg } from '@/ctx/ext-cfg' import { BaseTreeItemSource } from '@/tree-view/model/base-tree-item-source' +import { IconThemeCfg } from '@/ctx/cfg/icon-theme' +import { WorkspaceCfg } from '@/ctx/cfg/workspace' const contextValues = { post({ id }: Post) { @@ -15,7 +16,7 @@ const contextValues = { } const categoryIcon = () => { - const iconTheme = ExtCfg.iconTheme + const iconTheme = IconThemeCfg.getIconTheme() let iconId = 'folder' switch (iconTheme) { case 'vs-seti': @@ -46,7 +47,7 @@ const postConverter: Converter = obj => { contextValue: contextValues.post(obj), iconPath: new ThemeIcon(obj.isMarkdown ? 'markdown' : 'file-code'), description: localPath ? localPathForDesc : '', - resourceUri: Uri.joinPath(ExtCfg.workspaceUri, obj.title + (obj.isMarkdown ? '.md' : '.html')), + resourceUri: Uri.joinPath(WorkspaceCfg.getWorkspaceUri(), obj.title + (obj.isMarkdown ? '.md' : '.html')), }) } diff --git a/src/tree-view/model/blog-export/post.ts b/src/tree-view/model/blog-export/post.ts index db5c309d..335c9425 100644 --- a/src/tree-view/model/blog-export/post.ts +++ b/src/tree-view/model/blog-export/post.ts @@ -1,9 +1,9 @@ import type { ExportPost } from '@/model/blog-export/export-post' -import { ExtCfg } from '@/ctx/ext-cfg' import { BaseTreeItemSource } from '@/tree-view/model/base-tree-item-source' import { ExportPostEntryTreeItem } from '@/tree-view/model/blog-export' import { ThemeIcon, TreeItem, TreeItemCollapsibleState, Uri } from 'vscode' import { globalCtx } from '@/ctx/global-ctx' +import { WorkspaceCfg } from '@/ctx/cfg/workspace' export class ExportPostTreeItem extends BaseTreeItemSource { readonly contextValue = 'cnblogs-export-post' @@ -27,7 +27,7 @@ export class ExportPostTreeItem extends BaseTreeItemSource { command: `${globalCtx.extName}.blog-export.view-post`, arguments: [this], }, - resourceUri: Uri.joinPath(ExtCfg.workspaceUri, title + (isMarkdown ? '.md' : '.html')), + resourceUri: Uri.joinPath(WorkspaceCfg.getWorkspaceUri(), title + (isMarkdown ? '.md' : '.html')), contextValue, } } diff --git a/src/tree-view/provider/post-data-provider.ts b/src/tree-view/provider/post-data-provider.ts index 591cccca..62862f9a 100644 --- a/src/tree-view/provider/post-data-provider.ts +++ b/src/tree-view/provider/post-data-provider.ts @@ -4,11 +4,11 @@ import { Post } from '@/model/post' import { PageModel } from '@/model/page-model' import { Alert } from '@/infra/alert' import { PostService } from '@/service/post' -import { ExtCfg } from '@/ctx/ext-cfg' import { toTreeItem } from '@/tree-view/convert' import { PostEntryMetadata, PostMetadata } from '@/tree-view/model/post-metadata' import { PostSearchResultEntry } from '@/tree-view/model/post-search-result-entry' import { PostTreeItem } from '@/tree-view/model/post-tree-item' +import { PostListCfg } from '@/ctx/cfg/post-list' export type PostListTreeItem = Post | PostTreeItem | TreeItem | PostMetadata | PostSearchResultEntry @@ -63,11 +63,11 @@ export class PostDataProvider implements TreeDataProvider { async loadPost(): Promise | null> { const { pageIndex } = PostService.getPostListState() ?? {} - const pageSize = ExtCfg.postListPageSize + const pageSize = PostListCfg.getPostListPageSize() this._pagedPost = await PostService.fetchPostList({ pageIndex, pageSize }).catch(e => { - if (e instanceof Error) Alert.err(e.message) - else Alert.err(`加载博文失败\n${JSON.stringify(e)}`) + if (e instanceof Error) void Alert.err(e.message) + else void Alert.err(`加载博文失败\n${JSON.stringify(e)}`) return undefined }) From 06d5c96aabb833c0b00b420b44c04fffa13b2870 Mon Sep 17 00:00:00 2001 From: Thaumy Date: Wed, 26 Jul 2023 00:11:20 +0800 Subject: [PATCH 030/157] chore: update ui es verion --- ui/tsconfig.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/tsconfig.json b/ui/tsconfig.json index f29341d5..c9699fa7 100644 --- a/ui/tsconfig.json +++ b/ui/tsconfig.json @@ -1,7 +1,7 @@ { "compilerOptions": { - "module": "es2015", - "target": "es5", + "module": "ES2020", + "target": "ES2020", "noImplicitAny": true, "removeComments": true, "preserveConstEnums": true, From 79b1234153df4e1d083e1e213ed410982093f4a4 Mon Sep 17 00:00:00 2001 From: Thaumy Date: Wed, 26 Jul 2023 10:33:05 +0800 Subject: [PATCH 031/157] ui: tweak confirmation text --- src/cmd/post-list/upload-post.ts | 4 ++-- src/cmd/pull-remote-post.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cmd/post-list/upload-post.ts b/src/cmd/post-list/upload-post.ts index 0fea1f4b..c4bd5491 100644 --- a/src/cmd/post-list/upload-post.ts +++ b/src/cmd/post-list/upload-post.ts @@ -151,10 +151,10 @@ export const uploadPost = async (input: Post | PostTreeItem | PostEditDto | unde if (MarkdownCfg.isShowConfirmMsgWhenUploadPost()) { const answer = await Alert.warn( - '确认上传吗?', + '确认上传博文吗?', { modal: true, - detail: '本地博文将对远程博文进行覆盖, 操作不可逆!(此消息可在设置中关闭)', + detail: '本地博文将保存至服务端(该对话框可在设置中关闭)', }, '确认' ) diff --git a/src/cmd/pull-remote-post.ts b/src/cmd/pull-remote-post.ts index ad585a7b..40a44548 100644 --- a/src/cmd/pull-remote-post.ts +++ b/src/cmd/pull-remote-post.ts @@ -22,7 +22,7 @@ export async function pullRemotePost(input: Post | PostTreeItem | Uri | undefine '确认要拉取远程博文吗?', { modal: true, - detail: `本地文件 ${resolveFileNames(ctxList)} 将被覆盖, 请谨慎操作!(此消息可在设置中关闭)`, + detail: `本地文件 ${resolveFileNames(ctxList)} 将被覆盖(可通过设置关闭对话框)`, } as MessageOptions, '确认' ) From 12986e005ff3c4e1a0ead7ab7274554d91601a29 Mon Sep 17 00:00:00 2001 From: Thaumy Date: Wed, 26 Jul 2023 10:33:58 +0800 Subject: [PATCH 032/157] refactor: update App.tsx --- ui/ing/App.tsx | 43 +++++++++++++++++++++---------------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/ui/ing/App.tsx b/ui/ing/App.tsx index ca328fe6..d4c74cdb 100644 --- a/ui/ing/App.tsx +++ b/ui/ing/App.tsx @@ -48,28 +48,27 @@ export class App extends Component { private observeMessages() { window.addEventListener('message', ({ data: { command, payload } }: { data: IngWebviewUiCmd }) => { - switch (command) { - case WebviewCmd.IngCmd.UiCmd.setAppState: { - const { ingList, isRefreshing, comments } = payload as Partial - this.setState({ - ingList: ingList?.map(Ing.parse) ?? this.state.ingList, - isRefreshing: isRefreshing ?? this.state.isRefreshing, - comments: comments - ? Object.assign( - {}, - this.state.comments ?? {}, - cloneWith(comments, v => { - for (const key in v) v[key] = v[key].map(IngComment.parse) - return v - }) - ) - : this.state.comments, - }) - break - } - case WebviewCmd.IngCmd.UiCmd.updateTheme: - this.setState({ theme: activeThemeProvider.activeTheme() }) - break + if (command === WebviewCmd.IngCmd.UiCmd.setAppState) { + const { ingList, isRefreshing, comments } = payload as Partial + this.setState({ + ingList: ingList?.map(Ing.parse) ?? this.state.ingList, + isRefreshing: isRefreshing ?? this.state.isRefreshing, + comments: comments + ? Object.assign( + {}, + this.state.comments ?? {}, + cloneWith(comments, v => { + for (const key in v) v[key] = v[key].map(IngComment.parse) + return v + }) + ) + : this.state.comments, + }) + return + } + if (command === WebviewCmd.IngCmd.UiCmd.updateTheme) { + this.setState({ theme: activeThemeProvider.activeTheme() }) + return } }) } From ec6914602e92eb29ad4deb6e5a634de5c40bc0d4 Mon Sep 17 00:00:00 2001 From: Thaumy Date: Wed, 26 Jul 2023 11:14:13 +0800 Subject: [PATCH 033/157] feat: configurable YFM upload --- package.json | 20 ++++++++++++++------ src/ctx/cfg/markdown.ts | 4 ++++ src/infra/rm-yfm.ts | 5 +++++ src/service/post.ts | 3 +++ 4 files changed, 26 insertions(+), 6 deletions(-) create mode 100644 src/infra/rm-yfm.ts diff --git a/package.json b/package.json index 181adb3d..cc753999 100644 --- a/package.json +++ b/package.json @@ -545,8 +545,16 @@ "editPresentation": "singlelineText", "markdownDescription": "在拉取博文时显示确认消息" }, - "cnblogsClient.menus.context.explorer": { + "cnblogsClient.markdown.ignoreYfmWhenUploadPost": { "order": 13, + "type": "boolean", + "scope": "application", + "default": true, + "editPresentation": "singlelineText", + "markdownDescription": "上传博文时忽略 YAML front matter" + }, + "cnblogsClient.menus.context.explorer": { + "order": 14, "type": "object", "additionalProperties": false, "default": { @@ -605,7 +613,7 @@ } }, "cnblogsClient.menus.context.editor": { - "order": 14, + "order": 15, "type": "object", "default": { "upload-post-file": true, @@ -683,28 +691,28 @@ "markdownDescription": "控制要在编辑器右键菜单中显示的命令" }, "cnblogsClient.ui.textIngStar": { - "order": 15, + "order": 16, "type": "boolean", "scope": "application", "default": false, "markdownDescription": "闪存星文本化" }, "cnblogsClient.ui.textIngEmoji": { - "order": 16, + "order": 17, "type": "boolean", "scope": "application", "default": false, "markdownDescription": "闪存 Emoji 文本化" }, "cnblogsClient.ui.disableIngUserAvatar": { - "order": 17, + "order": 18, "type": "boolean", "scope": "application", "default": false, "markdownDescription": "禁用闪存用户头像" }, "cnblogsClient.ui.treeViewTitleStyle": { - "order": 18, + "order": 19, "scope": "application", "default": "normal", "markdownDescription": "侧栏标题风格", diff --git a/src/ctx/cfg/markdown.ts b/src/ctx/cfg/markdown.ts index 8a313736..0c94bfbf 100644 --- a/src/ctx/cfg/markdown.ts +++ b/src/ctx/cfg/markdown.ts @@ -9,6 +9,10 @@ export namespace MarkdownCfg { return cfgGet('showConfirmMsgWhenUploadPost') ?? true } + export function isIgnoreYfmWhenUploadPost(): boolean { + return cfgGet('ignoreYfmWhenUploadPost') ?? true + } + export function isShowConfirmMsgWhenPullPost(): boolean { return cfgGet('showConfirmMsgWhenPullPost') ?? true } diff --git a/src/infra/rm-yfm.ts b/src/infra/rm-yfm.ts new file mode 100644 index 00000000..bb7d8c35 --- /dev/null +++ b/src/infra/rm-yfm.ts @@ -0,0 +1,5 @@ +// remove YAML front matter in markdown +export function rmYfm(mkd: string) { + const reg = /^---\n(\n|.)*?\n---\n*/g + return mkd.replace(reg, '') +} diff --git a/src/service/post.ts b/src/service/post.ts index 731b634f..b2f77871 100644 --- a/src/service/post.ts +++ b/src/service/post.ts @@ -13,6 +13,8 @@ import { ZzkSearchResult } from '@/model/zzk-search-result' import got from '@/infra/http-client' import httpClient from '@/infra/http-client' import iconv from 'iconv-lite' +import { MarkdownCfg } from '@/ctx/cfg/markdown' +import { rmYfm } from '@/infra/rm-yfm' const defaultPageSize = 30 let newPostTemplate: PostEditDto | undefined @@ -106,6 +108,7 @@ export namespace PostService { } export async function updatePost(post: Post): Promise { + if (MarkdownCfg.isIgnoreYfmWhenUploadPost()) post.postBody = rmYfm(post.postBody) const { ok: isOk, url, From a32060166a0acfb65d11d828a11d264d0b5042d8 Mon Sep 17 00:00:00 2001 From: Thaumy Date: Wed, 26 Jul 2023 15:32:20 +0800 Subject: [PATCH 034/157] refactor: upload post --- src/cmd/post-list/upload-post.ts | 175 ++++++++++++++++--------------- src/service/post.ts | 76 +++++++------- 2 files changed, 123 insertions(+), 128 deletions(-) diff --git a/src/cmd/post-list/upload-post.ts b/src/cmd/post-list/upload-post.ts index c4bd5491..68e8942c 100644 --- a/src/cmd/post-list/upload-post.ts +++ b/src/cmd/post-list/upload-post.ts @@ -17,80 +17,76 @@ import { extractImg } from '@/cmd/extract-img' import { PostTreeItem } from '@/tree-view/model/post-tree-item' import { MarkdownCfg } from '@/ctx/cfg/markdown' -const parseFileUri = async (fileUri: Uri | undefined): Promise => { - if (fileUri && fileUri.scheme !== 'file') { - fileUri = undefined - } else if (!fileUri) { - const { activeTextEditor } = window - if (activeTextEditor) { - const { document } = activeTextEditor - if (document.languageId === 'markdown' && !document.isUntitled) { - await document.save() - fileUri = document.uri - } - } +async function parseFileUri(fileUri: Uri | undefined) { + if (fileUri !== undefined && fileUri.scheme !== 'file') return undefined + if (fileUri !== undefined) return fileUri + + const { activeTextEditor } = window + if (activeTextEditor === undefined) return undefined + + const { document } = activeTextEditor + if (document.languageId === 'markdown' && !document.isUntitled) { + await document.save() + return document.uri } - return fileUri + return undefined } export const uploadPostFile = async (fileUri: Uri | undefined) => { - fileUri = await parseFileUri(fileUri) - if (!fileUri) return + const parsedFileUri = await parseFileUri(fileUri) + if (parsedFileUri === undefined) return - const { fsPath: filePath } = fileUri + const { fsPath: filePath } = parsedFileUri const postId = PostFileMapManager.getPostId(filePath) - if (postId && postId >= 0) { - await uploadPost(await PostService.fetchPostEditDto(postId)) - } else { - const options = [`新建博文`, `关联已有博文`] - const selected = await Alert.info( - '本地文件尚未关联到博客园博文', - { - modal: true, - detail: `您可以选择新建一篇博文或将本地文件关联到一篇博客园博文(您可以根据标题搜索您在博客园博文)`, - } as MessageOptions, - ...options - ) - switch (selected) { - case options[1]: - { - const selectedPost = await searchPostByTitle({ - postTitle: path.basename(filePath, path.extname(filePath)), - quickPickTitle: '搜索要关联的博文', - }) - if (selectedPost) { - await PostFileMapManager.updateOrCreate(selectedPost.id, filePath) - const postEditDto = await PostService.fetchPostEditDto(selectedPost.id) - if (postEditDto) { - const fileContent = Buffer.from(await workspace.fs.readFile(fileUri)).toString() - if (!fileContent) - await workspace.fs.writeFile(fileUri, Buffer.from(postEditDto.post.postBody)) - - await uploadPost(postEditDto.post) - } - } - } - break - case options[0]: - await saveLocalDraftToCnblogs(new LocalDraft(filePath)) - break - } + + if (postId !== undefined && postId >= 0) { + const dto = await PostService.fetchPostEditDto(postId) + if (dto !== undefined) await uploadPost(dto) + return } -} -export const saveLocalDraftToCnblogs = async (localDraft: LocalDraft) => { - if (!localDraft) return + const fileContent = Buffer.from(await workspace.fs.readFile(parsedFileUri)).toString() + if (isEmptyBody(fileContent)) return + + const options = ['新建博文', '关联已有博文'] + const selected = await window.showInformationMessage( + '本地文件尚未关联到博客园博文', + { + modal: true, + detail: `您可以选择新建一篇博文或将本地文件关联到一篇博客园博文(您可以根据标题搜索您在博客园博文)`, + } as MessageOptions, + ...options + ) + if (selected === '关联已有博文') { + const selectedPost = await searchPostByTitle({ + postTitle: path.basename(filePath, path.extname(filePath)), + quickPickTitle: '搜索要关联的博文', + }) + if (selectedPost === undefined) return + + await PostFileMapManager.updateOrCreate(selectedPost.id, filePath) + const postEditDto = await PostService.fetchPostEditDto(selectedPost.id) + if (postEditDto === undefined) return + if (!fileContent) await workspace.fs.writeFile(parsedFileUri, Buffer.from(postEditDto.post.postBody)) + + await uploadPost(postEditDto.post) + } else if (selected === '新建博文') { + await saveLocalDraft(new LocalDraft(filePath)) + } +} +async function saveLocalDraft(localDraft: LocalDraft) { // check format - if (!['.md'].some(x => localDraft.fileExt === x)) { - void Alert.warn('不受支持的文件格式! 只支持markdown格式') + if (!['.md', '.mkd'].some(x => localDraft.fileExt === x)) { + void Alert.warn('格式错误, 只支持 Markdown 文件') return } const editDto = await PostService.fetchPostEditTemplate() if (!editDto) return const { post } = editDto + post.title = localDraft.fileNameWithoutExt post.isMarkdown = true post.categoryIds ??= [] @@ -115,9 +111,8 @@ export const saveLocalDraftToCnblogs = async (localDraft: LocalDraft) => { void Alert.warn('本地文件已删除, 无法新建博文') return false } - const autoExtractImgSrc = MarkdownCfg.getAutoExtractImgSrc() - if (autoExtractImgSrc !== undefined) - await extractImg(localDraft.filePathUri, autoExtractImgSrc).catch(console.warn) + if (MarkdownCfg.getAutoExtractImgSrc()) + await extractImg(localDraft.filePathUri, MarkdownCfg.getAutoExtractImgSrc()).catch(console.warn) postToSave.postBody = await localDraft.readAllText() return true @@ -126,41 +121,44 @@ export const saveLocalDraftToCnblogs = async (localDraft: LocalDraft) => { } export const uploadPost = async (input: Post | PostTreeItem | PostEditDto | undefined) => { - input = input instanceof PostTreeItem ? input.post : input - const post = - input instanceof PostEditDto - ? input.post - : input - ? (await PostService.fetchPostEditDto(input.id))?.post - : undefined - if (!post) return - - const { id: postId } = post - const localFilePath = PostFileMapManager.getFilePath(postId) + if (input === undefined) return + if (input instanceof PostTreeItem) input = input.post + + let post: Post | undefined + + if (input instanceof PostEditDto) post = input.post + else (await PostService.fetchPostEditDto(input.id))?.post + + if (post === undefined) return + + const localFilePath = PostFileMapManager.getFilePath(post.id) if (!localFilePath) return Alert.warn('本地无该博文的编辑记录') - const autoExtractImgSrc = MarkdownCfg.getAutoExtractImgSrc() - if (autoExtractImgSrc !== undefined) - await extractImg(Uri.file(localFilePath), autoExtractImgSrc).catch(console.warn) + if (MarkdownCfg.getAutoExtractImgSrc()) + await extractImg(Uri.file(localFilePath), MarkdownCfg.getAutoExtractImgSrc()).catch(console.warn) await saveFilePendingChanges(localFilePath) post.postBody = (await workspace.fs.readFile(Uri.file(localFilePath))).toString() - post.isMarkdown = path.extname(localFilePath).endsWith('md') || post.isMarkdown - if (!validatePost(post)) return false + if (isEmptyBody(post.postBody)) return false + + post.isMarkdown = + path.extname(localFilePath).endsWith('md') || path.extname(localFilePath).endsWith('mkd') || post.isMarkdown if (MarkdownCfg.isShowConfirmMsgWhenUploadPost()) { const answer = await Alert.warn( '确认上传博文吗?', { modal: true, - detail: '本地博文将保存至服务端(该对话框可在设置中关闭)', + detail: '本地博文将保存至服务端(可通过设置关闭对话框)', }, '确认' ) if (answer !== '确认') return false } + const thePost = post // Dup code for type checking + return window.withProgress( { location: ProgressLocation.Notification, @@ -171,13 +169,15 @@ export const uploadPost = async (input: Post | PostTreeItem | PostEditDto | unde progress.report({ increment: 10, }) - let hasSaved = false + + let isSaved = false + try { - const { id: postId } = await PostService.updatePost(post) + const { id: postId } = await PostService.updatePost(thePost) await openPostInVscode(postId) - post.id = postId + thePost.id = postId - hasSaved = true + isSaved = true progress.report({ increment: 100 }) void Alert.info('上传成功') await refreshPostList() @@ -186,16 +186,17 @@ export const uploadPost = async (input: Post | PostTreeItem | PostEditDto | unde void Alert.err(`上传失败\n${err instanceof Error ? err.message : JSON.stringify(err)}`) console.error(err) } - return hasSaved + + return isSaved } ) } -const validatePost = (post: Post): boolean => { - if (!post.postBody) { - void Alert.warn('文件内容为空!') - return false +function isEmptyBody(body: string) { + if (body === '') { + void Alert.warn('博文内容不能为空') + return true } - return true + return false } diff --git a/src/service/post.ts b/src/service/post.ts index b2f77871..94d9e02c 100644 --- a/src/service/post.ts +++ b/src/service/post.ts @@ -2,12 +2,10 @@ import fetch from '@/infra/fetch-client' import { Post } from '@/model/post' import { globalCtx } from '@/ctx/global-ctx' import { PageModel } from '@/model/page-model' -import { PostListState } from '@/model/post-list-state' import { PostEditDto } from '@/model/post-edit-dto' import { PostUpdatedResponse } from '@/model/post-updated-response' import { throwIfNotOkGotResponse } from '@/infra/response-err' import { IErrorResponse } from '@/model/error-response' -import { Alert } from '@/infra/alert' import { PostFileMapManager } from './post-file-map' import { ZzkSearchResult } from '@/model/zzk-search-result' import got from '@/infra/http-client' @@ -15,8 +13,9 @@ import httpClient from '@/infra/http-client' import iconv from 'iconv-lite' import { MarkdownCfg } from '@/ctx/cfg/markdown' import { rmYfm } from '@/infra/rm-yfm' +import { PostListState } from '@/model/post-list-state' +import { Alert } from '@/infra/alert' -const defaultPageSize = 30 let newPostTemplate: PostEditDto | undefined export namespace PostService { @@ -27,13 +26,9 @@ export namespace PostService { export async function fetchPostList({ search = '', pageIndex = 1, - pageSize = defaultPageSize, + pageSize = 30, categoryId = null, - }): Promise< - PageModel & { - zzkSearchResult?: ZzkSearchResult - } - > { + }) { const s = new URLSearchParams([ ['t', '1'], ['p', `${pageIndex}`], @@ -60,17 +55,14 @@ export namespace PostService { ) } - export async function fetchPostEditDto( - postId: number, - muteErrorNotification = false - ): Promise { - const response = await httpClient.get(`${getBaseUrl()}/api/posts/${postId}`, { + export async function fetchPostEditDto(postId: number, muteErrorNotification = false) { + const res = await httpClient.get(`${getBaseUrl()}/api/posts/${postId}`, { throwHttpErrors: false, responseType: 'buffer', }) try { - throwIfNotOkGotResponse(response) + throwIfNotOkGotResponse(res) } catch (e) { const { statusCode, errors } = e as IErrorResponse if (!muteErrorNotification) { @@ -85,11 +77,13 @@ export namespace PostService { return undefined } - const decodedBody = iconv.decode(response.rawBody, 'utf-8') + const decodedBody = iconv.decode(res.rawBody, 'utf-8') const { blogPost, myConfig } = JSON.parse(decodedBody) as { blogPost?: Post; myConfig?: unknown } - return blogPost ? new PostEditDto(Object.assign(new Post(), blogPost), myConfig) : undefined + if (blogPost !== undefined) return new PostEditDto(Object.assign(new Post(), blogPost), myConfig) + + return undefined } export async function deletePost(...postIds: number[]) { @@ -107,7 +101,7 @@ export namespace PostService { } } - export async function updatePost(post: Post): Promise { + export async function updatePost(post: Post) { if (MarkdownCfg.isIgnoreYfmWhenUploadPost()) post.postBody = rmYfm(post.postBody) const { ok: isOk, @@ -121,32 +115,32 @@ export namespace PostService { return PostUpdatedResponse.parse(body) } - export async function updatePostListState(state: PostListState | undefined | PageModel) { - const finalState: PostListState | undefined = - state instanceof PageModel - ? { - pageIndex: state.pageIndex, - pageSize: state.pageSize, - totalItemsCount: state.totalItemsCount, - itemsCount: state.items?.length ?? 0, - timestamp: new Date(), - hasNext: state.hasNext, - hasPrevious: state.hasPrevious, - pageCount: state.pageCount, - } - : state - await globalCtx.storage.update('postListState', finalState) + export async function updatePostListState(state: PostListState | PageModel) { + if (state instanceof PageModel) { + const finalState = { + pageIndex: state.pageIndex, + pageSize: state.pageSize, + totalItemsCount: state.totalItemsCount, + itemsCount: state.items?.length ?? 0, + timestamp: new Date(), + hasNext: state.hasNext, + hasPrevious: state.hasPrevious, + pageCount: state.pageCount, + } + await globalCtx.storage.update('postListState', finalState) + } + + await globalCtx.storage.update('postListState', state) } - export async function fetchPostEditTemplate(): Promise { - if (!newPostTemplate) newPostTemplate = await fetchPostEditDto(-1) + export async function fetchPostEditTemplate() { + newPostTemplate ??= await fetchPostEditDto(-1) + if (newPostTemplate === undefined) return undefined - return newPostTemplate - ? new PostEditDto( - Object.assign(new Post(), newPostTemplate.post), - Object.assign({}, newPostTemplate.config) - ) - : undefined + return new PostEditDto( + Object.assign(new Post(), newPostTemplate.post), + Object.assign({}, newPostTemplate.config) + ) } } From 22e2665830e9c8d1635f689f76e6c9de36c88841 Mon Sep 17 00:00:00 2001 From: Thaumy Date: Wed, 26 Jul 2023 16:32:23 +0800 Subject: [PATCH 035/157] ui: tweak setting order --- package.json | 56 ++++++++++++++++++++++++++-------------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/package.json b/package.json index cc753999..3f290116 100644 --- a/package.json +++ b/package.json @@ -466,8 +466,28 @@ "type": "boolean", "markdownDescription": "创建本地博文时, 是否根据博文分类保存到对应的文件夹中" }, - "cnblogsClient.markdown.autoExtractImages": { + "cnblogsClient.pageSize.postList": { "order": 6, + "default": 30, + "scope": "application", + "editPresentation": "singlelineText", + "markdownDescription": "随笔列表分页大小, 自定义随笔列表每页展示数量", + "type": "integer", + "maximum": 100, + "enum": [ + 20, + 30, + 40, + 50, + 60, + 70, + 80, + 90, + 100 + ] + }, + "cnblogsClient.markdown.autoExtractImages": { + "order": 7, "default": "disable", "scope": "application", "enum": [ @@ -487,26 +507,6 @@ "editPresentation": "singlelineText", "markdownDescription": "提取图片, 配置上传到博客园时要自动提取上传到博客园的图片" }, - "cnblogsClient.pageSize.postList": { - "order": 7, - "default": 30, - "scope": "application", - "editPresentation": "singlelineText", - "markdownDescription": "随笔列表分页大小, 自定义随笔列表每页展示数量", - "type": "integer", - "maximum": 100, - "enum": [ - 20, - 30, - 40, - 50, - 60, - 70, - 80, - 90, - 100 - ] - }, "cnblogsClient.markdown.enableEnhancement": { "order": 8, "markdownDescription": "启用博客园 Markdown 语法扩展", @@ -569,45 +569,45 @@ "markdownDescription": "控制要在资源管理器右键菜单中显示的命令", "properties": { "upload-post-file": { + "order": 0, "description": "上传到博客园", "type": "boolean", - "order": 0, "default": true }, "pull-remote-post": { + "order": 1, "description": "拉取博文", "type": "boolean", - "order": 1, "default": true }, "modify-post-setting": { + "order": 2, "description": "博文设置", "type": "boolean", - "order": 2, "default": true }, "show-post-to-local-file-info": { + "order": 3, "description": "博客园关联博文", "type": "boolean", - "order": 3, "default": true }, "open-post-in-blog-admin": { + "order": 4, "description": "在博客后台中编辑", "type": "boolean", - "order": 4, "default": true }, "export-post-to-pdf": { + "order": 5, "description": "导出 PDF", "type": "boolean", - "order": 5, "default": true }, "copy-post-link": { + "order": 6, "description": "复制博文链接", "type": "boolean", - "order": 6, "default": true } } From 4f14407f0c91818ee423ecbebe78cf86f0c2a847 Mon Sep 17 00:00:00 2001 From: Thaumy Date: Wed, 26 Jul 2023 16:34:11 +0800 Subject: [PATCH 036/157] fix: cfg listening --- src/setup/setup-watch.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/setup/setup-watch.ts b/src/setup/setup-watch.ts index e7f5aca2..061bdf49 100644 --- a/src/setup/setup-watch.ts +++ b/src/setup/setup-watch.ts @@ -9,17 +9,17 @@ import { LocalState } from '@/ctx/local-state' export const setupCfgWatch = () => workspace.onDidChangeConfiguration(ev => { - if (ev.affectsConfiguration('cnblogsConfig')) isTargetWorkspace() + if (ev.affectsConfiguration('cnblogsClient')) isTargetWorkspace() if (ev.affectsConfiguration('workbench.iconTheme')) refreshPostCategoryList() - if (ev.affectsConfiguration('cnblogsConfig.pageSize.postList')) + if (ev.affectsConfiguration('cnblogsClient.pageSize.postList')) refreshPostList({ queue: true }).catch(() => undefined) - if (ev.affectsConfiguration('cnblogsConfig.markdown')) + if (ev.affectsConfiguration('cnblogsClient.markdown')) execCmd('markdown.preview.refresh').then(undefined, () => undefined) - if (ev.affectsConfiguration('cnblogsConfig.ui')) setupUi(LocalState.getExtCfg()) + if (ev.affectsConfiguration('cnblogsClient.ui')) setupUi(LocalState.getExtCfg()) }) export const setupWorkspaceWatch = () => From 4fcf3a01d2684d93611ee81d2e7c14e7dbcff85e Mon Sep 17 00:00:00 2001 From: Thaumy Date: Wed, 26 Jul 2023 17:39:44 +0800 Subject: [PATCH 037/157] fix: logout --- src/auth/account-manager.ts | 6 +++--- src/service/oauth.api.ts | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/auth/account-manager.ts b/src/auth/account-manager.ts index 6f2953bb..67f7109b 100644 --- a/src/auth/account-manager.ts +++ b/src/auth/account-manager.ts @@ -53,7 +53,7 @@ class AccountManager extends vscode.Disposable { * This will reject with a human-readable reason string if not sign-in or the token has expired. * @returns The access token of the active session */ - async acquireToken(): Promise { + async acquireToken() { const session = await this.ensureSession({ createIfNone: false }) if (session == null) return Promise.reject(ACQUIRE_TOKEN_REJECT_UNAUTHENTICATED) @@ -78,8 +78,8 @@ class AccountManager extends vscode.Disposable { if (session === undefined) return try { - await authProvider.removeSession(session.id) await Oauth.revokeToken(session.accessToken) + await authProvider.removeSession(session.id) } catch (e: any) { void Alert.err(`登出发生错误: ${e}`) } @@ -98,7 +98,7 @@ class AccountManager extends vscode.Disposable { } } - private async ensureSession(opt?: AuthenticationGetSessionOptions): Promise { + private async ensureSession(opt?: AuthenticationGetSessionOptions) { const session = await authentication.getSession(authProvider.providerId, [], opt).then( session => (session ? AuthSession.from(session) : null), e => { diff --git a/src/service/oauth.api.ts b/src/service/oauth.api.ts index 462dc432..e9039ab5 100644 --- a/src/service/oauth.api.ts +++ b/src/service/oauth.api.ts @@ -16,6 +16,7 @@ export type UserInfoSpec = Pick & { export namespace Oauth { export const AuthHeaderKey = 'Authorization' + export async function fetchToken(verifyCode: string, authCode: string, cancelToken?: CancellationToken) { const abortControl = new AbortController() if (cancelToken?.isCancellationRequested) abortControl.abort() @@ -68,7 +69,7 @@ export namespace Oauth { return res.body } - export async function revokeToken(token: string): Promise { + export async function revokeToken(token: string) { const { clientId, revocationEndpoint, authority } = globalCtx.config.oauth const body = new URLSearchParams([ From 0605fe4dfd0b86694241f5f1180d4f7ad9131a01 Mon Sep 17 00:00:00 2001 From: Thaumy Date: Wed, 26 Jul 2023 17:43:59 +0800 Subject: [PATCH 038/157] fix: dup extract img --- src/service/mkd-img-extractor.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/service/mkd-img-extractor.ts b/src/service/mkd-img-extractor.ts index e0b6e2a5..5f052095 100644 --- a/src/service/mkd-img-extractor.ts +++ b/src/service/mkd-img-extractor.ts @@ -164,10 +164,10 @@ export class MkdImgExtractor { // TODO: better filter design needed // remove cnblogs img link - return acc.filter(x => !cnblogsDomainRegExp.test(x.data)) + return acc.filter(x => x.data.match(cnblogsDomainRegExp) == null) } - this._images ??= acc() + this._images = acc() // apply settings return this._images.filter(x => newImgSrcFilter(this._imageSrc)(x)) From 4a5e0c5b4da9747fa9b8d89de901f8619ff47d74 Mon Sep 17 00:00:00 2001 From: Thaumy Date: Wed, 26 Jul 2023 17:59:03 +0800 Subject: [PATCH 039/157] chore: fallback vscode to 1.70.0 --- README.md | 2 +- package-lock.json | 2 +- package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 31a12d92..843eee93 100644 --- a/README.md +++ b/README.md @@ -219,7 +219,7 @@ ## VSCode 版本要求 -`1.80.0` 或更高 +`1.70.0` 或更高 ## 插件设置 diff --git a/package-lock.json b/package-lock.json index 167b2501..b4739722 100644 --- a/package-lock.json +++ b/package-lock.json @@ -92,7 +92,7 @@ "webpack-cli": "^5.0.1" }, "engines": { - "vscode": "^1.80.0" + "vscode": "^1.70.0" } }, "node_modules/@aashutoshrathi/word-wrap": { diff --git a/package.json b/package.json index 3f290116..a690485e 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ ], "icon": "dist/assets/logo.png", "engines": { - "vscode": "^1.80.0" + "vscode": "^1.70.0" }, "categories": [ "Other" From d4768de5adc9423222fe1a618c6793854f9748b7 Mon Sep 17 00:00:00 2001 From: Thaumy Date: Wed, 26 Jul 2023 18:09:20 +0800 Subject: [PATCH 040/157] chore: remove option --- package.json | 7 ------- src/ctx/cfg/ui.ts | 18 ++++++++++++++---- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/package.json b/package.json index a690485e..c0e56c23 100644 --- a/package.json +++ b/package.json @@ -697,13 +697,6 @@ "default": false, "markdownDescription": "闪存星文本化" }, - "cnblogsClient.ui.textIngEmoji": { - "order": 17, - "type": "boolean", - "scope": "application", - "default": false, - "markdownDescription": "闪存 Emoji 文本化" - }, "cnblogsClient.ui.disableIngUserAvatar": { "order": 18, "type": "boolean", diff --git a/src/ctx/cfg/ui.ts b/src/ctx/cfg/ui.ts index 7a86aeb2..245441f2 100644 --- a/src/ctx/cfg/ui.ts +++ b/src/ctx/cfg/ui.ts @@ -8,15 +8,25 @@ export namespace UiCfg { return cfgGet('textIngStar') ?? false } - export function isEnableTextIngEmoji() { - return cfgGet('textIngEmoji') ?? false - } - export function isDisableIngUserAvatar() { return cfgGet('disableIngUserAvatar') ?? false } } +/* +// TODO: need solution +"cnblogsClient.ui.textIngEmoji": { + "order": 17, + "type": "boolean", + "scope": "application", + "default": false, + "markdownDescription": "闪存 Emoji 文本化" +}, +export function isEnableTextIngEmoji() { + return cfgGet('textIngEmoji') ?? false +} +*/ + /* // TODO: waiting for VSC API support "cnblogsClient.ui.fakeExtIcon": { From 35382155825d25982d775b85c4da2648fef8a1a9 Mon Sep 17 00:00:00 2001 From: Thaumy Date: Thu, 27 Jul 2023 10:51:22 +0800 Subject: [PATCH 041/157] docs: tweak README.md --- README.md | 83 +++++++++++++++++++++++++++---------------------------- 1 file changed, 41 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index 843eee93..221189c7 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ - [功能概览](#功能概览) - [登录 / 授权](#登录-%2F-授权) - - [将本地 Markdown 文件发布到博客园](#将本地-markdown-文件发布到博客园) + - [将本地 markdown 发布到博客园](#将本地-markdown-发布到博客园) - [博客园博文列表](#博客园博文列表) - [搜索博文](#搜索博文) - [将本地文件关联到博客园博文](#将本地文件关联到博客园博文) @@ -35,7 +35,7 @@ -### 将本地 Markdown 文件发布到博客园 +### 将本地 markdown 发布到博客园 @@ -43,47 +43,47 @@ 若本地文件已经关联到一篇博客园博文,那么会直接更新这篇博文。 -也通过 VSCode 的 `Command Palette`(唤起 `Command Palette` 快捷键,windows:`ctrl+shift+p`,macos:`command+shift+p`)调用 `Cnblogs: 上传到博客园`命令,将当前正在编辑的 Markdown 文件上传到博客园上 +也通过 VSCode 的 `Command Palette`(唤起 `Command Palette` 快捷键,windows:ctrl+shift+p,macOS:cmd+shift+p)调用 `Cnblogs: 上传到博客园`命令,将当前正在编辑的 markdown 上传到博客园。 ### 博客园博文列表 -当点击列表中的博文时,会自动将博文内容下载到工作空间一个本地文件中(此时这个本地文件就关联到了这篇博文),完成编辑后可以再将本地的内容上传到博客园 +当点击列表中的博文时,会自动将博文内容下载到工作空间一个本地文件中(此时这个本地文件就关联到了这篇博文),完成编辑后可以再将本地的内容上传到博客园。 ### 搜索博文 -在博文列表的工具栏中,包含一个搜索的图标,点击这个图标可以触发搜索功能,点击后会先要求输入关键词,输入完成后按回车确认,搜索结果将在列表中进行展示 +在博文列表的工具栏中,包含一个搜索的图标,点击这个图标可以触发搜索功能,点击后会先要求输入关键词,输入完成后按回车确认,搜索结果将在列表中进行展示。 -列表中的 `搜索结果` 那一项的工具栏包含两个可以使用的命令,分别是 `刷新搜索结果` 和 `清除搜索结果`; 也可以通过右键上下文菜单调用这两个命令 +列表中的 `搜索结果` 那一项的工具栏包含两个可以使用的命令,分别是 `刷新搜索结果` 和 `清除搜索结果`; 也可以通过右键上下文菜单调用这两个命令。 ### 将本地文件关联到博客园博文 -一个本地文件可以关联到一篇博客园博文,本地文件必须在 `vscode-cnb.workspace` 配置的工作目录中 +一个本地文件可以关联到一篇博客园博文,本地文件必须在 `vscode-cnb.workspace` 配置的工作目录中。 ### 拉取远程博文内容更新本地文件 -本地文件和博文关联后,如果通过博客后台更新了这篇博文,此时本地文件是不会自动更新的,但是可以通过 `Cnblogs: 拉取博文`命令来更新本地博文 +本地文件和博文关联后,如果通过博客后台更新了这篇博文,此时本地文件是不会自动更新的,但是可以通过 `Cnblogs: 拉取博文`命令来更新本地博文。 -可以在下面这些地方可以调用 `Cnblogs: 拉取博文` +可以在下面这些地方可以调用 `Cnblogs: 拉取博文`。 - 博客园随笔列表视图中的博文的上下文菜单`拉取博文`(仅已关联本地文件的博文) -- 编辑器上下文菜单中的`拉取博文`(仅针对 Markdown 文件) +- 编辑器上下文菜单中的`拉取博文`(仅针对 markdown) -- 文件浏览器上下文菜单中的`拉取博文`(仅针对 Markdown 文件) +- 文件浏览器上下文菜单中的`拉取博文`(仅针对 markdown) @@ -91,57 +91,57 @@ -在更新本地文件之前会弹出确认对话框,因为此操作会覆盖本地文件的内容,所以请谨慎使用。 +在更新本地文件之前会弹出确认对话框,此操作会覆盖本地文件的内容。 ### 图片上传 -当 VSCode 处于配置好的 `vscode-cnb` 工作空间时,可以通过快捷键,上下文菜单,编辑器工具栏等方式上传本地或剪贴板中的图片到博客园 +当 VSCode 处于配置好的 `vscode-cnb` 工作空间时,可以通过快捷键,上下文菜单,编辑器工具栏等方式上传本地或剪贴板中的图片到博客园。 ### 博文分类管理 -支持新建,删除(可批量操作),修改博客园博文分类 +支持新建,删除(可批量操作),修改博客园博文分类。 ### 导出 PDF -支持将博文导出为 PDF 格式的文件到本地,此功能依赖于 [Chromium](https://www.chromium.org/chromium-projects/),vscode-cnb 默认会先从本地寻找是否有已安装的 Chrome 或基于 Chromium 的 Edge 浏览器,若有的话则会直接使用本地的 Chrome 或基于 Chromium 的 Edge; 若未找到,那么会提示用户手动选择本地的 Chromium 或其他基于 Chromium 的浏览器 +支持将博文导出为 PDF 格式的文件到本地,此功能依赖于 [Chromium](https://www.chromium.org/chromium-projects/),vscode-cnb 默认会先从本地寻找是否有已安装的 Chrome 或基于 Chromium 的 Edge 浏览器,若有的话则会直接使用本地的 Chrome 或基于 Chromium 的 Edge; 若未找到,那么会提示用户手动选择本地的 Chromium 或其他基于 Chromium 的浏览器。 -也可以在 VSCode 的设置中手动配置 **Chromium 或其他基于 Chromium 的浏览器的可执行文件路径**,这个路径针对 windows 和 macos 是不同的两个配置,可以根据自己使用的系统进行配置 +也可以在 VSCode 的设置中手动配置 **Chromium 或其他基于 Chromium 的浏览器的可执行文件路径**,这个路径针对 windows 和 macOS 是不同的两个配置,可以根据自己使用的系统进行配置。 -列表中选择要导出的博文时,支持多选 +列表中选择要导出的博文时,支持多选。 ### 提取图片 -您可能会在 Markdown 文件中使用本地的相对路径的图片,将这样的 Markdown 发布到博客园会导致图片无法正常展示,为此我们提供了 `提取图片` 功能,您可以通过编辑器的上下文菜单调用此功能 +您可能会在 markdown 中使用本地的相对路径的图片,将这样的 markdown 发布到博客园会导致图片无法正常展示,为此我们提供了 `提取图片` 功能,您可以通过编辑器的上下文菜单调用此功能。 ![image](https://img2022.cnblogs.com/blog/1596066/202209/1596066-20220917215536822-836105648.png) -也可以在设置中配置上传到博客园时自动提取图片 +也可以在设置中配置上传到博客园时自动提取图片。 ![image](https://img2022.cnblogs.com/blog/1596066/202209/1596066-20220917215650930-372126612.png) -此功能除了可以提取本地图片,也可以提取其他承载在第三方图床中的图片 +此功能除了可以提取本地图片,也可以提取其他承载在第三方图床中的图片。 ![image](https://img2022.cnblogs.com/blog/1596066/202209/1596066-20220917215802986-44248462.png) -此功能会上传图片到博客园然后替换源 Markdown 文件中的图片链接 +此功能会上传图片到博客园然后替换源 markdown 中的图片链接。 ### 博文设置面板 -首次发布本地 Markdown 文件到博客园时,会打开博文设置面板允许编辑博文相关的设置 +首次发布本地 markdown 到博客园时,会打开博文设置面板允许编辑博文相关的设置。 -同时,也可以在博客园随笔列表视图,文件列表视图和 Markdown 编辑器中上下文菜单中可以通过**博文设置**命令打开博文设置面板 +同时,也可以在博客园随笔列表视图,文件列表视图和 markdown 编辑器中上下文菜单中可以通过**博文设置**命令打开博文设置面板。 @@ -149,9 +149,9 @@ -本插件支持对闪存进行**查看**,**发布**,**评论**等操作,在侧边栏博客园视图中,展开 `闪存` 即可; 点击闪存标题栏中的加号图标可以发布新闪存; +本插件支持对闪存进行**查看**,**发布**,**评论**等操作,在侧边栏博客园视图中,展开 `闪存` 即可; 点击闪存标题栏中的加号图标可以发布新闪存。 -也可以在编辑器中选中一段文本或代码,然后鼠标右键唤起上下文菜单,可以将选中的内容发到闪存; +也可以在编辑器中选中一段文本或代码,然后鼠标右键唤起上下文菜单,可以将选中的内容发到闪存。 > PS: 上下文菜单的"将选中内容发到闪存"功能默认处于禁用,您可以在 VSCode 设置中启用此功能 > demo-settings-enable-publish-select-to-ing @@ -160,21 +160,21 @@ -编辑完内容后回车会弹出确认框,此时如果需要添加标签或者修改访问权限,可以使用确认对话框中的 `编辑访问权限` `编辑标签` 或 `编辑内容` 选项 +编辑完内容后回车会弹出确认框,此时如果需要添加标签或者修改访问权限,可以使用确认对话框中的 `编辑访问权限` `编辑标签` 或 `编辑内容` 选项。 -也可以通过 VSCode 命令面板(`ctrl/cmd + p`唤起命令面板)调用发闪存命令 +也可以通过 VSCode 命令面板(ctrl/cmd+p唤起命令面板)调用发闪存命令。 -通过本插件发布的闪存,在尾部会显示一个 VSCode 图标 +通过本插件发布的闪存,在尾部会显示一个 VSCode 图标。 -此外,插件设置中提供了用于调整闪存用户头像和星星样式的选项,或许能进一步改善您的摸鱼体验 +此外,插件设置中提供了用于调整闪存用户头像和星星样式的选项,或许能进一步改善您的摸鱼体验。 ### Markdown 语法扩展 -本插件可以让 VSCode 中的 Markdown 预览支持博客园中扩展的 Markdown 语法,您可以通过设置来控制是否要启用此功能 +本插件可以让 VSCode 中的 markdown 预览支持博客园中扩展的 markdown 语法,您可以通过设置来控制是否要启用此功能。 @@ -184,18 +184,17 @@ ### 复制博文链接 -文件浏览器和随笔列表中的上下文菜单里有`复制博文链接`选项,点击后可以复制不同格式的博文链接 +文件浏览器和随笔列表中的上下文菜单里有`复制博文链接`选项,点击后可以复制不同格式的博文链接。 https://img2023.cnblogs.com/blog/35695/202301/35695-20230130155516202-1979736560.png - -默认的的链接形如: `https://www.cnblogs.com/cmt/p/47365.html` - Markdown 格式链接形如: `[博文标题](https://www.cnblogs.com/cmt/p/47365.html)` -也可以选择仅复制博文的Id +默认的的链接形如: `https://www.cnblogs.com/cmt/p/47365.html` +Markdown 下的链接形如: `[博文标题](https://www.cnblogs.com/cmt/p/47365.html)` +也可以选择仅复制博文的Id。 ## 博客备份 -您可以通过本插件创建或浏览您的博客备份; +您可以通过本插件创建或浏览您的博客备份。 > **博客备份说明** > @@ -203,27 +202,27 @@ -创建博客备份后,在博客备份记录列表中,您可以看到博客备份记录的状态会实时更新 +创建博客备份后,在博客备份记录列表中,您可以看到博客备份记录的状态会实时更新。 -您可以通过下载按钮将博客备份下载到本地; 下载过程中您可以看到实时的下载进度; 下载完成后,插件会帮您自动进行解压(解压完成后会自动删除源压缩文件) +您可以通过下载按钮将博客备份下载到本地; 下载过程中您可以看到实时的下载进度; 下载完成后,插件会帮您自动进行解压(解压完成后会自动删除源压缩文件)。 -您可以在插件中浏览您博客备份中的博文 +您可以在插件中浏览您博客备份中的博文。 -您可以删除博客列表中的备份记录,已下载备份; 删除前,会弹出确认对话框,您可以根据提示确认删除操作或取消(友情提示: 请谨慎删除数据) +您可以删除博客列表中的备份记录,已下载备份。 ## VSCode 版本要求 -`1.70.0` 或更高 +`1.70.0` 或更高。 ## 插件设置 -* `workspace`:`vscode-cnb` 需要用到的一个工作空间,`vscode-cnb` 只有检测到 VSCode 处于此目录下才会生效,默认会使用 `~/Documents/Cnblogs` 作为工作空间 +* `workspace`:扩展需要用到的工作空间,扩展仅当检测到 VSCode 处于此目录下才会生效,默认值为 `~/Documents/Cnblogs`。 From aa71082b6bf0b5675a26d6114a62eb4647bbd7a6 Mon Sep 17 00:00:00 2001 From: Thaumy Date: Thu, 27 Jul 2023 13:17:13 +0800 Subject: [PATCH 042/157] refactor: simplify code --- src/auth/auth-provider.ts | 2 +- src/cmd/blog-export/open-local.ts | 8 +-- src/cmd/extract-img.ts | 2 +- src/cmd/pdf/export-pdf.ts | 27 ++++------ src/cmd/pdf/post-pdf-template-builder.ts | 4 +- .../post-category/delete-selected-category.ts | 4 +- src/cmd/post-category/new-post-category.ts | 6 +-- src/cmd/post-category/update-post-category.ts | 4 +- src/cmd/post-list/open-post-in-vscode.ts | 4 +- src/cmd/set-workspace.ts | 2 +- src/cmd/show-local-file-to-post-info.ts | 10 ++-- src/infra/input-post-setting.ts | 20 +++---- src/model/post.ts | 5 +- src/model/zzk-search-result.ts | 2 +- src/service/blog-export-post.store.ts | 48 ++++++----------- src/service/blog-export-records.store.ts | 34 ++++++------ src/service/downloaded-export.store.ts | 9 ++-- src/service/local-draft.ts | 10 +++- src/service/mkd-img-extractor.ts | 21 +++----- src/service/post-category.ts | 49 +++++------------ src/service/post-cfg-panel.ts | 10 ++-- src/service/post-file-map.ts | 52 +++++++++++-------- src/service/search-post-by-title.ts | 8 +-- src/tree-view/model/post-metadata.ts | 4 +- .../provider/blog-export-provider.ts | 18 ++----- .../post-category-tree-data-provider.ts | 4 +- src/tree-view/tree-view-register.ts | 2 +- ui/post-cfg/components/PostForm.tsx | 2 +- 28 files changed, 159 insertions(+), 212 deletions(-) diff --git a/src/auth/auth-provider.ts b/src/auth/auth-provider.ts index 3806f039..3a3d7862 100644 --- a/src/auth/auth-provider.ts +++ b/src/auth/auth-provider.ts @@ -49,7 +49,7 @@ export class AuthProvider implements AuthenticationProvider, Disposable { return this._sessionChangeEmitter.event } - async getSessions(scopes?: readonly string[] | undefined): Promise { + async getSessions(scopes?: readonly string[]): Promise { const sessions = await this.getAllSessions() const parsedScopes = this.ensureScopes(scopes) diff --git a/src/cmd/blog-export/open-local.ts b/src/cmd/blog-export/open-local.ts index 9404e5bc..bff32075 100644 --- a/src/cmd/blog-export/open-local.ts +++ b/src/cmd/blog-export/open-local.ts @@ -1,4 +1,3 @@ -import { CmdHandler } from '@/cmd/cmd-handler' import { window } from 'vscode' import path from 'path' import fs from 'fs' @@ -6,6 +5,7 @@ import { promisify } from 'util' import { Alert } from '@/infra/alert' import { DownloadedExportStore } from '@/service/downloaded-export.store' import { BlogExportProvider } from '@/tree-view/provider/blog-export-provider' +import { BlogExportRecordsStore } from '@/service/blog-export-records.store' const defaultOptions = { confirmUnzip: true } @@ -56,9 +56,9 @@ export async function openLocalExport(opts: Partial = def const treeProvider = BlogExportProvider.optionalInstance const dbFileSize = (await promisify(fs.stat)(dbFilePath)).size - const exportRecord = await treeProvider?.store - .list() - .then(x => x.items.find(i => i.fileName === dbFileName && i.fileBytes === dbFileSize)) + const exportRecord = await BlogExportRecordsStore.list().then(x => + x.items.find(i => i.fileName === dbFileName && i.fileBytes === dbFileSize) + ) await DownloadedExportStore.add(dbFilePath, exportRecord?.id) if (exportRecord) await treeProvider?.refreshRecords({ force: false }) diff --git a/src/cmd/extract-img.ts b/src/cmd/extract-img.ts index 076382a6..a92c10bb 100644 --- a/src/cmd/extract-img.ts +++ b/src/cmd/extract-img.ts @@ -57,7 +57,7 @@ export async function extractImg(arg: unknown, inputImgSrc?: ImgSrc) { if (selectedSrc === undefined) return - extractor.imageSrc = selectedSrc + extractor.imgSrc = selectedSrc const failedImages = await window.withProgress( { title: '正在提取图片', location: ProgressLocation.Notification }, diff --git a/src/cmd/pdf/export-pdf.ts b/src/cmd/pdf/export-pdf.ts index 4f49037e..20740618 100644 --- a/src/cmd/pdf/export-pdf.ts +++ b/src/cmd/pdf/export-pdf.ts @@ -15,15 +15,7 @@ import { PostEditDto } from '@/model/post-edit-dto' import { postPdfTemplateBuilder } from '@/cmd/pdf/post-pdf-template-builder' import { ChromiumCfg } from '@/ctx/cfg/chromium' -const launchBrowser = async ( - chromiumPath: string -): Promise< - | { - browser: puppeteer.Browser - page: puppeteer.Page - } - | undefined -> => { +async function launchBrowser(chromiumPath: string) { try { const puppeteer = (await import('puppeteer-core')).default const browser = await puppeteer.launch({ @@ -130,15 +122,18 @@ const retrieveChromiumPath = async (): Promise => { return path } -const inputTargetFolder = async (): Promise => - ((await window.showOpenDialog({ +async function inputTargetFolder() { + const uris = await window.showOpenDialog({ canSelectFiles: false, canSelectFolders: true, canSelectMany: false, title: '请选择用于保存 PDF 的目录', - })) ?? [])[0] + }) + if (uris === undefined) return undefined + else return uris[0] +} -const handlePostInput = (post: Post | PostTreeItem): Promise => { +function handlePostInput(post: Post | PostTreeItem) { const postList: Post[] = [post instanceof PostTreeItem ? post.post : post] extTreeViews.visiblePostList()?.selection.map(item => { item = item instanceof PostTreeItem ? item.post : item @@ -147,7 +142,7 @@ const handlePostInput = (post: Post | PostTreeItem): Promise => { return Promise.resolve(postList) } -const handleUriInput = async (uri: Uri): Promise => { +async function handleUriInput(uri: Uri) { const postList: Post[] = [] const { fsPath } = uri const postId = PostFileMapManager.getPostId(fsPath) @@ -182,7 +177,7 @@ const reportErrors = (errors: string[] | undefined) => { } } -const exportPostToPdf = async (input: Post | PostTreeItem | Uri | unknown): Promise => { +export async function exportPostToPdf(input: Post | PostTreeItem | Uri | unknown): Promise { if (!(input instanceof Post) && !(input instanceof PostTreeItem) && !(input instanceof Uri)) return const chromiumPath = await retrieveChromiumPath() @@ -232,5 +227,3 @@ const exportPostToPdf = async (input: Post | PostTreeItem | Uri | unknown): Prom ) ) } - -export { exportPostToPdf } diff --git a/src/cmd/pdf/post-pdf-template-builder.ts b/src/cmd/pdf/post-pdf-template-builder.ts index 09673bf4..cd4cc0e9 100644 --- a/src/cmd/pdf/post-pdf-template-builder.ts +++ b/src/cmd/pdf/post-pdf-template-builder.ts @@ -3,7 +3,7 @@ import { PostFileMapManager } from '@/service/post-file-map' import fs from 'fs' import { BlogSettingService } from '@/service/blog-setting' import { accountManager } from '@/auth/account-manager' -import { postCategoryService } from '@/service/post-category' +import { PostCategoryService } from '@/service/post-category' import { PostCategory } from '@/model/post-category' import { markdownItFactory } from '@cnblogs/markdown-it-presets' @@ -36,7 +36,7 @@ export namespace postPdfTemplateBuilder { } const buildCategoryHtml = async (): Promise => { - const categories = await postCategoryService.listCategories() + const categories = await PostCategoryService.listCategories() const postCategories = post.categoryIds ?.map(categoryId => categories.find(x => x.categoryId === categoryId)) diff --git a/src/cmd/post-category/delete-selected-category.ts b/src/cmd/post-category/delete-selected-category.ts index 29e432a5..9c1a35a2 100644 --- a/src/cmd/post-category/delete-selected-category.ts +++ b/src/cmd/post-category/delete-selected-category.ts @@ -1,6 +1,6 @@ import { MessageOptions, ProgressLocation, window } from 'vscode' import { PostCategory } from '@/model/post-category' -import { postCategoryService } from '@/service/post-category' +import { PostCategoryService } from '@/service/post-category' import { PostCategoriesListTreeItem } from '@/tree-view/model/category-list-tree-item' import { BaseMultiSelectablePostCategoryTreeViewCmdHandler } from './base-tree-view-cmd-handler' import { Alert } from '@/infra/alert' @@ -36,7 +36,7 @@ export class DeletePostCategoriesHandler extends BaseMultiSelectablePostCategory try { const increment = Math.round(10 + idx / selectedCategories.length / 90) p.report({ increment, message: `正在删除: 📂${category.title}` }) - await postCategoryService.deleteCategory(category.categoryId) + await PostCategoryService.deleteCategory(category.categoryId) idx++ } catch (err) { errs.push([category, err]) diff --git a/src/cmd/post-category/new-post-category.ts b/src/cmd/post-category/new-post-category.ts index 53614160..7a8fef6f 100644 --- a/src/cmd/post-category/new-post-category.ts +++ b/src/cmd/post-category/new-post-category.ts @@ -1,5 +1,5 @@ import { MessageOptions, ProgressLocation, window } from 'vscode' -import { postCategoryService } from '@/service/post-category' +import { PostCategoryService } from '@/service/post-category' import { extTreeViews } from '@/tree-view/tree-view-register' import { inputPostCategory } from './input-post-category' import { refreshPostCategoryList } from './refresh-post-category-list' @@ -21,12 +21,12 @@ export const newPostCategory = async () => { increment: 50, }) try { - await postCategoryService.newCategory(input) + await PostCategoryService.newCategory(input) p.report({ increment: 90, }) refreshPostCategoryList() - const newCategory = (await postCategoryService.listCategories()).find(x => x.title === input.title) + const newCategory = (await PostCategoryService.listCategories()).find(x => x.title === input.title) if (newCategory) await extTreeViews.postCategoriesList.reveal(newCategory) } catch (err) { void Alert.err('新建博文分类时遇到了错误', { diff --git a/src/cmd/post-category/update-post-category.ts b/src/cmd/post-category/update-post-category.ts index 6081b448..d1d73c42 100644 --- a/src/cmd/post-category/update-post-category.ts +++ b/src/cmd/post-category/update-post-category.ts @@ -1,7 +1,7 @@ import fs from 'fs' import { MessageOptions, ProgressLocation, window, Uri, workspace } from 'vscode' import { PostCategory } from '@/model/post-category' -import { postCategoryService } from '@/service/post-category' +import { PostCategoryService } from '@/service/post-category' import { inputPostCategory } from './input-post-category' import { refreshPostCategoryList } from './refresh-post-category-list' import { BasePostCategoryTreeViewCmdHandler } from './base-tree-view-cmd-handler' @@ -30,7 +30,7 @@ class UpdatePostCategoryTreeViewCmdHandler extends BasePostCategoryTreeViewCmdHa async p => { p.report({ increment: 10 }) try { - await postCategoryService.updateCategory(updateDto) + await PostCategoryService.updateCategory(updateDto) refreshPostCategoryList() // 如果选择了createLocalPostFileWithCategory模式且本地有该目录,则重命名该目录 const workspaceUri = WorkspaceCfg.getWorkspaceUri() diff --git a/src/cmd/post-list/open-post-in-vscode.ts b/src/cmd/post-list/open-post-in-vscode.ts index 94f382a5..f1df24ba 100644 --- a/src/cmd/post-list/open-post-in-vscode.ts +++ b/src/cmd/post-list/open-post-in-vscode.ts @@ -7,7 +7,7 @@ import { PostService } from '@/service/post' import { PostFileMapManager } from '@/service/post-file-map' import { openPostFile } from './open-post-file' import { PostTitleSanitizer } from '@/service/post-title-sanitizer' -import { postCategoryService } from '@/service/post-category' +import { PostCategoryService } from '@/service/post-category' import sanitizeFileName from 'sanitize-filename' import { WorkspaceCfg } from '@/ctx/cfg/workspace' import { PostCategoryCfg } from '@/ctx/cfg/post-category' @@ -20,7 +20,7 @@ const buildLocalPostFileUri = async (post: Post, includePostId = false): Promise const { text: postTitle } = await PostTitleSanitizer.sanitize(post) if (shouldCreateLocalPostFileWithCategory) { const firstCategoryId = post.categoryIds?.[0] - const category = firstCategoryId ? await postCategoryService.find(firstCategoryId) : null + const category = firstCategoryId ? await PostCategoryService.find(firstCategoryId) : null let i: typeof category | undefined = category let categoryTitle = '' while (i != null) { diff --git a/src/cmd/set-workspace.ts b/src/cmd/set-workspace.ts index eafe71a9..bbfde82b 100644 --- a/src/cmd/set-workspace.ts +++ b/src/cmd/set-workspace.ts @@ -2,7 +2,7 @@ import { window } from 'vscode' import { Alert } from '@/infra/alert' import { WorkspaceCfg } from '@/ctx/cfg/workspace' -export const setWorkspace = async () => { +export async function setWorkspace() { const uris = (await window.showOpenDialog({ title: '选择工作空间', diff --git a/src/cmd/show-local-file-to-post-info.ts b/src/cmd/show-local-file-to-post-info.ts index f76d64b6..be2c013f 100644 --- a/src/cmd/show-local-file-to-post-info.ts +++ b/src/cmd/show-local-file-to-post-info.ts @@ -1,8 +1,8 @@ import path from 'path' -import { MessageOptions, Uri, window } from 'vscode' +import { MessageOptions, Uri } from 'vscode' import { Alert } from '@/infra/alert' import { PostService } from '@/service/post' -import { postCategoryService } from '@/service/post-category' +import { PostCategoryService } from '@/service/post-category' import { PostFileMapManager } from '@/service/post-file-map' import { searchPostByTitle } from '@/service/search-post-by-title' import { viewPostOnline } from './view-post-online' @@ -37,7 +37,7 @@ export const showLocalFileToPostInfo = async (input: Uri | number): Promise post.categoryIds?.includes(x.categoryId)) const categoryDesc = categories.length > 0 ? `博文分类: ${categories.map(c => c.title).join(', ')}\n` : '' const tagsDesc = post.tags?.length ?? 0 > 0 ? `博文标签: ${post.tags?.join(', ')}\n` : '' @@ -75,6 +75,6 @@ export const showLocalFileToPostInfo = async (input: Uri | number): Promise(obj: T | undefined | null) { + static parse(obj?: T | null) { return obj == null ? null : new ZzkSearchResult(obj.postIds) } } diff --git a/src/service/blog-export-post.store.ts b/src/service/blog-export-post.store.ts index ca8ac0ca..f4947a40 100644 --- a/src/service/blog-export-post.store.ts +++ b/src/service/blog-export-post.store.ts @@ -1,36 +1,21 @@ import { DownloadedBlogExport } from '@/model/blog-export' -import { ExportPost, ExportPostModel } from '@/model/blog-export/export-post' +import { ExportPostModel } from '@/model/blog-export/export-post' import { DataTypes, Op, Sequelize } from 'sequelize' import { Disposable } from 'vscode' import sqlite3 from 'sqlite3' +import { isDevEnv } from '@/model/config' export class ExportPostStore implements Disposable { - private _sequelize?: null | Sequelize - private _table?: typeof ExportPostModel | null + private _sequelize = new Sequelize({ + dialect: 'sqlite', + storage: this.downloadedExport.filePath, + dialectModule: sqlite3, + logging: (...msg) => (isDevEnv() ? console.log(msg) : undefined), + }) - constructor(public readonly downloadedExport: DownloadedBlogExport) {} + private _table = ExportPostModel - protected get sequelize() { - if (this._sequelize != null) return this._sequelize - - const { - downloadedExport: { filePath }, - } = this - - this._sequelize = new Sequelize({ - dialect: 'sqlite', - storage: filePath, - dialectModule: sqlite3, - logging: (...msg) => (process.env.NODE_ENV?.toLowerCase() === 'development' ? console.log(msg) : undefined), - }) - - return this._sequelize - } - - protected get table(): typeof ExportPostModel { - if (this._table) return this._table - - const { sequelize } = this + constructor(public readonly downloadedExport: DownloadedBlogExport) { ExportPostModel.init( { id: { @@ -80,13 +65,12 @@ export class ExportPostStore implements Disposable { allowNull: false, }, }, - { sequelize, tableName: 'blog_Content', timestamps: false } + { sequelize: this._sequelize, tableName: 'blog_Content', timestamps: false } ) - return (this._table = ExportPostModel) } - list(): Promise { - return this.table + list() { + return this._table .findAll({ where: { postType: { @@ -102,8 +86,8 @@ export class ExportPostStore implements Disposable { .then(data => data.map(x => x.dataValues)) } - getBody(id: number): Promise { - return this.table + getBody(id: number) { + return this._table .findOne({ where: { id: { @@ -117,7 +101,5 @@ export class ExportPostStore implements Disposable { dispose() { this._sequelize?.close().catch(console.warn) - this._sequelize = null - this._table = null } } diff --git a/src/service/blog-export-records.store.ts b/src/service/blog-export-records.store.ts index 0a2831c3..41778dc2 100644 --- a/src/service/blog-export-records.store.ts +++ b/src/service/blog-export-records.store.ts @@ -1,29 +1,27 @@ import { BlogExportRecordList } from '@/model/blog-export' import { BlogExportApi } from '@/service/blog-export.api' -export class BlogExportRecordsStore { - private _cachedList: Promise | null = null - private _cached: BlogExportRecordList | null = null +export namespace BlogExportRecordsStore { + let cacheList: Promise | null = null + let cache: BlogExportRecordList | null = null - get cached() { - return this._cached + export function getCached() { + return cache } - async refresh( - options?: BlogExportRecordsStore['list'] extends (opt: infer U) => unknown ? U : never - ): Promise { - await this.clearCache() - return this.list(options) + export async function refresh(options?: { pageIndex?: number; pageSize?: number; shouldRefresh?: boolean }) { + await clearCache() + return list(options) } - async clearCache(): Promise { - if (this._cachedList) await this._cachedList.catch(() => false) + export async function clearCache(): Promise { + if (cacheList) await cacheList.catch(() => false) - this._cachedList = null - this._cached = null + cacheList = null + cache = null } - async list({ + export async function list({ pageIndex = 1, pageSize = 500, }: { @@ -31,9 +29,9 @@ export class BlogExportRecordsStore { pageSize?: number shouldRefresh?: boolean } = {}): Promise { - this._cachedList ??= BlogExportApi.list({ pageIndex, pageSize }) - this._cached = await this._cachedList + cacheList ??= BlogExportApi.list({ pageIndex, pageSize }) + cache = await cacheList - return this._cached + return cache } } diff --git a/src/service/downloaded-export.store.ts b/src/service/downloaded-export.store.ts index 6b03fc96..57768773 100644 --- a/src/service/downloaded-export.store.ts +++ b/src/service/downloaded-export.store.ts @@ -13,7 +13,7 @@ const updateExport = (id: number, value?: DownloadedBlogExport | null) => globalCtx.storage.update(`${metadataKey}${id}`, value) export namespace DownloadedExportStore { - export async function add(filePath: string, id?: number | null): Promise { + export async function add(filePath: string, id?: number | null) { const item: DownloadedBlogExport = { id, filePath } const list = await DownloadedExportStore.list() const oldIdx = list.findIndex(x => x.filePath === filePath) @@ -26,7 +26,7 @@ export namespace DownloadedExportStore { ]).then(() => undefined) } - export async function list({ prune = true } = {}): Promise { + export async function list({ prune = true } = {}) { let items = globalCtx.storage.get(listKey) ?? [] if (prune) { @@ -62,10 +62,7 @@ export namespace DownloadedExportStore { ]) } - export async function findById( - id: number, - { prune = true } = {} - ): Promise { + export async function findById(id: number, { prune = true } = {}) { const key = `${metadataKey}${id}` let item = globalCtx.storage.get(key) diff --git a/src/service/local-draft.ts b/src/service/local-draft.ts index c723d2cb..d2cd2ef8 100644 --- a/src/service/local-draft.ts +++ b/src/service/local-draft.ts @@ -8,20 +8,26 @@ export class LocalDraft { get fileName(): string { return path.basename(this.filePath) } + get fileNameWithoutExt(): string { return path.basename(this.filePath, this.fileExt) } + get fileExt() { return path.extname(this.filePath) } + get filePathUri() { return Uri.file(this.filePath) } + get exist() { return fs.existsSync(this.filePath) } - async readAllText(): Promise { - return Buffer.from(await workspace.fs.readFile(this.filePathUri)).toString() + async readAllText() { + const arr = await workspace.fs.readFile(this.filePathUri) + const buf = Buffer.from(arr) + return buf.toString() } } diff --git a/src/service/mkd-img-extractor.ts b/src/service/mkd-img-extractor.ts index 5f052095..9ce52b0d 100644 --- a/src/service/mkd-img-extractor.ts +++ b/src/service/mkd-img-extractor.ts @@ -66,26 +66,19 @@ enum ExtractorSt { } export class MkdImgExtractor { - private _imageSrc = ImgSrc.any private _status = ExtractorSt.pending private _errors: [imgLink: string, msg: string][] = [] - private _images: ImgInfo[] | null | undefined = null - private readonly _workspaceDirs: string[] | undefined + private _images: ImgInfo[] = [] + private readonly _workspaceDirs: string[] = [] constructor( private readonly markdown: string, private readonly targetFileUri: Uri, + public imgSrc: ImgSrc = ImgSrc.any, public onProgress?: (index: number, images: ImgInfo[]) => void ) { - this._workspaceDirs = workspace.workspaceFolders?.map(({ uri: { fsPath } }) => fsPath) - } - - get imageSrc() { - return this._imageSrc - } - - set imageSrc(v) { - this._imageSrc = v + if (workspace.workspaceFolders !== undefined) + this._workspaceDirs = workspace.workspaceFolders.map(({ uri: { fsPath } }) => fsPath) } get status() { @@ -170,7 +163,7 @@ export class MkdImgExtractor { this._images = acc() // apply settings - return this._images.filter(x => newImgSrcFilter(this._imageSrc)(x)) + return this._images.filter(x => newImgSrcFilter(this.imgSrc)(x)) } private async resolveWebImg(url: string) { @@ -204,7 +197,7 @@ export class MkdImgExtractor { continue } - searchingDirs ??= [path.dirname(this.targetFileUri.fsPath), ...(this._workspaceDirs ?? [])] + searchingDirs ??= [path.dirname(this.targetFileUri.fsPath), ...this._workspaceDirs] iPath = iDir >= 0 && searchingDirs.length > iDir ? path.resolve(searchingDirs[iDir], imgPath) : undefined iDir++ isEncodedPath = false diff --git a/src/service/post-category.ts b/src/service/post-category.ts index ab9a3722..9bdcbf0f 100644 --- a/src/service/post-category.ts +++ b/src/service/post-category.ts @@ -3,44 +3,23 @@ import { PostCategories, PostCategory, PostCategoryAddDto } from '@/model/post-c import { globalCtx } from '@/ctx/global-ctx' import { URLSearchParams } from 'url' -export class PostCategoryService { - private static _instance: PostCategoryService | null = null +let cache: Map | null = null - private _cache?: Map - - private constructor() {} - - static get instance(): PostCategoryService { - this._instance ??= new PostCategoryService() - - return this._instance - } - - async findCategories(ids: number[], { useCache = true } = {}): Promise { +export namespace PostCategoryService { + export async function findCategories(ids: number[], { useCache = true } = {}) { ids = ids.filter(x => x > 0) if (ids.length <= 0) return [] - const categories = await this.listCategories(!useCache) + const categories = await listCategories(!useCache) return categories.filter(({ categoryId }) => ids.includes(categoryId)) } - listCategories(): Promise - listCategories({ - forceRefresh = false, - parentId = -1, - }: { - forceRefresh?: boolean | null - parentId?: number - }): Promise - listCategories(forceRefresh: boolean): Promise - async listCategories( - option: boolean | { forceRefresh?: boolean | null; parentId?: number } = {} - ): Promise { + export async function listCategories(option: boolean | { forceRefresh?: boolean | null; parentId?: number } = {}) { const parentId = typeof option === 'object' ? option.parentId ?? -1 : -1 const shouldForceRefresh = option === true || (typeof option === 'object' ? option.forceRefresh ?? false : false) - this._cache ??= new Map() - const map = this._cache + cache ??= new Map() + const map = cache const cachedCategories = map.get(parentId) if (cachedCategories && !shouldForceRefresh) return cachedCategories @@ -57,7 +36,7 @@ export class PostCategoryService { return categories } - async find(id: number) { + export async function find(id: number) { const res = await fetch( `${globalCtx.config.apiBaseUrl}/api/v2/blog-category-types/1/categories?${new URLSearchParams([ ['parent', id <= 0 ? '' : `${id}`], @@ -68,7 +47,7 @@ export class PostCategoryService { return Object.assign(new PostCategory(), parent) } - async newCategory(categoryAddDto: PostCategoryAddDto) { + export async function newCategory(categoryAddDto: PostCategoryAddDto) { const res = await fetch(`${globalCtx.config.apiBaseUrl}/api/category/blog/1`, { method: 'POST', body: JSON.stringify(categoryAddDto), @@ -77,7 +56,7 @@ export class PostCategoryService { if (!res.ok) throw Error(`${res.status}-${res.statusText}\n${await res.text()}`) } - async updateCategory(category: PostCategory) { + export async function updateCategory(category: PostCategory) { const res = await fetch(`${globalCtx.config.apiBaseUrl}/api/category/blog/${category.categoryId}`, { method: 'PUT', body: JSON.stringify(category), @@ -86,7 +65,7 @@ export class PostCategoryService { if (!res.ok) throw Error(`${res.status}-${res.statusText}\n${await res.text()}`) } - async deleteCategory(categoryId: number) { + export async function deleteCategory(categoryId: number) { if (categoryId <= 0) throw Error('Invalid param categoryId') const res = await fetch(`${globalCtx.config.apiBaseUrl}/api/category/blog/${categoryId}`, { @@ -96,9 +75,7 @@ export class PostCategoryService { if (!res.ok) throw Error(`${res.status}-${res.statusText}\n${await res.text()}`) } - clearCache() { - this._cache = undefined + export function clearCache() { + cache = null } } - -export const postCategoryService = PostCategoryService.instance diff --git a/src/service/post-cfg-panel.ts b/src/service/post-cfg-panel.ts index 59aa9ff1..95779a01 100644 --- a/src/service/post-cfg-panel.ts +++ b/src/service/post-cfg-panel.ts @@ -2,7 +2,7 @@ import { cloneDeep } from 'lodash-es' import vscode, { Uri } from 'vscode' import { Post } from '@/model/post' import { globalCtx } from '@/ctx/global-ctx' -import { postCategoryService } from './post-category' +import { PostCategoryService } from './post-category' import { siteCategoryService } from './site-category' import { PostTagService } from './post-tag' import { PostService } from './post' @@ -60,7 +60,7 @@ export namespace PostCfgPanel { command: WebviewCmd.UiCmd.editPostCfg, post: cloneDeep(post), activeTheme: vscode.window.activeColorTheme.kind, - personalCategories: cloneDeep(await postCategoryService.listCategories()), + personalCategories: cloneDeep(await PostCategoryService.listCategories()), siteCategories: cloneDeep(await siteCategoryService.fetchAll()), tags: cloneDeep(await PostTagService.fetchTags()), breadcrumbs, @@ -211,9 +211,9 @@ export namespace PostCfgPanel { await webview.postMessage({ command: WebviewCmd.UiCmd.updateChildCategories, payload: { - value: await postCategoryService - .listCategories({ parentId: payload.parentId }) - .catch(() => []), + value: await PostCategoryService.listCategories({ parentId: payload.parentId }).catch( + () => [] + ), parentId: payload.parentId, }, } as WebviewCommonCmd) diff --git a/src/service/post-file-map.ts b/src/service/post-file-map.ts index bcfb8c83..4fc56934 100644 --- a/src/service/post-file-map.ts +++ b/src/service/post-file-map.ts @@ -6,18 +6,24 @@ const validatePostFileMap = (map: PostFileMap) => map[0] >= 0 && !!map[1] export type PostFileMap = [postId: number, filePath: string] -export class PostFileMapManager { - static storageKey = 'postFileMaps' +const storageKey = 'postFileMaps' - private static get maps(): PostFileMap[] { - return globalCtx.storage.get(this.storageKey) ?? [] - } +function getMaps(): PostFileMap[] { + return globalCtx.storage.get(storageKey) ?? [] +} - static updateOrCreateMany(maps: PostFileMap[]): Promise - static updateOrCreateMany(options: { emitEvent?: boolean; maps: PostFileMap[] }): Promise - static async updateOrCreateMany(arg: { emitEvent?: boolean; maps: PostFileMap[] } | PostFileMap[]): Promise { +export namespace PostFileMapManager { + export async function updateOrCreateMany( + arg: + | { + emitEvent?: boolean + maps: PostFileMap[] + } + | PostFileMap[] + ) { let maps: PostFileMap[] = [] let shouldEmitEvent = true + if (Array.isArray(arg)) { maps = arg } else { @@ -25,43 +31,45 @@ export class PostFileMapManager { shouldEmitEvent = arg.emitEvent ?? true } - for (const map of maps) await this.updateOrCreate(map[0], map[1], { emitEvent: shouldEmitEvent }) + for (const map of maps) await updateOrCreate(map[0], map[1], { emitEvent: shouldEmitEvent }) } - static async updateOrCreate(postId: number, filePath: string, { emitEvent = true } = {}): Promise { + export async function updateOrCreate(postId: number, filePath: string, { emitEvent = true } = {}) { const validFileExt = ['.md', '.html'] if (filePath && !validFileExt.some(x => filePath.endsWith(x))) throw Error('Invalid filepath, file must have type markdown or html') - const maps = this.maps + const maps = getMaps() const exist = maps.find(p => p[0] === postId) if (exist) exist[1] = filePath else maps.push([postId, filePath]) - await globalCtx.storage.update(this.storageKey, maps.filter(validatePostFileMap)) + await globalCtx.storage.update(storageKey, maps.filter(validatePostFileMap)) if (emitEvent) { postDataProvider.fireTreeDataChangedEvent(postId) postCategoryDataProvider.onPostUpdated({ refreshPost: false, postIds: [postId] }) } } - static findByPostId(postId: number) { - const maps = this.maps.filter(validatePostFileMap) + export function findByPostId(postId: number) { + const maps = getMaps().filter(validatePostFileMap) return maps.find(x => x[0] === postId) } - static findByFilePath(path: string) { - const maps = this.maps.filter(validatePostFileMap) + export function findByFilePath(path: string) { + const maps = getMaps().filter(validatePostFileMap) return maps.find(x => x[0] && x[1] === path) } - static getFilePath(postId: number) { - const map = this.findByPostId(postId) - return map ? map[1] : undefined + export function getFilePath(postId: number) { + const map = findByPostId(postId) + if (map === undefined) return + return map[1] } - static getPostId(filePath: string) { - const map = this.findByFilePath(filePath) - return map ? map[0] : undefined + export function getPostId(filePath: string) { + const map = findByFilePath(filePath) + if (map === undefined) return + return map[0] } } diff --git a/src/service/search-post-by-title.ts b/src/service/search-post-by-title.ts index f081ed8d..ca4f1457 100644 --- a/src/service/search-post-by-title.ts +++ b/src/service/search-post-by-title.ts @@ -4,10 +4,10 @@ import { PostService } from './post' class PostPickItem implements QuickPickItem { label: string - description?: string | undefined - detail?: string | undefined - picked?: boolean | undefined - alwaysShow?: boolean | undefined + description?: string + detail?: string + picked?: boolean + alwaysShow?: boolean constructor(public post: Post) { this.label = post.title diff --git a/src/tree-view/model/post-metadata.ts b/src/tree-view/model/post-metadata.ts index 136f4d1b..81182e1e 100644 --- a/src/tree-view/model/post-metadata.ts +++ b/src/tree-view/model/post-metadata.ts @@ -6,7 +6,7 @@ import zhCN from 'date-fns/locale/zh-CN' import { TreeItem, TreeItemCollapsibleState, ThemeIcon } from 'vscode' import { AccessPermission, Post, formatAccessPermission } from '@/model/post' import { PostEditDto } from '@/model/post-edit-dto' -import { postCategoryService } from '@/service/post-category' +import { PostCategoryService } from '@/service/post-category' import { PostService } from '@/service/post' import { BaseEntryTreeItem } from './base-entry-tree-item' import { BaseTreeItemSource } from './base-tree-item-source' @@ -130,7 +130,7 @@ export class PostCategoryMetadata extends PostMetadata { const { post: { categoryIds }, } = editDto - return (await Promise.all((categoryIds ?? []).map(categoryId => postCategoryService.find(categoryId)))) + return (await Promise.all((categoryIds ?? []).map(categoryId => PostCategoryService.find(categoryId)))) .filter((x): x is PostCategory => x != null) .map( category => diff --git a/src/tree-view/provider/blog-export-provider.ts b/src/tree-view/provider/blog-export-provider.ts index 8c6ed006..7af8877c 100644 --- a/src/tree-view/provider/blog-export-provider.ts +++ b/src/tree-view/provider/blog-export-provider.ts @@ -19,7 +19,6 @@ export class BlogExportProvider implements TreeDataProvider private static _instance: BlogExportProvider | null = null private _treeDataChangedSource?: EventEmitter | null - private _store?: BlogExportRecordsStore | null private _downloadedExportEntry?: DownloadedExportsEntryTreeItem | null static get instance(): BlogExportProvider { @@ -36,11 +35,6 @@ export class BlogExportProvider implements TreeDataProvider return this._treeDataChangedSource.event } - get store(): BlogExportRecordsStore { - this._store ??= new BlogExportRecordsStore() - return this._store - } - getTreeItem(element: BlogExportTreeItem): TreeItem | Thenable { return element instanceof TreeItem ? element : element.toTreeItem() } @@ -105,14 +99,13 @@ export class BlogExportProvider implements TreeDataProvider clearCache = true, } = {}): Promise { const hasCacheRefreshed = force - ? await this._store - ?.refresh() + ? await BlogExportRecordsStore?.refresh() .then(() => true) .catch(e => { - if (notifyOnError) Alert.err(`刷新博客备份记录失败: ${e.message}`) + if (notifyOnError) void Alert.err(`刷新博客备份记录失败: ${e.message}`) }) : clearCache - ? await this._store?.clearCache().then( + ? await BlogExportRecordsStore.clearCache().then( () => true, () => true ) @@ -128,10 +121,7 @@ export class BlogExportProvider implements TreeDataProvider } private listRecords(): BlogExportRecordTreeItem[] { - const { - store: { cached }, - } = this - // eslint-disable-next-line @typescript-eslint/no-floating-promises + const cached = BlogExportRecordsStore.getCached() if (cached == null) void this.refreshRecords() const items: BlogExportRecord[] = cached?.items ?? [] return parseBlogExportRecords(this, items) diff --git a/src/tree-view/provider/post-category-tree-data-provider.ts b/src/tree-view/provider/post-category-tree-data-provider.ts index 056f180b..1250ace2 100644 --- a/src/tree-view/provider/post-category-tree-data-provider.ts +++ b/src/tree-view/provider/post-category-tree-data-provider.ts @@ -2,7 +2,7 @@ import { flattenDepth, take } from 'lodash-es' import { EventEmitter, ProviderResult, TreeDataProvider, TreeItem } from 'vscode' import { PostCategories } from '@/model/post-category' import { globalCtx } from '@/ctx/global-ctx' -import { postCategoryService } from '@/service/post-category' +import { PostCategoryService } from '@/service/post-category' import { PostService } from '@/service/post' import { toTreeItem } from '@/tree-view/convert' import { PostCategoriesListTreeItem } from '@/tree-view/model/category-list-tree-item' @@ -130,7 +130,7 @@ export class PostCategoryTreeDataProvider implements TreeDataProvider diff --git a/ui/post-cfg/components/PostForm.tsx b/ui/post-cfg/components/PostForm.tsx index 5f49903a..c2f6ab47 100644 --- a/ui/post-cfg/components/PostForm.tsx +++ b/ui/post-cfg/components/PostForm.tsx @@ -32,7 +32,7 @@ export interface IPostFormProps { export interface IPostFormState extends PostCfg {} export class PostForm extends React.Component { - static contextType?: React.Context | undefined = PostFormContext + static contextType?: React.Context = PostFormContext declare context: React.ContextType constructor(props: IPostFormProps) { From 0ee4dc407d20ff32af1145df517cc11157e0b9c2 Mon Sep 17 00:00:00 2001 From: Thaumy Date: Thu, 27 Jul 2023 14:33:21 +0800 Subject: [PATCH 043/157] refactor: img extract --- src/cmd/extract-img.ts | 18 +++--- ...le-in-os.ts => os-open-local-post-file.ts} | 6 +- src/cmd/os-open-workspace.ts | 4 ++ src/cmd/post-list/create-local-draft.ts | 6 +- src/cmd/post-list/delete-post.ts | 8 +-- src/cmd/post-list/open-post-in-vscode.ts | 4 +- src/cmd/reveal-workspace-in-os.ts | 4 -- src/cmd/upload-img/upload-clipboard-img.ts | 3 +- src/cmd/upload-img/upload-fs-img.ts | 10 ++-- src/cmd/upload-img/upload-img.ts | 24 ++++---- src/ctx/cfg/markdown.ts | 2 +- src/infra/filter/find-img-link.ts | 43 +++++++++++++ src/infra/{ => filter}/rm-yfm.ts | 0 src/infra/os-open-active-file.ts | 3 + src/infra/reveal-active-file.ts | 3 - .../mkd-img-extractor.ts | 60 ++----------------- src/service/post.ts | 2 +- src/setup/setup-cmd.ts | 8 +-- 18 files changed, 101 insertions(+), 107 deletions(-) rename src/cmd/{reveal-local-post-file-in-os.ts => os-open-local-post-file.ts} (67%) create mode 100644 src/cmd/os-open-workspace.ts delete mode 100644 src/cmd/reveal-workspace-in-os.ts create mode 100644 src/infra/filter/find-img-link.ts rename src/infra/{ => filter}/rm-yfm.ts (100%) create mode 100644 src/infra/os-open-active-file.ts delete mode 100644 src/infra/reveal-active-file.ts rename src/{service => markdown}/mkd-img-extractor.ts (68%) diff --git a/src/cmd/extract-img.ts b/src/cmd/extract-img.ts index a92c10bb..6f752a6a 100644 --- a/src/cmd/extract-img.ts +++ b/src/cmd/extract-img.ts @@ -1,6 +1,7 @@ import { MessageItem, MessageOptions, ProgressLocation, Range, Uri, window, workspace, WorkspaceEdit } from 'vscode' -import { ImgInfo, ImgSrc, MkdImgExtractor, newImgSrcFilter } from '@/service/mkd-img-extractor' +import { ImgInfo, ImgSrc, MkdImgExtractor, newImgSrcFilter } from '@/markdown/mkd-img-extractor' import { Alert } from '@/infra/alert' +import { findImgLink } from '@/infra/filter/find-img-link' type ExtractOption = MessageItem & Partial<{ imageSrc: ImgSrc }> @@ -14,17 +15,16 @@ export async function extractImg(arg: unknown, inputImgSrc?: ImgSrc) { await textDocument.save() const markdown = (await workspace.fs.readFile(arg)).toString() - const extractor = new MkdImgExtractor(markdown, arg) + const imgInfoList = findImgLink(markdown) - const images = extractor.findImages() - if (images.length <= 0) { + if (imgInfoList.length <= 0) { if (inputImgSrc !== undefined) void Alert.info('没有找到可以提取的图片') return } - const webImgCount = images.filter(newImgSrcFilter(ImgSrc.web)).length - const dataUrlImgCount = images.filter(newImgSrcFilter(ImgSrc.dataUrl)).length - const fsImgCount = images.filter(newImgSrcFilter(ImgSrc.fs)).length + const webImgCount = imgInfoList.filter(newImgSrcFilter(ImgSrc.web)).length + const dataUrlImgCount = imgInfoList.filter(newImgSrcFilter(ImgSrc.dataUrl)).length + const fsImgCount = imgInfoList.filter(newImgSrcFilter(ImgSrc.fs)).length const displayOptions: ExtractOption[] = [ { title: '提取全部', imageSrc: ImgSrc.any }, @@ -57,7 +57,7 @@ export async function extractImg(arg: unknown, inputImgSrc?: ImgSrc) { if (selectedSrc === undefined) return - extractor.imgSrc = selectedSrc + const extractor = new MkdImgExtractor(arg, selectedSrc) const failedImages = await window.withProgress( { title: '正在提取图片', location: ProgressLocation.Notification }, @@ -71,7 +71,7 @@ export async function extractImg(arg: unknown, inputImgSrc?: ImgSrc) { }) } - const extracted = await extractor.extract() + const extracted = await extractor.extract(imgInfoList) const extractedLen = extracted.length const idx = 0 diff --git a/src/cmd/reveal-local-post-file-in-os.ts b/src/cmd/os-open-local-post-file.ts similarity index 67% rename from src/cmd/reveal-local-post-file-in-os.ts rename to src/cmd/os-open-local-post-file.ts index 3fc23734..3cfdfa8e 100644 --- a/src/cmd/reveal-local-post-file-in-os.ts +++ b/src/cmd/os-open-local-post-file.ts @@ -3,11 +3,11 @@ import { execCmd } from '@/infra/cmd' import { Post } from '@/model/post' import { PostFileMapManager } from '@/service/post-file-map' -export const revealLocalPostFileInOs = (post: Post) => { - if (!post) return +export function osOpenLocalPostFile(post: Post | undefined) { + if (post === undefined) return const postFilePath = PostFileMapManager.getFilePath(post.id) - if (!postFilePath) return + if (postFilePath === undefined) return return execCmd('revealFileInOS', Uri.file(postFilePath)) } diff --git a/src/cmd/os-open-workspace.ts b/src/cmd/os-open-workspace.ts new file mode 100644 index 00000000..f1b11ed8 --- /dev/null +++ b/src/cmd/os-open-workspace.ts @@ -0,0 +1,4 @@ +import { execCmd } from '@/infra/cmd' +import { WorkspaceCfg } from '@/ctx/cfg/workspace' + +export const osOpenWorkspace = () => execCmd('revealFileInOS', WorkspaceCfg.getWorkspaceUri()) diff --git a/src/cmd/post-list/create-local-draft.ts b/src/cmd/post-list/create-local-draft.ts index ea082409..31d2b20b 100644 --- a/src/cmd/post-list/create-local-draft.ts +++ b/src/cmd/post-list/create-local-draft.ts @@ -1,7 +1,7 @@ import { homedir } from 'os' import path from 'path' import { Uri, window, workspace } from 'vscode' -import { revealActiveFileInExplorer } from '@/infra/reveal-active-file' +import { osOpenActiveFile } from '@/infra/os-open-active-file' import { openPostFile } from './open-post-file' import { WorkspaceCfg } from '@/ctx/cfg/workspace' @@ -32,9 +32,9 @@ export const createLocalDraft = async () => { } await openPostFile(filePath) - await revealActiveFileInExplorer() + await osOpenActiveFile() // 设置中关闭了 `autoReveal` 的情况下, 需要两次调用 `workbench.files.action.showActiveFileInExplorer` 命令, 才能正确 `reveal` - if (!workspace.getConfiguration('explorer').get('autoReveal')) await revealActiveFileInExplorer() + if (!workspace.getConfiguration('explorer').get('autoReveal')) await osOpenActiveFile() const focusEditor = async () => { const { activeTextEditor } = window diff --git a/src/cmd/post-list/delete-post.ts b/src/cmd/post-list/delete-post.ts index 04f8496b..ec373ba0 100644 --- a/src/cmd/post-list/delete-post.ts +++ b/src/cmd/post-list/delete-post.ts @@ -11,9 +11,7 @@ import { postCategoryDataProvider } from '@/tree-view/provider/post-category-tre let isDeleting = false -const confirmDelete = async ( - selectedPost: Post[] -): Promise<{ confirmed: boolean; deleteLocalFileAtSameTime: boolean }> => { +async function confirmDelete(selectedPost: Post[]) { const result = { confirmed: false, deleteLocalFileAtSameTime: false } if (!selectedPost || selectedPost.length <= 0) return result @@ -38,7 +36,7 @@ const confirmDelete = async ( return result } -export const deleteSelectedPost = async (arg: unknown) => { +export async function deleteSelectedPost(arg: unknown) { let post: Post if (arg instanceof Post) post = arg else if (arg instanceof PostTreeItem) post = arg.post @@ -55,7 +53,7 @@ export const deleteSelectedPost = async (arg: unknown) => { if (selectedPost.length <= 0) return if (isDeleting) { - Alert.warn('休息会儿再点吧~') + void Alert.warn('休息会儿再点吧~') return } diff --git a/src/cmd/post-list/open-post-in-vscode.ts b/src/cmd/post-list/open-post-in-vscode.ts index f1df24ba..3a7f6bc9 100644 --- a/src/cmd/post-list/open-post-in-vscode.ts +++ b/src/cmd/post-list/open-post-in-vscode.ts @@ -92,13 +92,13 @@ export const openPostInVscode = async (postId: number, forceUpdateLocalPostFile return fileUri } -const createDirectoryIfNotExist = async (uri: Uri) => { +async function createDirectoryIfNotExist(uri: Uri) { try { await workspace.fs.readDirectory(uri) } catch (err) { if (err instanceof FileSystemError) await workspace.fs.createDirectory(uri) - Alert.err('Create workspace directory failed') + void Alert.err('Create workspace directory failed') console.error(err) } } diff --git a/src/cmd/reveal-workspace-in-os.ts b/src/cmd/reveal-workspace-in-os.ts deleted file mode 100644 index 372f5c30..00000000 --- a/src/cmd/reveal-workspace-in-os.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { execCmd } from '@/infra/cmd' -import { WorkspaceCfg } from '@/ctx/cfg/workspace' - -export const revealWorkspaceInOs = () => execCmd('revealFileInOS', WorkspaceCfg.getWorkspaceUri()) diff --git a/src/cmd/upload-img/upload-clipboard-img.ts b/src/cmd/upload-img/upload-clipboard-img.ts index c893807c..07284596 100644 --- a/src/cmd/upload-img/upload-clipboard-img.ts +++ b/src/cmd/upload-img/upload-clipboard-img.ts @@ -6,8 +6,9 @@ import getClipboardImage from '@/infra/get-clipboard-img' const noImagePath = 'no image' -export const uploadImgFromClipboard = async () => { +export async function uploadImgFromClipboard() { const clipboardImage = await getClipboardImage() + if (clipboardImage.imgPath === noImagePath) { void Alert.warn('剪贴板中没有找到图片') return diff --git a/src/cmd/upload-img/upload-fs-img.ts b/src/cmd/upload-img/upload-fs-img.ts index 489b6bae..cdadfb52 100644 --- a/src/cmd/upload-img/upload-fs-img.ts +++ b/src/cmd/upload-img/upload-fs-img.ts @@ -2,16 +2,18 @@ import { ProgressLocation, window } from 'vscode' import { ImgService } from '@/service/img' import fs from 'fs' -export const uploadFsImage = async () => { - const imageFileUri = ((await window.showOpenDialog({ +export async function uploadFsImage() { + const uriList = await window.showOpenDialog({ title: '选择要上传的图片(图片最大不能超过20M)', canSelectMany: false, canSelectFolders: false, filters: { images: ['png', 'jpg', 'bmp', 'jpeg', 'webp', 'svg', 'gif'], }, - })) ?? [])[0] - if (!imageFileUri) return + }) + if (uriList === undefined) return + + const imageFileUri = uriList[0] const imageFilePath = imageFileUri.fsPath return window.withProgress( diff --git a/src/cmd/upload-img/upload-img.ts b/src/cmd/upload-img/upload-img.ts index 6452befa..411efe7a 100644 --- a/src/cmd/upload-img/upload-img.ts +++ b/src/cmd/upload-img/upload-img.ts @@ -3,18 +3,20 @@ import { uploadImgFromClipboard } from './upload-clipboard-img' import { insertImgLinkToActiveEditor, showUploadSuccessModel } from './upload-img-util' import { uploadFsImage } from './upload-fs-img' -export const uploadImg = async (autoInsertToActiveEditor = true, from?: 'local' | 'clipboard') => { +export async function uploadImg(autoInsertToActiveEditor = true, from?: 'local' | 'clipboard') { const options = ['本地图片文件', '剪贴板图片'] - const selected = !from - ? await Alert.info( - '上传图片到博客园', - { - modal: true, - detail: '选择图片来源', - }, - ...options - ) - : from + let selected = undefined + + if (from !== undefined) { + selected = await Alert.info( + '上传图片到博客园', + { + modal: true, + detail: '选择图片来源', + }, + ...options + ) + } let imageUrl: string | undefined const caughtFailedUpload = (e: unknown) => diff --git a/src/ctx/cfg/markdown.ts b/src/ctx/cfg/markdown.ts index 0c94bfbf..90551e02 100644 --- a/src/ctx/cfg/markdown.ts +++ b/src/ctx/cfg/markdown.ts @@ -1,6 +1,6 @@ import { LocalState } from '@/ctx/local-state' import getExtCfg = LocalState.getExtCfg -import { ImgSrc } from '@/service/mkd-img-extractor' +import { ImgSrc } from '@/markdown/mkd-img-extractor' export namespace MarkdownCfg { const cfgGet = (key: string) => getExtCfg().get(`markdown.${key}`) diff --git a/src/infra/filter/find-img-link.ts b/src/infra/filter/find-img-link.ts new file mode 100644 index 00000000..93561b98 --- /dev/null +++ b/src/infra/filter/find-img-link.ts @@ -0,0 +1,43 @@ +// Data URL reference see in: +// https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URLs +// Related RFC: +// https://datatracker.ietf.org/doc/html/rfc2397 + +import { DataType, ImgInfo } from '@/markdown/mkd-img-extractor' + +const imgTagDataUrlImgPat = /()/g +const imgTagUrlImgPat = /()/gi +const mkdDataUrlImgPat = /(!\[.*?]\()(data:image\/.*?,[a-zA-Z0-9+/]*?=?=?)(\))/g +const mkdUrlImgPat = /(!\[.*?]\()(.*?\.(?:png|jpg|jpeg|webp|svg|gif))(\))/gi + +const cnblogsDomainRegExp = /\.cnblogs\.com\//gi + +export function findImgLink(text: string): ImgInfo[] { + const imgTagUrlImgMatchGroups = Array.from(text.matchAll(imgTagUrlImgPat)) + const mkdUrlImgMatchGroups = Array.from(text.matchAll(mkdUrlImgPat)) + const urlImgInfo = imgTagUrlImgMatchGroups.concat(mkdUrlImgMatchGroups).map(mg => ({ + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + startOffset: mg.index!, + dataType: DataType.url, + data: mg[2], + prefix: mg[1], + postfix: mg[3], + })) + + const imgTagDataUrlImgMatchGroups = Array.from(text.matchAll(imgTagDataUrlImgPat)) + const mkdDataUrlImgMatchGroups = Array.from(text.matchAll(mkdDataUrlImgPat)) + const dataUrlImgInfo = imgTagDataUrlImgMatchGroups.concat(mkdDataUrlImgMatchGroups).map(mg => ({ + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + startOffset: mg.index!, + dataType: DataType.dataUrl, + data: mg[2], + prefix: mg[1], + postfix: mg[3], + })) + + const acc = urlImgInfo.concat(dataUrlImgInfo) + + // TODO: better filter design needed + // remove cnblogs img link + return acc.filter(x => x.data.match(cnblogsDomainRegExp) == null) +} diff --git a/src/infra/rm-yfm.ts b/src/infra/filter/rm-yfm.ts similarity index 100% rename from src/infra/rm-yfm.ts rename to src/infra/filter/rm-yfm.ts diff --git a/src/infra/os-open-active-file.ts b/src/infra/os-open-active-file.ts new file mode 100644 index 00000000..f7711135 --- /dev/null +++ b/src/infra/os-open-active-file.ts @@ -0,0 +1,3 @@ +import { execCmd } from '@/infra/cmd' + +export const osOpenActiveFile = () => execCmd('workbench.files.action.showActiveFileInExplorer') diff --git a/src/infra/reveal-active-file.ts b/src/infra/reveal-active-file.ts deleted file mode 100644 index 0d3eb6af..00000000 --- a/src/infra/reveal-active-file.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { execCmd } from '@/infra/cmd' - -export const revealActiveFileInExplorer = () => execCmd('workbench.files.action.showActiveFileInExplorer') diff --git a/src/service/mkd-img-extractor.ts b/src/markdown/mkd-img-extractor.ts similarity index 68% rename from src/service/mkd-img-extractor.ts rename to src/markdown/mkd-img-extractor.ts index 9ce52b0d..a20f241a 100644 --- a/src/service/mkd-img-extractor.ts +++ b/src/markdown/mkd-img-extractor.ts @@ -21,18 +21,6 @@ export interface ImgInfo { postfix: string } -// Data URL reference see in: -// https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URLs -// Related RFC: -// https://datatracker.ietf.org/doc/html/rfc2397 - -const imgTagDataUrlImgPat = /()/g -const imgTagUrlImgPat = /()/gi -const mkdDataUrlImgPat = /(!\[.*?]\()(data:image\/.*?,[a-zA-Z0-9+/]*?=?=?)(\))/g -const mkdUrlImgPat = /(!\[.*?]\()(.*?\.(?:png|jpg|jpeg|webp|svg|gif))(\))/gi - -const cnblogsDomainRegExp = /\.cnblogs\.com\//gi - export const enum ImgSrc { web, dataUrl, @@ -68,13 +56,11 @@ enum ExtractorSt { export class MkdImgExtractor { private _status = ExtractorSt.pending private _errors: [imgLink: string, msg: string][] = [] - private _images: ImgInfo[] = [] private readonly _workspaceDirs: string[] = [] constructor( - private readonly markdown: string, private readonly targetFileUri: Uri, - public imgSrc: ImgSrc = ImgSrc.any, + private imgSrc: ImgSrc, public onProgress?: (index: number, images: ImgInfo[]) => void ) { if (workspace.workspaceFolders !== undefined) @@ -89,16 +75,15 @@ export class MkdImgExtractor { return this._errors } - async extract(): Promise<[src: ImgInfo, dst: ImgInfo | null][]> { + async extract(imgInfoList: ImgInfo[]): Promise<[src: ImgInfo, dst: ImgInfo | null][]> { this._status = ExtractorSt.extracting - const srcInfoArr = this.findImages() let count = 0 const result: ReturnType extends Promise ? U : never = [] - for (const srcInfo of srcInfoArr) { - if (this.onProgress) this.onProgress(count++, srcInfoArr) + for (const srcInfo of imgInfoList) { + if (this.onProgress) this.onProgress(count++, imgInfoList) // reuse resolved link const resolvedLink = result.find(([src, dst]) => dst != null && src.data === srcInfo.data)?.[1]?.data @@ -129,43 +114,6 @@ export class MkdImgExtractor { return result } - findImages(): ImgInfo[] { - const acc = () => { - const imgTagUrlImgMatchGroups = Array.from(this.markdown.matchAll(imgTagUrlImgPat)) - const mkdUrlImgMatchGroups = Array.from(this.markdown.matchAll(mkdUrlImgPat)) - const urlImgInfo = imgTagUrlImgMatchGroups.concat(mkdUrlImgMatchGroups).map(mg => ({ - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - startOffset: mg.index!, - dataType: DataType.url, - data: mg[2], - prefix: mg[1], - postfix: mg[3], - })) - - const imgTagDataUrlImgMatchGroups = Array.from(this.markdown.matchAll(imgTagDataUrlImgPat)) - const mkdDataUrlImgMatchGroups = Array.from(this.markdown.matchAll(mkdDataUrlImgPat)) - const dataUrlImgInfo = imgTagDataUrlImgMatchGroups.concat(mkdDataUrlImgMatchGroups).map(mg => ({ - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - startOffset: mg.index!, - dataType: DataType.dataUrl, - data: mg[2], - prefix: mg[1], - postfix: mg[3], - })) - - const acc = urlImgInfo.concat(dataUrlImgInfo) - - // TODO: better filter design needed - // remove cnblogs img link - return acc.filter(x => x.data.match(cnblogsDomainRegExp) == null) - } - - this._images = acc() - - // apply settings - return this._images.filter(x => newImgSrcFilter(this.imgSrc)(x)) - } - private async resolveWebImg(url: string) { try { return await ImgService.download(url) diff --git a/src/service/post.ts b/src/service/post.ts index 94d9e02c..a67a4695 100644 --- a/src/service/post.ts +++ b/src/service/post.ts @@ -12,7 +12,7 @@ import got from '@/infra/http-client' import httpClient from '@/infra/http-client' import iconv from 'iconv-lite' import { MarkdownCfg } from '@/ctx/cfg/markdown' -import { rmYfm } from '@/infra/rm-yfm' +import { rmYfm } from '@/infra/filter/rm-yfm' import { PostListState } from '@/model/post-list-state' import { Alert } from '@/infra/alert' diff --git a/src/setup/setup-cmd.ts b/src/setup/setup-cmd.ts index 7d9490e2..45c8305f 100644 --- a/src/setup/setup-cmd.ts +++ b/src/setup/setup-cmd.ts @@ -13,7 +13,7 @@ import { createLocalDraft } from '@/cmd/post-list/create-local-draft' import { deleteSelectedPost } from '@/cmd/post-list/delete-post' import { modifyPostSetting } from '@/cmd/post-list/modify-post-setting' import { uploadImg } from '@/cmd/upload-img/upload-img' -import { revealLocalPostFileInOs } from '@/cmd/reveal-local-post-file-in-os' +import { osOpenLocalPostFile } from '@/cmd/os-open-local-post-file' import { showLocalFileToPostInfo } from '@/cmd/show-local-file-to-post-info' import { newPostCategory } from '@/cmd/post-category/new-post-category' import { refreshPostCategoryList } from '@/cmd/post-category/refresh-post-category-list' @@ -24,7 +24,7 @@ import { renamePost } from '@/cmd/post-list/rename-post' import { openPostInBlogAdmin } from '@/cmd/open/open-post-in-blog-admin' import { openWorkspace } from '@/cmd/open/open-workspace' import { setWorkspace } from '@/cmd/set-workspace' -import { revealWorkspaceInOs } from '@/cmd/reveal-workspace-in-os' +import { osOpenWorkspace } from '@/cmd/os-open-workspace' import { viewPostOnline } from '@/cmd/view-post-online' import { pullRemotePost } from '@/cmd/pull-remote-post' import { extractImg } from '@/cmd/extract-img' @@ -81,7 +81,7 @@ export function setupExtCmd() { regCmd(withAppName('.clear-post-search-results'), clearPostSearchResults), regCmd(withAppName('.refresh-post-search-results'), refreshPostSearchResults), regCmd(withAppName('.copy-post-link'), input => new CopyPostLinkCmdHandler(input).handle()), - regCmd(withAppName('.reveal-local-post-file-in-os'), revealLocalPostFileInOs), + regCmd(withAppName('.reveal-local-post-file-in-os'), osOpenLocalPostFile), regCmd(withAppName('.show-post-to-local-file-info'), showLocalFileToPostInfo), // img regCmd(withAppName('.extract-img'), extractImg), @@ -96,7 +96,7 @@ export function setupExtCmd() { // workspace regCmd(withAppName('.open-workspace'), openWorkspace), regCmd(withAppName('.set-workspace'), setWorkspace), - regCmd(withAppName('.reveal-workspace-in-os'), revealWorkspaceInOs), + regCmd(withAppName('.reveal-workspace-in-os'), osOpenWorkspace), // ing regCmd(withAppName('.ing.publish'), () => new PublishIngCmdHandler('input').handle()), regCmd(withAppName('.ing.publish-select'), () => new PublishIngCmdHandler('select').handle()), From 709a6fcf385ee074e6ce9792041e536ce658a8b8 Mon Sep 17 00:00:00 2001 From: Thaumy Date: Thu, 27 Jul 2023 18:19:09 +0800 Subject: [PATCH 044/157] refactor: replace with rs impl regex match --- build-node.sh | 4 + build-wasm.sh | 3 + build.sh | 5 +- fmt.sh | 3 + package.json | 2 +- rs/.gitignore | 1 + rs/Cargo.lock | 188 ++++++++++++++++++++++++++++++ rs/Cargo.toml | 14 +++ rs/src/lib.rs | 25 ++++ src/cmd/extract-img.ts | 2 +- src/infra/filter/find-img-link.ts | 6 +- webpack.config.mjs | 11 +- 12 files changed, 251 insertions(+), 13 deletions(-) create mode 100755 build-node.sh create mode 100755 build-wasm.sh create mode 100755 fmt.sh create mode 100644 rs/.gitignore create mode 100644 rs/Cargo.lock create mode 100644 rs/Cargo.toml create mode 100644 rs/src/lib.rs diff --git a/build-node.sh b/build-node.sh new file mode 100755 index 00000000..9a6324d6 --- /dev/null +++ b/build-node.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash + +npm run package -- --env CLIENTID="${1}" --env CLIENTSECRET="${2}" +npm run ui:package diff --git a/build-wasm.sh b/build-wasm.sh new file mode 100755 index 00000000..55d74b79 --- /dev/null +++ b/build-wasm.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash + +wasm-pack build rs --target=nodejs --out-dir ../src/wasm diff --git a/build.sh b/build.sh index 88732e43..593de6e6 100755 --- a/build.sh +++ b/build.sh @@ -2,6 +2,5 @@ set -e -npm run package -- --env CLIENTID="${1?"Please provide the CLIENTID"}" --env CLIENTSECRET="${2?"Please provide the CLIENTSECRET"}" -npm run ui:package - +./build-wasm.sh +./build-node.sh "${1}" "${2}" diff --git a/fmt.sh b/fmt.sh new file mode 100755 index 00000000..33e11799 --- /dev/null +++ b/fmt.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash + +npm run format diff --git a/package.json b/package.json index c0e56c23..aa0e74f7 100644 --- a/package.json +++ b/package.json @@ -1301,7 +1301,7 @@ ] }, "scripts": { - "watch": "webpack --watch --mode=development", + "watch": "./build-wasm.sh && webpack --watch --mode=development", "ui:watch": "webpack watch -c ./ui/webpack.config.mjs", "package": "webpack --mode production --devtool hidden-source-map", "ui:package": "webpack --mode production --devtool hidden-source-map -c ./ui/webpack.config.mjs", diff --git a/rs/.gitignore b/rs/.gitignore new file mode 100644 index 00000000..eb5a316c --- /dev/null +++ b/rs/.gitignore @@ -0,0 +1 @@ +target diff --git a/rs/Cargo.lock b/rs/Cargo.lock new file mode 100644 index 00000000..2c8bf217 --- /dev/null +++ b/rs/Cargo.lock @@ -0,0 +1,188 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" +dependencies = [ + "memchr", +] + +[[package]] +name = "bumpalo" +version = "3.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "js-sys" +version = "0.3.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "log" +version = "0.4.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + +[[package]] +name = "proc-macro2" +version = "1.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regex" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39354c10dd07468c2e73926b23bb9c2caca74c5501e38a35da70406f1d923310" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" + +[[package]] +name = "rs" +version = "0.0.1" +dependencies = [ + "regex", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "syn" +version = "2.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b60f673f44a8255b9c8c657daf66a596d435f2da81a555b06dc644d080ba45e0" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" + +[[package]] +name = "wasm-bindgen" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" + +[[package]] +name = "web-sys" +version = "0.3.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" +dependencies = [ + "js-sys", + "wasm-bindgen", +] diff --git a/rs/Cargo.toml b/rs/Cargo.toml new file mode 100644 index 00000000..77dd6b38 --- /dev/null +++ b/rs/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "rs" +version = "0.0.1" +license = "MIT" +edition = "2018" + +[lib] +crate-type = ["cdylib"] + +[dependencies] + +wasm-bindgen = "0.2.84" +web-sys = "0.3.61" +regex = "1.8.1" diff --git a/rs/src/lib.rs b/rs/src/lib.rs new file mode 100644 index 00000000..eabe871f --- /dev/null +++ b/rs/src/lib.rs @@ -0,0 +1,25 @@ +use std::ops::Not; +use wasm_bindgen::prelude::*; +use regex::Regex; + +#[wasm_bindgen(js_name = "isRegMatch")] +pub fn is_reg_match(reg: &str, str: &str) -> bool { + let reg = Regex::new(reg); + if reg.is_err() { + return false; + } + reg.unwrap().is_match(str) +} + +#[test] +fn test_is_reg_match() { + let text = "https://img2023.cnblogs.com/blog/2993952/202307/2993952-20230726164744582-682495539.png"; + let reg = r"\.cnblogs\.com\/"; + assert!(is_reg_match(reg, text)) +} + + +#[wasm_bindgen(js_name = "notRegMatch")] +pub fn not_reg_match(reg: &str, str: &str) -> bool { + is_reg_match(reg, str).not() +} diff --git a/src/cmd/extract-img.ts b/src/cmd/extract-img.ts index 6f752a6a..98c0c285 100644 --- a/src/cmd/extract-img.ts +++ b/src/cmd/extract-img.ts @@ -18,7 +18,7 @@ export async function extractImg(arg: unknown, inputImgSrc?: ImgSrc) { const imgInfoList = findImgLink(markdown) if (imgInfoList.length <= 0) { - if (inputImgSrc !== undefined) void Alert.info('没有找到可以提取的图片') + if (inputImgSrc === undefined) void Alert.info('没有找到可以提取的图片') return } diff --git a/src/infra/filter/find-img-link.ts b/src/infra/filter/find-img-link.ts index 93561b98..cfccbc94 100644 --- a/src/infra/filter/find-img-link.ts +++ b/src/infra/filter/find-img-link.ts @@ -4,13 +4,13 @@ // https://datatracker.ietf.org/doc/html/rfc2397 import { DataType, ImgInfo } from '@/markdown/mkd-img-extractor' +import { notRegMatch } from '@/wasm' const imgTagDataUrlImgPat = /()/g const imgTagUrlImgPat = /()/gi const mkdDataUrlImgPat = /(!\[.*?]\()(data:image\/.*?,[a-zA-Z0-9+/]*?=?=?)(\))/g const mkdUrlImgPat = /(!\[.*?]\()(.*?\.(?:png|jpg|jpeg|webp|svg|gif))(\))/gi - -const cnblogsDomainRegExp = /\.cnblogs\.com\//gi +const cnblogsDomain = `\.cnblogs\.com\/` export function findImgLink(text: string): ImgInfo[] { const imgTagUrlImgMatchGroups = Array.from(text.matchAll(imgTagUrlImgPat)) @@ -39,5 +39,5 @@ export function findImgLink(text: string): ImgInfo[] { // TODO: better filter design needed // remove cnblogs img link - return acc.filter(x => x.data.match(cnblogsDomainRegExp) == null) + return acc.filter(x => notRegMatch(cnblogsDomain, x.data)) } diff --git a/webpack.config.mjs b/webpack.config.mjs index 3f56b22b..2b057558 100644 --- a/webpack.config.mjs +++ b/webpack.config.mjs @@ -45,13 +45,12 @@ const preserveModules = [ ] //@ts-check -/** @typedef {import('webpack').Configuration} WebpackConfig **/ +/** @typedef {import("webpack").Configuration} WebpackConfig **/ export default (env, { mode }) => { const isProd = mode === 'production' - /** @type WebpackConfig */ - const extensionConfig = { + return { target: 'node', // vscode extensions run in a Node.js-context 📖 -> https://webpack.js.org/configuration/node/ mode: mode, // this leaves the source code as close as possible to the original (when packaging we set this to 'production') @@ -112,6 +111,10 @@ export default (env, { mode }) => { from: 'node_modules/@cnblogs/code-highlight-adapter/index.min.css', to: 'assets/styles/highlight-code-lines.css', }, + { + from: 'src/wasm/rs_bg.wasm', + to: 'rs_bg.wasm', + }, ...preserveModules.map(m => ({ from: `node_modules/${m}`, to: `node_modules/${m}` })), ], }), @@ -125,6 +128,4 @@ export default (env, { mode }) => { usedExports: true, }, } - - return extensionConfig } From bf1c75bb7df45e8c24daa33df7b4e99c36719ef4 Mon Sep 17 00:00:00 2001 From: Thaumy Date: Fri, 28 Jul 2023 11:14:42 +0800 Subject: [PATCH 045/157] docs: update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 221189c7..cdbc7cc9 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,8 @@ +在上传博文时,扩展会默认忽略 YAML front matter,此行为可于设置中变更。 + ### 博客园博文列表 当点击列表中的博文时,会自动将博文内容下载到工作空间一个本地文件中(此时这个本地文件就关联到了这篇博文),完成编辑后可以再将本地的内容上传到博客园。 From e77ced0cfa6cc09c57b71cafafe61e1580300683 Mon Sep 17 00:00:00 2001 From: Thaumy Date: Fri, 28 Jul 2023 11:14:58 +0800 Subject: [PATCH 046/157] fix: #166 --- src/cmd/post-list/upload-post.ts | 8 ++++++-- src/setup/setup-cmd.ts | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/cmd/post-list/upload-post.ts b/src/cmd/post-list/upload-post.ts index 68e8942c..bd17015e 100644 --- a/src/cmd/post-list/upload-post.ts +++ b/src/cmd/post-list/upload-post.ts @@ -126,8 +126,12 @@ export const uploadPost = async (input: Post | PostTreeItem | PostEditDto | unde let post: Post | undefined - if (input instanceof PostEditDto) post = input.post - else (await PostService.fetchPostEditDto(input.id))?.post + if (input instanceof PostEditDto) { + post = input.post + } else { + const dto = await PostService.fetchPostEditDto(input.id) + post = dto?.post + } if (post === undefined) return diff --git a/src/setup/setup-cmd.ts b/src/setup/setup-cmd.ts index 45c8305f..00a6b092 100644 --- a/src/setup/setup-cmd.ts +++ b/src/setup/setup-cmd.ts @@ -65,13 +65,13 @@ export function setupExtCmd() { regCmd(withAppName('.next-post-list'), goNextPostList), regCmd(withAppName('.seek-post-list'), seekPostList), // post - regCmd(withAppName('.upload-post'), uploadPost), regCmd(withAppName('.delete-post'), deleteSelectedPost), regCmd(withAppName('.edit-post'), openPostInVscode), regCmd(withAppName('.search-post'), searchPost), regCmd(withAppName('.rename-post'), renamePost), regCmd(withAppName('.modify-post-setting'), modifyPostSetting), regCmd(withAppName('.create-local-draft'), createLocalDraft), + regCmd(withAppName('.upload-post'), uploadPost), regCmd(withAppName('.upload-post-file'), uploadPostFile), regCmd(withAppName('.pull-remote-post'), pullRemotePost), regCmd(withAppName('.open-post-in-blog-admin'), openPostInBlogAdmin), From f7f0a92a6f8024b7dffc7d5e3f4cbbe4a8eb097d Mon Sep 17 00:00:00 2001 From: Thaumy Date: Fri, 28 Jul 2023 11:47:43 +0800 Subject: [PATCH 047/157] style: reformat --- .eslintrc.json | 10 +++++++++- fmt.sh => fmt-lint.sh | 1 + src/cmd/blog-export/download.ts | 2 +- src/cmd/post-list/modify-post-setting.ts | 2 +- src/cmd/post-list/refresh-post-list.ts | 2 +- src/infra/filter/find-img-link.ts | 1 + src/infra/get-clipboard-img.ts | 2 +- src/infra/input-post-setting.ts | 2 +- src/service/ing.api.ts | 4 ++-- 9 files changed, 18 insertions(+), 8 deletions(-) rename fmt.sh => fmt-lint.sh (73%) diff --git a/.eslintrc.json b/.eslintrc.json index 67bb5092..caab5a92 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -17,7 +17,15 @@ } ] }, - "ignorePatterns": ["out", "dist", "src/test/**", "**/*.d.ts", "__mocks__/vscode.ts", "src/assets/**"], + "ignorePatterns": [ + "out", + "dist", + "src/test/**", + "**/*.d.ts", + "__mocks__/vscode.ts", + "src/assets/**", + "src/wasm/**" + ], "overrides": [ { "files": ["*.config.js"], diff --git a/fmt.sh b/fmt-lint.sh similarity index 73% rename from fmt.sh rename to fmt-lint.sh index 33e11799..ac9c2306 100755 --- a/fmt.sh +++ b/fmt-lint.sh @@ -1,3 +1,4 @@ #!/usr/bin/env bash npm run format +npm run lint diff --git a/src/cmd/blog-export/download.ts b/src/cmd/blog-export/download.ts index bd6fe19e..cfb93baf 100644 --- a/src/cmd/blog-export/download.ts +++ b/src/cmd/blog-export/download.ts @@ -38,7 +38,7 @@ export async function downloadBlogExport(input: unknown) { await setIsDownloading(true) const onError = (msg?: string | null) => { - if (msg) Alert.warn(msg) + if (msg) void Alert.warn(msg) if (!isFileExist) fs.rmSync(zipFilePath) blogExportProvider?.refreshItem(treeItem) setIsDownloading(false).then(undefined, console.warn) diff --git a/src/cmd/post-list/modify-post-setting.ts b/src/cmd/post-list/modify-post-setting.ts index a234b684..8dec1d5f 100644 --- a/src/cmd/post-list/modify-post-setting.ts +++ b/src/cmd/post-list/modify-post-setting.ts @@ -40,7 +40,7 @@ export const modifyPostSetting = async (input: Post | PostTreeItem | Uri) => { post: postEditDto, localFileUri: localFilePath ? Uri.file(localFilePath) : undefined, successCallback: ({ id }) => { - Alert.info('博文已更新') + void Alert.info('博文已更新') postDataProvider.fireTreeDataChangedEvent(id) postCategoryDataProvider.onPostUpdated({ refreshPost: false, postIds: [id] }) }, diff --git a/src/cmd/post-list/refresh-post-list.ts b/src/cmd/post-list/refresh-post-list.ts index 2393ba10..77d0e6cb 100644 --- a/src/cmd/post-list/refresh-post-list.ts +++ b/src/cmd/post-list/refresh-post-list.ts @@ -33,7 +33,7 @@ export const refreshPostList = async ({ queue = false } = {}): Promise ) .then(pagedPost => { if (pagedPost == null) { - return Promise.resolve(false).finally(() => Alert.err('刷新博文列表失败')) + return Promise.resolve(false).finally(() => void Alert.err('刷新博文列表失败')) } else { return PostService.updatePostListState(pagedPost) .then(() => updatePostListViewTitle()) diff --git a/src/infra/filter/find-img-link.ts b/src/infra/filter/find-img-link.ts index cfccbc94..7052416e 100644 --- a/src/infra/filter/find-img-link.ts +++ b/src/infra/filter/find-img-link.ts @@ -10,6 +10,7 @@ const imgTagDataUrlImgPat = /()/gi const mkdDataUrlImgPat = /(!\[.*?]\()(data:image\/.*?,[a-zA-Z0-9+/]*?=?=?)(\))/g const mkdUrlImgPat = /(!\[.*?]\()(.*?\.(?:png|jpg|jpeg|webp|svg|gif))(\))/gi +//eslint-disable-next-line const cnblogsDomain = `\.cnblogs\.com\/` export function findImgLink(text: string): ImgInfo[] { diff --git a/src/infra/get-clipboard-img.ts b/src/infra/get-clipboard-img.ts index 47b84c74..38de90fc 100644 --- a/src/infra/get-clipboard-img.ts +++ b/src/infra/get-clipboard-img.ts @@ -94,7 +94,7 @@ const getClipboardImage = (): Promise => { execution.stdout.on('data', (data: Buffer) => { if (platform === 'linux') { if (data.toString().trim() === 'no xclip') { - Alert.warn('xclip not found, Please install xclip first') + void Alert.warn('xclip not found, Please install xclip first') return reject(new Error('Please install xclip first')) } } diff --git a/src/infra/input-post-setting.ts b/src/infra/input-post-setting.ts index fff8273b..32ee89d2 100644 --- a/src/infra/input-post-setting.ts +++ b/src/infra/input-post-setting.ts @@ -102,7 +102,7 @@ export const inputPostSetting = ( try { categories = await PostCategoryService.listCategories() } catch (err) { - Alert.err(err instanceof Error ? err.message : JSON.stringify(err)) + void Alert.err(err instanceof Error ? err.message : JSON.stringify(err)) // 取消 throw InputFlowAction.cancel } diff --git a/src/service/ing.api.ts b/src/service/ing.api.ts index 0fa4389c..32070b9a 100644 --- a/src/service/ing.api.ts +++ b/src/service/ing.api.ts @@ -85,12 +85,12 @@ export namespace IngApi { }) if (!res.ok) { - Alert.err(`发表评论失败, ${await res.text()}`) + void Alert.err(`发表评论失败, ${await res.text()}`) return false } } catch (e) { // eslint-disable-next-line @typescript-eslint/restrict-template-expressions - Alert.err(`发表评论失败, ${e}`) + void Alert.err(`发表评论失败, ${e}`) return false } From 1d89785a1305f3b6c0b3448a856d9a6ab605f4aa Mon Sep 17 00:00:00 2001 From: Thaumy Date: Fri, 28 Jul 2023 13:05:40 +0800 Subject: [PATCH 048/157] refactor: simplify code --- rs/src/lib.rs | 26 +------------------ rs/src/regex.rs | 17 ++++++++++++ .../delete-post-to-local-file-map.ts | 4 +-- src/cmd/post-list/modify-post-setting.ts | 2 +- src/cmd/post-list/open-post-file.ts | 2 +- src/cmd/post-list/open-post-in-vscode.ts | 4 +-- src/cmd/post-list/refresh-post-list.ts | 11 ++++---- src/cmd/post-list/rename-post.ts | 4 +-- src/cmd/post-list/search.ts | 2 +- src/cmd/post-list/upload-post.ts | 2 +- src/cmd/pull-remote-post.ts | 2 +- src/cmd/show-local-file-to-post-info.ts | 2 +- src/cmd/view-post-online.ts | 2 +- src/infra/filter/find-img-link.ts | 4 +-- 14 files changed, 39 insertions(+), 45 deletions(-) create mode 100644 rs/src/regex.rs diff --git a/rs/src/lib.rs b/rs/src/lib.rs index eabe871f..1d9dab60 100644 --- a/rs/src/lib.rs +++ b/rs/src/lib.rs @@ -1,25 +1 @@ -use std::ops::Not; -use wasm_bindgen::prelude::*; -use regex::Regex; - -#[wasm_bindgen(js_name = "isRegMatch")] -pub fn is_reg_match(reg: &str, str: &str) -> bool { - let reg = Regex::new(reg); - if reg.is_err() { - return false; - } - reg.unwrap().is_match(str) -} - -#[test] -fn test_is_reg_match() { - let text = "https://img2023.cnblogs.com/blog/2993952/202307/2993952-20230726164744582-682495539.png"; - let reg = r"\.cnblogs\.com\/"; - assert!(is_reg_match(reg, text)) -} - - -#[wasm_bindgen(js_name = "notRegMatch")] -pub fn not_reg_match(reg: &str, str: &str) -> bool { - is_reg_match(reg, str).not() -} +pub mod regex; diff --git a/rs/src/regex.rs b/rs/src/regex.rs new file mode 100644 index 00000000..972ba25b --- /dev/null +++ b/rs/src/regex.rs @@ -0,0 +1,17 @@ +use wasm_bindgen::prelude::*; +use regex::Regex; + +#[wasm_bindgen(js_name = RsRegex)] +pub struct RsRegex; + +#[wasm_bindgen(js_class = RsRegex)] +impl RsRegex { + #[wasm_bindgen(js_name = isMatch)] + pub fn is_match(regex: &str, text: &str) -> bool { + let regex = Regex::new(regex); + let Ok(regex) = regex else { return false; }; + + regex.is_match(text) + } +} + diff --git a/src/cmd/post-list/delete-post-to-local-file-map.ts b/src/cmd/post-list/delete-post-to-local-file-map.ts index 221571a4..26bf61b9 100644 --- a/src/cmd/post-list/delete-post-to-local-file-map.ts +++ b/src/cmd/post-list/delete-post-to-local-file-map.ts @@ -6,7 +6,7 @@ import { PostTreeItem } from '@/tree-view/model/post-tree-item' import { extTreeViews } from '@/tree-view/tree-view-register' import { Alert } from '@/infra/alert' -const confirm = async (postList: Post[]): Promise => { +async function confirm(postList: Post[]): Promise { const options = ['确定'] const input = await Alert.info( '确定要取消这些博文与本地文件的关联吗?', @@ -19,7 +19,7 @@ const confirm = async (postList: Post[]): Promise => { return input === options[0] } -export const deletePostToLocalFileMap = async (post: Post | PostTreeItem) => { +export async function deletePostToLocalFileMap(post: Post | PostTreeItem) { post = post instanceof PostTreeItem ? post.post : post const view = extTreeViews.postList let selectedPost = view.selection diff --git a/src/cmd/post-list/modify-post-setting.ts b/src/cmd/post-list/modify-post-setting.ts index 8dec1d5f..073e4023 100644 --- a/src/cmd/post-list/modify-post-setting.ts +++ b/src/cmd/post-list/modify-post-setting.ts @@ -12,7 +12,7 @@ import { postDataProvider } from '@/tree-view/provider/post-data-provider' import { PostTreeItem } from '@/tree-view/model/post-tree-item' import { postCategoryDataProvider } from '@/tree-view/provider/post-category-tree-data-provider' -export const modifyPostSetting = async (input: Post | PostTreeItem | Uri) => { +export async function modifyPostSetting(input: Post | PostTreeItem | Uri) { let post: Post | undefined let postId = -1 input = input instanceof PostTreeItem ? input.post : input diff --git a/src/cmd/post-list/open-post-file.ts b/src/cmd/post-list/open-post-file.ts index 7d6524f2..e2f8fac9 100644 --- a/src/cmd/post-list/open-post-file.ts +++ b/src/cmd/post-list/open-post-file.ts @@ -4,7 +4,7 @@ import { Post } from '@/model/post' import { LocalDraft } from '@/service/local-draft' import { PostFileMapManager } from '@/service/post-file-map' -export const openPostFile = async (post: LocalDraft | Post | string, options?: TextDocumentShowOptions) => { +export async function openPostFile(post: LocalDraft | Post | string, options?: TextDocumentShowOptions) { let filePath = '' if (post instanceof LocalDraft) filePath = post.filePath else if (post instanceof Post) filePath = PostFileMapManager.getFilePath(post.id) ?? '' diff --git a/src/cmd/post-list/open-post-in-vscode.ts b/src/cmd/post-list/open-post-in-vscode.ts index 3a7f6bc9..731882e2 100644 --- a/src/cmd/post-list/open-post-in-vscode.ts +++ b/src/cmd/post-list/open-post-in-vscode.ts @@ -12,7 +12,7 @@ import sanitizeFileName from 'sanitize-filename' import { WorkspaceCfg } from '@/ctx/cfg/workspace' import { PostCategoryCfg } from '@/ctx/cfg/post-category' -const buildLocalPostFileUri = async (post: Post, includePostId = false): Promise => { +async function buildLocalPostFileUri(post: Post, includePostId = false): Promise { const workspaceUri = WorkspaceCfg.getWorkspaceUri() const shouldCreateLocalPostFileWithCategory = PostCategoryCfg.isCreateLocalPostFileWithCategory() const ext = `.${post.isMarkdown ? 'md' : 'html'}` @@ -39,7 +39,7 @@ const buildLocalPostFileUri = async (post: Post, includePostId = false): Promise } } -export const openPostInVscode = async (postId: number, forceUpdateLocalPostFile = false): Promise => { +export async function openPostInVscode(postId: number, forceUpdateLocalPostFile = false): Promise { let mappedPostFilePath = PostFileMapManager.getFilePath(postId) const isFileExist = !!mappedPostFilePath && fs.existsSync(mappedPostFilePath) if (mappedPostFilePath && isFileExist && !forceUpdateLocalPostFile) { diff --git a/src/cmd/post-list/refresh-post-list.ts b/src/cmd/post-list/refresh-post-list.ts index 77d0e6cb..3a03be49 100644 --- a/src/cmd/post-list/refresh-post-list.ts +++ b/src/cmd/post-list/refresh-post-list.ts @@ -9,7 +9,7 @@ import { execCmd } from '@/infra/cmd' let refreshTask: Promise | null = null -export const refreshPostList = async ({ queue = false } = {}): Promise => { +export async function refreshPostList({ queue = false } = {}): Promise { if (isRefreshing && !queue) { alertRefreshing() await refreshTask @@ -53,7 +53,7 @@ export const goNextPostList = () => goPage(i => i + 1) export const goPrevPostList = () => goPage(i => i - 1) -export const seekPostList = async () => { +export async function seekPostList() { const input = await window.showInputBox({ placeHolder: '请输入页码', validateInput: i => { @@ -73,13 +73,14 @@ export const seekPostList = async () => { } let isRefreshing = false -const setRefreshing = async (value = false) => { + +async function setRefreshing(value = false) { const extName = globalCtx.extName await execCmd('setContext', `${extName}.post-list.refreshing`, value).then(undefined, () => false) isRefreshing = value } -const setPostListContext = async (pageCount: number, hasPrevious: boolean, hasNext: boolean) => { +async function setPostListContext(pageCount: number, hasPrevious: boolean, hasNext: boolean) { const extName = globalCtx.extName await execCmd('setContext', `${extName}.post-list.hasPrevious`, hasPrevious) await execCmd('setContext', `${extName}.post-list.hasNext`, hasNext) @@ -90,7 +91,7 @@ const alertRefreshing = () => { void Alert.info('正在刷新, 请勿重复操作') } -const goPage = async (pageIndex: (currentIndex: number) => number) => { +async function goPage(pageIndex: (currentIndex: number) => number) { if (isRefreshing) { alertRefreshing() return diff --git a/src/cmd/post-list/rename-post.ts b/src/cmd/post-list/rename-post.ts index 6146c16f..d716c6d3 100644 --- a/src/cmd/post-list/rename-post.ts +++ b/src/cmd/post-list/rename-post.ts @@ -9,7 +9,7 @@ import { revealPostListItem } from '@/service/post-list-view' import { PostTreeItem } from '@/tree-view/model/post-tree-item' import { Alert } from '@/infra/alert' -const renameLinkedFile = async (post: Post): Promise => { +async function renameLinkedFile(post: Post): Promise { const filePath = PostFileMapManager.getFilePath(post.id) if (!filePath) return @@ -34,7 +34,7 @@ const renameLinkedFile = async (post: Post): Promise => { } } -export const renamePost = async (arg: Post | PostTreeItem) => { +export async function renamePost(arg: Post | PostTreeItem) { const post = arg instanceof PostTreeItem ? arg.post : arg if (!post) return diff --git a/src/cmd/post-list/search.ts b/src/cmd/post-list/search.ts index 2ae294de..f28fd766 100644 --- a/src/cmd/post-list/search.ts +++ b/src/cmd/post-list/search.ts @@ -1,7 +1,7 @@ import { window } from 'vscode' import { postDataProvider } from '@/tree-view/provider/post-data-provider' -export const searchPost = async () => { +export async function searchPost() { const searchKey = await window.showInputBox({ ignoreFocusOut: true, title: '搜索博文', diff --git a/src/cmd/post-list/upload-post.ts b/src/cmd/post-list/upload-post.ts index bd17015e..e853ba41 100644 --- a/src/cmd/post-list/upload-post.ts +++ b/src/cmd/post-list/upload-post.ts @@ -120,7 +120,7 @@ async function saveLocalDraft(localDraft: LocalDraft) { }) } -export const uploadPost = async (input: Post | PostTreeItem | PostEditDto | undefined) => { +export async function uploadPost(input: Post | PostTreeItem | PostEditDto | undefined) { if (input === undefined) return if (input instanceof PostTreeItem) input = input.post diff --git a/src/cmd/pull-remote-post.ts b/src/cmd/pull-remote-post.ts index 40a44548..e7772b29 100644 --- a/src/cmd/pull-remote-post.ts +++ b/src/cmd/pull-remote-post.ts @@ -41,7 +41,7 @@ type CmdCtx = { postId: number; fileUri: Uri } const parsePostInput = (input: InputType): input is Post => input instanceof Post -const handlePostInput = async (post: Post, contexts: CmdCtx[]) => { +async function handlePostInput(post: Post, contexts: CmdCtx[]) { const { id: postId } = post let filePath = PostFileMapManager.getFilePath(postId) if (filePath && !fs.existsSync(filePath)) { diff --git a/src/cmd/show-local-file-to-post-info.ts b/src/cmd/show-local-file-to-post-info.ts index be2c013f..f11cf4d9 100644 --- a/src/cmd/show-local-file-to-post-info.ts +++ b/src/cmd/show-local-file-to-post-info.ts @@ -14,7 +14,7 @@ import format from 'date-fns/format' * @param {(Uri | number)} input * @returns {*} {Promise} */ -export const showLocalFileToPostInfo = async (input: Uri | number): Promise => { +export async function showLocalFileToPostInfo(input: Uri | number): Promise { let filePath: string | undefined let postId: number | undefined if (input instanceof Uri && input.scheme === 'file') { diff --git a/src/cmd/view-post-online.ts b/src/cmd/view-post-online.ts index 8d66b8b6..66fbe16a 100644 --- a/src/cmd/view-post-online.ts +++ b/src/cmd/view-post-online.ts @@ -5,7 +5,7 @@ import { PostService } from '@/service/post' import { PostFileMapManager } from '@/service/post-file-map' import { PostTreeItem } from '@/tree-view/model/post-tree-item' -export const viewPostOnline = async (input?: Post | PostTreeItem | Uri) => { +export async function viewPostOnline(input?: Post | PostTreeItem | Uri) { let post: Post | undefined = input instanceof Post ? input : input instanceof PostTreeItem ? input.post : undefined if (!input) input = window.activeTextEditor?.document.uri diff --git a/src/infra/filter/find-img-link.ts b/src/infra/filter/find-img-link.ts index 7052416e..90d79fec 100644 --- a/src/infra/filter/find-img-link.ts +++ b/src/infra/filter/find-img-link.ts @@ -4,7 +4,7 @@ // https://datatracker.ietf.org/doc/html/rfc2397 import { DataType, ImgInfo } from '@/markdown/mkd-img-extractor' -import { notRegMatch } from '@/wasm' +import { RsRegex } from '@/wasm' const imgTagDataUrlImgPat = /()/g const imgTagUrlImgPat = /()/gi @@ -40,5 +40,5 @@ export function findImgLink(text: string): ImgInfo[] { // TODO: better filter design needed // remove cnblogs img link - return acc.filter(x => notRegMatch(cnblogsDomain, x.data)) + return acc.filter(x => RsRegex.isMatch(cnblogsDomain, x.data)) } From 233716bba76c9e271db69c5532b04600ee09cfe9 Mon Sep 17 00:00:00 2001 From: Thaumy Date: Fri, 28 Jul 2023 15:15:42 +0800 Subject: [PATCH 049/157] ui: disable confirm of upload post in some menus --- package.json | 84 +++++++------ src/cmd/post-list/upload-post.ts | 203 +++++++++++++++++++++++-------- src/setup/setup-cmd.ts | 4 +- 3 files changed, 203 insertions(+), 88 deletions(-) diff --git a/package.json b/package.json index aa0e74f7..a0d580df 100644 --- a/package.json +++ b/package.json @@ -147,13 +147,6 @@ "enablement": "vscode-cnb.isAuthorized && !vscode-cnb.post-list.refreshing", "category": "Cnblogs Post List" }, - { - "command": "vscode-cnb.upload-post", - "title": "上传博文", - "icon": "$(cloud-upload)", - "category": "Cnblogs Post List", - "enablement": "vscode-cnb.isAuthorized" - }, { "command": "vscode-cnb.delete-post", "title": "删除随笔(支持多选)", @@ -174,6 +167,34 @@ "category": "Cnblogs Post List", "enablement": "vscode-cnb.isAuthorized" }, + { + "command": "vscode-cnb.upload-post", + "title": "上传博文", + "icon": "$(cloud-upload)", + "category": "Cnblogs Post List", + "enablement": "vscode-cnb.isAuthorized" + }, + { + "command": "vscode-cnb.upload-post-file", + "title": "上传到博客园", + "icon": "$(vscode-cnb-cloud-upload)", + "enablement": "vscode-cnb.isAuthorized", + "category": "Cnblogs" + }, + { + "command": "vscode-cnb.upload-post-no-confirm", + "title": "上传博文", + "icon": "$(cloud-upload)", + "category": "Cnblogs Post List", + "enablement": "vscode-cnb.isAuthorized" + }, + { + "command": "vscode-cnb.upload-post-file-no-confirm", + "title": "上传到博客园", + "icon": "$(vscode-cnb-cloud-upload)", + "enablement": "vscode-cnb.isAuthorized", + "category": "Cnblogs" + }, { "command": "vscode-cnb.upload-img", "title": "上传图片到博客园", @@ -198,13 +219,6 @@ "title": "在文件资源管理器中打开", "category": "Cnblogs" }, - { - "command": "vscode-cnb.upload-post-file", - "title": "上传到博客园", - "icon": "$(vscode-cnb-cloud-upload)", - "enablement": "vscode-cnb.isAuthorized", - "category": "Cnblogs" - }, { "command": "vscode-cnb.pull-remote-post", "title": "拉取博文", @@ -545,20 +559,13 @@ "editPresentation": "singlelineText", "markdownDescription": "在拉取博文时显示确认消息" }, - "cnblogsClient.markdown.ignoreYfmWhenUploadPost": { - "order": 13, - "type": "boolean", - "scope": "application", - "default": true, - "editPresentation": "singlelineText", - "markdownDescription": "上传博文时忽略 YAML front matter" - }, "cnblogsClient.menus.context.explorer": { - "order": 14, + "order": 13, + "markdownDescription": "要在资源管理器右键菜单中显示的命令", "type": "object", "additionalProperties": false, "default": { - "upload-post-file": true, + "upload-post-file-no-confirm": true, "pull-remote-post": true, "modify-post-setting": true, "show-post-to-local-file-info": true, @@ -566,9 +573,8 @@ "export-post-to-pdf": true, "copy-post-link": true }, - "markdownDescription": "控制要在资源管理器右键菜单中显示的命令", "properties": { - "upload-post-file": { + "upload-post-file-no-confirm": { "order": 0, "description": "上传到博客园", "type": "boolean", @@ -613,10 +619,13 @@ } }, "cnblogsClient.menus.context.editor": { - "order": 15, + "order": 14, + "markdownDescription": "要在编辑器右键菜单中显示的命令", "type": "object", + "scope": "application", + "additionalProperties": false, "default": { - "upload-post-file": true, + "upload-post-file-no-confirm": true, "pull-remote-post": true, "modify-post-setting": true, "show-post-to-local-file-info": true, @@ -629,7 +638,7 @@ "ing:publish-select": false }, "properties": { - "upload-post-file": { + "upload-post-file-no-confirm": { "order": 0, "description": "上传到博客园", "type": "boolean" @@ -685,27 +694,24 @@ "description": "将选中内容发到闪存", "type": "boolean" } - }, - "scope": "application", - "additionalProperties": false, - "markdownDescription": "控制要在编辑器右键菜单中显示的命令" + } }, "cnblogsClient.ui.textIngStar": { - "order": 16, + "order": 15, "type": "boolean", "scope": "application", "default": false, "markdownDescription": "闪存星文本化" }, "cnblogsClient.ui.disableIngUserAvatar": { - "order": 18, + "order": 17, "type": "boolean", "scope": "application", "default": false, "markdownDescription": "禁用闪存用户头像" }, "cnblogsClient.ui.treeViewTitleStyle": { - "order": 19, + "order": 18, "scope": "application", "default": "normal", "markdownDescription": "侧栏标题风格", @@ -1042,7 +1048,7 @@ "group": "delete@2" }, { - "command": "vscode-cnb.upload-post", + "command": "vscode-cnb.upload-post-no-confirm", "group": "0@1", "when": "viewItem == cnb-post-cached" }, @@ -1147,8 +1153,8 @@ "group": "cnblogs@1" }, { - "command": "vscode-cnb.upload-post-file", - "when": "resourceLangId == markdown && config.cnblogsClient.menus.context.editor.upload-post-file", + "command": "vscode-cnb.upload-post-file-no-confirm", + "when": "resourceLangId == markdown && config.cnblogsClient.menus.context.editor.upload-post-file-no-confirm", "group": "cnblogs@2" }, { diff --git a/src/cmd/post-list/upload-post.ts b/src/cmd/post-list/upload-post.ts index e853ba41..58935c22 100644 --- a/src/cmd/post-list/upload-post.ts +++ b/src/cmd/post-list/upload-post.ts @@ -33,49 +33,6 @@ async function parseFileUri(fileUri: Uri | undefined) { return undefined } -export const uploadPostFile = async (fileUri: Uri | undefined) => { - const parsedFileUri = await parseFileUri(fileUri) - if (parsedFileUri === undefined) return - - const { fsPath: filePath } = parsedFileUri - const postId = PostFileMapManager.getPostId(filePath) - - if (postId !== undefined && postId >= 0) { - const dto = await PostService.fetchPostEditDto(postId) - if (dto !== undefined) await uploadPost(dto) - return - } - - const fileContent = Buffer.from(await workspace.fs.readFile(parsedFileUri)).toString() - if (isEmptyBody(fileContent)) return - - const options = ['新建博文', '关联已有博文'] - const selected = await window.showInformationMessage( - '本地文件尚未关联到博客园博文', - { - modal: true, - detail: `您可以选择新建一篇博文或将本地文件关联到一篇博客园博文(您可以根据标题搜索您在博客园博文)`, - } as MessageOptions, - ...options - ) - if (selected === '关联已有博文') { - const selectedPost = await searchPostByTitle({ - postTitle: path.basename(filePath, path.extname(filePath)), - quickPickTitle: '搜索要关联的博文', - }) - if (selectedPost === undefined) return - - await PostFileMapManager.updateOrCreate(selectedPost.id, filePath) - const postEditDto = await PostService.fetchPostEditDto(selectedPost.id) - if (postEditDto === undefined) return - if (!fileContent) await workspace.fs.writeFile(parsedFileUri, Buffer.from(postEditDto.post.postBody)) - - await uploadPost(postEditDto.post) - } else if (selected === '新建博文') { - await saveLocalDraft(new LocalDraft(filePath)) - } -} - async function saveLocalDraft(localDraft: LocalDraft) { // check format if (!['.md', '.mkd'].some(x => localDraft.fileExt === x)) { @@ -120,6 +77,15 @@ async function saveLocalDraft(localDraft: LocalDraft) { }) } +function isEmptyBody(body: string) { + if (body === '') { + void Alert.warn('博文内容不能为空') + return true + } + + return false +} + export async function uploadPost(input: Post | PostTreeItem | PostEditDto | undefined) { if (input === undefined) return if (input instanceof PostTreeItem) input = input.post @@ -196,11 +162,152 @@ export async function uploadPost(input: Post | PostTreeItem | PostEditDto | unde ) } -function isEmptyBody(body: string) { - if (body === '') { - void Alert.warn('博文内容不能为空') - return true +export async function uploadPostFile(fileUri: Uri | undefined) { + const parsedFileUri = await parseFileUri(fileUri) + if (parsedFileUri === undefined) return + + const { fsPath: filePath } = parsedFileUri + const postId = PostFileMapManager.getPostId(filePath) + + if (postId !== undefined && postId >= 0) { + const dto = await PostService.fetchPostEditDto(postId) + if (dto !== undefined) await uploadPost(dto) + return } - return false + const fileContent = Buffer.from(await workspace.fs.readFile(parsedFileUri)).toString() + if (isEmptyBody(fileContent)) return + + const options = ['新建博文', '关联已有博文'] + const selected = await window.showInformationMessage( + '本地文件尚未关联到博客园博文', + { + modal: true, + detail: `您可以选择新建一篇博文或将本地文件关联到一篇博客园博文(您可以根据标题搜索您在博客园博文)`, + } as MessageOptions, + ...options + ) + if (selected === '关联已有博文') { + const selectedPost = await searchPostByTitle({ + postTitle: path.basename(filePath, path.extname(filePath)), + quickPickTitle: '搜索要关联的博文', + }) + if (selectedPost === undefined) return + + await PostFileMapManager.updateOrCreate(selectedPost.id, filePath) + const postEditDto = await PostService.fetchPostEditDto(selectedPost.id) + if (postEditDto === undefined) return + if (!fileContent) await workspace.fs.writeFile(parsedFileUri, Buffer.from(postEditDto.post.postBody)) + + await uploadPost(postEditDto.post) + } else if (selected === '新建博文') { + await saveLocalDraft(new LocalDraft(filePath)) + } +} + +export async function uploadPostNoConfirm(input: Post | PostTreeItem | PostEditDto | undefined) { + if (input === undefined) return + if (input instanceof PostTreeItem) input = input.post + + let post: Post | undefined + + if (input instanceof PostEditDto) { + post = input.post + } else { + const dto = await PostService.fetchPostEditDto(input.id) + post = dto?.post + } + + if (post === undefined) return + + const localFilePath = PostFileMapManager.getFilePath(post.id) + if (!localFilePath) return Alert.warn('本地无该博文的编辑记录') + + if (MarkdownCfg.getAutoExtractImgSrc()) + await extractImg(Uri.file(localFilePath), MarkdownCfg.getAutoExtractImgSrc()).catch(console.warn) + + await saveFilePendingChanges(localFilePath) + post.postBody = (await workspace.fs.readFile(Uri.file(localFilePath))).toString() + + if (isEmptyBody(post.postBody)) return false + + post.isMarkdown = + path.extname(localFilePath).endsWith('md') || path.extname(localFilePath).endsWith('mkd') || post.isMarkdown + + const thePost = post // Dup code for type checking + + return window.withProgress( + { + location: ProgressLocation.Notification, + title: '正在上传博文', + cancellable: false, + }, + async progress => { + progress.report({ + increment: 10, + }) + + let isSaved = false + + try { + const { id: postId } = await PostService.updatePost(thePost) + await openPostInVscode(postId) + thePost.id = postId + + isSaved = true + progress.report({ increment: 100 }) + void Alert.info('上传成功') + await refreshPostList() + } catch (err) { + progress.report({ increment: 100 }) + void Alert.err(`上传失败\n${err instanceof Error ? err.message : JSON.stringify(err)}`) + console.error(err) + } + + return isSaved + } + ) +} + +export async function uploadPostFileNoConfirm(fileUri: Uri | undefined) { + const parsedFileUri = await parseFileUri(fileUri) + if (parsedFileUri === undefined) return + + const { fsPath: filePath } = parsedFileUri + const postId = PostFileMapManager.getPostId(filePath) + + if (postId !== undefined && postId >= 0) { + const dto = await PostService.fetchPostEditDto(postId) + if (dto !== undefined) await uploadPostNoConfirm(dto) + return + } + + const fileContent = Buffer.from(await workspace.fs.readFile(parsedFileUri)).toString() + if (isEmptyBody(fileContent)) return + + const options = ['新建博文', '关联已有博文'] + const selected = await window.showInformationMessage( + '本地文件尚未关联到博客园博文', + { + modal: true, + detail: `您可以选择新建一篇博文或将本地文件关联到一篇博客园博文(您可以根据标题搜索您在博客园博文)`, + } as MessageOptions, + ...options + ) + if (selected === '关联已有博文') { + const selectedPost = await searchPostByTitle({ + postTitle: path.basename(filePath, path.extname(filePath)), + quickPickTitle: '搜索要关联的博文', + }) + if (selectedPost === undefined) return + + await PostFileMapManager.updateOrCreate(selectedPost.id, filePath) + const postEditDto = await PostService.fetchPostEditDto(selectedPost.id) + if (postEditDto === undefined) return + if (!fileContent) await workspace.fs.writeFile(parsedFileUri, Buffer.from(postEditDto.post.postBody)) + + await uploadPostNoConfirm(postEditDto.post) + } else if (selected === '新建博文') { + await saveLocalDraft(new LocalDraft(filePath)) + } } diff --git a/src/setup/setup-cmd.ts b/src/setup/setup-cmd.ts index 00a6b092..cdcaac49 100644 --- a/src/setup/setup-cmd.ts +++ b/src/setup/setup-cmd.ts @@ -8,7 +8,7 @@ import { openMyHomePage } from '@/cmd/open/open-my-home-page' import { openMyBlog } from '@/cmd/open/open-my-blog' import { globalCtx } from '@/ctx/global-ctx' import { goNextPostList, goPrevPostList, refreshPostList, seekPostList } from '@/cmd/post-list/refresh-post-list' -import { uploadPostFile, uploadPost } from '@/cmd/post-list/upload-post' +import { uploadPostFile, uploadPost, uploadPostNoConfirm, uploadPostFileNoConfirm } from '@/cmd/post-list/upload-post' import { createLocalDraft } from '@/cmd/post-list/create-local-draft' import { deleteSelectedPost } from '@/cmd/post-list/delete-post' import { modifyPostSetting } from '@/cmd/post-list/modify-post-setting' @@ -73,6 +73,8 @@ export function setupExtCmd() { regCmd(withAppName('.create-local-draft'), createLocalDraft), regCmd(withAppName('.upload-post'), uploadPost), regCmd(withAppName('.upload-post-file'), uploadPostFile), + regCmd(withAppName('.upload-post-no-confirm'), uploadPostNoConfirm), + regCmd(withAppName('.upload-post-file-no-confirm'), uploadPostFileNoConfirm), regCmd(withAppName('.pull-remote-post'), pullRemotePost), regCmd(withAppName('.open-post-in-blog-admin'), openPostInBlogAdmin), regCmd(withAppName('.delete-post-to-local-file-map'), deletePostToLocalFileMap), From 00f3c328bdcf8699d48b35b2dccebe421436ae6f Mon Sep 17 00:00:00 2001 From: Thaumy Date: Sat, 29 Jul 2023 11:09:44 +0800 Subject: [PATCH 050/157] refactor: rs impl regex matches --- rs/Cargo.lock | 33 +++++++++++++++++ rs/Cargo.toml | 9 ++++- rs/src/regex.rs | 47 ++++++++++++++++++++++-- src/cmd/extract-img.ts | 10 +++--- src/infra/convert/string-literal.ts | 1 + src/infra/filter/find-img-link.ts | 55 +++++++++++++++-------------- src/markdown/mkd-img-extractor.ts | 8 ++--- 7 files changed, 123 insertions(+), 40 deletions(-) create mode 100644 src/infra/convert/string-literal.ts diff --git a/rs/Cargo.lock b/rs/Cargo.lock index 2c8bf217..2e55804b 100644 --- a/rs/Cargo.lock +++ b/rs/Cargo.lock @@ -102,10 +102,43 @@ name = "rs" version = "0.0.1" dependencies = [ "regex", + "serde", + "serde-wasm-bindgen", "wasm-bindgen", "web-sys", ] +[[package]] +name = "serde" +version = "1.0.177" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63ba2516aa6bf82e0b19ca8b50019d52df58455d3cf9bdaf6315225fdd0c560a" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde-wasm-bindgen" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3b143e2833c57ab9ad3ea280d21fd34e285a42837aeb0ee301f4f41890fa00e" +dependencies = [ + "js-sys", + "serde", + "wasm-bindgen", +] + +[[package]] +name = "serde_derive" +version = "1.0.177" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "401797fe7833d72109fedec6bfcbe67c0eed9b99772f26eb8afd261f0abc6fd3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "syn" version = "2.0.27" diff --git a/rs/Cargo.toml b/rs/Cargo.toml index 77dd6b38..95b2e65b 100644 --- a/rs/Cargo.toml +++ b/rs/Cargo.toml @@ -9,6 +9,13 @@ crate-type = ["cdylib"] [dependencies] -wasm-bindgen = "0.2.84" +wasm-bindgen = "0.2.87" +serde-wasm-bindgen = "0.5.0" web-sys = "0.3.61" regex = "1.8.1" + +[dependencies.serde] + +version = "1.0.177" +features = ["derive"] + diff --git a/rs/src/regex.rs b/rs/src/regex.rs index 972ba25b..2914597a 100644 --- a/rs/src/regex.rs +++ b/rs/src/regex.rs @@ -1,17 +1,60 @@ -use wasm_bindgen::prelude::*; use regex::Regex; +use serde::{Deserialize, Serialize}; +use wasm_bindgen::prelude::*; #[wasm_bindgen(js_name = RsRegex)] pub struct RsRegex; +#[wasm_bindgen(typescript_custom_section)] +const _: &str = r" +export type RsMatch = { offset: number, groups: string[] } +"; + +#[derive(Serialize, Deserialize, Debug)] +pub struct RsMatch { + offset: usize, + groups: Vec, +} + #[wasm_bindgen(js_class = RsRegex)] impl RsRegex { #[wasm_bindgen(js_name = isMatch)] - pub fn is_match(regex: &str, text: &str) -> bool { + pub fn export_is_match(regex: &str, text: &str) -> bool { let regex = Regex::new(regex); let Ok(regex) = regex else { return false; }; regex.is_match(text) } + + #[wasm_bindgen(js_name = matches)] + pub fn export_matches(regex: &str, text: &str) -> JsValue { + let ret = matches(regex, text); + serde_wasm_bindgen::to_value(&ret).unwrap() + } +} + +fn matches(regex: &str, text: &str) -> Vec { + let regex = Regex::new(regex); + let Ok(regex) = regex else { return vec![]; }; + + regex + .captures_iter(text) + .map(|caps| { + let offset = caps.get(0).unwrap().start(); + let groups = caps + .iter() + .map(|m| m.map(|s| s.as_str()).unwrap_or("").to_string()) + .collect(); + + RsMatch { offset, groups } + }) + .collect() } +#[test] +fn test_matches() { + let text = "![img](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA0AAAAQCAYAAADNo/U5AAAABHNCSVQICAgIfAhkiAAAABl0RVh0U29mdHdhcmUAZ25vbWUtc2NyZWVuc2hvdO8Dvz4AAAAtdEVYdENyZWF0aW9uIFRpbWUARnJpIDE0IEp1bCAyMDIzIDExOjAzOjAwIEFNIENTVCKwI9kAAACwSURBVCiR7dK/DsFwFMXx76WNLrUR7Jq+hcRTGD2C0XuYvISIRYLEKDFLTBYmpP41oaXyM4iIomnMznhOPtO9cvTOilC8yZRZpYpeyGP12uGZxFsTI38UhZT8gCSVumPvFB/p2QwAwWbH9eDGQ8m0iWEXAdi2Oq+jUsinNwJwB0PmtTqIYJZLGLYFvo87Gn9HAPtun1WjyXm+eJYi0eiRYLnm4jiIpqEXcvFQOD8d9wYk9T77dSRnWwAAAABJRU5ErkJggg==)"; + let regex = r#"(!\[.*?]\()(data:image\/.*?,[a-zA-Z0-9+/]*?=?=?)(\))"#; + let mgs = matches(regex, text); + println!("{:?}", mgs); +} diff --git a/src/cmd/extract-img.ts b/src/cmd/extract-img.ts index 98c0c285..6819fdf9 100644 --- a/src/cmd/extract-img.ts +++ b/src/cmd/extract-img.ts @@ -15,7 +15,7 @@ export async function extractImg(arg: unknown, inputImgSrc?: ImgSrc) { await textDocument.save() const markdown = (await workspace.fs.readFile(arg)).toString() - const imgInfoList = findImgLink(markdown) + let imgInfoList = findImgLink(markdown) if (imgInfoList.length <= 0) { if (inputImgSrc === undefined) void Alert.info('没有找到可以提取的图片') @@ -57,7 +57,9 @@ export async function extractImg(arg: unknown, inputImgSrc?: ImgSrc) { if (selectedSrc === undefined) return - const extractor = new MkdImgExtractor(arg, selectedSrc) + imgInfoList = imgInfoList.filter(newImgSrcFilter(selectedSrc)) + + const extractor = new MkdImgExtractor(arg) const failedImages = await window.withProgress( { title: '正在提取图片', location: ProgressLocation.Notification }, @@ -80,9 +82,9 @@ export async function extractImg(arg: unknown, inputImgSrc?: ImgSrc) { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion .map(([src, dst]) => [src, dst!]) .map(([src, dst]) => { - const posL = textDocument.positionAt(src.startOffset) + const posL = textDocument.positionAt(src.offset) const posR = textDocument.positionAt( - src.startOffset + src.prefix.length + src.data.length + src.postfix.length + src.offset + src.prefix.length + src.data.length + src.postfix.length ) const range = new Range(posL, posR) diff --git a/src/infra/convert/string-literal.ts b/src/infra/convert/string-literal.ts new file mode 100644 index 00000000..efe10784 --- /dev/null +++ b/src/infra/convert/string-literal.ts @@ -0,0 +1 @@ +export const r = String.raw diff --git a/src/infra/filter/find-img-link.ts b/src/infra/filter/find-img-link.ts index 90d79fec..52ee956d 100644 --- a/src/infra/filter/find-img-link.ts +++ b/src/infra/filter/find-img-link.ts @@ -1,44 +1,45 @@ +import { DataType, ImgInfo } from '@/markdown/mkd-img-extractor' +import { r } from '@/infra/convert/string-literal' +import { RsMatch, RsRegex } from '@/wasm' + // Data URL reference see in: // https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URLs // Related RFC: // https://datatracker.ietf.org/doc/html/rfc2397 -import { DataType, ImgInfo } from '@/markdown/mkd-img-extractor' -import { RsRegex } from '@/wasm' +const imgExtPat = r`png|jpg|jpeg|webp|svg|gif` +const imgUrlPat = r`.*?\.(?:${imgExtPat})` +const dataUrlPat = r`data:image\/.*?,[a-zA-Z0-9+/]*?=?=?` -const imgTagDataUrlImgPat = /()/g -const imgTagUrlImgPat = /()/gi -const mkdDataUrlImgPat = /(!\[.*?]\()(data:image\/.*?,[a-zA-Z0-9+/]*?=?=?)(\))/g -const mkdUrlImgPat = /(!\[.*?]\()(.*?\.(?:png|jpg|jpeg|webp|svg|gif))(\))/gi -//eslint-disable-next-line -const cnblogsDomain = `\.cnblogs\.com\/` +const imgTagDataUrlImgPat = r`()` +const mkdUrlImgPat = r`(!\[.*?]\()(${imgUrlPat})(\))` +const imgTagUrlImgPat = r`()` +const mkdDataUrlImgPat = r`(!\[.*?]\()(${dataUrlPat})(\))` +const cnbDomain = r`\.cnblogs\.com\/` export function findImgLink(text: string): ImgInfo[] { - const imgTagUrlImgMatchGroups = Array.from(text.matchAll(imgTagUrlImgPat)) - const mkdUrlImgMatchGroups = Array.from(text.matchAll(mkdUrlImgPat)) - const urlImgInfo = imgTagUrlImgMatchGroups.concat(mkdUrlImgMatchGroups).map(mg => ({ - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - startOffset: mg.index!, + const imgTagUrlImgMgs = RsRegex.matches(imgTagUrlImgPat, text) as RsMatch[] + const mkdUrlImgMgs = RsRegex.matches(mkdUrlImgPat, text) as RsMatch[] + const urlImgInfo = imgTagUrlImgMgs.concat(mkdUrlImgMgs).map(mg => ({ + offset: mg.offset, dataType: DataType.url, - data: mg[2], - prefix: mg[1], - postfix: mg[3], + data: mg.groups[2], + prefix: mg.groups[1], + postfix: mg.groups[3], })) - const imgTagDataUrlImgMatchGroups = Array.from(text.matchAll(imgTagDataUrlImgPat)) - const mkdDataUrlImgMatchGroups = Array.from(text.matchAll(mkdDataUrlImgPat)) - const dataUrlImgInfo = imgTagDataUrlImgMatchGroups.concat(mkdDataUrlImgMatchGroups).map(mg => ({ - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - startOffset: mg.index!, + const imgTagDataUrlImgMgs = RsRegex.matches(imgTagDataUrlImgPat, text) as RsMatch[] + const mkdDataUrlImgMgs = RsRegex.matches(mkdDataUrlImgPat, text) as RsMatch[] + const dataUrlImgInfo = imgTagDataUrlImgMgs.concat(mkdDataUrlImgMgs).map(mg => ({ + offset: mg.offset, dataType: DataType.dataUrl, - data: mg[2], - prefix: mg[1], - postfix: mg[3], + data: mg.groups[2], + prefix: mg.groups[1], + postfix: mg.groups[3], })) const acc = urlImgInfo.concat(dataUrlImgInfo) - // TODO: better filter design needed - // remove cnblogs img link - return acc.filter(x => RsRegex.isMatch(cnblogsDomain, x.data)) + // keep links while not cnb + return acc.filter(x => !RsRegex.isMatch(cnbDomain, x.data.toLowerCase())) } diff --git a/src/markdown/mkd-img-extractor.ts b/src/markdown/mkd-img-extractor.ts index a20f241a..9c4fc848 100644 --- a/src/markdown/mkd-img-extractor.ts +++ b/src/markdown/mkd-img-extractor.ts @@ -14,7 +14,7 @@ export const enum DataType { } export interface ImgInfo { - startOffset: number + offset: number data: string dataType: DataType prefix: string @@ -58,11 +58,7 @@ export class MkdImgExtractor { private _errors: [imgLink: string, msg: string][] = [] private readonly _workspaceDirs: string[] = [] - constructor( - private readonly targetFileUri: Uri, - private imgSrc: ImgSrc, - public onProgress?: (index: number, images: ImgInfo[]) => void - ) { + constructor(private readonly targetFileUri: Uri, public onProgress?: (index: number, images: ImgInfo[]) => void) { if (workspace.workspaceFolders !== undefined) this._workspaceDirs = workspace.workspaceFolders.map(({ uri: { fsPath } }) => fsPath) } From 85daedb2f050e1af0ca9c24b8c38539567d6a1f3 Mon Sep 17 00:00:00 2001 From: Thaumy Date: Sat, 29 Jul 2023 19:37:48 +0800 Subject: [PATCH 051/157] refactor: extract img --- src/cmd/extract-img.ts | 87 +++++++++++++++---------------- src/infra/filter/find-img-link.ts | 48 ++++++++++------- src/infra/fp/ord.ts | 24 +++++++++ src/markdown/mkd-img-extractor.ts | 34 ++---------- 4 files changed, 100 insertions(+), 93 deletions(-) create mode 100644 src/infra/fp/ord.ts diff --git a/src/cmd/extract-img.ts b/src/cmd/extract-img.ts index 6819fdf9..81e4e2d1 100644 --- a/src/cmd/extract-img.ts +++ b/src/cmd/extract-img.ts @@ -1,10 +1,8 @@ -import { MessageItem, MessageOptions, ProgressLocation, Range, Uri, window, workspace, WorkspaceEdit } from 'vscode' -import { ImgInfo, ImgSrc, MkdImgExtractor, newImgSrcFilter } from '@/markdown/mkd-img-extractor' +import { MessageOptions, ProgressLocation, Range, Uri, window, workspace, WorkspaceEdit } from 'vscode' +import { ImgInfo, ImgSrc, MkdImgExtractor } from '@/markdown/mkd-img-extractor' import { Alert } from '@/infra/alert' import { findImgLink } from '@/infra/filter/find-img-link' -type ExtractOption = MessageItem & Partial<{ imageSrc: ImgSrc }> - export async function extractImg(arg: unknown, inputImgSrc?: ImgSrc) { if (!(arg instanceof Uri && arg.scheme === 'file')) return @@ -22,42 +20,48 @@ export async function extractImg(arg: unknown, inputImgSrc?: ImgSrc) { return } - const webImgCount = imgInfoList.filter(newImgSrcFilter(ImgSrc.web)).length - const dataUrlImgCount = imgInfoList.filter(newImgSrcFilter(ImgSrc.dataUrl)).length - const fsImgCount = imgInfoList.filter(newImgSrcFilter(ImgSrc.fs)).length + const webImgCount = imgInfoList.filter(i => i.src === ImgSrc.web).length + const dataUrlImgCount = imgInfoList.filter(i => i.src === ImgSrc.dataUrl).length + const fsImgCount = imgInfoList.filter(i => i.src === ImgSrc.fs).length - const displayOptions: ExtractOption[] = [ - { title: '提取全部', imageSrc: ImgSrc.any }, - { title: '提取网络图片', imageSrc: ImgSrc.web }, - { title: '提取 Data Url 图片', imageSrc: ImgSrc.dataUrl }, - { title: '提取本地图片', imageSrc: ImgSrc.fs }, - { title: '取消', imageSrc: undefined, isCloseAffordance: true }, + const options = [ + { title: '提取全部', src: ImgSrc.any }, + { title: '取消', src: undefined, isCloseAffordance: true }, ] + const detail = ['共找到:'] + + if (webImgCount > 0) { + options.push({ title: '提取网络图片', src: ImgSrc.web }) + detail.push(`${webImgCount} 张可以提取的网络图片`) + } + if (dataUrlImgCount > 0) { + options.push({ title: '提取 Data Url 图片', src: ImgSrc.dataUrl }) + detail.push(`${dataUrlImgCount} 张可以提取的 Data Url 图片`) + } + if (fsImgCount > 0) { + options.push({ title: '提取本地图片', src: ImgSrc.fs }) + detail.push(`${fsImgCount} 张可以提取的本地图片`) + } - let selectedSrc + let selectedSrc: ImgSrc | undefined if (inputImgSrc !== undefined) { - selectedSrc = displayOptions.find(ent => ent.imageSrc === inputImgSrc)?.imageSrc + selectedSrc = inputImgSrc } else { // if src is not specified: - const selectedOption = await Alert.info( + const selected = await Alert.info( '要提取哪些图片? 此操作会替换源文件中的图片链接!', { modal: true, - detail: - '共找到:\n' + - `${webImgCount} 张可以提取的网络图片\n` + - `${dataUrlImgCount} 张可以提取的 Data Url 图片\n` + - `${fsImgCount} 张可以提取的本地图片`, + detail: detail.join('\n'), } as MessageOptions, - ...displayOptions + ...options ) - selectedSrc = selectedOption?.imageSrc + selectedSrc = selected?.src } if (selectedSrc === undefined) return - - imgInfoList = imgInfoList.filter(newImgSrcFilter(selectedSrc)) + if (selectedSrc !== ImgSrc.any) imgInfoList = imgInfoList.filter(i => i.src === selectedSrc) const extractor = new MkdImgExtractor(arg) @@ -68,42 +72,37 @@ export async function extractImg(arg: unknown, inputImgSrc?: ImgSrc) { const total = info.length const image = info[count] progress.report({ - increment: (count / total) * 80, + increment: (count / total) * 50, message: `[${count + 1} / ${total}] 正在提取 ${image.data}`, }) } const extracted = await extractor.extract(imgInfoList) const extractedLen = extracted.length - const idx = 0 const we = extracted .filter(([, dst]) => dst != null) // eslint-disable-next-line @typescript-eslint/no-non-null-assertion .map(([src, dst]) => [src, dst!]) - .map(([src, dst]) => { + .map(([src, dst], i) => { const posL = textDocument.positionAt(src.offset) - const posR = textDocument.positionAt( - src.offset + src.prefix.length + src.data.length + src.postfix.length - ) + const posR = textDocument.positionAt(src.offset + src.data.length) const range = new Range(posL, posR) // just for ts type inferring - const ret: [Range, ImgInfo] = [range, dst] + const ret: [Range, ImgInfo, number] = [range, dst, i] return ret }) - .reduce((we, [range, dst]) => { - if (range) { - progress.report({ - increment: (idx / extractedLen) * 20 + 80, - message: `[${idx + 1} / ${extractedLen}] 正在替换图片链接 ${dst.data}`, - }) - const newText = dst.prefix + dst.data + dst.postfix - we.replace(textDocument.uri, range, newText, { - needsConfirmation: false, - label: dst.data, - }) - } + .reduce((we, [range, dst, i]) => { + progress.report({ + increment: (i / extractedLen) * 20 + 80, + message: `正在替换图片链接 ${dst.data}`, + }) + const newText = dst.data + we.replace(textDocument.uri, range, newText, { + needsConfirmation: false, + label: dst.data, + }) return we }, new WorkspaceEdit()) diff --git a/src/infra/filter/find-img-link.ts b/src/infra/filter/find-img-link.ts index 52ee956d..7656253e 100644 --- a/src/infra/filter/find-img-link.ts +++ b/src/infra/filter/find-img-link.ts @@ -1,4 +1,4 @@ -import { DataType, ImgInfo } from '@/markdown/mkd-img-extractor' +import { ImgInfo, ImgSrc } from '@/markdown/mkd-img-extractor' import { r } from '@/infra/convert/string-literal' import { RsMatch, RsRegex } from '@/wasm' @@ -11,32 +11,42 @@ const imgExtPat = r`png|jpg|jpeg|webp|svg|gif` const imgUrlPat = r`.*?\.(?:${imgExtPat})` const dataUrlPat = r`data:image\/.*?,[a-zA-Z0-9+/]*?=?=?` -const imgTagDataUrlImgPat = r`()` -const mkdUrlImgPat = r`(!\[.*?]\()(${imgUrlPat})(\))` -const imgTagUrlImgPat = r`()` -const mkdDataUrlImgPat = r`(!\[.*?]\()(${dataUrlPat})(\))` +const imgTagDataUrlImgPat = r`(` +const mkdUrlImgPat = r`(!\[.*?]\()(${imgUrlPat})\)` +const imgTagUrlImgPat = r`(` +const mkdDataUrlImgPat = r`(!\[.*?]\()(${dataUrlPat})\)` const cnbDomain = r`\.cnblogs\.com\/` export function findImgLink(text: string): ImgInfo[] { const imgTagUrlImgMgs = RsRegex.matches(imgTagUrlImgPat, text) as RsMatch[] const mkdUrlImgMgs = RsRegex.matches(mkdUrlImgPat, text) as RsMatch[] - const urlImgInfo = imgTagUrlImgMgs.concat(mkdUrlImgMgs).map(mg => ({ - offset: mg.offset, - dataType: DataType.url, - data: mg.groups[2], - prefix: mg.groups[1], - postfix: mg.groups[3], - })) + const urlImgInfo = imgTagUrlImgMgs.concat(mkdUrlImgMgs).map(mg => { + const data = mg.groups[2] + const prefix = mg.groups[1] + + let src + if (/https?:\/\//.test(data)) src = ImgSrc.web + else src = ImgSrc.fs + + return { + offset: mg.offset + prefix.length, + data, + src, + } + }) const imgTagDataUrlImgMgs = RsRegex.matches(imgTagDataUrlImgPat, text) as RsMatch[] const mkdDataUrlImgMgs = RsRegex.matches(mkdDataUrlImgPat, text) as RsMatch[] - const dataUrlImgInfo = imgTagDataUrlImgMgs.concat(mkdDataUrlImgMgs).map(mg => ({ - offset: mg.offset, - dataType: DataType.dataUrl, - data: mg.groups[2], - prefix: mg.groups[1], - postfix: mg.groups[3], - })) + const dataUrlImgInfo = imgTagDataUrlImgMgs.concat(mkdDataUrlImgMgs).map(mg => { + const data = mg.groups[2] + const prefix = mg.groups[1] + + return { + offset: mg.offset + prefix.length, + data, + src: ImgSrc.dataUrl, + } + }) const acc = urlImgInfo.concat(dataUrlImgInfo) diff --git a/src/infra/fp/ord.ts b/src/infra/fp/ord.ts new file mode 100644 index 00000000..fc01b2b2 --- /dev/null +++ b/src/infra/fp/ord.ts @@ -0,0 +1,24 @@ +export const gt = + (a: T) => + (b: T) => + a > b + +export const ge = + (a: T) => + (b: T) => + a >= b + +export const eq = + (a: T) => + (b: T) => + a === b + +export const le = + (a: T) => + (b: T) => + a <= b + +export const lt = + (a: T) => + (b: T) => + a < b diff --git a/src/markdown/mkd-img-extractor.ts b/src/markdown/mkd-img-extractor.ts index 9c4fc848..8dbb60b6 100644 --- a/src/markdown/mkd-img-extractor.ts +++ b/src/markdown/mkd-img-extractor.ts @@ -8,17 +8,10 @@ import { promisify } from 'util' import { Readable } from 'stream' import { tmpdir } from 'os' -export const enum DataType { - dataUrl, - url, -} - export interface ImgInfo { offset: number data: string - dataType: DataType - prefix: string - postfix: string + src: ImgSrc } export const enum ImgSrc { @@ -28,25 +21,6 @@ export const enum ImgSrc { any, } -export const newImgSrcFilter = (type: ImgSrc) => { - const isWebImg = (imgInfo: ImgInfo) => imgInfo.dataType === DataType.url && /https?:\/\//.test(imgInfo.data) - const isFsImg = (imgInfo: ImgInfo) => imgInfo.dataType === DataType.url && !isWebImg(imgInfo) - const isDataUrlImg = (imgInfo: ImgInfo) => imgInfo.dataType === DataType.dataUrl - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const isAnyImg = (_: ImgInfo) => true - - switch (type) { - case ImgSrc.web: - return isWebImg - case ImgSrc.fs: - return isFsImg - case ImgSrc.dataUrl: - return isDataUrlImg - case ImgSrc.any: - return isAnyImg - } -} - enum ExtractorSt { pending, extracting, @@ -169,13 +143,13 @@ export class MkdImgExtractor { private async resolveImgInfo(info: ImgInfo): Promise { // for web img // eslint-disable-next-line no-return-await - if (newImgSrcFilter(ImgSrc.web)(info)) return await this.resolveWebImg(info.data) + if (info.src === ImgSrc.web) return await this.resolveWebImg(info.data) // for fs img // eslint-disable-next-line no-return-await - if (newImgSrcFilter(ImgSrc.fs)(info)) return await this.resolveFsImg(info.data) + if (info.src === ImgSrc.fs) return await this.resolveFsImg(info.data) // for data url img - if (newImgSrcFilter(ImgSrc.dataUrl)(info)) return this.resolveDataUrlImg(info.data) + if (info.src === ImgSrc.dataUrl) return this.resolveDataUrlImg(info.data) } } From 27d47e6113976d6fc6cac63e14ca77f7abb01017 Mon Sep 17 00:00:00 2001 From: Thaumy Date: Sun, 30 Jul 2023 13:56:54 +0800 Subject: [PATCH 052/157] feat: add RsHttp --- rs/Cargo.lock | 904 +++++++++++++++++++++++++++++++++++++++++ rs/Cargo.toml | 16 +- rs/src/http.rs | 1 + rs/src/http/get.rs | 37 ++ rs/src/infra.rs | 2 + rs/src/infra/option.rs | 11 + rs/src/infra/result.rs | 15 + rs/src/lib.rs | 5 + rs/src/regex.rs | 23 +- 9 files changed, 1002 insertions(+), 12 deletions(-) create mode 100644 rs/src/http.rs create mode 100644 rs/src/http/get.rs create mode 100644 rs/src/infra.rs create mode 100644 rs/src/infra/option.rs create mode 100644 rs/src/infra/result.rs diff --git a/rs/Cargo.lock b/rs/Cargo.lock index 2e55804b..a49771fb 100644 --- a/rs/Cargo.lock +++ b/rs/Cargo.lock @@ -2,6 +2,21 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "addr2line" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + [[package]] name = "aho-corasick" version = "1.0.2" @@ -11,18 +26,330 @@ dependencies = [ "memchr", ] +[[package]] +name = "anyhow" +version = "1.0.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b13c32d80ecc7ab747b80c3784bce54ee8a7a0cc4fbda9bf4cda2cf6fe90854" + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "backtrace" +version = "0.3.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "base64" +version = "0.21.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" + [[package]] name = "bumpalo" version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" +[[package]] +name = "bytes" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" + +[[package]] +name = "cc" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" + [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "core-foundation" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" + +[[package]] +name = "encoding_rs" +version = "0.8.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "errno" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" +dependencies = [ + "errno-dragonfly", + "libc", + "windows-sys", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "fastrand" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures-channel" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" + +[[package]] +name = "futures-sink" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" + +[[package]] +name = "futures-task" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" + +[[package]] +name = "futures-util" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "pin-utils", +] + +[[package]] +name = "gimli" +version = "0.27.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" + +[[package]] +name = "h2" +version = "0.3.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97ec8491ebaf99c8eaa73058b045fe58073cd6be7f596ac993ced0b0a0c01049" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "http" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" + +[[package]] +name = "httpdate" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" + +[[package]] +name = "hyper" +version = "0.14.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper", + "native-tls", + "tokio", + "tokio-native-tls", +] + +[[package]] +name = "idna" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "ipnet" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" + +[[package]] +name = "itoa" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" + [[package]] name = "js-sys" version = "0.3.64" @@ -32,6 +359,24 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" + +[[package]] +name = "linux-raw-sys" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09fc20d2ca12cb9f044c93e3bd6d32d523e6e2ec3db4f7b2939cd99026ecd3f0" + [[package]] name = "log" version = "0.4.19" @@ -44,12 +389,133 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" +dependencies = [ + "libc", + "wasi", + "windows-sys", +] + +[[package]] +name = "native-tls" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" +dependencies = [ + "lazy_static", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "object" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" +dependencies = [ + "memchr", +] + [[package]] name = "once_cell" version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +[[package]] +name = "openssl" +version = "0.10.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "345df152bc43501c5eb9e4654ff05f794effb78d4efe3d53abc158baddc0703d" +dependencies = [ + "bitflags 1.3.2", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "374533b0e45f3a7ced10fcaeccca020e66656bc03dac384f852e4e5a7a8104a6" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "percent-encoding" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" + +[[package]] +name = "pin-project-lite" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c40d25201921e5ff0c862a505c6557ea88568a4e3ace775ab55e93f2f4f9d57" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" + [[package]] name = "proc-macro2" version = "1.0.66" @@ -68,6 +534,15 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "redox_syscall" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +dependencies = [ + "bitflags 1.3.2", +] + [[package]] name = "regex" version = "1.9.1" @@ -97,17 +572,117 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" +[[package]] +name = "reqwest" +version = "0.11.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cde824a14b7c14f85caff81225f411faacc04a2013f41670f41443742b1c1c55" +dependencies = [ + "base64", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-tls", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "serde", + "serde_json", + "serde_urlencoded", + "tokio", + "tokio-native-tls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winreg", +] + [[package]] name = "rs" version = "0.0.1" dependencies = [ + "anyhow", + "base64", "regex", + "reqwest", "serde", "serde-wasm-bindgen", + "serde_json", + "serde_qs", "wasm-bindgen", + "wasm-bindgen-futures", "web-sys", ] +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + +[[package]] +name = "rustix" +version = "0.38.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a962918ea88d644592894bc6dc55acc6c0956488adcebbfb6e273506b7fd6e5" +dependencies = [ + "bitflags 2.3.3", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "ryu" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" + +[[package]] +name = "schannel" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "security-framework" +version = "2.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "serde" version = "1.0.177" @@ -139,6 +714,59 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "076066c5f1078eac5b722a31827a8832fe108bed65dfa75e233c89f8206e976c" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_qs" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0431a35568651e363364210c91983c1da5eb29404d9f0928b67d4ebcfa7d330c" +dependencies = [ + "percent-encoding", + "serde", + "thiserror", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "slab" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" +dependencies = [ + "autocfg", +] + +[[package]] +name = "socket2" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "syn" version = "2.0.27" @@ -150,12 +778,179 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "tempfile" +version = "3.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5486094ee78b2e5038a6382ed7645bc084dc2ec433426ca4c3cb61e2007b8998" +dependencies = [ + "cfg-if", + "fastrand", + "redox_syscall", + "rustix", + "windows-sys", +] + +[[package]] +name = "thiserror" +version = "1.0.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "611040a08a0439f8248d1990b111c95baa9c704c805fa1f62104b39655fd7f90" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "532826ff75199d5833b9d2c5fe410f29235e25704ee5f0ef599fb51c21f4a4da" +dependencies = [ + "autocfg", + "backtrace", + "bytes", + "libc", + "mio", + "pin-project-lite", + "socket2", + "windows-sys", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", + "tracing", +] + +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + +[[package]] +name = "tracing" +version = "0.1.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +dependencies = [ + "cfg-if", + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" +dependencies = [ + "once_cell", +] + +[[package]] +name = "try-lock" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" + +[[package]] +name = "unicode-bidi" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" + [[package]] name = "unicode-ident" version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "url" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + [[package]] name = "wasm-bindgen" version = "0.2.87" @@ -181,6 +976,18 @@ dependencies = [ "wasm-bindgen-shared", ] +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "wasm-bindgen-macro" version = "0.2.87" @@ -219,3 +1026,100 @@ dependencies = [ "js-sys", "wasm-bindgen", ] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" + +[[package]] +name = "winreg" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" +dependencies = [ + "winapi", +] diff --git a/rs/Cargo.toml b/rs/Cargo.toml index 95b2e65b..869b5979 100644 --- a/rs/Cargo.toml +++ b/rs/Cargo.toml @@ -9,13 +9,17 @@ crate-type = ["cdylib"] [dependencies] -wasm-bindgen = "0.2.87" -serde-wasm-bindgen = "0.5.0" -web-sys = "0.3.61" regex = "1.8.1" +base64 = "0.21.2" +anyhow = "1.0.72" -[dependencies.serde] +web-sys = "0.3.64" +serde-wasm-bindgen = "0.5.0" +wasm-bindgen = "0.2.87" +wasm-bindgen-futures = "0.4.37" -version = "1.0.177" -features = ["derive"] +serde = { version = "1.0.177", features = ["derive"] } +serde_qs = "0.12.0" +serde_json = { version = "1.0", default-features = false, features = ["alloc"] } +reqwest = { version = "0.11.16", features = ["json"] } diff --git a/rs/src/http.rs b/rs/src/http.rs new file mode 100644 index 00000000..125ca70d --- /dev/null +++ b/rs/src/http.rs @@ -0,0 +1 @@ +pub mod get; diff --git a/rs/src/http/get.rs b/rs/src/http/get.rs new file mode 100644 index 00000000..21857512 --- /dev/null +++ b/rs/src/http/get.rs @@ -0,0 +1,37 @@ +use crate::infra::result::IntoResult; +use alloc::string::{String, ToString}; +use anyhow::Result; +use core::convert::TryFrom; +use core::str::FromStr; +use reqwest::header::HeaderMap; +use serde_json::Value; +use wasm_bindgen::__rt::std::collections::HashMap; +use wasm_bindgen::prelude::wasm_bindgen; + +#[wasm_bindgen(js_name = RsHttp)] +struct RsHttp; + +#[wasm_bindgen(js_class = RsHttp)] +impl RsHttp { + #[wasm_bindgen(js_name = get)] + pub async fn export_get(url: &str, header_json: &str) -> Result { + let body = get(url, header_json).await; + let Ok(body) = body else { return body.unwrap_err().to_string().into_err(); }; + + Ok(body) + } +} + +async fn get(url: &str, header_json: &str) -> Result { + let header_json = Value::from_str(header_json)?; + let header = serde_json::from_value::>(header_json)?; + let header = HeaderMap::try_from(&header)?; + + let client = reqwest::Client::new(); + + let resp = client.get(url).headers(header).send().await?; + + let body = resp.text().await?; + + Ok(body) +} diff --git a/rs/src/infra.rs b/rs/src/infra.rs new file mode 100644 index 00000000..8c45a69b --- /dev/null +++ b/rs/src/infra.rs @@ -0,0 +1,2 @@ +pub mod option; +pub mod result; diff --git a/rs/src/infra/option.rs b/rs/src/infra/option.rs new file mode 100644 index 00000000..80f0380f --- /dev/null +++ b/rs/src/infra/option.rs @@ -0,0 +1,11 @@ +pub trait IntoOption +where + Self: Sized, +{ + #[inline] + fn into_some(self) -> Option { + Some(self) + } +} + +impl IntoOption for T {} diff --git a/rs/src/infra/result.rs b/rs/src/infra/result.rs new file mode 100644 index 00000000..c5e2b1a9 --- /dev/null +++ b/rs/src/infra/result.rs @@ -0,0 +1,15 @@ +pub trait IntoResult +where + Self: Sized, +{ + #[inline] + fn into_ok(self) -> Result { + Ok(self) + } + #[inline] + fn into_err(self) -> Result { + Err(self) + } +} + +impl IntoResult for T {} diff --git a/rs/src/lib.rs b/rs/src/lib.rs index 1d9dab60..ec2da401 100644 --- a/rs/src/lib.rs +++ b/rs/src/lib.rs @@ -1 +1,6 @@ +#![no_std] +extern crate alloc; + +pub mod http; +pub mod infra; pub mod regex; diff --git a/rs/src/regex.rs b/rs/src/regex.rs index 2914597a..5741a077 100644 --- a/rs/src/regex.rs +++ b/rs/src/regex.rs @@ -1,21 +1,24 @@ +use alloc::string::{String, ToString}; +use alloc::vec; +use alloc::vec::Vec; use regex::Regex; use serde::{Deserialize, Serialize}; use wasm_bindgen::prelude::*; -#[wasm_bindgen(js_name = RsRegex)] -pub struct RsRegex; - #[wasm_bindgen(typescript_custom_section)] const _: &str = r" export type RsMatch = { offset: number, groups: string[] } "; -#[derive(Serialize, Deserialize, Debug)] +#[derive(Serialize, Deserialize, Debug, PartialEq)] pub struct RsMatch { offset: usize, groups: Vec, } +#[wasm_bindgen(js_name = RsRegex)] +pub struct RsRegex; + #[wasm_bindgen(js_class = RsRegex)] impl RsRegex { #[wasm_bindgen(js_name = isMatch)] @@ -54,7 +57,15 @@ fn matches(regex: &str, text: &str) -> Vec { #[test] fn test_matches() { let text = "![img](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA0AAAAQCAYAAADNo/U5AAAABHNCSVQICAgIfAhkiAAAABl0RVh0U29mdHdhcmUAZ25vbWUtc2NyZWVuc2hvdO8Dvz4AAAAtdEVYdENyZWF0aW9uIFRpbWUARnJpIDE0IEp1bCAyMDIzIDExOjAzOjAwIEFNIENTVCKwI9kAAACwSURBVCiR7dK/DsFwFMXx76WNLrUR7Jq+hcRTGD2C0XuYvISIRYLEKDFLTBYmpP41oaXyM4iIomnMznhOPtO9cvTOilC8yZRZpYpeyGP12uGZxFsTI38UhZT8gCSVumPvFB/p2QwAwWbH9eDGQ8m0iWEXAdi2Oq+jUsinNwJwB0PmtTqIYJZLGLYFvo87Gn9HAPtun1WjyXm+eJYi0eiRYLnm4jiIpqEXcvFQOD8d9wYk9T77dSRnWwAAAABJRU5ErkJggg==)"; - let regex = r#"(!\[.*?]\()(data:image\/.*?,[a-zA-Z0-9+/]*?=?=?)(\))"#; + let regex = r#"(!\[.*?]\()(data:image\/.*?,[a-zA-Z0-9+/]*?=?=?)\)"#; let mgs = matches(regex, text); - println!("{:?}", mgs); + let expect = vec![RsMatch { + offset: 0, + groups: vec![ + "![img](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA0AAAAQCAYAAADNo/U5AAAABHNCSVQICAgIfAhkiAAAABl0RVh0U29mdHdhcmUAZ25vbWUtc2NyZWVuc2hvdO8Dvz4AAAAtdEVYdENyZWF0aW9uIFRpbWUARnJpIDE0IEp1bCAyMDIzIDExOjAzOjAwIEFNIENTVCKwI9kAAACwSURBVCiR7dK/DsFwFMXx76WNLrUR7Jq+hcRTGD2C0XuYvISIRYLEKDFLTBYmpP41oaXyM4iIomnMznhOPtO9cvTOilC8yZRZpYpeyGP12uGZxFsTI38UhZT8gCSVumPvFB/p2QwAwWbH9eDGQ8m0iWEXAdi2Oq+jUsinNwJwB0PmtTqIYJZLGLYFvo87Gn9HAPtun1WjyXm+eJYi0eiRYLnm4jiIpqEXcvFQOD8d9wYk9T77dSRnWwAAAABJRU5ErkJggg==)".to_string(), + "![img](".to_string(), + "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA0AAAAQCAYAAADNo/U5AAAABHNCSVQICAgIfAhkiAAAABl0RVh0U29mdHdhcmUAZ25vbWUtc2NyZWVuc2hvdO8Dvz4AAAAtdEVYdENyZWF0aW9uIFRpbWUARnJpIDE0IEp1bCAyMDIzIDExOjAzOjAwIEFNIENTVCKwI9kAAACwSURBVCiR7dK/DsFwFMXx76WNLrUR7Jq+hcRTGD2C0XuYvISIRYLEKDFLTBYmpP41oaXyM4iIomnMznhOPtO9cvTOilC8yZRZpYpeyGP12uGZxFsTI38UhZT8gCSVumPvFB/p2QwAwWbH9eDGQ8m0iWEXAdi2Oq+jUsinNwJwB0PmtTqIYJZLGLYFvo87Gn9HAPtun1WjyXm+eJYi0eiRYLnm4jiIpqEXcvFQOD8d9wYk9T77dSRnWwAAAABJRU5ErkJggg==".to_string(), + ], + }]; + assert_eq!(mgs, expect); } From a0589146e49ea0c13c8f633d1a8991648e898a5f Mon Sep 17 00:00:00 2001 From: Thaumy Date: Sun, 30 Jul 2023 13:57:48 +0800 Subject: [PATCH 053/157] feat: new http infra --- src/infra/convert/mapToJson.ts | 5 +++++ src/infra/http/get.ts | 30 +++++++++++++++++++++++++++ src/infra/http/infra/consReqHeader.ts | 5 +++++ src/infra/http/infra/consUrlPara.ts | 4 ++++ 4 files changed, 44 insertions(+) create mode 100644 src/infra/convert/mapToJson.ts create mode 100644 src/infra/http/get.ts create mode 100644 src/infra/http/infra/consReqHeader.ts create mode 100644 src/infra/http/infra/consUrlPara.ts diff --git a/src/infra/convert/mapToJson.ts b/src/infra/convert/mapToJson.ts new file mode 100644 index 00000000..28df0682 --- /dev/null +++ b/src/infra/convert/mapToJson.ts @@ -0,0 +1,5 @@ +// eslint-disable-next-line @typescript-eslint/naming-convention +export function mapToJson(map: Map) { + const obj = Object.fromEntries(map) + return JSON.stringify(obj) +} diff --git a/src/infra/http/get.ts b/src/infra/http/get.ts new file mode 100644 index 00000000..5e8ad375 --- /dev/null +++ b/src/infra/http/get.ts @@ -0,0 +1,30 @@ +import { accountManager } from '@/auth/account-manager' +import { RsHttp } from '@/wasm' + +import fetch, { Headers, Request, Response } from 'node-fetch' +import { mapToJson } from '@/infra/convert/mapToJson' + +/* eslint-disable */ +// @ts-ignore +global.fetch = fetch +// @ts-ignore +global.Headers = Headers +// @ts-ignore +global.Request = Request +// @ts-ignore +global.Response = Response +/* eslint-disable */ + +export namespace Http { + export async function noAuthGet(url: string, header: Map) { + const headerJson = mapToJson(header) + return await RsHttp.get(url, headerJson) + } + + export async function get(url: string, header: Map) { + const token = await accountManager.acquireToken() + header.set('Authorization', `Bearer ${token}`) + + return noAuthGet(url, header) + } +} diff --git a/src/infra/http/infra/consReqHeader.ts b/src/infra/http/infra/consReqHeader.ts new file mode 100644 index 00000000..2a086a36 --- /dev/null +++ b/src/infra/http/infra/consReqHeader.ts @@ -0,0 +1,5 @@ +export function consReqHeader(...kvs: [string, string][]) { + const header = new Map() + kvs.forEach(([k, v]) => header.set(k, v)) + return header +} diff --git a/src/infra/http/infra/consUrlPara.ts b/src/infra/http/infra/consUrlPara.ts new file mode 100644 index 00000000..65cdb984 --- /dev/null +++ b/src/infra/http/infra/consUrlPara.ts @@ -0,0 +1,4 @@ +export function consUrlPara(...kvs: [string, string][]) { + const para = new URLSearchParams(kvs) + return para.toString() +} From 2c6ac5a80144f9a0c829ba88f7fda3634a33bf77 Mon Sep 17 00:00:00 2001 From: Thaumy Date: Sun, 30 Jul 2023 13:58:47 +0800 Subject: [PATCH 054/157] refactor: get req --- package-lock.json | 159 +++++++++++++++++++++++++--- package.json | 1 + src/auth/auth-provider.ts | 2 +- src/service/ing.api.ts | 68 +++++------- src/service/oauth.api.ts | 23 ++-- src/service/post.ts | 44 ++++---- src/service/search-post-by-title.ts | 3 + 7 files changed, 202 insertions(+), 98 deletions(-) diff --git a/package-lock.json b/package-lock.json index b4739722..83900f98 100644 --- a/package-lock.json +++ b/package-lock.json @@ -30,6 +30,7 @@ "markdown-it-table-of-contents": "^0.6.0", "mime-types": "^2.1.34", "node-abort-controller": "^3.1.1", + "node-fetch": "^3.3.2", "puppeteer-core": "^13.5.1", "randomstring": "^1.1.4", "react": "^17.0.2", @@ -1810,6 +1811,25 @@ "semver": "bin/semver.js" } }, + "node_modules/@mapbox/node-pre-gyp/node_modules/node-fetch": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.12.tgz", + "integrity": "sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, "node_modules/@microsoft/load-themed-styles": { "version": "1.10.249", "resolved": "https://registry.npmjs.org/@microsoft/load-themed-styles/-/load-themed-styles-1.10.249.tgz", @@ -4206,6 +4226,14 @@ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.11.tgz", "integrity": "sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw==" }, + "node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "engines": { + "node": ">= 12" + } + }, "node_modules/date-fns": { "version": "2.28.0", "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.28.0.tgz", @@ -5217,6 +5245,28 @@ "pend": "~1.2.0" } }, + "node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -5353,6 +5403,17 @@ "node": ">= 14.17" } }, + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -7850,23 +7911,39 @@ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz", "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==" }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "engines": { + "node": ">=10.5.0" + } + }, "node_modules/node-fetch": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.9.tgz", - "integrity": "sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", "dependencies": { - "whatwg-url": "^5.0.0" + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" }, "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" } }, "node_modules/node-gyp": { @@ -13942,6 +14019,14 @@ "node": ">=10.13.0" } }, + "node_modules/web-streams-polyfill": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", + "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==", + "engines": { + "node": ">= 8" + } + }, "node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", @@ -15665,6 +15750,14 @@ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" } } + }, + "node-fetch": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.12.tgz", + "integrity": "sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g==", + "requires": { + "whatwg-url": "^5.0.0" + } } } }, @@ -17509,6 +17602,11 @@ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.11.tgz", "integrity": "sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw==" }, + "data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==" + }, "date-fns": { "version": "2.28.0", "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.28.0.tgz", @@ -18307,6 +18405,15 @@ "pend": "~1.2.0" } }, + "fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "requires": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + } + }, "file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -18414,6 +18521,14 @@ "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.4.tgz", "integrity": "sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==" }, + "formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "requires": { + "fetch-blob": "^3.1.2" + } + }, "forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -20293,12 +20408,19 @@ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz", "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==" }, + "node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==" + }, "node-fetch": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.9.tgz", - "integrity": "sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", "requires": { - "whatwg-url": "^5.0.0" + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" } }, "node-gyp": { @@ -24437,6 +24559,11 @@ "graceful-fs": "^4.1.2" } }, + "web-streams-polyfill": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", + "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==" + }, "webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", diff --git a/package.json b/package.json index a0d580df..6e0e5c44 100644 --- a/package.json +++ b/package.json @@ -1396,6 +1396,7 @@ "markdown-it-table-of-contents": "^0.6.0", "mime-types": "^2.1.34", "node-abort-controller": "^3.1.1", + "node-fetch": "^3.3.2", "puppeteer-core": "^13.5.1", "randomstring": "^1.1.4", "react": "^17.0.2", diff --git a/src/auth/auth-provider.ts b/src/auth/auth-provider.ts index 3a3d7862..ba39bb34 100644 --- a/src/auth/auth-provider.ts +++ b/src/auth/auth-provider.ts @@ -211,7 +211,7 @@ export class AuthProvider implements AuthenticationProvider, Disposable { try { onStateChange?.('正在获取账户信息...') - const spec = await ifNotCancelledThen(() => Oauth.fetchUserInfo(accessToken, cancelToken)) + const spec = await Oauth.fetchUserInfo(accessToken) onStateChange?.('即将完成...') diff --git a/src/service/ing.api.ts b/src/service/ing.api.ts index 32070b9a..bca34854 100644 --- a/src/service/ing.api.ts +++ b/src/service/ing.api.ts @@ -2,8 +2,17 @@ import { Ing, IngComment, IngPublishModel, IngType } from '@/model/ing' import { Alert } from '@/infra/alert' import { globalCtx } from '@/ctx/global-ctx' import fetch from '@/infra/fetch-client' -import { URLSearchParams } from 'url' -import { isArray, isObject } from 'lodash-es' +import { Http } from '@/infra/http/get' +import { consReqHeader } from '@/infra/http/infra/consReqHeader' +import { consUrlPara } from '@/infra/http/infra/consUrlPara' + +async function getIngComment(id: number) { + const url = `${globalCtx.config.cnblogsOpenApiUrl}/api/statuses/${id}/comments` + const header = consReqHeader(['Content-Type', 'application/json']) + const resp = await Http.get(url, header) + const list = JSON.parse(resp) as [] + return list.map(IngComment.parse) +} export namespace IngApi { export async function publishIng(ing: IngPublishModel): Promise { @@ -20,53 +29,32 @@ export namespace IngApi { } export async function list({ pageIndex = 1, pageSize = 30, type = IngType.all } = {}) { - const res = await fetch( - `${globalCtx.config.cnblogsOpenApiUrl}/api/statuses/@${type}?${new URLSearchParams({ - pageIndex: `${pageIndex}`, - pageSize: `${pageSize}`, - }).toString()}`, - { - method: 'GET', - headers: [['Content-Type', 'application/json']], - } - ).catch(e => void Alert.warn(JSON.stringify(e))) - - if (!res || !res.ok) { - void Alert.err(`获取闪存列表失败, ${res?.statusText ?? ''} ${JSON.stringify((await res?.text()) ?? '')}`) - return [] - } + const para = consUrlPara(['pageIndex', `${pageIndex}`], ['pageSize', `${pageSize}`]) + const header = consReqHeader(['Content-Type', 'application/json']) - const arr = await res.json() + const url = `${globalCtx.config.cnblogsOpenApiUrl}/api/statuses/@${type}?${para}` + let list: Ing[] try { - if (isArray(arr) && arr.every(isObject)) return arr.map(Ing.parse) - void Alert.err('获取闪存列表失败, 无法读取响应') + const resp = await Http.get(url, header) + const arr = JSON.parse(resp) as unknown[] + list = arr.map(Ing.parse) } catch (e) { - void Alert.err(JSON.stringify(e)) + // eslint-disable-next-line @typescript-eslint/restrict-template-expressions + void Alert.err(`获取闪存列表失败: ${e}`) + list = [] } - return [] + return list } export async function listComments(...ingIds: number[]) { - const tasks = ingIds.map(id => - fetch(`${globalCtx.config.cnblogsOpenApiUrl}/api/statuses/${id}/comments`, { - method: 'GET', - headers: [['Content-Type', 'application/json']], - }).then( - resp => - resp?.json().then(obj => [id, obj as IngComment[] | null | undefined] as const) ?? - Promise.resolve(undefined), - reason => void Alert.warn(JSON.stringify(reason)) - ) - ) - - const results = await Promise.all(tasks) - - return results.reduce>((p, v) => { - if (v) p[v[0]] = (v[1] ?? []).map(IngComment.parse) - return p - }, {}) + const futList = ingIds.map(async id => { + const comment = await getIngComment(id) + return { [id]: comment } + }) + const resList = await Promise.all(futList) + return resList.reduce((acc, it) => Object.assign(it, acc), {}) } export async function comment( diff --git a/src/service/oauth.api.ts b/src/service/oauth.api.ts index e9039ab5..7de26200 100644 --- a/src/service/oauth.api.ts +++ b/src/service/oauth.api.ts @@ -7,6 +7,8 @@ import got from '@/infra/http-client' import { CancellationToken } from 'vscode' import { AbortController } from 'node-abort-controller' import { objectKeysToCamelCase } from '@/infra/convert/object-keys-to-camel-case' +import { Http } from '@/infra/http/get' +import { consReqHeader } from '@/infra/http/infra/consReqHeader' export type UserInfoSpec = Pick & { readonly blog_id: string @@ -48,25 +50,14 @@ export namespace Oauth { ) } - export async function fetchUserInfo(token: string, cancelToken?: CancellationToken) { + export async function fetchUserInfo(token: string) { const { authority, userInfoEndpoint } = globalCtx.config.oauth - const abortController = new AbortController() - if (cancelToken?.isCancellationRequested) abortController.abort() + const url = `${authority}${userInfoEndpoint}` + const header = consReqHeader(['Authorization', `Bearer ${token}`]) + const resp = await Http.noAuthGet(url, header) - const cancelSub = cancelToken?.onCancellationRequested(() => abortController.abort()) - - const res = await got(`${authority}${userInfoEndpoint}`, { - method: 'GET', - // eslint-disable-next-line @typescript-eslint/naming-convention - headers: { Authorization: `Bearer ${token}` }, - signal: abortController.signal, - responseType: 'json', - }).finally(() => { - cancelSub?.dispose() - }) - - return res.body + return JSON.parse(resp) as UserInfoSpec } export async function revokeToken(token: string) { diff --git a/src/service/post.ts b/src/service/post.ts index a67a4695..6b2a1bdd 100644 --- a/src/service/post.ts +++ b/src/service/post.ts @@ -15,43 +15,37 @@ import { MarkdownCfg } from '@/ctx/cfg/markdown' import { rmYfm } from '@/infra/filter/rm-yfm' import { PostListState } from '@/model/post-list-state' import { Alert } from '@/infra/alert' +import { Http } from '@/infra/http/get' +import { consUrlPara } from '@/infra/http/infra/consUrlPara' +import { consReqHeader } from '@/infra/http/infra/consReqHeader' let newPostTemplate: PostEditDto | undefined -export namespace PostService { - const getBaseUrl = () => globalCtx.config.apiBaseUrl +const getBaseUrl = () => globalCtx.config.apiBaseUrl +export namespace PostService { export const getPostListState = () => globalCtx.storage.get('postListState') - export async function fetchPostList({ - search = '', - pageIndex = 1, - pageSize = 30, - categoryId = null, - }) { - const s = new URLSearchParams([ + export async function fetchPostList({ search = '', pageIndex = 1, pageSize = 30, categoryId = <'' | number>'' }) { + const para = consUrlPara( ['t', '1'], - ['p', `${pageIndex}`], - ['s', `${pageSize}`], + ['p', pageIndex.toString()], + ['s', pageSize.toString()], ['search', search], - ['cid', categoryId != null && categoryId > 0 ? `${categoryId}` : ''], - ]) - const response = await fetch(`${getBaseUrl()}/api/posts/list?${s.toString()}`, { - method: 'GET', - }) - if (!response.ok) throw Error(`请求博文列表失败: ${response.status}, ${await response.text()}`) - - const obj = await response.json() - const { zzkSearchResult } = obj + ['cid', categoryId.toString()] + ) + const url = `${getBaseUrl()}/api/posts/list?${para}` + const resp = await Http.get(url, consReqHeader()) + const model = await JSON.parse(resp) return Object.assign( new PageModel( - obj.pageIndex, - obj.pageSize, - obj.postCount, - obj.postList.map(x => Object.assign(new Post(), x)) + model.pageIndex, + model.pageSize, + model.postCount, + model.postList.map(x => Object.assign(new Post(), x)) ), - { zzkSearchResult: ZzkSearchResult.parse(zzkSearchResult) || undefined } + { zzkSearchResult: ZzkSearchResult.parse(model.zzkSearchResult) || undefined } ) } diff --git a/src/service/search-post-by-title.ts b/src/service/search-post-by-title.ts index ca4f1457..ff3b9ef7 100644 --- a/src/service/search-post-by-title.ts +++ b/src/service/search-post-by-title.ts @@ -30,6 +30,9 @@ export const searchPostByTitle = ({ postTitle = '', quickPickTitle = '按标题 const paged = await PostService.fetchPostList({ search: value }) const pickItems = paged.items.map(p => new PostPickItem(p)) if (value === quickPick.value) quickPick.items = pickItems + } catch (e) { + // eslint-disable-next-line @typescript-eslint/restrict-template-expressions + throw Error(`请求博文列表失败: ${e}`) } finally { quickPick.busy = false } From be836f9e63fbd14424120899b51ae13117d8d618 Mon Sep 17 00:00:00 2001 From: Thaumy Date: Sun, 30 Jul 2023 14:29:05 +0800 Subject: [PATCH 055/157] feat: http post --- rs/src/http.rs | 22 ++++++++++++++++++++++ rs/src/http/get.rs | 19 +++++-------------- rs/src/http/post.rs | 28 ++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 14 deletions(-) create mode 100644 rs/src/http/post.rs diff --git a/rs/src/http.rs b/rs/src/http.rs index 125ca70d..2a60c257 100644 --- a/rs/src/http.rs +++ b/rs/src/http.rs @@ -1 +1,23 @@ pub mod get; +pub mod post; + +use alloc::string::String; +use core::convert::TryFrom; +use core::str::FromStr; +use reqwest::header::HeaderMap; +use serde_json::Value; +use wasm_bindgen::prelude::*; +use anyhow::Result; +use wasm_bindgen::__rt::std::collections::HashMap; +use crate::infra::result::IntoResult; + +#[wasm_bindgen(js_name = RsHttp)] +pub struct RsHttp; + +fn header_json_to_header_map(header_json: &str) -> Result { + let header_json = Value::from_str(header_json)?; + let header = serde_json::from_value::>(header_json)?; + let header_map = HeaderMap::try_from(&header)?; + + header_map.into_ok() +} \ No newline at end of file diff --git a/rs/src/http/get.rs b/rs/src/http/get.rs index 21857512..883b1ee0 100644 --- a/rs/src/http/get.rs +++ b/rs/src/http/get.rs @@ -1,16 +1,9 @@ +use crate::http::{header_json_to_header_map, RsHttp}; use crate::infra::result::IntoResult; use alloc::string::{String, ToString}; use anyhow::Result; -use core::convert::TryFrom; -use core::str::FromStr; -use reqwest::header::HeaderMap; -use serde_json::Value; -use wasm_bindgen::__rt::std::collections::HashMap; use wasm_bindgen::prelude::wasm_bindgen; -#[wasm_bindgen(js_name = RsHttp)] -struct RsHttp; - #[wasm_bindgen(js_class = RsHttp)] impl RsHttp { #[wasm_bindgen(js_name = get)] @@ -18,20 +11,18 @@ impl RsHttp { let body = get(url, header_json).await; let Ok(body) = body else { return body.unwrap_err().to_string().into_err(); }; - Ok(body) + body.into_ok() } } async fn get(url: &str, header_json: &str) -> Result { - let header_json = Value::from_str(header_json)?; - let header = serde_json::from_value::>(header_json)?; - let header = HeaderMap::try_from(&header)?; + let header_map = header_json_to_header_map(header_json)?; let client = reqwest::Client::new(); - let resp = client.get(url).headers(header).send().await?; + let resp = client.get(url).headers(header_map).send().await?; let body = resp.text().await?; - Ok(body) + body.into_ok() } diff --git a/rs/src/http/post.rs b/rs/src/http/post.rs new file mode 100644 index 00000000..553bc30b --- /dev/null +++ b/rs/src/http/post.rs @@ -0,0 +1,28 @@ +use crate::http::{header_json_to_header_map, RsHttp}; +use crate::infra::result::IntoResult; +use alloc::string::{String, ToString}; +use anyhow::Result; +use wasm_bindgen::prelude::wasm_bindgen; + +#[wasm_bindgen(js_class = RsHttp)] +impl RsHttp { + #[wasm_bindgen(js_name = post)] + pub async fn export_post(url: &str, body: String, header_json: &str) -> Result { + let body = post(url, body, header_json).await; + let Ok(body) = body else { return body.unwrap_err().to_string().into_err(); }; + + body.into_ok() + } +} + +async fn post(url: &str, body: String, header_json: &str) -> Result { + let header_map = header_json_to_header_map(header_json)?; + + let client = reqwest::Client::new(); + + let resp = client.post(url).headers(header_map).body(body).send().await?; + + let body = resp.text().await?; + + body.into_ok() +} From e950bd5c1dbd0406eff79b4565b77c40b91f2d48 Mon Sep 17 00:00:00 2001 From: Thaumy Date: Sun, 30 Jul 2023 14:53:53 +0800 Subject: [PATCH 056/157] feat: http delete --- rs/src/http.rs | 1 + rs/src/http/delete.rs | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 rs/src/http/delete.rs diff --git a/rs/src/http.rs b/rs/src/http.rs index 2a60c257..ac3af681 100644 --- a/rs/src/http.rs +++ b/rs/src/http.rs @@ -1,5 +1,6 @@ pub mod get; pub mod post; +pub mod delete; use alloc::string::String; use core::convert::TryFrom; diff --git a/rs/src/http/delete.rs b/rs/src/http/delete.rs new file mode 100644 index 00000000..d26771f2 --- /dev/null +++ b/rs/src/http/delete.rs @@ -0,0 +1,28 @@ +use crate::http::{header_json_to_header_map, RsHttp}; +use crate::infra::result::IntoResult; +use alloc::string::{String, ToString}; +use anyhow::Result; +use wasm_bindgen::prelude::wasm_bindgen; + +#[wasm_bindgen(js_class = RsHttp)] +impl RsHttp { + #[wasm_bindgen(js_name = delete)] + pub async fn export_delete(url: &str, header_json: &str) -> Result { + let body = delete(url, header_json).await; + let Ok(body) = body else { return body.unwrap_err().to_string().into_err(); }; + + body.into_ok() + } +} + +async fn delete(url: &str, header_json: &str) -> Result { + let header_map = header_json_to_header_map(header_json)?; + + let client = reqwest::Client::new(); + + let resp = client.delete(url).headers(header_map).send().await?; + + let body = resp.text().await?; + + body.into_ok() +} From 07d0c4872f0c92c6644fc4b2044705b8235d4147 Mon Sep 17 00:00:00 2001 From: Thaumy Date: Sun, 30 Jul 2023 14:56:55 +0800 Subject: [PATCH 057/157] feat: http put --- rs/src/http.rs | 1 + rs/src/http/put.rs | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 rs/src/http/put.rs diff --git a/rs/src/http.rs b/rs/src/http.rs index ac3af681..c82e5a0e 100644 --- a/rs/src/http.rs +++ b/rs/src/http.rs @@ -1,6 +1,7 @@ pub mod get; pub mod post; pub mod delete; +pub mod put; use alloc::string::String; use core::convert::TryFrom; diff --git a/rs/src/http/put.rs b/rs/src/http/put.rs new file mode 100644 index 00000000..b6854f9e --- /dev/null +++ b/rs/src/http/put.rs @@ -0,0 +1,28 @@ +use crate::http::{header_json_to_header_map, RsHttp}; +use crate::infra::result::IntoResult; +use alloc::string::{String, ToString}; +use anyhow::Result; +use wasm_bindgen::prelude::wasm_bindgen; + +#[wasm_bindgen(js_class = RsHttp)] +impl RsHttp { + #[wasm_bindgen(js_name = put)] + pub async fn export_put(url: &str, body: String, header_json: &str) -> Result { + let body = put(url, body, header_json).await; + let Ok(body) = body else { return body.unwrap_err().to_string().into_err(); }; + + body.into_ok() + } +} + +async fn put(url: &str, body: String, header_json: &str) -> Result { + let header_map = header_json_to_header_map(header_json)?; + + let client = reqwest::Client::new(); + + let resp = client.put(url).headers(header_map).body(body).send().await?; + + let body = resp.text().await?; + + body.into_ok() +} From bd65f4346da2766b5b681ff7c4aff3206da72638 Mon Sep 17 00:00:00 2001 From: Thaumy Date: Sun, 30 Jul 2023 15:27:09 +0800 Subject: [PATCH 058/157] refactor(http): infra --- rs/src/http.rs | 2 +- rs/src/http/{delete.rs => del.rs} | 8 ++-- src/infra/http-client.ts | 5 ++- src/infra/http/authed-req.ts | 35 +++++++++++++++++ src/infra/http/get.ts | 30 -------------- src/infra/http/infra/bearer.ts | 3 ++ .../infra/{consReqHeader.ts => header.ts} | 5 +++ .../http/infra/{consUrlPara.ts => url.ts} | 0 src/infra/http/req.ts | 39 +++++++++++++++++++ src/service/ing.api.ts | 14 +++---- src/service/oauth.api.ts | 12 +++--- src/service/post.ts | 8 ++-- 12 files changed, 106 insertions(+), 55 deletions(-) rename rs/src/http/{delete.rs => del.rs} (70%) create mode 100644 src/infra/http/authed-req.ts delete mode 100644 src/infra/http/get.ts create mode 100644 src/infra/http/infra/bearer.ts rename src/infra/http/infra/{consReqHeader.ts => header.ts} (56%) rename src/infra/http/infra/{consUrlPara.ts => url.ts} (100%) create mode 100644 src/infra/http/req.ts diff --git a/rs/src/http.rs b/rs/src/http.rs index c82e5a0e..03d86492 100644 --- a/rs/src/http.rs +++ b/rs/src/http.rs @@ -1,6 +1,6 @@ pub mod get; pub mod post; -pub mod delete; +pub mod del; pub mod put; use alloc::string::String; diff --git a/rs/src/http/delete.rs b/rs/src/http/del.rs similarity index 70% rename from rs/src/http/delete.rs rename to rs/src/http/del.rs index d26771f2..e6146555 100644 --- a/rs/src/http/delete.rs +++ b/rs/src/http/del.rs @@ -6,16 +6,16 @@ use wasm_bindgen::prelude::wasm_bindgen; #[wasm_bindgen(js_class = RsHttp)] impl RsHttp { - #[wasm_bindgen(js_name = delete)] - pub async fn export_delete(url: &str, header_json: &str) -> Result { - let body = delete(url, header_json).await; + #[wasm_bindgen(js_name = del)] + pub async fn export_del(url: &str, header_json: &str) -> Result { + let body = del(url, header_json).await; let Ok(body) = body else { return body.unwrap_err().to_string().into_err(); }; body.into_ok() } } -async fn delete(url: &str, header_json: &str) -> Result { +async fn del(url: &str, header_json: &str) -> Result { let header_map = header_json_to_header_map(header_json)?; let client = reqwest::Client::new(); diff --git a/src/infra/http-client.ts b/src/infra/http-client.ts index 4d31273d..89e10492 100644 --- a/src/infra/http-client.ts +++ b/src/infra/http-client.ts @@ -2,17 +2,18 @@ import { accountManager } from '@/auth/account-manager' import got, { BeforeRequestHook } from 'got' import { isString } from 'lodash-es' import { Oauth } from '@/service/oauth.api' +import { ReqHeaderKey } from "@/infra/http/infra/header"; const bearerTokenHook: BeforeRequestHook = async opt => { const { headers } = opt const headerKeys = Object.keys(headers) - const keyIndex = headerKeys.findIndex(x => x.toLowerCase() === Oauth.AuthHeaderKey.toLowerCase()) + const keyIndex = headerKeys.findIndex(x => x.toLowerCase() === ReqHeaderKey.AUTHORIZATION.toLowerCase()) if (keyIndex < 0) { const token = await accountManager.acquireToken() - if (isString(token)) headers[Oauth.AuthHeaderKey] = `Bearer ${token}` + if (isString(token)) headers[ReqHeaderKey.AUTHORIZATION] = `Bearer ${token}` } } diff --git a/src/infra/http/authed-req.ts b/src/infra/http/authed-req.ts new file mode 100644 index 00000000..232b433e --- /dev/null +++ b/src/infra/http/authed-req.ts @@ -0,0 +1,35 @@ +import { accountManager } from '@/auth/account-manager' + +import { ReqHeaderKey } from '@/infra/http/infra/header' +import { bearer } from '@/infra/http/infra/bearer' +import { Req } from '@/infra/http/req' + +export namespace AuthedReq { + export async function put(url: string, body: string, header: Map) { + const token = await accountManager.acquireToken() + header.set(ReqHeaderKey.AUTHORIZATION, bearer(token)) + + return Req.put(url, body, header) + } + + export async function del(url: string, header: Map) { + const token = await accountManager.acquireToken() + header.set(ReqHeaderKey.AUTHORIZATION, bearer(token)) + + return Req.del(url, header) + } + + export async function post(url: string, body: string, header: Map) { + const token = await accountManager.acquireToken() + header.set(ReqHeaderKey.AUTHORIZATION, bearer(token)) + + return Req.post(url, body, header) + } + + export async function get(url: string, header: Map) { + const token = await accountManager.acquireToken() + header.set(ReqHeaderKey.AUTHORIZATION, bearer(token)) + + return Req.get(url, header) + } +} diff --git a/src/infra/http/get.ts b/src/infra/http/get.ts deleted file mode 100644 index 5e8ad375..00000000 --- a/src/infra/http/get.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { accountManager } from '@/auth/account-manager' -import { RsHttp } from '@/wasm' - -import fetch, { Headers, Request, Response } from 'node-fetch' -import { mapToJson } from '@/infra/convert/mapToJson' - -/* eslint-disable */ -// @ts-ignore -global.fetch = fetch -// @ts-ignore -global.Headers = Headers -// @ts-ignore -global.Request = Request -// @ts-ignore -global.Response = Response -/* eslint-disable */ - -export namespace Http { - export async function noAuthGet(url: string, header: Map) { - const headerJson = mapToJson(header) - return await RsHttp.get(url, headerJson) - } - - export async function get(url: string, header: Map) { - const token = await accountManager.acquireToken() - header.set('Authorization', `Bearer ${token}`) - - return noAuthGet(url, header) - } -} diff --git a/src/infra/http/infra/bearer.ts b/src/infra/http/infra/bearer.ts new file mode 100644 index 00000000..3ebeabbb --- /dev/null +++ b/src/infra/http/infra/bearer.ts @@ -0,0 +1,3 @@ +export function bearer(token: string) { + return `Bearer ${token}` +} diff --git a/src/infra/http/infra/consReqHeader.ts b/src/infra/http/infra/header.ts similarity index 56% rename from src/infra/http/infra/consReqHeader.ts rename to src/infra/http/infra/header.ts index 2a086a36..b60eae41 100644 --- a/src/infra/http/infra/consReqHeader.ts +++ b/src/infra/http/infra/header.ts @@ -1,3 +1,8 @@ +export namespace ReqHeaderKey { + export const CONTENT_TYPE = 'Content-Type' + export const AUTHORIZATION = 'Authorization' +} + export function consReqHeader(...kvs: [string, string][]) { const header = new Map() kvs.forEach(([k, v]) => header.set(k, v)) diff --git a/src/infra/http/infra/consUrlPara.ts b/src/infra/http/infra/url.ts similarity index 100% rename from src/infra/http/infra/consUrlPara.ts rename to src/infra/http/infra/url.ts diff --git a/src/infra/http/req.ts b/src/infra/http/req.ts new file mode 100644 index 00000000..51e186b0 --- /dev/null +++ b/src/infra/http/req.ts @@ -0,0 +1,39 @@ +import { RsHttp } from '@/wasm' + +import fetch, { Headers, Request, Response } from 'node-fetch' +import { mapToJson } from '@/infra/convert/mapToJson' + +/* eslint-disable */ +// @ts-ignore +global.fetch = fetch +// @ts-ignore +global.Headers = Headers +// @ts-ignore +global.Request = Request +// @ts-ignore +global.Response = Response +/* eslint-disable */ + +type Header = Map + +export namespace Req { + export function put(url: string, body: string, header: Header) { + const headerJson = mapToJson(header) + return RsHttp.put(url, body, headerJson) + } + + export function del(url: string, header: Header) { + const headerJson = mapToJson(header) + return RsHttp.del(url, headerJson) + } + + export function post(url: string, body: string, header: Header) { + const headerJson = mapToJson(header) + return RsHttp.post(url, body, headerJson) + } + + export function get(url: string, header: Header) { + const headerJson = mapToJson(header) + return RsHttp.get(url, headerJson) + } +} diff --git a/src/service/ing.api.ts b/src/service/ing.api.ts index bca34854..14ccd9c1 100644 --- a/src/service/ing.api.ts +++ b/src/service/ing.api.ts @@ -2,14 +2,14 @@ import { Ing, IngComment, IngPublishModel, IngType } from '@/model/ing' import { Alert } from '@/infra/alert' import { globalCtx } from '@/ctx/global-ctx' import fetch from '@/infra/fetch-client' -import { Http } from '@/infra/http/get' -import { consReqHeader } from '@/infra/http/infra/consReqHeader' -import { consUrlPara } from '@/infra/http/infra/consUrlPara' +import { consUrlPara } from '@/infra/http/infra/url' +import { consReqHeader, ReqHeaderKey } from '@/infra/http/infra/header' +import { AuthedReq } from '@/infra/http/authed-req' async function getIngComment(id: number) { const url = `${globalCtx.config.cnblogsOpenApiUrl}/api/statuses/${id}/comments` - const header = consReqHeader(['Content-Type', 'application/json']) - const resp = await Http.get(url, header) + const header = consReqHeader([ReqHeaderKey.CONTENT_TYPE, 'application/json']) + const resp = await AuthedReq.get(url, header) const list = JSON.parse(resp) as [] return list.map(IngComment.parse) } @@ -30,13 +30,13 @@ export namespace IngApi { export async function list({ pageIndex = 1, pageSize = 30, type = IngType.all } = {}) { const para = consUrlPara(['pageIndex', `${pageIndex}`], ['pageSize', `${pageSize}`]) - const header = consReqHeader(['Content-Type', 'application/json']) + const header = consReqHeader([ReqHeaderKey.CONTENT_TYPE, 'application/json']) const url = `${globalCtx.config.cnblogsOpenApiUrl}/api/statuses/@${type}?${para}` let list: Ing[] try { - const resp = await Http.get(url, header) + const resp = await AuthedReq.get(url, header) const arr = JSON.parse(resp) as unknown[] list = arr.map(Ing.parse) } catch (e) { diff --git a/src/service/oauth.api.ts b/src/service/oauth.api.ts index 7de26200..44499fb3 100644 --- a/src/service/oauth.api.ts +++ b/src/service/oauth.api.ts @@ -7,8 +7,8 @@ import got from '@/infra/http-client' import { CancellationToken } from 'vscode' import { AbortController } from 'node-abort-controller' import { objectKeysToCamelCase } from '@/infra/convert/object-keys-to-camel-case' -import { Http } from '@/infra/http/get' -import { consReqHeader } from '@/infra/http/infra/consReqHeader' +import { consReqHeader, ReqHeaderKey } from '@/infra/http/infra/header' +import { Req } from '@/infra/http/req' export type UserInfoSpec = Pick & { readonly blog_id: string @@ -17,8 +17,6 @@ export type UserInfoSpec = Pick & { } export namespace Oauth { - export const AuthHeaderKey = 'Authorization' - export async function fetchToken(verifyCode: string, authCode: string, cancelToken?: CancellationToken) { const abortControl = new AbortController() if (cancelToken?.isCancellationRequested) abortControl.abort() @@ -39,7 +37,7 @@ export namespace Oauth { responseType: 'json', signal: abortControl.signal, headers: { - [AuthHeaderKey]: '', + [ReqHeaderKey.AUTHORIZATION]: '', }, }) @@ -54,8 +52,8 @@ export namespace Oauth { const { authority, userInfoEndpoint } = globalCtx.config.oauth const url = `${authority}${userInfoEndpoint}` - const header = consReqHeader(['Authorization', `Bearer ${token}`]) - const resp = await Http.noAuthGet(url, header) + const header = consReqHeader([ReqHeaderKey.AUTHORIZATION, `Bearer ${token}`]) + const resp = await Req.get(url, header) return JSON.parse(resp) as UserInfoSpec } diff --git a/src/service/post.ts b/src/service/post.ts index 6b2a1bdd..56987cae 100644 --- a/src/service/post.ts +++ b/src/service/post.ts @@ -15,9 +15,9 @@ import { MarkdownCfg } from '@/ctx/cfg/markdown' import { rmYfm } from '@/infra/filter/rm-yfm' import { PostListState } from '@/model/post-list-state' import { Alert } from '@/infra/alert' -import { Http } from '@/infra/http/get' -import { consUrlPara } from '@/infra/http/infra/consUrlPara' -import { consReqHeader } from '@/infra/http/infra/consReqHeader' +import { consUrlPara } from '@/infra/http/infra/url' +import { consReqHeader } from '@/infra/http/infra/header' +import { AuthedReq } from '@/infra/http/authed-req' let newPostTemplate: PostEditDto | undefined @@ -35,7 +35,7 @@ export namespace PostService { ['cid', categoryId.toString()] ) const url = `${getBaseUrl()}/api/posts/list?${para}` - const resp = await Http.get(url, consReqHeader()) + const resp = await AuthedReq.get(url, consReqHeader()) const model = await JSON.parse(resp) return Object.assign( From d0241906045f553fcb640bd158328f4430d26d79 Mon Sep 17 00:00:00 2001 From: Thaumy Date: Sun, 30 Jul 2023 19:13:12 +0800 Subject: [PATCH 059/157] refactor: http post req --- src/cmd/ing/comment-ing.ts | 2 +- src/cmd/ing/publish-ing.ts | 2 +- src/service/ing.api.ts | 38 ++++++++++++++++-------------------- src/service/oauth.api.ts | 27 ++++++++++++++----------- src/service/post-category.ts | 26 ++++++++++++------------ 5 files changed, 48 insertions(+), 47 deletions(-) diff --git a/src/cmd/ing/comment-ing.ts b/src/cmd/ing/comment-ing.ts index 70ea73c6..f61efdd6 100644 --- a/src/cmd/ing/comment-ing.ts +++ b/src/cmd/ing/comment-ing.ts @@ -29,7 +29,7 @@ export class CommentIngCmdHandler implements CmdHandler { if (this._content) { return window.withProgress( - { location: ProgressLocation.Notification, title: '正在发表评论, 请稍后...' }, + { location: ProgressLocation.Notification, title: '正在请求...' }, p => { p.report({ increment: 30 }) return IngApi.comment(this._ingId, { diff --git a/src/cmd/ing/publish-ing.ts b/src/cmd/ing/publish-ing.ts index 9e496d24..86337140 100644 --- a/src/cmd/ing/publish-ing.ts +++ b/src/cmd/ing/publish-ing.ts @@ -85,7 +85,7 @@ export class PublishIngCmdHandler implements CmdHandler { private async publish(model: IngPublishModel): Promise { return this.onPublished( - await window.withProgress({ location: ProgressLocation.Notification, title: '正在发闪, 请稍候...' }, p => { + await window.withProgress({ location: ProgressLocation.Notification, title: '正在发布...' }, p => { p.report({ increment: 30 }) return IngApi.publishIng(model).then(isPublished => { p.report({ increment: 70 }) diff --git a/src/service/ing.api.ts b/src/service/ing.api.ts index 14ccd9c1..35a8c7cb 100644 --- a/src/service/ing.api.ts +++ b/src/service/ing.api.ts @@ -16,16 +16,18 @@ async function getIngComment(id: number) { export namespace IngApi { export async function publishIng(ing: IngPublishModel): Promise { - const res = await fetch(`${globalCtx.config.cnblogsOpenApiUrl}/api/statuses`, { - method: 'POST', - body: JSON.stringify(ing), - headers: [['Content-Type', 'application/json']], - }).catch(reason => void Alert.warn(JSON.stringify(reason))) - - if (!res || !res.ok) - void Alert.err(`闪存发布失败, ${res?.statusText ?? ''} ${JSON.stringify((await res?.text()) ?? '')}`) + const url = `${globalCtx.config.cnblogsOpenApiUrl}/api/statuses` + const header = consReqHeader([ReqHeaderKey.CONTENT_TYPE, 'application/json']) + const body = JSON.stringify(ing) - return res != null && res.ok + try { + await AuthedReq.post(url, body, header) + return true + } catch (e) { + // eslint-disable-next-line @typescript-eslint/restrict-template-expressions + void Alert.err(`闪存发布失败: ${e}`) + return false + } } export async function list({ pageIndex = 1, pageSize = 30, type = IngType.all } = {}) { @@ -65,23 +67,17 @@ export namespace IngApi { content: string } ) { - try { - const res = await fetch(`${globalCtx.config.cnblogsOpenApiUrl}/api/statuses/${ingId}/comments`, { - method: 'POST', - headers: [['Content-Type', 'application/json']], - body: JSON.stringify(data), - }) + const url = `${globalCtx.config.cnblogsOpenApiUrl}/api/statuses/${ingId}/comments` + const header = consReqHeader([ReqHeaderKey.CONTENT_TYPE, 'application/json']) + const body = JSON.stringify(data) - if (!res.ok) { - void Alert.err(`发表评论失败, ${await res.text()}`) - return false - } + try { + await AuthedReq.post(url, body, header) + return true } catch (e) { // eslint-disable-next-line @typescript-eslint/restrict-template-expressions void Alert.err(`发表评论失败, ${e}`) return false } - - return true } } diff --git a/src/service/oauth.api.ts b/src/service/oauth.api.ts index 44499fb3..719e94e4 100644 --- a/src/service/oauth.api.ts +++ b/src/service/oauth.api.ts @@ -2,13 +2,14 @@ import { TokenInfo } from '@/model/token-info' import { AccountInfo } from '@/auth/account-info' import { globalCtx } from '@/ctx/global-ctx' -import fetch from '@/infra/fetch-client' import got from '@/infra/http-client' import { CancellationToken } from 'vscode' import { AbortController } from 'node-abort-controller' import { objectKeysToCamelCase } from '@/infra/convert/object-keys-to-camel-case' import { consReqHeader, ReqHeaderKey } from '@/infra/http/infra/header' import { Req } from '@/infra/http/req' +import { AuthedReq } from '@/infra/http/authed-req' +import { Alert } from '@/infra/alert' export type UserInfoSpec = Pick & { readonly blog_id: string @@ -59,20 +60,24 @@ export namespace Oauth { } export async function revokeToken(token: string) { + // FIX: revoke url is deprecated const { clientId, revocationEndpoint, authority } = globalCtx.config.oauth - const body = new URLSearchParams([ - ['client_id', clientId], - ['token', token], - ['token_type_hint', 'access_token'], - ]) const url = `${authority}${revocationEndpoint}` - const res = await fetch(url, { - method: 'POST', - body: body, - headers: [['Content-Type', 'application/x-www-form-urlencoded']], + const header = consReqHeader([ReqHeaderKey.CONTENT_TYPE, 'application/x-www-form-urlencoded']) + const body = JSON.stringify({ + client_id: clientId, + token: token, + token_type_hint: 'access_token', }) - return res.ok + try { + await AuthedReq.post(url, body, header) + return true + } catch (e) { + // eslint-disable-next-line @typescript-eslint/restrict-template-expressions + void Alert.err(`Revoke token 失败: ${e}`) + return false + } } } diff --git a/src/service/post-category.ts b/src/service/post-category.ts index 9bdcbf0f..9b36eee1 100644 --- a/src/service/post-category.ts +++ b/src/service/post-category.ts @@ -2,6 +2,8 @@ import fetch from '@/infra/fetch-client' import { PostCategories, PostCategory, PostCategoryAddDto } from '@/model/post-category' import { globalCtx } from '@/ctx/global-ctx' import { URLSearchParams } from 'url' +import { AuthedReq } from '@/infra/http/authed-req' +import { consReqHeader, ReqHeaderKey } from '@/infra/http/infra/header' let cache: Map | null = null @@ -47,22 +49,20 @@ export namespace PostCategoryService { return Object.assign(new PostCategory(), parent) } - export async function newCategory(categoryAddDto: PostCategoryAddDto) { - const res = await fetch(`${globalCtx.config.apiBaseUrl}/api/category/blog/1`, { - method: 'POST', - body: JSON.stringify(categoryAddDto), - headers: [['Content-Type', 'application/json']], - }) - if (!res.ok) throw Error(`${res.status}-${res.statusText}\n${await res.text()}`) + export async function newCategory(dto: PostCategoryAddDto) { + const url = `${globalCtx.config.apiBaseUrl}/api/category/blog/1` + const header = consReqHeader([ReqHeaderKey.CONTENT_TYPE, 'application/json']) + const body = JSON.stringify(dto) + + await AuthedReq.post(url, body, header) } export async function updateCategory(category: PostCategory) { - const res = await fetch(`${globalCtx.config.apiBaseUrl}/api/category/blog/${category.categoryId}`, { - method: 'PUT', - body: JSON.stringify(category), - headers: [['Content-Type', 'application/json']], - }) - if (!res.ok) throw Error(`${res.status}-${res.statusText}\n${await res.text()}`) + const url = `${globalCtx.config.apiBaseUrl}/api/category/blog/${category.categoryId}` + const header = consReqHeader([ReqHeaderKey.CONTENT_TYPE, 'application/json']) + const body = JSON.stringify(category) + + await AuthedReq.put(url, body, header) } export async function deleteCategory(categoryId: number) { From 614d76894a622ba3b3e8a7918e072555ba659531 Mon Sep 17 00:00:00 2001 From: Thaumy Date: Sun, 30 Jul 2023 20:19:40 +0800 Subject: [PATCH 060/157] feat: handle http err code --- rs/src/http.rs | 22 +++++++++++++++++----- rs/src/http/del.rs | 6 ++---- rs/src/http/get.rs | 6 ++---- rs/src/http/post.rs | 19 +++++++++++-------- rs/src/http/put.rs | 19 +++++++++++-------- src/infra/http/authed-req.ts | 8 ++++---- src/infra/http/req.ts | 8 ++++---- src/service/ing.api.ts | 4 ++-- src/service/oauth.api.ts | 2 +- src/service/post-category.ts | 4 ++-- 10 files changed, 56 insertions(+), 42 deletions(-) diff --git a/rs/src/http.rs b/rs/src/http.rs index 03d86492..c4503757 100644 --- a/rs/src/http.rs +++ b/rs/src/http.rs @@ -1,17 +1,18 @@ +pub mod del; pub mod get; pub mod post; -pub mod del; pub mod put; +use crate::infra::result::IntoResult; use alloc::string::String; +use anyhow::{bail, Result}; use core::convert::TryFrom; use core::str::FromStr; use reqwest::header::HeaderMap; +use reqwest::{Response, StatusCode}; use serde_json::Value; -use wasm_bindgen::prelude::*; -use anyhow::Result; use wasm_bindgen::__rt::std::collections::HashMap; -use crate::infra::result::IntoResult; +use wasm_bindgen::prelude::*; #[wasm_bindgen(js_name = RsHttp)] pub struct RsHttp; @@ -22,4 +23,15 @@ fn header_json_to_header_map(header_json: &str) -> Result { let header_map = HeaderMap::try_from(&header)?; header_map.into_ok() -} \ No newline at end of file +} + +async fn body_or_err(resp: Response) -> Result { + let status = resp.status(); + let body = resp.text().await?; + + if status == StatusCode::OK { + body.into_ok() + } else { + bail!("{}: {}", status, body) + } +} diff --git a/rs/src/http/del.rs b/rs/src/http/del.rs index e6146555..8a97054d 100644 --- a/rs/src/http/del.rs +++ b/rs/src/http/del.rs @@ -1,4 +1,4 @@ -use crate::http::{header_json_to_header_map, RsHttp}; +use crate::http::{body_or_err, header_json_to_header_map, RsHttp}; use crate::infra::result::IntoResult; use alloc::string::{String, ToString}; use anyhow::Result; @@ -22,7 +22,5 @@ async fn del(url: &str, header_json: &str) -> Result { let resp = client.delete(url).headers(header_map).send().await?; - let body = resp.text().await?; - - body.into_ok() + body_or_err(resp).await } diff --git a/rs/src/http/get.rs b/rs/src/http/get.rs index 883b1ee0..7ef24454 100644 --- a/rs/src/http/get.rs +++ b/rs/src/http/get.rs @@ -1,4 +1,4 @@ -use crate::http::{header_json_to_header_map, RsHttp}; +use crate::http::{body_or_err, header_json_to_header_map, RsHttp}; use crate::infra::result::IntoResult; use alloc::string::{String, ToString}; use anyhow::Result; @@ -22,7 +22,5 @@ async fn get(url: &str, header_json: &str) -> Result { let resp = client.get(url).headers(header_map).send().await?; - let body = resp.text().await?; - - body.into_ok() + body_or_err(resp).await } diff --git a/rs/src/http/post.rs b/rs/src/http/post.rs index 553bc30b..fd2d2f32 100644 --- a/rs/src/http/post.rs +++ b/rs/src/http/post.rs @@ -1,4 +1,4 @@ -use crate::http::{header_json_to_header_map, RsHttp}; +use crate::http::{body_or_err, header_json_to_header_map, RsHttp}; use crate::infra::result::IntoResult; use alloc::string::{String, ToString}; use anyhow::Result; @@ -7,22 +7,25 @@ use wasm_bindgen::prelude::wasm_bindgen; #[wasm_bindgen(js_class = RsHttp)] impl RsHttp { #[wasm_bindgen(js_name = post)] - pub async fn export_post(url: &str, body: String, header_json: &str) -> Result { - let body = post(url, body, header_json).await; + pub async fn export_post(url: &str, header_json: &str, body: String) -> Result { + let body = post(url, header_json, body).await; let Ok(body) = body else { return body.unwrap_err().to_string().into_err(); }; body.into_ok() } } -async fn post(url: &str, body: String, header_json: &str) -> Result { +async fn post(url: &str, header_json: &str, body: String) -> Result { let header_map = header_json_to_header_map(header_json)?; let client = reqwest::Client::new(); - let resp = client.post(url).headers(header_map).body(body).send().await?; + let resp = client + .post(url) + .headers(header_map) + .body(body) + .send() + .await?; - let body = resp.text().await?; - - body.into_ok() + body_or_err(resp).await } diff --git a/rs/src/http/put.rs b/rs/src/http/put.rs index b6854f9e..a70f7d56 100644 --- a/rs/src/http/put.rs +++ b/rs/src/http/put.rs @@ -1,4 +1,4 @@ -use crate::http::{header_json_to_header_map, RsHttp}; +use crate::http::{body_or_err, header_json_to_header_map, RsHttp}; use crate::infra::result::IntoResult; use alloc::string::{String, ToString}; use anyhow::Result; @@ -7,22 +7,25 @@ use wasm_bindgen::prelude::wasm_bindgen; #[wasm_bindgen(js_class = RsHttp)] impl RsHttp { #[wasm_bindgen(js_name = put)] - pub async fn export_put(url: &str, body: String, header_json: &str) -> Result { - let body = put(url, body, header_json).await; + pub async fn export_put(url: &str, header_json: &str, body: String) -> Result { + let body = put(url, header_json, body).await; let Ok(body) = body else { return body.unwrap_err().to_string().into_err(); }; body.into_ok() } } -async fn put(url: &str, body: String, header_json: &str) -> Result { +async fn put(url: &str, header_json: &str, body: String) -> Result { let header_map = header_json_to_header_map(header_json)?; let client = reqwest::Client::new(); - let resp = client.put(url).headers(header_map).body(body).send().await?; + let resp = client + .put(url) + .headers(header_map) + .body(body) + .send() + .await?; - let body = resp.text().await?; - - body.into_ok() + body_or_err(resp).await } diff --git a/src/infra/http/authed-req.ts b/src/infra/http/authed-req.ts index 232b433e..86b832c4 100644 --- a/src/infra/http/authed-req.ts +++ b/src/infra/http/authed-req.ts @@ -5,11 +5,11 @@ import { bearer } from '@/infra/http/infra/bearer' import { Req } from '@/infra/http/req' export namespace AuthedReq { - export async function put(url: string, body: string, header: Map) { + export async function put(url: string, header: Map, body: string) { const token = await accountManager.acquireToken() header.set(ReqHeaderKey.AUTHORIZATION, bearer(token)) - return Req.put(url, body, header) + return Req.put(url, header, body) } export async function del(url: string, header: Map) { @@ -19,11 +19,11 @@ export namespace AuthedReq { return Req.del(url, header) } - export async function post(url: string, body: string, header: Map) { + export async function post(url: string, header: Map, body: string) { const token = await accountManager.acquireToken() header.set(ReqHeaderKey.AUTHORIZATION, bearer(token)) - return Req.post(url, body, header) + return Req.post(url, header, body) } export async function get(url: string, header: Map) { diff --git a/src/infra/http/req.ts b/src/infra/http/req.ts index 51e186b0..cbda2cae 100644 --- a/src/infra/http/req.ts +++ b/src/infra/http/req.ts @@ -17,9 +17,9 @@ global.Response = Response type Header = Map export namespace Req { - export function put(url: string, body: string, header: Header) { + export function put(url: string, header: Header, body: string) { const headerJson = mapToJson(header) - return RsHttp.put(url, body, headerJson) + return RsHttp.put(url, headerJson, body) } export function del(url: string, header: Header) { @@ -27,9 +27,9 @@ export namespace Req { return RsHttp.del(url, headerJson) } - export function post(url: string, body: string, header: Header) { + export function post(url: string, header: Header, body: string) { const headerJson = mapToJson(header) - return RsHttp.post(url, body, headerJson) + return RsHttp.post(url, headerJson, body) } export function get(url: string, header: Header) { diff --git a/src/service/ing.api.ts b/src/service/ing.api.ts index 35a8c7cb..0d7ef397 100644 --- a/src/service/ing.api.ts +++ b/src/service/ing.api.ts @@ -21,7 +21,7 @@ export namespace IngApi { const body = JSON.stringify(ing) try { - await AuthedReq.post(url, body, header) + await AuthedReq.post(url, header, body) return true } catch (e) { // eslint-disable-next-line @typescript-eslint/restrict-template-expressions @@ -72,7 +72,7 @@ export namespace IngApi { const body = JSON.stringify(data) try { - await AuthedReq.post(url, body, header) + await AuthedReq.post(url, header, body) return true } catch (e) { // eslint-disable-next-line @typescript-eslint/restrict-template-expressions diff --git a/src/service/oauth.api.ts b/src/service/oauth.api.ts index 719e94e4..c1eed168 100644 --- a/src/service/oauth.api.ts +++ b/src/service/oauth.api.ts @@ -72,7 +72,7 @@ export namespace Oauth { }) try { - await AuthedReq.post(url, body, header) + await AuthedReq.post(url, header, body) return true } catch (e) { // eslint-disable-next-line @typescript-eslint/restrict-template-expressions diff --git a/src/service/post-category.ts b/src/service/post-category.ts index 9b36eee1..c5f374ac 100644 --- a/src/service/post-category.ts +++ b/src/service/post-category.ts @@ -54,7 +54,7 @@ export namespace PostCategoryService { const header = consReqHeader([ReqHeaderKey.CONTENT_TYPE, 'application/json']) const body = JSON.stringify(dto) - await AuthedReq.post(url, body, header) + await AuthedReq.post(url, header, body) } export async function updateCategory(category: PostCategory) { @@ -62,7 +62,7 @@ export namespace PostCategoryService { const header = consReqHeader([ReqHeaderKey.CONTENT_TYPE, 'application/json']) const body = JSON.stringify(category) - await AuthedReq.put(url, body, header) + await AuthedReq.put(url, header, body) } export async function deleteCategory(categoryId: number) { From db2e79e497d1c0639abe725594e735aafe3c6662 Mon Sep 17 00:00:00 2001 From: Thaumy Date: Sun, 30 Jul 2023 20:46:50 +0800 Subject: [PATCH 061/157] refactor: http delete req --- .../post-category/delete-selected-category.ts | 2 +- src/service/post-category.ts | 15 ++++++++---- src/service/post.ts | 24 ++++++++++++------- 3 files changed, 26 insertions(+), 15 deletions(-) diff --git a/src/cmd/post-category/delete-selected-category.ts b/src/cmd/post-category/delete-selected-category.ts index 9c1a35a2..f481a6cc 100644 --- a/src/cmd/post-category/delete-selected-category.ts +++ b/src/cmd/post-category/delete-selected-category.ts @@ -66,7 +66,7 @@ export class DeletePostCategoriesHandler extends BaseMultiSelectablePostCategory const clicked = await Alert.warn( '确定要删除这些博文分类吗', { - detail: `${this.selections.map(x => `📂${x.title}`).join(', ')} 将被永久删除! 请谨慎操作!`, + detail: `${this.selections.map(x => `${x.title}`).join(', ')} 将被删除`, modal: true, } as MessageOptions, ...options diff --git a/src/service/post-category.ts b/src/service/post-category.ts index c5f374ac..6ce3859b 100644 --- a/src/service/post-category.ts +++ b/src/service/post-category.ts @@ -4,6 +4,7 @@ import { globalCtx } from '@/ctx/global-ctx' import { URLSearchParams } from 'url' import { AuthedReq } from '@/infra/http/authed-req' import { consReqHeader, ReqHeaderKey } from '@/infra/http/infra/header' +import { Alert } from '@/infra/alert' let cache: Map | null = null @@ -68,11 +69,15 @@ export namespace PostCategoryService { export async function deleteCategory(categoryId: number) { if (categoryId <= 0) throw Error('Invalid param categoryId') - const res = await fetch(`${globalCtx.config.apiBaseUrl}/api/category/blog/${categoryId}`, { - method: 'DELETE', - headers: [['Content-Type', 'application/json']], - }) - if (!res.ok) throw Error(`${res.status}-${res.statusText}\n${await res.text()}`) + const url = `${globalCtx.config.apiBaseUrl}/api/category/blog/${categoryId}` + const header = consReqHeader([ReqHeaderKey.CONTENT_TYPE, 'application/json']) + + try { + await AuthedReq.del(url, header) + } catch (e) { + // eslint-disable-next-line @typescript-eslint/restrict-template-expressions + void Alert.err(`删除分类失败: ${e}`) + } } export function clearCache() { diff --git a/src/service/post.ts b/src/service/post.ts index 56987cae..c228998c 100644 --- a/src/service/post.ts +++ b/src/service/post.ts @@ -82,16 +82,22 @@ export namespace PostService { export async function deletePost(...postIds: number[]) { if (postIds.length === 1) { - const res = await fetch(`${getBaseUrl()}/api/posts/${postIds[0]}`, { - method: 'DELETE', - }) - if (!res.ok) throw Error(`删除博文失败!\n${res.status}\n${await res.text()}`) + const url = `${getBaseUrl()}/api/posts/${postIds[0]}` + try { + await AuthedReq.del(url, consReqHeader()) + } catch (e) { + // eslint-disable-next-line @typescript-eslint/restrict-template-expressions + void Alert.err(`删除博文失败: ${e}`) + } } else { - const searchParams = new URLSearchParams(postIds.map<[string, string]>(id => ['postIds', `${id}`])) - const res = await fetch(`${getBaseUrl()}/api/bulk-operation/post?${searchParams.toString()}`, { - method: 'DELETE', - }) - if (!res.ok) throw Error(`删除博文失败!\n${res.status}\n${await res.text()}`) + const para = consUrlPara(...postIds.map(id => ['postIds', id.toString()] as [string, string])) + const url = `${getBaseUrl()}/api/bulk-operation/post?${para}` + try { + await AuthedReq.del(url, consReqHeader()) + } catch (e) { + // eslint-disable-next-line @typescript-eslint/restrict-template-expressions + void Alert.err(`删除博文失败: ${e}`) + } } } From 14311c2389108dda8a8a144fb88e8ebcc8996ceb Mon Sep 17 00:00:00 2001 From: Thaumy Date: Sun, 30 Jul 2023 20:47:01 +0800 Subject: [PATCH 062/157] fix: status code check --- rs/src/http.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/rs/src/http.rs b/rs/src/http.rs index c4503757..631595cc 100644 --- a/rs/src/http.rs +++ b/rs/src/http.rs @@ -9,7 +9,7 @@ use anyhow::{bail, Result}; use core::convert::TryFrom; use core::str::FromStr; use reqwest::header::HeaderMap; -use reqwest::{Response, StatusCode}; +use reqwest::Response; use serde_json::Value; use wasm_bindgen::__rt::std::collections::HashMap; use wasm_bindgen::prelude::*; @@ -26,12 +26,12 @@ fn header_json_to_header_map(header_json: &str) -> Result { } async fn body_or_err(resp: Response) -> Result { - let status = resp.status(); + let code = resp.status(); let body = resp.text().await?; - if status == StatusCode::OK { + if code.is_success() { body.into_ok() } else { - bail!("{}: {}", status, body) + bail!("{}: {}", code, body) } } From d9bfacfbd71f391c6eeaab43cc34d5377a761554 Mon Sep 17 00:00:00 2001 From: Thaumy Date: Sun, 30 Jul 2023 21:07:32 +0800 Subject: [PATCH 063/157] refactor: SiteCategoryService --- src/cmd/ing/comment-ing.ts | 19 ++++++------- src/infra/http-client.ts | 3 +- src/model/site-category.ts | 6 +--- src/model/webview-msg.ts | 4 +-- src/service/ing.api.ts | 1 - src/service/post-cfg-panel.ts | 4 +-- src/service/post.ts | 1 - src/service/site-category.ts | 28 +++++++++++-------- .../components/SiteCategorySelector.tsx | 4 +-- ui/post-cfg/service/site-category-store.ts | 8 +++--- 10 files changed, 37 insertions(+), 41 deletions(-) diff --git a/src/cmd/ing/comment-ing.ts b/src/cmd/ing/comment-ing.ts index f61efdd6..97f33037 100644 --- a/src/cmd/ing/comment-ing.ts +++ b/src/cmd/ing/comment-ing.ts @@ -28,17 +28,14 @@ export class CommentIngCmdHandler implements CmdHandler { const atContent = atUserAlias ? `@${atUserAlias} ` : '' if (this._content) { - return window.withProgress( - { location: ProgressLocation.Notification, title: '正在请求...' }, - p => { - p.report({ increment: 30 }) - return IngApi.comment(this._ingId, { - replyTo: atUserId, - content: atContent + this._content, - parentCommentId: this._parentCommentId ?? 0, - }).then(hasCommented => (hasCommented ? this.onCommented() : undefined)) - } - ) + return window.withProgress({ location: ProgressLocation.Notification, title: '正在请求...' }, p => { + p.report({ increment: 30 }) + return IngApi.comment(this._ingId, { + replyTo: atUserId, + content: atContent + this._content, + parentCommentId: this._parentCommentId ?? 0, + }).then(hasCommented => (hasCommented ? this.onCommented() : undefined)) + }) } } diff --git a/src/infra/http-client.ts b/src/infra/http-client.ts index 89e10492..19a726b4 100644 --- a/src/infra/http-client.ts +++ b/src/infra/http-client.ts @@ -1,8 +1,7 @@ import { accountManager } from '@/auth/account-manager' import got, { BeforeRequestHook } from 'got' import { isString } from 'lodash-es' -import { Oauth } from '@/service/oauth.api' -import { ReqHeaderKey } from "@/infra/http/infra/header"; +import { ReqHeaderKey } from '@/infra/http/infra/header' const bearerTokenHook: BeforeRequestHook = async opt => { const { headers } = opt diff --git a/src/model/site-category.ts b/src/model/site-category.ts index c519642b..5fedc9bb 100644 --- a/src/model/site-category.ts +++ b/src/model/site-category.ts @@ -1,10 +1,6 @@ -class SiteCategory { +export class SiteCategory { id = -1 title = '' parentId = -1 children: SiteCategory[] = [] } - -type SiteCategories = SiteCategory[] - -export { SiteCategory, SiteCategories } diff --git a/src/model/webview-msg.ts b/src/model/webview-msg.ts index 49fd2b14..83456f77 100644 --- a/src/model/webview-msg.ts +++ b/src/model/webview-msg.ts @@ -2,10 +2,10 @@ import { Post } from './post' import { WebviewCmd } from './webview-cmd' import { ColorThemeKind } from 'vscode' import { PostCategories } from './post-category' -import { SiteCategories } from './site-category' import { PostTags } from './post-tag' import { IErrorResponse as ErrorResponse } from './error-response' import { ImgUploadStatus } from './img-upload-status' +import { SiteCategory } from '@/model/site-category' export namespace webviewMessage { export interface Message { @@ -16,7 +16,7 @@ export namespace webviewMessage { post: Post activeTheme: ColorThemeKind personalCategories: PostCategories - siteCategories: SiteCategories + siteCategories: SiteCategory[] tags: PostTags breadcrumbs?: string[] fileName: string diff --git a/src/service/ing.api.ts b/src/service/ing.api.ts index 0d7ef397..20e95a6b 100644 --- a/src/service/ing.api.ts +++ b/src/service/ing.api.ts @@ -1,7 +1,6 @@ import { Ing, IngComment, IngPublishModel, IngType } from '@/model/ing' import { Alert } from '@/infra/alert' import { globalCtx } from '@/ctx/global-ctx' -import fetch from '@/infra/fetch-client' import { consUrlPara } from '@/infra/http/infra/url' import { consReqHeader, ReqHeaderKey } from '@/infra/http/infra/header' import { AuthedReq } from '@/infra/http/authed-req' diff --git a/src/service/post-cfg-panel.ts b/src/service/post-cfg-panel.ts index 95779a01..e3a414be 100644 --- a/src/service/post-cfg-panel.ts +++ b/src/service/post-cfg-panel.ts @@ -3,7 +3,7 @@ import vscode, { Uri } from 'vscode' import { Post } from '@/model/post' import { globalCtx } from '@/ctx/global-ctx' import { PostCategoryService } from './post-category' -import { siteCategoryService } from './site-category' +import { SiteCategoryService } from './site-category' import { PostTagService } from './post-tag' import { PostService } from './post' import { isErrorResponse } from '@/model/error-response' @@ -61,7 +61,7 @@ export namespace PostCfgPanel { post: cloneDeep(post), activeTheme: vscode.window.activeColorTheme.kind, personalCategories: cloneDeep(await PostCategoryService.listCategories()), - siteCategories: cloneDeep(await siteCategoryService.fetchAll()), + siteCategories: cloneDeep(await SiteCategoryService.fetchAll()), tags: cloneDeep(await PostTagService.fetchTags()), breadcrumbs, fileName: localFileUri diff --git a/src/service/post.ts b/src/service/post.ts index c228998c..a4f36b14 100644 --- a/src/service/post.ts +++ b/src/service/post.ts @@ -1,4 +1,3 @@ -import fetch from '@/infra/fetch-client' import { Post } from '@/model/post' import { globalCtx } from '@/ctx/global-ctx' import { PageModel } from '@/model/page-model' diff --git a/src/service/site-category.ts b/src/service/site-category.ts index fd782023..9356135b 100644 --- a/src/service/site-category.ts +++ b/src/service/site-category.ts @@ -1,18 +1,24 @@ -import fetch from '@/infra/fetch-client' -import { SiteCategories, SiteCategory } from '@/model/site-category' +import { SiteCategory } from '@/model/site-category' import { globalCtx } from '@/ctx/global-ctx' +import { AuthedReq } from '@/infra/http/authed-req' +import { consReqHeader } from '@/infra/http/infra/header' -export namespace siteCategoryService { - let cached: SiteCategories | null = null +let cached: SiteCategory[] | null = null - export const fetchAll = async (forceRefresh = false): Promise => { +export namespace SiteCategoryService { + export async function fetchAll(forceRefresh = false) { if (cached && !forceRefresh) return cached - const response = await fetch(`${globalCtx.config.apiBaseUrl}/api/category/site`) - if (!response.ok) throw Error(`Failed to fetch post category\n${response.status}\n${await response.text()}`) - - const categories = await response.json() - cached = categories.map(c => Object.assign(new SiteCategory(), c)) - return categories + const url = `${globalCtx.config.apiBaseUrl}/api/category/site` + try { + const resp = await AuthedReq.get(url, consReqHeader()) + const list = JSON.parse(resp) + cached = list + return list + } catch (e) { + // eslint-disable-next-line @typescript-eslint/restrict-template-expressions + console.log(`获取随笔分类失败: ${e}`) + return [] + } } } diff --git a/ui/post-cfg/components/SiteCategorySelector.tsx b/ui/post-cfg/components/SiteCategorySelector.tsx index 393d3715..d2775359 100644 --- a/ui/post-cfg/components/SiteCategorySelector.tsx +++ b/ui/post-cfg/components/SiteCategorySelector.tsx @@ -1,5 +1,5 @@ import { ActionButton, Checkbox, Label, Stack } from '@fluentui/react' -import { SiteCategories } from '@/model/site-category' +import { SiteCategory } from '@/model/site-category' import React from 'react' import { siteCategoriesStore } from '../service/site-category-store' @@ -9,7 +9,7 @@ export interface ISiteCategoriesSelectorProps { } export interface ISiteCategoriesSelectorState { - siteCategories: SiteCategories + siteCategories: SiteCategory[] isCollapsed: boolean categoryIds: number[] categoryExpandState: { [key: number]: boolean | undefined } diff --git a/ui/post-cfg/service/site-category-store.ts b/ui/post-cfg/service/site-category-store.ts index 2d89bb9c..028a84f6 100644 --- a/ui/post-cfg/service/site-category-store.ts +++ b/ui/post-cfg/service/site-category-store.ts @@ -1,7 +1,7 @@ -import { SiteCategories } from '../../../src/model/site-category' +import { SiteCategory } from '../../../src/model/site-category' export namespace siteCategoriesStore { - let items: SiteCategories = [] - export const get = (): SiteCategories => items ?? [] - export const set = (value: SiteCategories) => (items = value ?? []) + let items: SiteCategory[] = [] + export const get = (): SiteCategory[] => items ?? [] + export const set = (value: SiteCategory[]) => (items = value ?? []) } From 51aa52606e1b90f3f70a4f7c8097c883eca67929 Mon Sep 17 00:00:00 2001 From: Thaumy Date: Sun, 30 Jul 2023 21:43:31 +0800 Subject: [PATCH 064/157] refactor: BlogSettingService --- src/cmd/pdf/export-pdf.ts | 6 ++--- src/cmd/pdf/post-pdf-template-builder.ts | 29 ++++++++++++++---------- src/service/blog-setting.ts | 26 +++++++++++++-------- 3 files changed, 36 insertions(+), 25 deletions(-) diff --git a/src/cmd/pdf/export-pdf.ts b/src/cmd/pdf/export-pdf.ts index 20740618..87724df8 100644 --- a/src/cmd/pdf/export-pdf.ts +++ b/src/cmd/pdf/export-pdf.ts @@ -12,7 +12,7 @@ import { accountManager } from '@/auth/account-manager' import { Alert } from '@/infra/alert' import { PostTreeItem } from '@/tree-view/model/post-tree-item' import { PostEditDto } from '@/model/post-edit-dto' -import { postPdfTemplateBuilder } from '@/cmd/pdf/post-pdf-template-builder' +import { PostPdfTemplateBuilder } from '@/cmd/pdf/post-pdf-template-builder' import { ChromiumCfg } from '@/ctx/cfg/chromium' async function launchBrowser(chromiumPath: string) { @@ -50,13 +50,13 @@ const exportOne = async ( }) } report(10) - const html = await postPdfTemplateBuilder.build(post, blogApp) + const html = await PostPdfTemplateBuilder.build(post, blogApp) report(15) // Wait for code block highlight finished await Promise.all([ new Promise(resolve => { page.on('console', ev => { - if (ev.text() === postPdfTemplateBuilder.HighlightedMessage) resolve() + if (ev.text() === PostPdfTemplateBuilder.HighlightedMessage) resolve() }) }), page.setContent(html, { diff --git a/src/cmd/pdf/post-pdf-template-builder.ts b/src/cmd/pdf/post-pdf-template-builder.ts index cd4cc0e9..64e5eda3 100644 --- a/src/cmd/pdf/post-pdf-template-builder.ts +++ b/src/cmd/pdf/post-pdf-template-builder.ts @@ -7,10 +7,10 @@ import { PostCategoryService } from '@/service/post-category' import { PostCategory } from '@/model/post-category' import { markdownItFactory } from '@cnblogs/markdown-it-presets' -export namespace postPdfTemplateBuilder { +export namespace PostPdfTemplateBuilder { export const HighlightedMessage = 'markdown-highlight-finished' - export const build = async (post: Post, blogApp: string): Promise => { + export async function build(post: Post, blogApp: string): Promise { let { postBody } = post const { isMarkdown, id: postId } = post @@ -56,14 +56,19 @@ export namespace postPdfTemplateBuilder { const tagHtml = await buildTagHtml() const categoryHtml = await buildCategoryHtml() + const setting = await BlogSettingService.getBlogSetting() + if (setting == null) return '' + const { codeHighlightEngine, codeHighlightTheme, enableCodeLineNumber: isCodeLineNumberEnabled, blogId, - } = await BlogSettingService.getBlogSetting() + } = setting + const { userId } = accountManager.currentUser - return ` + + return ` ${post.title}