Skip to content

Commit ff67d29

Browse files
committed
refactor: post pull
1 parent 094fbc4 commit ff67d29

File tree

5 files changed

+95
-140
lines changed

5 files changed

+95
-140
lines changed

src/cmd/post-list/open-post-file.ts

Lines changed: 3 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ import { PostFileMapManager } from '@/service/post/post-file-map'
55
import { LocalPost } from '@/service/local-post'
66
import { fsUtil } from '@/infra/fs/fsUtil'
77
import { postPull } from './post-pull'
8-
import { Alert } from '@/infra/alert'
9-
import { WorkspaceCfg } from '@/ctx/cfg/workspace'
108

119
export async function openPostFile(
1210
post: LocalPost | Post | string,
@@ -19,27 +17,14 @@ export async function openPostFile(
1917
} else if (post instanceof Post) {
2018
filePath = PostFileMapManager.getFilePath(post.id) ?? ''
2119
if (autoPull) {
22-
if (!(await fsUtil.exists(filePath)) || filePath.indexOf(WorkspaceCfg.getWorkspaceUri().path) < 0)
23-
await postPull(post, false, true)
20+
if (filePath.length === 0 || (filePath.length > 0 && !(await fsUtil.exists(filePath))))
21+
if (await postPull(post, true, true)) filePath = PostFileMapManager.getFilePath(post.id) ?? ''
2422
}
2523
} else {
2624
filePath = post
2725
}
2826

29-
if (filePath === '') return
30-
31-
if (!(await fsUtil.exists(filePath))) await new Promise(f => setTimeout(f, 200))
32-
33-
try {
34-
await openFile(filePath, options)
35-
} catch (e) {
36-
await new Promise(f => setTimeout(f, 500))
37-
try {
38-
await openFile(filePath, options)
39-
} catch (e2) {
40-
await Alert.err(`打开本地博文文件失败,重新操作通常可恢复,错误信息: ${<string>e2}`)
41-
}
42-
}
27+
if (filePath.length > 0) await openFile(filePath, options)
4328
}
4429

4530
function openFile(filePath: string, options?: TextDocumentShowOptions) {
Lines changed: 15 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
1-
import path from 'path'
2-
import { FileSystemError, Uri, workspace } from 'vscode'
1+
import { Uri } from 'vscode'
32
import { Post } from '@/model/post'
43
import { Alert } from '@/infra/alert'
5-
import { PostService } from '@/service/post/post'
64
import { PostFileMapManager } from '@/service/post/post-file-map'
75
import { openPostFile } from './open-post-file'
86
import sanitizeFileName from 'sanitize-filename'
97
import { WorkspaceCfg } from '@/ctx/cfg/workspace'
108
import { fsUtil } from '@/infra/fs/fsUtil'
9+
import { postPull } from './post-pull'
1110

1211
export function buildLocalPostFileUri(post: Post, appendToFileName = ''): Uri {
1312
const workspaceUri = WorkspaceCfg.getWorkspaceUri()
@@ -17,54 +16,23 @@ export function buildLocalPostFileUri(post: Post, appendToFileName = ''): Uri {
1716
return Uri.joinPath(workspaceUri, `${postTitle}${appendToFileName}.${post.id}.${ext}`)
1817
}
1918

20-
export async function openPostInVscode(postId: number, forceUpdateLocalPostFile = false): Promise<Uri | false> {
21-
const mappedPostFilePath = PostFileMapManager.getFilePath(postId)
22-
23-
const isFileExist = mappedPostFilePath !== undefined && (await fsUtil.exists(mappedPostFilePath))
24-
if (mappedPostFilePath !== undefined && isFileExist && !forceUpdateLocalPostFile) {
25-
await openPostFile(mappedPostFilePath)
26-
return Uri.file(mappedPostFilePath)
27-
}
19+
export async function openPostInVscode(postId: number): Promise<Uri | undefined> {
20+
const mappedPostFilePath = await getMappedPostFilePath(postId)
2821

29-
// 本地文件已经被删除了, 确保重新生成博文与本地文件的关联
30-
if (mappedPostFilePath !== undefined && !isFileExist)
31-
await PostFileMapManager.updateOrCreate(postId, mappedPostFilePath)
22+
// pull 时取消覆盖本地文件也会执行此处代码
23+
if (mappedPostFilePath == null) return
3224

33-
const { post } = await PostService.getPostEditDto(postId)
34-
35-
const workspaceUri = WorkspaceCfg.getWorkspaceUri()
36-
await mkDirIfNotExist(workspaceUri)
37-
let fileUri = mappedPostFilePath !== undefined ? Uri.file(mappedPostFilePath) : buildLocalPostFileUri(post)
38-
39-
// 博文尚未关联到本地文件的情况
40-
// 本地存在和博文同名的文件, 询问用户是要覆盖还是同时保留两者
41-
if (mappedPostFilePath === undefined && (await fsUtil.exists(fileUri.fsPath))) {
42-
const opt = ['保留本地文件并新建另一个文件', '覆盖本地文件']
43-
const selected = await Alert.info(
44-
`无法建立博文与本地文件的关联, 文件名冲突`,
45-
{ detail: `本地已存在名为 ${path.basename(fileUri.fsPath)} 的文件`, modal: true },
46-
...opt
47-
)
48-
49-
if (selected === opt[0]) fileUri = buildLocalPostFileUri(post, '-new')
25+
if (!(await fsUtil.exists(mappedPostFilePath))) {
26+
void Alert.err(`博文关联的本地文件不存在,postId: ${postId},path: ${mappedPostFilePath}`)
27+
return
5028
}
5129

52-
// 博文内容写入本地文件, 若文件不存在, 会自动创建对应的文件
53-
await workspace.fs.writeFile(fileUri, Buffer.from(post.postBody))
54-
await PostFileMapManager.updateOrCreate(postId, fileUri.path)
55-
await openPostFile(post)
56-
return fileUri
30+
await openPostFile(mappedPostFilePath)
31+
return Uri.file(mappedPostFilePath)
5732
}
5833

59-
async function mkDirIfNotExist(uri: Uri) {
60-
try {
61-
await workspace.fs.stat(uri)
62-
} catch (err) {
63-
try {
64-
if (err instanceof FileSystemError) await workspace.fs.createDirectory(uri)
65-
} catch (e) {
66-
void Alert.err(`创建目录失败: ${<string>e}`)
67-
throw e
68-
}
69-
}
34+
async function getMappedPostFilePath(postId: number) {
35+
const mappedPostFilePath = PostFileMapManager.getFilePath(postId)
36+
if (mappedPostFilePath != null && (await fsUtil.exists(mappedPostFilePath))) return mappedPostFilePath
37+
if (await postPull(postId, true, true)) return PostFileMapManager.getFilePath(postId)
7038
}

src/cmd/post-list/post-pull.ts

Lines changed: 71 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -11,74 +11,86 @@ import { MarkdownCfg } from '@/ctx/cfg/markdown'
1111
import { fsUtil } from '@/infra/fs/fsUtil'
1212
import { searchPostByTitle } from '@/service/post/search-post-by-title'
1313

14-
export async function postPull(input: Post | PostTreeItem | Uri | undefined | null, showConfirm = true, mute = false) {
15-
const ctxList: CmdCtx[] = []
16-
let isFreshPull = false
17-
input = input instanceof PostTreeItem ? input.post : input
18-
if (parsePostInput(input) && input.id > 0) {
19-
const post = input
20-
const path = PostFileMapManager.getFilePath(post.id)
21-
if (path === undefined || !(await fsUtil.exists(path))) {
22-
isFreshPull = true
23-
const uri = buildLocalPostFileUri(post)
24-
await workspace.fs.writeFile(uri, Buffer.from(post.postBody))
25-
await PostFileMapManager.updateOrCreate(post.id, uri.path)
26-
await handlePostInput(input, ctxList, uri.path)
27-
} else {
28-
isFreshPull = !(await fsUtil.exists(path))
29-
if (!path.startsWith('/')) await PostFileMapManager.updateOrCreate(post.id, Uri.file(path).path)
30-
await handlePostInput(input, ctxList, path)
31-
}
32-
} else {
33-
const uri = parseUriInput(input)
34-
if (uri != null) await handleUriInput(uri, ctxList)
14+
type InputType = Post | PostTreeItem | Uri | number | undefined | null
15+
16+
async function getPostId(input: InputType): Promise<number | undefined | null> {
17+
if (typeof input === 'number') return input
18+
if (input instanceof Post && input.id > 0) return input.id
19+
if (input instanceof PostTreeItem && input.post.id > 0) return input.post.id
20+
if (input instanceof Uri) {
21+
const postId = await getPostIdFromUri(input)
22+
return postId
3523
}
3624

37-
const fileName = resolveFileNames(ctxList)
38-
39-
if (showConfirm && !isFreshPull && MarkdownCfg.isShowConfirmMsgWhenPullPost()) {
40-
const answer = await Alert.warn(
41-
'确认要拉取远程博文吗?',
42-
{
43-
modal: true,
44-
detail: `本地文件「${fileName}」将被覆盖(可通过设置关闭对话框)`,
45-
},
46-
'确认'
47-
)
48-
if (answer !== '确认') return
25+
const doc = window.activeTextEditor?.document
26+
if (doc != null && !doc.isUntitled) {
27+
const postId = await getPostIdFromUri(doc.uri)
28+
return postId
4929
}
30+
}
5031

51-
if (ctxList.length <= 0) return
32+
export async function postPull(input: InputType, showConfirm = true, mute = false): Promise<boolean> {
33+
let isFreshPull = false
34+
let post: Post | null = null
5235

53-
await update(ctxList)
36+
const postId = await getPostId(input)
37+
if (postId == null) {
38+
void Alert.err(`无效的额 postId,值为 ${postId}`)
39+
return false
40+
}
5441

55-
if (!mute) {
56-
if (isFreshPull) await Alert.info(`博文已下载至本地:${resolveFileNames(ctxList)}`)
57-
else await Alert.info(`本地文件已更新: ${resolveFileNames(ctxList)}`)
42+
post = (await PostService.getPostEditDto(postId))?.post
43+
if (post == null) {
44+
void Alert.err(`对应的博文不存在,postId: ${postId}`)
45+
return false
5846
}
59-
}
6047

61-
type InputType = Post | Uri | undefined | null
62-
type CmdCtx = {
63-
postId: number
64-
fileUri: Uri
65-
}
48+
let uriPath = PostFileMapManager.getFilePath(post.id)
49+
let fileUri: Uri
50+
if (uriPath == null) {
51+
fileUri = buildLocalPostFileUri(post)
52+
} else {
53+
// replace fsPath with uriPath
54+
if (!uriPath.startsWith('/')) uriPath = Uri.file(uriPath).path
55+
if (!PostFileMapManager.isInWorkspace(uriPath)) fileUri = buildLocalPostFileUri(post)
56+
else fileUri = Uri.parse(uriPath)
57+
}
6658

67-
const parsePostInput = (input: InputType): input is Post => input instanceof Post
59+
uriPath = fileUri.path
60+
const fsPath = fileUri.fsPath
61+
const fileName = path.basename(fsPath)
62+
// eslint-disable-next-line @typescript-eslint/naming-convention
63+
const fileExists = await fsUtil.exists(fsPath)
64+
65+
if (fileExists) {
66+
if (showConfirm && !isFreshPull && MarkdownCfg.isShowConfirmMsgWhenPullPost()) {
67+
const answer = await Alert.warn(
68+
'确认要拉取远程博文吗?',
69+
{
70+
modal: true,
71+
detail: `本地文件「${fileName}」将被覆盖(可通过设置关闭对话框)`,
72+
},
73+
'确认'
74+
)
75+
if (answer !== '确认') return false
76+
}
77+
} else {
78+
isFreshPull = true
79+
}
6880

69-
async function handlePostInput(post: Post, contexts: CmdCtx[], path: string) {
81+
await workspace.fs.writeFile(fileUri, Buffer.from(post.postBody))
82+
await PostFileMapManager.updateOrCreate(post.id, uriPath)
7083
await revealPostListItem(post)
71-
contexts.push({ postId: post.id, fileUri: Uri.file(path) })
72-
}
7384

74-
function parseUriInput(input: InputType): Uri | undefined {
75-
if (input instanceof Uri) return input
85+
if (!mute) {
86+
if (isFreshPull) await Alert.info(`博文已下载至本地:${fileName}`)
87+
else await Alert.info(`本地文件已更新: ${fileName}`)
88+
}
7689

77-
const doc = window.activeTextEditor?.document
78-
if (doc !== undefined && !doc.isUntitled) return doc.uri
90+
return true
7991
}
8092

81-
async function handleUriInput(fileUri: Uri, contexts: CmdCtx[]) {
93+
async function getPostIdFromUri(fileUri: Uri): Promise<number | undefined> {
8294
let postId = PostFileMapManager.getPostId(fileUri.path)
8395
if (postId == null) {
8496
const mapPost = '关联已有博文并拉取'
@@ -97,32 +109,18 @@ async function handleUriInput(fileUri: Uri, contexts: CmdCtx[]) {
97109
postId = PostFileMapManager.extractPostId(filenName)
98110
if (postId == null) {
99111
const selectedPost = await searchPostByTitle(filenName, '搜索要关联的博文')
100-
if (selectedPost == null) return Alert.info('未选择要关联的博文')
112+
if (selectedPost == null) {
113+
void Alert.info('未选择要关联的博文')
114+
return
115+
}
101116
postId = selectedPost.id
102117
}
103118
}
104119

105120
if (postId != null) await PostFileMapManager.updateOrCreate(postId, fileUri.path)
106121
}
107122

108-
if (postId == null) return Alert.fileNotLinkedToPost(fileUri)
109-
110-
contexts.push({ postId, fileUri })
111-
}
112-
113-
async function update(contexts: CmdCtx[]) {
114-
for (const ctx of contexts) {
115-
const { fileUri, postId } = ctx
116-
117-
const { post } = await PostService.getPostEditDto(postId)
118-
119-
const textEditors = window.visibleTextEditors.filter(x => x.document.uri.fsPath === fileUri.fsPath)
120-
await Promise.all(textEditors.map(editor => editor.document.save()))
121-
await workspace.fs.writeFile(fileUri, Buffer.from(post.postBody))
122-
}
123-
}
123+
if (postId == null) Alert.fileNotLinkedToPost(fileUri)
124124

125-
function resolveFileNames(ctxList: CmdCtx[]) {
126-
const arr = ctxList.map(x => path.basename(x.fileUri.fsPath))
127-
return `${arr.join(', ')}`
125+
return postId
128126
}

src/infra/fs/fsUtil.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { Uri, workspace } from 'vscode'
22

33
export namespace fsUtil {
4-
export async function exists(path: string) {
4+
export async function exists(fsPath: string) {
55
try {
6-
await workspace.fs.stat(Uri.file(path))
6+
await workspace.fs.stat(Uri.file(fsPath))
77
return true
88
} catch (e) {
99
return false

src/service/post/post-file-map.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,4 +99,8 @@ export namespace PostFileMapManager {
9999
x[1] = filePath.replace(r`${oldWorkspaceUri.fsPath}`, r`${newWorkspaceUri.fsPath}`)
100100
})
101101
}
102+
103+
export function isInWorkspace(fileUriPath: string) {
104+
return fileUriPath.indexOf(WorkspaceCfg.getWorkspaceUri().path) >= 0
105+
}
102106
}

0 commit comments

Comments
 (0)