autosnippet 1.1.13 → 1.1.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +36 -36
- package/bin/asnip.js +58 -8
- package/bin/cache.js +7 -8
- package/bin/config.js +39 -0
- package/bin/create.js +157 -44
- package/bin/findPath.js +388 -132
- package/bin/init.js +7 -3
- package/bin/injection.js +49 -79
- package/bin/install.js +126 -13
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -1,36 +1,36 @@
|
|
|
1
1
|
# AutoSnippet
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
一个 iOS 模块管理工具。使用命令行创建 Xcode 代码片段,生成 JSON 配置文件,并在代码仓库中与其他开发者共享。
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## 安装
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
8
|
$ npm install -g autosnippet
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
##
|
|
11
|
+
## 命令选项
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
请在当前 Xcode 项目文件目录下使用以下所有命令。
|
|
14
14
|
|
|
15
15
|
### init
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
在 Xcode 项目的根目录执行此命令以创建工作空间:
|
|
18
18
|
|
|
19
19
|
```bash
|
|
20
20
|
$ asd init
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
创建工作空间时,会将子工作空间的 Snippet 配置信息收集到当前工作空间。
|
|
24
24
|
|
|
25
25
|
### create
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
创建 Xcode 代码片段的命令,在标记有 `// ACode` 代码的文件目录中:
|
|
28
28
|
|
|
29
29
|
```bash
|
|
30
30
|
$ asd c
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
代码示例:
|
|
34
34
|
|
|
35
35
|
```
|
|
36
36
|
// ACode
|
|
@@ -40,22 +40,22 @@ UIView *view = [[UIView alloc] init];
|
|
|
40
40
|
|
|
41
41
|
### install
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
将共享的代码片段添加到 Xcode 环境:
|
|
44
44
|
|
|
45
45
|
```bash
|
|
46
46
|
$ asd i
|
|
47
47
|
```
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
使用代码片段示例:
|
|
50
50
|
|
|
51
51
|
```
|
|
52
|
-
// view
|
|
52
|
+
// view 是创建时输入的代码键
|
|
53
53
|
@view
|
|
54
54
|
```
|
|
55
55
|
|
|
56
56
|
### share
|
|
57
57
|
|
|
58
|
-
|
|
58
|
+
共享本地代码片段:
|
|
59
59
|
|
|
60
60
|
```bash
|
|
61
61
|
$ asd s
|
|
@@ -63,60 +63,60 @@ $ asd s
|
|
|
63
63
|
|
|
64
64
|
### watch
|
|
65
65
|
|
|
66
|
-
|
|
66
|
+
在模块化项目中,识别代码片段并自动注入依赖头文件:
|
|
67
67
|
|
|
68
68
|
```bash
|
|
69
69
|
$ asd w
|
|
70
70
|
```
|
|
71
71
|
|
|
72
|
-
####
|
|
72
|
+
#### 追加头文件
|
|
73
73
|
|
|
74
|
-
|
|
74
|
+
开启监听后,如果想要追加头文件,请执行以下操作:
|
|
75
75
|
|
|
76
|
-
1.
|
|
77
|
-
2.
|
|
78
|
-
3. `Command + S`
|
|
76
|
+
1. 向下箭头选择代码片段的 headerVersion
|
|
77
|
+
2. 按 `Enter` 键
|
|
78
|
+
3. `Command + S` 保存文件
|
|
79
79
|
|
|
80
|
-
|
|
80
|
+
在 1 秒内,头文件会自动添加到文件头部。
|
|
81
81
|
|
|
82
|
-
####
|
|
82
|
+
#### 浏览器查看
|
|
83
83
|
|
|
84
|
-
|
|
84
|
+
开启监听后,如果想要在浏览器中查看模块的更多信息,请执行以下操作:
|
|
85
85
|
|
|
86
|
-
1.
|
|
87
|
-
2.
|
|
88
|
-
3. `Command + S`
|
|
86
|
+
1. 输入 `@` 和 `模块键`
|
|
87
|
+
2. 输入 `#` 和 `ALink`
|
|
88
|
+
3. `Command + S` 保存文件
|
|
89
89
|
|
|
90
|
-
|
|
90
|
+
会自动跳转到浏览器打开创建时配置的链接,如果没有链接则打开 README.md 文件。
|
|
91
91
|
|
|
92
|
-
|
|
92
|
+
使用 ALink 示例:
|
|
93
93
|
|
|
94
94
|
```
|
|
95
95
|
@view#ALink
|
|
96
96
|
```
|
|
97
97
|
|
|
98
|
-
##
|
|
98
|
+
## 其他
|
|
99
99
|
|
|
100
|
-
###
|
|
100
|
+
### 占位符快捷键
|
|
101
101
|
|
|
102
|
-
|
|
102
|
+
您也可以在代码片段中添加占位符,使用以下标签:
|
|
103
103
|
|
|
104
104
|
```
|
|
105
105
|
<#placeholder#>
|
|
106
106
|
```
|
|
107
107
|
|
|
108
|
-
|
|
108
|
+
例如:上面的占位符可以写成:
|
|
109
109
|
|
|
110
110
|
```
|
|
111
111
|
<#view: UIView#>
|
|
112
112
|
```
|
|
113
113
|
|
|
114
|
-
Xcode
|
|
114
|
+
Xcode 会检测 `<#` 和 `#>` 标记,并将它们之间的文本作为占位符。我们可以通过按 `Tab` 键在多个占位符之间切换。
|
|
115
115
|
|
|
116
|
-
|
|
116
|
+
当有多个相同的占位符时,使用 `⌥⌘E` 连续选择多个占位符:
|
|
117
117
|
|
|
118
|
-
1.
|
|
119
|
-
2. `⌥⌘E`
|
|
120
|
-
3.
|
|
118
|
+
1. 选择一个占位符
|
|
119
|
+
2. `⌥⌘E` 选择下一个占位符,`⌥⇧⌘E` 选择上一个占位符
|
|
120
|
+
3. 输入修改的内容,所有选中的占位符都会被修改
|
|
121
121
|
|
|
122
|
-
|
|
122
|
+
感谢使用。
|
package/bin/asnip.js
CHANGED
|
@@ -15,8 +15,57 @@ const watch = require('./watch.js');
|
|
|
15
15
|
const cache = require('./cache.js');
|
|
16
16
|
const share = require('./share.js');
|
|
17
17
|
const init = require('./init.js');
|
|
18
|
+
const config = require('./config.js');
|
|
18
19
|
|
|
19
|
-
|
|
20
|
+
// 获取配置文件路径
|
|
21
|
+
function getSpecFile(callback) {
|
|
22
|
+
// 向上查找 AutoSnippet.boxspec.json 配置文件
|
|
23
|
+
findPath.findASSpecPath(CMD_PATH, callback);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* 先查找包含 // ACode 标记的文件,找到后再询问
|
|
28
|
+
*/
|
|
29
|
+
async function findAndAsk(specFile) {
|
|
30
|
+
console.log('正在查找包含 // ACode 标记的文件...\n');
|
|
31
|
+
|
|
32
|
+
const filesWithACode = await create.findFilesWithACode(CMD_PATH);
|
|
33
|
+
|
|
34
|
+
if (filesWithACode.length === 0) {
|
|
35
|
+
console.log('未找到包含 // ACode 标记的文件。');
|
|
36
|
+
console.log('请在代码中添加 // ACode 标记,例如:');
|
|
37
|
+
console.log('');
|
|
38
|
+
console.log('// ACode');
|
|
39
|
+
console.log('UIView *view = [[UIView alloc] init];');
|
|
40
|
+
console.log('// ACode');
|
|
41
|
+
console.log('');
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// 显示找到的文件
|
|
46
|
+
console.log(`找到 ${filesWithACode.length} 个包含 // ACode 标记的文件:\n`);
|
|
47
|
+
filesWithACode.forEach((file, index) => {
|
|
48
|
+
console.log(` ${index + 1}. ${file.name} (第 ${file.line} 行)`);
|
|
49
|
+
});
|
|
50
|
+
console.log('');
|
|
51
|
+
|
|
52
|
+
// 如果只有一个文件,直接使用;如果有多个,让用户选择
|
|
53
|
+
let selectedFile = null;
|
|
54
|
+
if (filesWithACode.length === 1) {
|
|
55
|
+
selectedFile = filesWithACode[0].path;
|
|
56
|
+
console.log(`将使用文件: ${filesWithACode[0].name}\n`);
|
|
57
|
+
} else {
|
|
58
|
+
// 多个文件时,让用户选择(这里简化处理,使用第一个)
|
|
59
|
+
// 可以后续扩展为让用户选择
|
|
60
|
+
selectedFile = filesWithACode[0].path;
|
|
61
|
+
console.log(`将使用第一个文件: ${filesWithACode[0].name}\n`);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// 找到标记后,开始询问
|
|
65
|
+
askQuestions(specFile, selectedFile);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function askQuestions(specFile, selectedFilePath) {
|
|
20
69
|
// 开始问问题
|
|
21
70
|
const questions = [{
|
|
22
71
|
type: 'input',
|
|
@@ -106,7 +155,8 @@ function askQuestions(specFile) {
|
|
|
106
155
|
];
|
|
107
156
|
|
|
108
157
|
inquirer.prompt(questions).then((answers) => {
|
|
109
|
-
|
|
158
|
+
// 将选中的文件路径传递给 createCodeSnippets
|
|
159
|
+
create.createCodeSnippets(specFile, answers, null, selectedFilePath);
|
|
110
160
|
});
|
|
111
161
|
}
|
|
112
162
|
|
|
@@ -127,7 +177,7 @@ commander
|
|
|
127
177
|
.command('i')
|
|
128
178
|
.description('add the shared Snippet to the Xcode environment')
|
|
129
179
|
.action(() => {
|
|
130
|
-
|
|
180
|
+
getSpecFile(function (specFile) {
|
|
131
181
|
install.addCodeSnippets(specFile);
|
|
132
182
|
});
|
|
133
183
|
});
|
|
@@ -136,7 +186,7 @@ commander
|
|
|
136
186
|
.command('s')
|
|
137
187
|
.description('share local Xcode Snippet')
|
|
138
188
|
.action(() => {
|
|
139
|
-
|
|
189
|
+
getSpecFile(function (specFile) {
|
|
140
190
|
share.shareCodeSnippets(specFile);
|
|
141
191
|
});
|
|
142
192
|
});
|
|
@@ -145,8 +195,8 @@ commander
|
|
|
145
195
|
.command('c')
|
|
146
196
|
.description('create an Xcode Snippet, in the file directory marked with `// ACode` code')
|
|
147
197
|
.action(() => {
|
|
148
|
-
|
|
149
|
-
|
|
198
|
+
getSpecFile(function (specFile) {
|
|
199
|
+
findAndAsk(specFile);
|
|
150
200
|
});
|
|
151
201
|
});
|
|
152
202
|
|
|
@@ -154,7 +204,7 @@ commander
|
|
|
154
204
|
.command('u <word> [key] [value]')
|
|
155
205
|
.description('modify the `// ACode` code corresponding to `word`')
|
|
156
206
|
.action((word, key, value) => {
|
|
157
|
-
|
|
207
|
+
getSpecFile(function (specFile) {
|
|
158
208
|
create.updateCodeSnippets(specFile, word, key, value);
|
|
159
209
|
});
|
|
160
210
|
});
|
|
@@ -163,7 +213,7 @@ commander
|
|
|
163
213
|
.command('w')
|
|
164
214
|
.description('recognize that Snippet automatically injects dependency header files')
|
|
165
215
|
.action(() => {
|
|
166
|
-
|
|
216
|
+
getSpecFile(function (specFile) {
|
|
167
217
|
install.addCodeSnippets(specFile);
|
|
168
218
|
watch.watchFileChange(specFile);
|
|
169
219
|
});
|
package/bin/cache.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const config = require('./config.js');
|
|
4
6
|
|
|
5
7
|
const SpecCache = 'SpecCache_';
|
|
6
8
|
const KeysCache = 'KeysCache_';
|
|
@@ -114,15 +116,12 @@ async function getHeadCache(specFile) {
|
|
|
114
116
|
function getFilePathFromHolderPath(key, specFile) {
|
|
115
117
|
const pathBuff = Buffer.from(specFile, 'utf-8');
|
|
116
118
|
const fileName = key + pathBuff.toString('base64') + '.json';
|
|
117
|
-
|
|
119
|
+
|
|
120
|
+
// ✅ 使用配置模块获取缓存路径
|
|
121
|
+
const cachePath = config.getCachePath();
|
|
122
|
+
const filePath = path.join(cachePath, fileName);
|
|
118
123
|
|
|
119
|
-
|
|
120
|
-
fs.accessSync(filePath, fs.F_OK);
|
|
121
|
-
} catch (err) {
|
|
122
|
-
fs.mkdirSync(filePath);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
return filePath + fileName;
|
|
124
|
+
return filePath;
|
|
126
125
|
}
|
|
127
126
|
|
|
128
127
|
exports.updateCache = updateCache;
|
package/bin/config.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
|
|
6
|
+
// 获取代码片段输出路径(写入 Xcode CodeSnippets 目录)
|
|
7
|
+
function getSnippetsPath() {
|
|
8
|
+
const USER_HOME = process.env.HOME || process.env.USERPROFILE;
|
|
9
|
+
const snippetsPath = path.join(USER_HOME, 'Library/Developer/Xcode/UserData/CodeSnippets');
|
|
10
|
+
|
|
11
|
+
// 确保目录存在
|
|
12
|
+
try {
|
|
13
|
+
fs.accessSync(snippetsPath, fs.constants.F_OK);
|
|
14
|
+
} catch (err) {
|
|
15
|
+
fs.mkdirSync(snippetsPath, { recursive: true });
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return snippetsPath;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// 获取缓存目录路径(使用用户 home 目录下的缓存)
|
|
22
|
+
function getCachePath() {
|
|
23
|
+
const USER_HOME = process.env.HOME || process.env.USERPROFILE;
|
|
24
|
+
const cachePath = path.join(USER_HOME, '.autosnippet', 'cache');
|
|
25
|
+
|
|
26
|
+
// 确保目录存在
|
|
27
|
+
try {
|
|
28
|
+
fs.accessSync(cachePath, fs.constants.F_OK);
|
|
29
|
+
} catch (err) {
|
|
30
|
+
fs.mkdirSync(cachePath, { recursive: true });
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return cachePath;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
module.exports = {
|
|
37
|
+
getSnippetsPath,
|
|
38
|
+
getCachePath
|
|
39
|
+
};
|
package/bin/create.js
CHANGED
|
@@ -6,9 +6,32 @@ const readline = require('readline');
|
|
|
6
6
|
const cache = require('./cache.js');
|
|
7
7
|
const findPath = require('./findPath.js');
|
|
8
8
|
const install = require('./install.js');
|
|
9
|
+
// 全局常量
|
|
10
|
+
const README_NAME = 'readme.md';
|
|
9
11
|
// 全局路径
|
|
10
12
|
const CMD_PATH = process.cwd();
|
|
11
13
|
|
|
14
|
+
/**
|
|
15
|
+
* 根据文件路径确定模块名(SPM)
|
|
16
|
+
*/
|
|
17
|
+
function determineModuleName(filePath, packageInfo) {
|
|
18
|
+
// 从路径中提取模块名
|
|
19
|
+
// 例如:Services/Services/BDNetworkControl/Code/... -> BDNetworkControl
|
|
20
|
+
const packagePath = packageInfo.path;
|
|
21
|
+
const relativePath = path.relative(packagePath, filePath);
|
|
22
|
+
const segments = relativePath.split(path.sep);
|
|
23
|
+
|
|
24
|
+
// 查找匹配的 target
|
|
25
|
+
for (const segment of segments) {
|
|
26
|
+
if (packageInfo.targets.includes(segment)) {
|
|
27
|
+
return segment;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// 如果找不到,使用第一个 target
|
|
32
|
+
return packageInfo.targets[0] || packageInfo.name;
|
|
33
|
+
}
|
|
34
|
+
|
|
12
35
|
function updateCodeSnippets(specFile, word, key, value) {
|
|
13
36
|
if (key && key !== 'title' && key !== 'link' && key !== 'summary') {
|
|
14
37
|
console.log('此项属性不存在或不可修改。');
|
|
@@ -54,12 +77,61 @@ function updateCodeSnippets(specFile, word, key, value) {
|
|
|
54
77
|
}
|
|
55
78
|
}
|
|
56
79
|
|
|
57
|
-
|
|
80
|
+
/**
|
|
81
|
+
* 查找包含 // ACode 标记的文件
|
|
82
|
+
*/
|
|
83
|
+
async function findFilesWithACode(filePath) {
|
|
84
|
+
const filesWithACode = [];
|
|
85
|
+
|
|
86
|
+
try {
|
|
87
|
+
const files = await fs.promises.readdir(filePath);
|
|
88
|
+
|
|
89
|
+
for (const filename of files) {
|
|
90
|
+
const filedir = path.join(filePath, filename);
|
|
91
|
+
try {
|
|
92
|
+
const stats = await fs.promises.lstat(filedir);
|
|
93
|
+
if (stats.isFile()) {
|
|
94
|
+
// 只检查源代码文件
|
|
95
|
+
if (filename.endsWith('.m') || filename.endsWith('.h') || filename.endsWith('.swift')) {
|
|
96
|
+
const content = await fs.promises.readFile(filedir, 'utf8');
|
|
97
|
+
const lines = content.split('\n');
|
|
98
|
+
|
|
99
|
+
// 检查是否包含 // ACode 标记
|
|
100
|
+
for (let i = 0; i < lines.length; i++) {
|
|
101
|
+
if (lines[i].trim().toLowerCase() === '// acode') {
|
|
102
|
+
filesWithACode.push({
|
|
103
|
+
path: filedir,
|
|
104
|
+
name: filename,
|
|
105
|
+
line: i + 1
|
|
106
|
+
});
|
|
107
|
+
break; // 找到标记后跳出,每个文件只记录一次
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
} catch (err) {
|
|
113
|
+
// 忽略无法读取的文件
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
} catch (err) {
|
|
118
|
+
console.error('Error reading directory:', err);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return filesWithACode;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function createCodeSnippets(specFile, answers, updateSnippet, selectedFilePath) {
|
|
58
125
|
let snippet = updateSnippet;
|
|
59
126
|
let isHaveHeader = snippet === null ? false : (snippet['{headName}'] !== undefined);
|
|
60
127
|
|
|
61
128
|
if (snippet === null) {
|
|
62
|
-
|
|
129
|
+
// ✅ 处理 completion_more(可能是数组或字符串)
|
|
130
|
+
const completionMoreStr = Array.isArray(answers.completion_more)
|
|
131
|
+
? answers.completion_more.join('')
|
|
132
|
+
: answers.completion_more;
|
|
133
|
+
|
|
134
|
+
const answersKeys = answers.completion_first + completionMoreStr + answers.title;
|
|
63
135
|
const answersIdBuff = Buffer.from(answersKeys, 'utf-8');
|
|
64
136
|
const identifier = 'AutoSnip_' + answersIdBuff.toString('base64').replace(/\//g, '');
|
|
65
137
|
|
|
@@ -67,7 +139,7 @@ function createCodeSnippets(specFile, answers, updateSnippet) {
|
|
|
67
139
|
'{identifier}': identifier,
|
|
68
140
|
'{title}': answers.title,
|
|
69
141
|
'{completionKey}': answers.completion_first,
|
|
70
|
-
'{completion}': '@' + answers.completion_first +
|
|
142
|
+
'{completion}': '@' + answers.completion_first + completionMoreStr + '@Moudle',
|
|
71
143
|
'{summary}': answers.summary,
|
|
72
144
|
'{language}': 'Xcode.SourceCodeLanguage.Objective-C',
|
|
73
145
|
};
|
|
@@ -78,31 +150,39 @@ function createCodeSnippets(specFile, answers, updateSnippet) {
|
|
|
78
150
|
isHaveHeader = answers.header;
|
|
79
151
|
}
|
|
80
152
|
|
|
81
|
-
|
|
153
|
+
// ✅ 如果指定了文件路径,直接使用;否则查找当前目录下的所有文件
|
|
82
154
|
let filePathArr = [];
|
|
155
|
+
|
|
156
|
+
if (selectedFilePath) {
|
|
157
|
+
// 使用指定的文件
|
|
158
|
+
filePathArr = [selectedFilePath];
|
|
159
|
+
readStream(specFile, filePathArr, snippet, isHaveHeader);
|
|
160
|
+
} else {
|
|
161
|
+
// 原有逻辑:查找当前目录下的所有文件
|
|
162
|
+
const filePath = CMD_PATH;
|
|
163
|
+
fs.readdir(filePath, function (err, files) {
|
|
164
|
+
if (err) {
|
|
165
|
+
console.log(err);
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
83
168
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
const isFile = stats.isFile();
|
|
96
|
-
if (isFile) {
|
|
97
|
-
filePathArr.push(filedir);
|
|
169
|
+
files.forEach(function (filename) {
|
|
170
|
+
const filedir = path.join(filePath, filename);
|
|
171
|
+
try {
|
|
172
|
+
// 读取路径是否为文件
|
|
173
|
+
const stats = fs.lstatSync(filedir);
|
|
174
|
+
const isFile = stats.isFile();
|
|
175
|
+
if (isFile) {
|
|
176
|
+
filePathArr.push(filedir);
|
|
177
|
+
}
|
|
178
|
+
} catch (err) {
|
|
179
|
+
console.error(err);
|
|
98
180
|
}
|
|
99
|
-
}
|
|
100
|
-
console.error(err);
|
|
101
|
-
}
|
|
102
|
-
});
|
|
181
|
+
});
|
|
103
182
|
|
|
104
|
-
|
|
105
|
-
|
|
183
|
+
readStream(specFile, filePathArr, snippet, isHaveHeader);
|
|
184
|
+
});
|
|
185
|
+
}
|
|
106
186
|
}
|
|
107
187
|
|
|
108
188
|
function readStream(specFile, filePathArr, snippet, isHaveHeader) {
|
|
@@ -149,27 +229,58 @@ function readStream(specFile, filePathArr, snippet, isHaveHeader) {
|
|
|
149
229
|
const fileName = filePath.substring(slashIndex + 1, dotIndex + 1) + 'h';
|
|
150
230
|
const thePath = filePath.substring(0, slashIndex + 1);
|
|
151
231
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
const specPureName = specName.split('.')[0];
|
|
157
|
-
|
|
158
|
-
findPath.findSubHeaderPath(findFilePath, specPureName).then(function (headerPath) {
|
|
232
|
+
// ✅ 使用 SPM 的 Package.swift 查找(替代 .boxspec)
|
|
233
|
+
findPath.findPackageSwiftPath(thePath).then(async function (packagePath) {
|
|
234
|
+
if (!packagePath) {
|
|
235
|
+
console.log('未找到 Package.swift 文件,请检查路径。');
|
|
159
236
|
snippet['{content}'] = codeList;
|
|
160
|
-
snippet
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
if (headerPath) {
|
|
164
|
-
snippet['{specHeadPath}'] = encodeURI(headerPath.replace(specFilePath, ''));
|
|
165
|
-
}
|
|
237
|
+
saveFromFile(specFile, snippet);
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
166
240
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
}
|
|
241
|
+
// 解析 Package.swift 获取模块信息
|
|
242
|
+
const packageInfo = await findPath.parsePackageSwift(packagePath);
|
|
243
|
+
if (!packageInfo) {
|
|
244
|
+
snippet['{content}'] = codeList;
|
|
171
245
|
saveFromFile(specFile, snippet);
|
|
172
|
-
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// 根据当前文件路径确定模块名
|
|
250
|
+
const moduleName = determineModuleName(filePath, packageInfo);
|
|
251
|
+
const headerName = fileName.substring(0, fileName.length - 2); // 移除 .h
|
|
252
|
+
|
|
253
|
+
// ✅ 查找头文件(适配 SPM 的 include/ModuleName/ 结构)
|
|
254
|
+
const headerPath = await findPath.findSubHeaderPath(packageInfo.path, headerName, moduleName);
|
|
255
|
+
|
|
256
|
+
snippet['{content}'] = codeList;
|
|
257
|
+
snippet['{specName}'] = moduleName;
|
|
258
|
+
snippet['{headName}'] = fileName;
|
|
259
|
+
|
|
260
|
+
if (headerPath) {
|
|
261
|
+
// ✅ 使用 path.relative() 计算相对于配置文件的相对路径
|
|
262
|
+
const specFileDir = path.dirname(specFile);
|
|
263
|
+
const relativePath = path.relative(specFileDir, headerPath);
|
|
264
|
+
snippet['{specHeadPath}'] = encodeURI(relativePath);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// 查找 README.md
|
|
268
|
+
try {
|
|
269
|
+
const readmePath = path.join(packageInfo.path, README_NAME);
|
|
270
|
+
await fs.promises.access(readmePath);
|
|
271
|
+
// ✅ 使用 path.relative() 计算相对于配置文件的相对路径
|
|
272
|
+
const specFileDir = path.dirname(specFile);
|
|
273
|
+
const readmeRelativePath = path.relative(specFileDir, readmePath);
|
|
274
|
+
snippet['{readme}'] = encodeURI(readmeRelativePath);
|
|
275
|
+
} catch {
|
|
276
|
+
// README.md 不存在,跳过
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
saveFromFile(specFile, snippet);
|
|
280
|
+
}).catch(function (err) {
|
|
281
|
+
console.error('Error finding Package.swift:', err);
|
|
282
|
+
snippet['{content}'] = codeList;
|
|
283
|
+
saveFromFile(specFile, snippet);
|
|
173
284
|
});
|
|
174
285
|
} else {
|
|
175
286
|
snippet['{content}'] = codeList;
|
|
@@ -222,7 +333,8 @@ function saveFromFile(specFile, snippet) {
|
|
|
222
333
|
console.log(err);
|
|
223
334
|
}
|
|
224
335
|
cache.updateCache(specFile, content);
|
|
225
|
-
|
|
336
|
+
// ✅ 只写入刚创建的代码片段,而不是所有代码片段
|
|
337
|
+
install.addCodeSnippets(specFile, snippet);
|
|
226
338
|
}
|
|
227
339
|
}
|
|
228
340
|
}
|
|
@@ -258,4 +370,5 @@ function escapeString(string) {
|
|
|
258
370
|
|
|
259
371
|
exports.createCodeSnippets = createCodeSnippets;
|
|
260
372
|
exports.updateCodeSnippets = updateCodeSnippets;
|
|
261
|
-
exports.saveFromFile = saveFromFile;
|
|
373
|
+
exports.saveFromFile = saveFromFile;
|
|
374
|
+
exports.findFilesWithACode = findFilesWithACode;
|