Skip to content

Commit 25273fe

Browse files
author
winjo
committed
feat: 增加文件监听等
1 parent 523f358 commit 25273fe

16 files changed

Lines changed: 1474 additions & 267 deletions

packages/core/package.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,16 @@
3535
"assert": "^2.0.0",
3636
"browserfs": "~1.4.3",
3737
"fs-extra-factory": "^0.2.0",
38-
"uuid": "^8.3.1"
38+
"lodash.debounce": "^4.0.8",
39+
"md5": "^2.3.0",
40+
"uuid": "^3.3.2",
41+
"vscode-languageserver-types": "~3.14.0"
3942
},
4043
"devDependencies": {
4144
"@types/fs-extra": "^9.0.4",
45+
"@types/lodash.debounce": "^4.0.6",
46+
"@types/md5": "^2.2.1",
47+
"@types/uuid": "^3",
4248
"vscode": "^1.1.37"
4349
}
4450
}

packages/core/src/common/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
export * from './constant'
2+
export * from './util'

packages/core/src/common/util.ts

Lines changed: 0 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,3 @@
1-
/**
2-
* @class Mutex 使用 id 互斥操作
3-
*/
4-
5-
type MutextId = string | number | symbol
6-
7-
export class Mutex {
8-
private _waiting = new Map<
9-
MutextId,
10-
{
11-
resolveList: ((value: (id: MutextId) => void) => void)[]
12-
unlock: (id: MutextId) => void
13-
}
14-
>()
15-
16-
lock(id: string) {
17-
if (!this._waiting.has(id)) {
18-
this._waiting.set(id, {
19-
resolveList: [],
20-
unlock: this.unlock.bind(this, id),
21-
})
22-
}
23-
return new Promise<(id: MutextId) => void>((resolve) => {
24-
const { resolveList, unlock } = this._waiting.get(id)!
25-
resolveList.push(resolve)
26-
if (resolveList.length === 1) {
27-
resolve(unlock)
28-
}
29-
})
30-
}
31-
32-
unlock(id: string) {
33-
if (!this._waiting.has(id)) {
34-
throw new Error(`no lock for ${id}`)
35-
}
36-
const { resolveList, unlock } = this._waiting.get(id)!
37-
resolveList.shift()
38-
if (resolveList.length > 0) {
39-
resolveList[0](unlock)
40-
} else {
41-
this._waiting.delete(id)
42-
}
43-
}
44-
}
45-
461
/**
472
* 获取对象上所有函数的 property
483
*/

packages/core/src/server/core/common.server.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { ICommonServer, OS } from '@ali/ide-core-common'
44
@Injectable()
55
export class CommonServer implements ICommonServer {
66
async getBackendOS(): Promise<OS.Type> {
7-
return OS.type()
7+
// 使用 linux 作为 server,path 保持 posix 风格
8+
return OS.Type.Linux
89
}
910
}

packages/core/src/server/core/modules.ts

Lines changed: 0 additions & 1 deletion
This file was deleted.
Lines changed: 53 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -1,165 +1,106 @@
1-
import { Injectable, Autowired } from '@ali/common-di'
2-
import {
3-
IEditorDocumentModelSaveResult,
4-
URI,
5-
IEditorDocumentChange,
6-
BasicTextLines,
7-
isEditChange,
8-
Uri,
9-
} from '@ali/ide-core-common'
10-
import { IDiskFileProvider, FileAccess } from '@ali/ide-file-service'
11-
import md5 from 'md5'
12-
import {
13-
IFileSchemeDocNodeService,
14-
ISavingContent,
15-
IContentChange,
16-
} from '@ali/ide-file-scheme/lib/common'
1+
import { Injectable, Autowired } from '@ali/common-di';
2+
import { IEditorDocumentModelSaveResult, URI, IEditorDocumentChange, BasicTextLines, isEditChange } from '@ali/ide-core-common';
3+
import { IFileService } from '@ali/ide-file-service/lib/common';
4+
import md5 from 'md5';
5+
import { IFileSchemeDocNodeService, ISavingContent, IContentChange } from '@ali/ide-file-scheme/lib/common';
6+
import { fse } from '../node';
7+
import { encode, decode } from '../file-service/encoding'
178

18-
import { fse, buffer } from '../node'
19-
20-
const { existsSync, readFile, statSync, writeFile } = fse
21-
const { Buffer } = buffer
22-
23-
// TODO:
24-
// 只处理 file 协议,其它协议暂不支持
259
@Injectable()
2610
export class FileSchemeDocNodeServiceImpl implements IFileSchemeDocNodeService {
27-
@Autowired(IDiskFileProvider)
28-
private fileService: IDiskFileProvider
11+
@Autowired(IFileService)
12+
private fileService: IFileService;
13+
14+
// 由于此处只处理file协议,为了简洁,不再使用 fileService,
2915

30-
async $saveByChange(
31-
uri: string,
32-
change: IContentChange,
33-
encoding?: BufferEncoding | undefined,
34-
force: boolean = false
35-
): Promise<IEditorDocumentModelSaveResult> {
16+
async $saveByChange(uri: string, change: IContentChange, encoding?: string | undefined, force: boolean = false): Promise<IEditorDocumentModelSaveResult> {
3617
try {
37-
const fsPath = new URI(uri).codeUri.fsPath
38-
if (existsSync(fsPath)) {
39-
const mtime = statSync(fsPath).mtime.getTime()
40-
const contentBuffer = await readFile(fsPath)
41-
const content = contentBuffer.toString(encoding ? encoding : 'utf8')
18+
const fsPath = new URI(uri).codeUri.path;
19+
if (await fse.pathExists(fsPath)) {
20+
const mtime = (await fse.stat(fsPath)).mtime.getTime();
21+
const contentBuffer = await fse.readFile(fsPath);
22+
const content = decode(contentBuffer, encoding ? encoding : 'utf8');
4223
if (!force) {
43-
const currentMd5 = md5(content)
24+
const currentMd5 = md5(content);
4425
if (change.baseMd5 !== currentMd5) {
4526
return {
4627
state: 'diff',
47-
}
28+
};
4829
}
4930
}
50-
const contentRes = applyChanges(content, change.changes!, change.eol)
51-
if (statSync(fsPath).mtime.getTime() !== mtime) {
52-
throw new Error('File has been modified during saving, please retry')
31+
const contentRes = applyChanges(content, change.changes!, change.eol);
32+
if ((await fse.stat(fsPath)).mtime.getTime() !== mtime) {
33+
throw new Error('File has been modified during saving, please retry');
5334
}
54-
await writeFile(fsPath, Buffer.from(contentRes, encoding ? encoding : 'utf8'))
35+
await fse.writeFile(fsPath, encode(contentRes, encoding ? encoding : 'utf8'));
5536
return {
5637
state: 'success',
57-
}
58-
} else {
59-
return {
60-
state: 'error',
61-
errorMessage: 'useByContent',
62-
}
38+
};
39+
}
40+
return {
41+
state: 'error',
42+
errorMessage: 'useByContent',
6343
}
6444
} catch (e) {
6545
return {
6646
state: 'error',
6747
errorMessage: e.toString(),
68-
}
48+
};
6949
}
7050
}
7151

72-
async $saveByContent(
73-
uri: string,
74-
content: ISavingContent,
75-
encoding?: string | undefined,
76-
force: boolean = false
77-
): Promise<IEditorDocumentModelSaveResult> {
52+
async $saveByContent(uri: string, content: ISavingContent, encoding?: string | undefined, force: boolean = false): Promise<IEditorDocumentModelSaveResult> {
7853
try {
79-
const _uri = Uri.parse(uri)
80-
const stat = await this.fileService.stat(_uri)
54+
const stat = await this.fileService.getFileStat(uri);
8155
if (stat) {
8256
if (!force) {
83-
const res = await this.fileService.readFile(_uri, encoding)
84-
if (content.baseMd5 !== md5(res)) {
57+
const res = await this.fileService.resolveContent(uri, {encoding});
58+
if (content.baseMd5 !== md5(res.content)) {
8559
return {
8660
state: 'diff',
87-
}
61+
};
8862
}
8963
}
90-
await this.fileService.writeFile(_uri, content.content, {
91-
create: true,
92-
overwrite: false,
93-
encoding,
94-
})
95-
return {
96-
state: 'success',
97-
}
98-
} else {
99-
await this.fileService.writeFile(_uri, content.content, {
100-
create: true,
101-
overwrite: false,
102-
encoding,
103-
})
64+
await this.fileService.setContent(stat, content.content, {encoding});
10465
return {
10566
state: 'success',
106-
}
67+
};
10768
}
69+
await this.fileService.createFile(uri, {content: content.content, encoding});
70+
return {
71+
state: 'success',
72+
};
10873
} catch (e) {
10974
return {
11075
state: 'error',
11176
errorMessage: e.toString(),
112-
}
77+
};
11378
}
11479
}
11580

11681
async $getMd5(uri: string, encoding?: string | undefined): Promise<string | undefined> {
11782
try {
118-
const _uri = Uri.parse(uri)
119-
if (await this.fileService.access(_uri, FileAccess.Constants.F_OK)) {
120-
const res = await this.fileService.readFile(_uri, encoding)
121-
return md5(res)
122-
} else {
123-
return undefined
83+
if (await this.fileService.access(uri)) {
84+
const res = await this.fileService.resolveContent(uri, {encoding});
85+
return md5(res.content);
12486
}
12587
} catch (e) {
126-
return undefined
88+
return undefined;
12789
}
12890
}
12991
}
13092

131-
/**
132-
* 注意: 对于一个change来说,同时执行的多个 operation 对应的都是同一个原始 content;
133-
* 常见例子: vscode 中 cmd+d 编辑
134-
* @param content
135-
* @param changes
136-
*/
137-
138-
export function applyChanges(
139-
content: string,
140-
changes: IEditorDocumentChange[],
141-
eol: '\n' | '\r\n'
142-
): string {
143-
const textLines = new BasicTextLines(content.split(eol), eol)
93+
// TODO: eol 哪里的
94+
export function applyChanges(content: string, changes: IEditorDocumentChange[], eol: '\n' | '\r\n'): string {
95+
const textLines = new BasicTextLines(content.split(eol), eol);
14496
changes.forEach((change) => {
14597
if (isEditChange(change)) {
14698
change.changes.forEach((change) => {
147-
// 这里从前端传过来的 changes 已经倒序排序过,所以可以安全的 apply
148-
textLines.acceptChange(change)
149-
})
99+
textLines.acceptChange(change);
100+
});
150101
} else {
151-
textLines.acceptEol(change.eol)
102+
textLines.acceptEol(change.eol);
152103
}
153-
})
154-
return textLines.getContent()
155-
}
156-
157-
function getUri(uri: string | Uri): URI {
158-
const _uri = new URI(uri)
159-
160-
if (!_uri.scheme) {
161-
throw new Error(`没有设置 scheme: ${uri}`)
162-
}
163-
164-
return _uri
104+
});
105+
return textLines.getContent();
165106
}

0 commit comments

Comments
 (0)