diff --git a/package.json b/package.json index d46a47f7..dde37829 100644 --- a/package.json +++ b/package.json @@ -242,7 +242,7 @@ }, { "command": "vscode-cnb.post.show-local-file-info", - "title": "博客园关联博文", + "title": "关联博客园博文", "enablement": "vscode-cnb.isAuthed" }, { @@ -616,7 +616,7 @@ }, "post-show-local-file-info": { "order": 3, - "description": "博客园关联博文", + "description": "关联博客园博文", "type": "boolean", "default": true }, @@ -677,7 +677,7 @@ }, "post-show-local-file-info": { "order": 3, - "description": "博客园关联博文", + "description": "关联博客园博文", "type": "boolean" }, "post-open-in-blog-admin": { diff --git a/src/cmd/post-list/open-post-in-vscode.ts b/src/cmd/post-list/open-post-in-vscode.ts index b3a23cbb..11241538 100644 --- a/src/cmd/post-list/open-post-in-vscode.ts +++ b/src/cmd/post-list/open-post-in-vscode.ts @@ -11,9 +11,10 @@ import { fsUtil } from '@/infra/fs/fsUtil' export function buildLocalPostFileUri(post: Post, appendToFileName = ''): Uri { const workspaceUri = WorkspaceCfg.getWorkspaceUri() - const ext = `.${post.isMarkdown ? 'md' : 'html'}` - const postTitle = sanitizeFileName(post.title) - return Uri.joinPath(workspaceUri, `${postTitle}${appendToFileName}.${post.id}${ext}`) + const ext = `${post.isMarkdown ? 'md' : 'html'}` + let postTitle = sanitizeFileName(post.title) + if (/\.\d+$/.test(postTitle)) postTitle += '_' + return Uri.joinPath(workspaceUri, `${postTitle}${appendToFileName}.${post.id}.${ext}`) } export async function openPostInVscode(postId: number, forceUpdateLocalPostFile = false): Promise { diff --git a/src/cmd/post-list/post-pull.ts b/src/cmd/post-list/post-pull.ts index 1b6fc699..40113f81 100644 --- a/src/cmd/post-list/post-pull.ts +++ b/src/cmd/post-list/post-pull.ts @@ -9,6 +9,7 @@ import { revealPostListItem } from '@/service/post/post-list-view' import { PostTreeItem } from '@/tree-view/model/post-tree-item' import { MarkdownCfg } from '@/ctx/cfg/markdown' import { fsUtil } from '@/infra/fs/fsUtil' +import { searchPostByTitle } from '@/service/post/search-post-by-title' export async function postPull(input: Post | PostTreeItem | Uri | undefined | null, showConfirm = true, mute = false) { const ctxList: CmdCtx[] = [] @@ -30,7 +31,7 @@ export async function postPull(input: Post | PostTreeItem | Uri | undefined | nu } } else { const uri = parseUriInput(input) - if (uri !== undefined) handleUriInput(uri, ctxList) + if (uri != null) await handleUriInput(uri, ctxList) } const fileName = resolveFileNames(ctxList) @@ -77,9 +78,34 @@ function parseUriInput(input: InputType): Uri | undefined { if (doc !== undefined && !doc.isUntitled) return doc.uri } -function handleUriInput(fileUri: Uri, contexts: CmdCtx[]) { - const postId = PostFileMapManager.getPostId(fileUri.path) - if (postId === undefined) return Alert.fileNotLinkedToPost(fileUri) +async function handleUriInput(fileUri: Uri, contexts: CmdCtx[]) { + let postId = PostFileMapManager.getPostId(fileUri.path) + if (postId == null) { + const mapPost = '关联已有博文并拉取' + const selected = await Alert.info( + '本地文件尚未关联到博客园博文', + { + modal: true, + detail: `您可以将当前本地文件关联到已有博客园博文`, + }, + mapPost + ) + + if (selected === mapPost) { + const fsPath = fileUri.fsPath + const filenName = path.basename(fsPath, path.extname(fsPath)) + postId = PostFileMapManager.extractPostId(filenName) + if (postId == null) { + const selectedPost = await searchPostByTitle(filenName, '搜索要关联的博文') + if (selectedPost == null) return Alert.info('未选择要关联的博文') + postId = selectedPost.id + } + } + + if (postId != null) await PostFileMapManager.updateOrCreate(postId, fileUri.path) + } + + if (postId == null) return Alert.fileNotLinkedToPost(fileUri) contexts.push({ postId, fileUri }) } diff --git a/src/cmd/post-list/upload-post.ts b/src/cmd/post-list/upload-post.ts index ceacf656..b0293b5b 100644 --- a/src/cmd/post-list/upload-post.ts +++ b/src/cmd/post-list/upload-post.ts @@ -21,19 +21,17 @@ import { Workspace } from '@/cmd/workspace' import { fsUtil } from '@/infra/fs/fsUtil' async function parseFileUri(fileUri?: Uri) { - if (fileUri !== undefined && fileUri.scheme !== 'file') return undefined + if (fileUri !== undefined && fileUri.scheme !== 'file') return if (fileUri !== undefined) return fileUri const { activeTextEditor } = window - if (activeTextEditor === undefined) return undefined + if (activeTextEditor == null) return const { document } = activeTextEditor if (document.languageId === 'markdown' && !document.isUntitled) { await document.save() return document.uri } - - return undefined } export async function saveLocalPost(localPost: LocalPost) { @@ -202,43 +200,45 @@ export async function uploadPost(input?: Post | PostTreeItem | PostEditDto, conf export async function uploadPostFile(fileUri?: Uri, confirm = true) { const parsedFileUri = await parseFileUri(fileUri) - if (parsedFileUri === undefined) return - - const { fsPath: filePath } = parsedFileUri - const postId = PostFileMapManager.getPostId(parsedFileUri.path) - - if (postId !== undefined && postId >= 0) { - const dto = await PostService.getPostEditDto(postId) - if (dto !== undefined) await uploadPost(dto, confirm) - return - } + if (parsedFileUri == null) return const fileContent = Buffer.from(await workspace.fs.readFile(parsedFileUri)).toString() if (isEmptyBody(fileContent)) return - const selected = await Alert.info( - '本地文件尚未关联到博客园博文', - { - modal: true, - detail: `您可以选择新建一篇博文或将本地文件关联到一篇博客园博文(您可以根据标题搜索您在博客园博文)`, - }, - '新建博文', - '关联已有博文' - ) - if (selected === '关联已有博文') { - const selectedPost = await searchPostByTitle( - path.basename(filePath, path.extname(filePath)), - '搜索要关联的博文' + const { fsPath: fsPath } = parsedFileUri + let postId = PostFileMapManager.getPostId(parsedFileUri.path) + + if (postId == null) { + const createPost = '新建博文' + const mapPost = '关联已有博文并上传' + const selected = await Alert.info( + '本地文件尚未关联到博客园博文', + { + modal: true, + detail: `您可以选择新建一篇博文或将当前本地文件关联到已有博客园博文`, + }, + createPost, + mapPost ) - if (selectedPost === undefined) return - await PostFileMapManager.updateOrCreate(selectedPost.id, parsedFileUri.path) - const postEditDto = await PostService.getPostEditDto(selectedPost.id) - if (postEditDto === undefined) return - if (fileContent === '') await workspace.fs.writeFile(parsedFileUri, Buffer.from(postEditDto.post.postBody)) + if (selected === mapPost) { + const filenName = path.basename(fsPath, path.extname(fsPath)) + postId = PostFileMapManager.extractPostId(filenName) + if (postId == null) { + const selectedPost = await searchPostByTitle(filenName, '搜索要关联的博文') - await uploadPost(postEditDto.post, confirm) - } else if (selected === '新建博文') { - await saveLocalPost(new LocalPost(filePath)) + if (selectedPost == null) return Alert.info('未选择要关联的博文') + postId = selectedPost.id + } + if (postId != null) await PostFileMapManager.updateOrCreate(postId, parsedFileUri.path) + } else if (selected === createPost) { + await saveLocalPost(new LocalPost(fsPath)) + } + } + + if (postId != null) { + const dto = await PostService.getPostEditDto(postId) + if (dto == null) return Alert.err(`对应的博文不存在(Id: ${postId})`) + await uploadPost(dto, confirm) } } diff --git a/src/cmd/show-local-file-to-post-info.ts b/src/cmd/show-local-file-to-post-info.ts index 7a5d19a1..ac67ea20 100644 --- a/src/cmd/show-local-file-to-post-info.ts +++ b/src/cmd/show-local-file-to-post-info.ts @@ -14,13 +14,13 @@ import format from 'date-fns/format' * @param {(Uri | number)} input * @returns {*} {Promise} */ -export async function showLocalFileToPostInfo(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') { postId = PostFileMapManager.getPostId(input.path) filePath = input.fsPath - if (postId === undefined) { + if (postId == null) { const options = ['现在去关联'] const selected = await Alert.info( '本地文件尚未关联到博文', @@ -31,14 +31,27 @@ export async function showLocalFileToPostInfo(input: Uri | number): Promise map[0] >= 0 && map[1] !== '' - export type PostFileMap = [postId: number, filePath: string] - const storageKey = 'postFileMaps' function getMaps(): PostFileMap[] { @@ -36,7 +34,7 @@ export namespace PostFileMapManager { } export async function updateOrCreate(postId: number, filePath: string, { emitEvent = true } = {}) { - const validFileExt = ['.md', '.html'] + const validFileExt = ['.md', '.mkd', '.htm', '.html'] if (filePath !== '' && !validFileExt.some(x => filePath.endsWith(x))) throw Error('Invalid filepath, file must have type markdown or html') @@ -72,9 +70,15 @@ export namespace PostFileMapManager { return path.startsWith('/') ? Uri.parse(path).fsPath : path } - export function getPostId(filePath: string) { + export function getPostId(filePath: string): number | undefined { const map = findByFilePath(filePath) - if (map === undefined) return + if (map == null) return return map[0] } + + export function extractPostId(fileNameWithoutExt: string): number | undefined { + const match = /\.(\d+)$/g.exec(fileNameWithoutExt) + if (match == null) return + return Number(match[1]) + } }