jsir 1.3.1 → 2.0.0

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.
@@ -1,10 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  const {
3
- run, getLibDataDir, trim, regEach, getConfig, mkdir, reget,
4
- getCbText, e, sleep, objDataFile, setConfig, vl, md5, BigNumber,
3
+ getLibDataDir, trim, regEach, getConfig, mkdir, reget,
4
+ getCbText, e, sleep, objDataFile, vl, md5, BigNumber,
5
5
  info, warn, error, arrayDataFile, infoStr, warnStr, errorStack,
6
6
  getInfo, ei, pad, msgStr, getType,
7
- errorTag, isArgsMatch, draftQuery
7
+ errorTag, isArgsMatch, draftQuery, setConfig,
8
+ $log, $draft, $config, getTextComments
8
9
  } = require('../util')
9
10
  const evalCode = require('../evalCode')
10
11
 
@@ -16,112 +17,32 @@ const _types = {
16
17
  const _chokidar = require('chokidar');
17
18
  const _fs = require('fs')
18
19
  const _libDataDir = getLibDataDir()
19
- const _home = _libDataDir + '/ooa'
20
20
  const _args = process.argv.slice(2).map(trim)
21
21
  const _history9 = []
22
22
  const _tipsOnRm = {}
23
- const _setting = require('../setting')
24
23
  const readline = require("readline");
25
24
  const _fileWatcherMap = {}
26
-
25
+ const setting = require('../setting')
26
+ let _cmdMapFile = setting.name + 'CmdMap.json'
27
27
  let _cmdMap = {}
28
28
  let _rl
29
29
  let _rlHistory = []
30
30
  let _haveWrapperInput = true
31
- let _repos = arrayDataFile('repos.json')
31
+ let _workspaceConfigFile = 'workspace.json';
32
+ let _workspaces = arrayDataFile(_workspaceConfigFile)
32
33
  let _exit = false
33
34
 
34
35
  const $data = {}
36
+ const $homeDir = getLibDataDir()
37
+ const $lib = {...require('../util')}
35
38
 
36
- global.$lib = {}
37
39
  global.$tips = {}
38
40
  global.$newInput = false
39
-
40
- try {
41
- getConfig("jsLibSource")
42
- } catch (e) {
43
- error(e)
44
- }
41
+ global.$workspaceMap = {}
42
+ global.$defaultSpace = 'local'
45
43
 
46
44
  let _noAppendNextLine = true
47
45
 
48
- const _mainCmdMap = {
49
- repl: {
50
- comment: "交互界面",
51
- },
52
- add: {
53
- comment: "新增脚本",
54
- cmd: ['@e ']
55
- },
56
- note: {
57
- comment: "新增笔记",
58
- cmd: ['@']
59
- },
60
- config: {
61
- comment: "配置",
62
- cmd: []
63
- },
64
- init: {
65
- comment: "新增初始资源",
66
- cmd: ['@i ']
67
- },
68
- file: {
69
- comment: "工作脚本模式",
70
- cmd: ['@f ']
71
- },
72
- rm: {
73
- comment: "删除脚本",
74
- cmd: ['@-']
75
- },
76
- edit: {
77
- comment: "编辑脚本",
78
- cmd: ['@w']
79
- },
80
- diff: {
81
- comment: "比较脚本变更",
82
- cmd: ['@c']
83
- },
84
- push: {
85
- comment: "推送到本地仓库",
86
- cmd: ['@#']
87
- },
88
- pull: {
89
- comment: "更新工作空间脚本",
90
- cmd: ['@*']
91
- },
92
- repo: {
93
- comment: "设置本地仓库目录",
94
- cmd: ['@% ']
95
- },
96
- lib: {
97
- comment: "查看内置资源",
98
- cmd: ['*$lib ']
99
- },
100
- deps: {
101
- comment: "查看依赖",
102
- cmd: ['@^']
103
- }
104
- }
105
-
106
- Object.keys(_mainCmdMap).forEach(key => {
107
- let val = _mainCmdMap[key];
108
- delete _mainCmdMap[key];
109
- _mainCmdMap['--' + key] = val;
110
- })
111
-
112
- function isMainCmd(mainList) {
113
- if (!mainList) {
114
- mainList = Object.keys(_mainCmdMap)
115
- } else {
116
- mainList = mainList.map(item => '--' + item);
117
- }
118
- return mainList.indexOf(_args[0]) !== -1;
119
- }
120
-
121
- function initRuntime() {
122
- global.$lib = {...require('../util')}
123
- }
124
-
125
46
  function getFileOpenExe(fileName) {
126
47
  fileName = trim(fileName);
127
48
  let strs = fileName.split('.')
@@ -137,93 +58,51 @@ function getFileOpenExe(fileName) {
137
58
  return exe || 'idea';
138
59
  }
139
60
 
140
- run(async () => {
141
- mkdir(_home)
142
- if (isMainCmd(['config'])) {
143
- let fileName = 'config.json';
144
- let configFile = getLibDataDir() + '/' + fileName;
145
- ei('vi', [configFile])
146
- return
61
+ function checkWorkspaces() {
62
+ let localWorkspace = _libDataDir + '/local';
63
+ $workspaceMap['local'] = localWorkspace;
64
+ mkdir(localWorkspace)
65
+ for (let workspace of _workspaces) {
66
+ workspace = workspace.replace(/\/+$/, '')
67
+ let space = getSpaceFromDir(workspace);
68
+ if (space === 'local') {
69
+ continue
70
+ }
71
+ if (_fs.existsSync(workspace)) {
72
+ $workspaceMap[space] = workspace;
73
+ }
147
74
  }
75
+ _workspaces = Object.values($workspaceMap);
76
+ arrayDataFile(_workspaceConfigFile, () => _workspaces)
77
+ initWorkspace()
78
+ }
148
79
 
149
- dealSourceCmds()
80
+ async function start() {
81
+ checkWorkspaces()
150
82
 
151
- if (isMainCmd(['repl'])) {
152
- initRuntime()
83
+ if (_args[0] === '--repl') {
153
84
  _noAppendNextLine = false
154
- } else if (isMainCmd()){
155
- if (_noAppendNextLine) {
156
- _cmdMap = objDataFile('ooaCmdMap.json')
157
- }
158
-
159
- if (isMainCmd(['edit', 'rm', 'diff', 'push', 'pull', 'deps'])
160
- && _args[1] && !/^\d+$/.test(_args[1])) {
161
- warn('wrong args')
162
- return
163
- }
164
- if (isMainCmd(['lib'])) {
165
- initRuntime()
166
- }
167
- if (isMainCmd(['add', 'note', 'init'])
168
- && (!_args[1] || /^\d+$/.test(_args[1]))) {
169
- warn('wrong args')
170
- return
171
- }
172
-
173
- let argStr = _args.slice(1).map(i => {
174
- if (/\s+/.test(i) || !i) {
175
- i = `"${i}"`
176
- }
177
- return i
178
- }).join(' ').replace(/^@/, '')
179
- if (isMainCmd(['edit', 'rm', 'diff', 'push', 'pull', 'deps']) && !trim(argStr)) {
180
- _args[0] = '@'
181
- }
182
- if (isMainCmd(['file'])) {
183
- initRuntime()
184
- }
185
- let info = _mainCmdMap[_args[0]]
186
- if (info) {
187
- for(let cmd of info.cmd) {
188
- await wrapperInput(`${cmd}${argStr}`)
189
- }
190
- } else {
191
- await wrapperInput(`${_args[0]}${argStr}`)
192
- }
193
- } else if (_args[0] && _args[0].startsWith('-')) {
194
- let cols = []
195
- for (let key of Object.keys(_mainCmdMap)) {
196
- cols.push({
197
- cmd: key,
198
- comment: _mainCmdMap[key].comment
199
- })
200
- }
201
- console.table(cols)
85
+ console.log(warnStr("You can start with .help, use * to expand context"))
202
86
  } else if (_args[0]) {
203
87
  if (_noAppendNextLine) {
204
- _cmdMap = objDataFile('ooaCmdMap.json')
88
+ _cmdMap = objDataFile(_cmdMapFile)
205
89
  }
206
90
  let line = _args.map(i => {
207
91
  if (/\s+/.test(i) || !i) {
208
92
  i = `"${i}"`
209
93
  }
210
94
  return i
211
- }).join(' ').replace(/^@/, '')
212
- if (/^\d+$/.test(_args[0])) {
213
- if (_args[0] === '0' || (_cmdMap[_args[0]] && ['e ', 'f '].filter(i => _cmdMap[_args[0]].startsWith(i)).length > 0)) {
214
- initRuntime()
215
- }
216
- }
95
+ }).join(' ')
217
96
  await wrapperInput(line)
218
97
  } else {
219
98
  if (_noAppendNextLine) {
220
- _cmdMap = objDataFile('ooaCmdMap.json')
99
+ _cmdMap = objDataFile(_cmdMapFile)
221
100
  }
222
- await wrapperInput('@')
101
+ listCmd();
223
102
  }
224
- })
103
+ }
225
104
 
226
- async function getFileWatcher(fileName, workFilePath, text) {
105
+ async function getFileWatcher(workFilePath, text) {
227
106
  info("workFile open " + workFilePath)
228
107
  if (!_fileWatcherMap[workFilePath]) {
229
108
  _fs.unlinkSync(workFilePath)
@@ -246,22 +125,21 @@ function closeFileWatcher(workFilePath) {
246
125
  delete _fileWatcherMap[workFilePath]
247
126
  }
248
127
 
249
- async function workFile(name) {
250
- name = trim(name)
251
- if (!name) {
252
- name = 'workFile'
128
+ async function workFile(uniqueName) {
129
+ uniqueName = trim(uniqueName)
130
+ if (!uniqueName) {
131
+ uniqueName = toUniqueName('f workFile')
253
132
  }
254
- let fileName = `f ${toJsirFileName(name)}`
255
- await watchFile(fileName)
133
+ await watchFile(uniqueName)
256
134
  }
257
135
 
258
- async function watchFile(fileName) {
259
- let workFilePath = `${_home}/${fileName}`;
136
+ async function watchFile(uniqueName) {
137
+ let workFilePath = getFullPath(uniqueName);
260
138
  if (!_fs.existsSync(workFilePath)) {
261
139
  _fs.writeFileSync(workFilePath, '');
262
140
  }
263
141
  let text = String(_fs.readFileSync(workFilePath))
264
- let watcher = await getFileWatcher(fileName, workFilePath, text)
142
+ let watcher = await getFileWatcher(workFilePath, text)
265
143
 
266
144
  if (watcher) {
267
145
  watcher.on('change', async () => {
@@ -280,7 +158,7 @@ async function watchFile(fileName) {
280
158
  closeFileWatcher(workFilePath);
281
159
  });
282
160
  }
283
- await e(`"${getFileOpenExe(fileName)}" "${workFilePath}"`)
161
+ await e(`"${getFileOpenExe(parseUniqueName(uniqueName)[1])}" "${workFilePath}"`)
284
162
  }
285
163
 
286
164
  function getExeStr(oldText, newText) {
@@ -355,12 +233,11 @@ function initRl(callback, preStr, hidden) {
355
233
  _rl.history = _rlHistory
356
234
  }
357
235
 
358
- let repoTip = trim(trim(getConfig("jsLibSource")).split('/').map(trim).reverse().filter(i => i)[0])
359
236
  let promptStr = preStr
360
237
  if (promptStr !== '') {
361
238
  promptStr = (preStr
362
239
  || ((callback && callback !== wrapperInput) ? "-> ":"")
363
- || [Object.values(global.$tips).filter(i => String(i)).join(','), repoTip].filter(i => i).join(':') + `> `)
240
+ || [Object.values(global.$tips).filter(i => String(i)).join(','), $defaultSpace].filter(i => i).join(':') + `> `)
364
241
  promptStr = infoStr(promptStr)
365
242
  }
366
243
  if (hidden) {
@@ -446,26 +323,13 @@ async function nextText(callback, end, hidden) {
446
323
  })
447
324
  }
448
325
 
449
- function dealSourceCmds() {
450
- let source = trim(getConfig("jsLibSource"));
451
- if (source && _fs.existsSync(source)) {
452
- _fs.readdirSync(source).filter(isJsirFileName).forEach(item => {
453
- if (!_fs.existsSync(_home + "/" + item)) {
454
- _fs.writeFileSync(_home + "/" + item, String(_fs.readFileSync(source + "/" + item)))
455
- }
456
- })
457
- } else {
458
- warn(`require config.jsLibSource, run [${_setting.name} repo]`)
459
- }
460
- }
461
-
462
326
  async function save(args) {
463
- let name = toJsirFileName(args.join(' '))
464
- let path = `${_home}/${name}`
327
+ let uniqueName = toUniqueName(toJsirFileName(args.join(' ')))
328
+ let path = getFullPath(uniqueName)
465
329
  if (_fs.existsSync(path)) {
466
330
  warn(`${path} already exist`)
467
331
  _cmdMap = {
468
- 1: name
332
+ 1: uniqueName
469
333
  }
470
334
  listCmd()
471
335
  return
@@ -504,32 +368,24 @@ return {}
504
368
  _fs.writeFileSync(path, resp)
505
369
  info(`${path} created`)
506
370
  _cmdMap = {
507
- 1: name
371
+ 1: uniqueName
508
372
  }
509
373
  listCmd()
510
374
  }
511
375
 
512
- function rename(dir, oldName, newName, isOoa) {
376
+ function rename(dir, oldName, newName) {
513
377
  let old = dir + '/' + oldName;
514
378
  let _new = dir + '/' + newName;
515
379
  if (_fs.existsSync(_new)) {
516
- if (isOoa) {
517
- warn(`${_new} already exist`)
518
- _cmdMap = {
519
- 1: newName
520
- }
521
- listCmd()
522
- }
523
- return
524
- }
525
- _fs.rename(old, _new, ()=>{})
526
- if (isOoa) {
380
+ warn(`${_new} already exist`)
381
+ } else {
382
+ _fs.rename(old, _new, ()=>{})
527
383
  info(`${_new} renamed`)
528
- _cmdMap = {
529
- 1: newName
530
- }
531
- listCmd()
532
384
  }
385
+ _cmdMap = {
386
+ 1: toUniqueName(newName)
387
+ }
388
+ listCmd()
533
389
  }
534
390
 
535
391
  function putHis(x) {
@@ -552,85 +408,57 @@ function hisToCmdMap() {
552
408
  _cmdMap = cmdMap
553
409
  }
554
410
 
555
- function listCmd(prefixKey, inputCmdMap) {
556
- let currCmdMap = _cmdMap
557
- if (inputCmdMap) {
558
- currCmdMap =inputCmdMap;
559
- }
560
- let newCmdMap = {}
561
- let prefixMap = {}
562
- for (let i of Object.keys(currCmdMap)) {
563
- let jsLib = trim(getConfig("jsLibSource"))
564
- let sourceFile = jsLib + "/" + currCmdMap[i]
565
- let prefix = [' ', ' ']
566
- prefixMap[currCmdMap[i]] = prefix;
567
- if (jsLib && _fs.existsSync(sourceFile)) {
568
- prefix[1] = '#'
569
- let text1 = String(_fs.readFileSync(_home + "/" + currCmdMap[i]))
570
- let text2 = String(_fs.readFileSync(sourceFile))
571
- if (text1 !== text2) {
572
- prefix[0] = '*'
573
- }
574
- }
575
- }
576
- let items = Object.values(currCmdMap)
577
- .filter(item => _fs.existsSync(_home + "/" + item)
578
- && ((prefixKey === '' && prefixMap[item].filter(i => trim(i)).length <= 0)
579
- || (trim(prefixKey) && prefixMap[item].indexOf(trim(prefixKey)) !== -1)
580
- || (!prefixKey && prefixKey !== '')))
411
+ function listCmd() {
412
+ let items = Object.values(_cmdMap)
413
+ .filter(item => _fs.existsSync(getFullPath(item)))
581
414
  .sort((a,b) => {
415
+ a = parseUniqueName(a)[1];
416
+ b = parseUniqueName(b)[1];
582
417
  let typeKeys = Object.keys(_types);
583
418
  let orderA = typeKeys.indexOf(a.split(/\s+/)[0]);
584
419
  let orderB = typeKeys.indexOf(b.split(/\s+/)[0]);
585
- orderA = orderA === -1 ? 999:orderA;
586
- orderB = orderB === -1 ? 999:orderB;
420
+ orderA = orderA === -1 ? 999999:orderA;
421
+ orderB = orderB === -1 ? 999999:orderB;
587
422
  return orderA - orderB
588
423
  })
589
- for(let i = 0; i< items.length; i++) {
590
- newCmdMap[i + 1] =items[i]
591
- }
592
424
 
593
- currCmdMap = newCmdMap
594
- if (!inputCmdMap) {
595
- _cmdMap = newCmdMap
596
- if (_noAppendNextLine) {
597
- objDataFile('ooaCmdMap.json', () => _cmdMap)
598
- }
599
- } else {
600
- for (let key of Object.keys(inputCmdMap)) {
601
- delete inputCmdMap[key]
602
- }
603
- Object.assign(inputCmdMap, newCmdMap)
425
+ _cmdMap = arrayToCmdMap(items)
426
+ if (_noAppendNextLine) {
427
+ objDataFile(_cmdMapFile, () => _cmdMap)
604
428
  }
605
429
 
606
430
  items = []
607
- for (let i of Object.keys(currCmdMap)) {
608
- let prefix = prefixMap[currCmdMap[i]]
609
- let text = String(_fs.readFileSync(_home + "/" + currCmdMap[i]))
610
- let name = trimJsirFileName(currCmdMap[i])
611
- let suffix = getJsirFileSuffix(currCmdMap[i])
431
+ for (let i of Object.keys(_cmdMap)) {
432
+ let text = String(_fs.readFileSync(getFullPath(_cmdMap[i])))
433
+ let pair = parseUniqueName(_cmdMap[i])
434
+ let name = trimJsirFileName(pair[1])
435
+ let suffix = getJsirFileSuffix(pair[1])
612
436
  let item = {
613
- key: prefix.join('') + i,
614
- name: name.replace(/^[eif]\s+/, ''),
437
+ key: ' ' + i,
438
+ name: pair[0] + '/' + name.replace(/^[eif]\s+/, ''),
615
439
  type: [_types[name.split(/\s+/)[0]] || 'note', suffix].map(trim).join(".")
616
440
  }
617
441
  items.push(item)
618
442
 
619
443
  if (!text) {
620
- text = String(_fs.readFileSync(_home + "/" + currCmdMap[i]))
444
+ text = String(_fs.readFileSync(getFullPath(_cmdMap[i])))
621
445
  }
622
- getComments(i, currCmdMap[i], text, items, item)
446
+ getComments(i, _cmdMap[i], text, items, item)
623
447
  }
624
448
  if (Object.keys(items).length === 0) {
625
449
  warn("no items")
626
450
  } else {
627
451
  items.forEach(item => {
628
452
  if (item.type) {
453
+ let pair = parseUniqueName(item.name);
629
454
  if (item.type.startsWith('exe.')) {
630
- item.name = infoStr(item.name)
455
+ item.name = infoStr(pair[1])
631
456
  } else if (item.type.startsWith('init.')) {
632
- item.name = msgStr(item.name)
457
+ item.name = msgStr(pair[1])
458
+ } else {
459
+ item.name = pair[1]
633
460
  }
461
+ item.name = pair[0] + '/' + item.name
634
462
  }
635
463
  })
636
464
  console.table(items)
@@ -657,7 +485,7 @@ async function _wrapperInput(str) {
657
485
  let cmdStr = trim(str.substr(1));
658
486
  if (/^\d+$/.test(cmdStr) && _cmdMap[cmdStr]) {
659
487
  if (_cmdMap[cmdStr]) {
660
- ei('vi', [getLibDataDir() + '/ooa/' + _cmdMap[cmdStr]])
488
+ ei('vi', [getFullPath(_cmdMap[cmdStr])])
661
489
  } else {
662
490
  warn("no items")
663
491
  }
@@ -688,6 +516,9 @@ async function _wrapperInput(str) {
688
516
  if (is$) {
689
517
  console.log(await evalText('return ' + text))
690
518
  } else if (isStar) {
519
+ if (!text) {
520
+ text = '$context';
521
+ }
691
522
  let items = text.split(/\s+/).map(trim).filter(i => i)
692
523
  let result = await evalText('return ' + items[0])
693
524
  if (!result || typeof result === 'string' || Object.keys(result).length === 0) {
@@ -697,7 +528,7 @@ async function _wrapperInput(str) {
697
528
  let rows = []
698
529
  let matchs = items.slice(1)
699
530
  for (let key of Object.keys(result)) {
700
- if (matchs.length === 0 || isArgsMatch(key, matchs)){
531
+ if (matchs.length === 0 || isArgsMatch(key, [matchs.join(' ')])){
701
532
  rows.push(getInfo(result[key], key))
702
533
  }
703
534
  }
@@ -709,27 +540,26 @@ async function _wrapperInput(str) {
709
540
  } else {
710
541
  await evalText(text)
711
542
  }
712
- } else if (str.match(/^@/)) {
713
- let strs = trim(str.substring(1)).split(/\s+/)
714
- let fstr = strs[0]
715
- let ostr = strs.slice(1)
716
- if (fstr) {
717
- await dealKeyword(str, strs, fstr, ostr)
543
+ } else if (str.match(/^\./)) {
544
+ let argsStr = trim(str.substring(1))
545
+ if (argsStr) {
546
+ await dealKeyword(argsStr)
718
547
  } else {
719
- listCmd()
548
+ help()
720
549
  }
721
550
  } else if (!str.split(/\s+/)[0].match(/^\d+$/)) {
722
- _cmdMap = filterCmd(str.split(/\s+/))
551
+ _cmdMap = arrayToCmdMap(filterCmd(str))
723
552
  listCmd()
724
553
  } else {
725
554
  let strs = str.split(/\s+/)
726
555
  if (_cmdMap[strs[0]]) {
727
556
  putHis(_cmdMap[strs[0]])
728
- let path = _home + '/' + _cmdMap[strs[0]]
729
- let fileName = trim(_cmdMap[strs[0]]);
557
+ let path = getFullPath(_cmdMap[strs[0]])
558
+ let uniqueName = trim(_cmdMap[strs[0]]);
559
+ let fileName = parseUniqueName(uniqueName)[1]
730
560
  let firstName = fileName.split(/\s+/)[0]
731
561
  if (firstName === 'f') {
732
- await workFile(fileName.replace(/^\s*f\s*/, ''))
562
+ await workFile(uniqueName)
733
563
  } else if (firstName !== 'e') {
734
564
  console.log(String(_fs.readFileSync(path)));
735
565
  } else {
@@ -741,6 +571,25 @@ async function _wrapperInput(str) {
741
571
  }
742
572
  }
743
573
 
574
+ function arrayToCmdMap(cmds) {
575
+ let cmdMap = {}
576
+ for (let i = 0; i < cmds.length; i++) {
577
+ cmdMap[i + 1] = cmds[i];
578
+ }
579
+ return cmdMap
580
+ }
581
+
582
+ function help() {
583
+ console.nable(Object.keys(keywordDef).map(key => {
584
+ let item = keywordDef[key];
585
+ return {
586
+ keyword: ' ' + warnStr(`.${key}`),
587
+ short: ' ' + warnStr(`.${item.short}`),
588
+ comment: [item.comment, item.args ? getArgComments(item.args).join('\n'):''].filter(i => i).join("\n"),
589
+ }
590
+ }))
591
+ }
592
+
744
593
  function delTipsByIndex(idxs) {
745
594
  let keys = Object.keys($tips)
746
595
  let indexKeyMap = {}
@@ -760,271 +609,415 @@ function delTipsByIndex(idxs) {
760
609
  delTips(...params)
761
610
  }
762
611
 
763
- async function dealKeyword(str, strs, fstr, ostr) {
764
- if (fstr.startsWith("<")) {
765
- delTipsByIndex([fstr, ...ostr].join(" ").replace(/^</, '').split(/\s+/).filter(i => i))
766
- } else if (/^\d+$/.test(fstr)) {
767
- if (!_cmdMap[fstr]) {
768
- warn("no items")
769
- } else {
770
- let path = _home + '/' + _cmdMap[fstr]
771
- let sourceStr = String(_fs.readFileSync(path))
772
- console.log(sourceStr)
612
+ function copyToSpace(uniqueName) {
613
+ let path = getFullPath(uniqueName)
614
+ let text = String(_fs.readFileSync(path))
615
+ let fileName = parseUniqueName(uniqueName)[1];
616
+ let targetPath = $workspaceMap[$defaultSpace] + '/' + fileName;
617
+ if (_fs.existsSync(targetPath)) {
618
+ warn(`${fileName} already exist in ${$defaultSpace}`)
619
+ } else {
620
+ _fs.writeFileSync(targetPath, text)
621
+ info(`get ${uniqueName} to ${$defaultSpace}`)
622
+ }
623
+ }
624
+
625
+ let compareMode = {
626
+ 'a=': (aSpace, bSpace, as, bs) => {
627
+ let result = []
628
+ for (let a of as) {
629
+ if (bs.indexOf(a) !== -1) {
630
+ result.push(aSpace + '/' + a)
631
+ }
773
632
  }
774
- } else if (/^-\d*$/.test(fstr)) {
775
- let name = _cmdMap[String(Number(fstr) * -1)]
776
- if (!name) {
777
- warn("no items")
778
- } else {
779
- let path = _home + '/' + name
780
- _fs.unlinkSync(path)
781
- let jsLibDir = trim(getConfig("jsLibSource"))
782
- if (jsLibDir && _fs.existsSync(jsLibDir)) {
783
- if (_fs.existsSync(jsLibDir + '/' + name)) {
784
- _fs.unlinkSync(jsLibDir + '/' + name)
785
- }
633
+ return result
634
+ },
635
+ 'b=': (aSpace, bSpace, as, bs) => {
636
+ let result = []
637
+ for (let a of as) {
638
+ if (bs.indexOf(a) !== -1) {
639
+ result.push(bSpace + '/' + a)
786
640
  }
787
- info(`${path} removed`)
788
641
  }
789
- } else if (/^\+\d*$/.test(fstr)) {
790
- let name = _cmdMap[trim(fstr.replace(/^\+/, ''))]
791
- if (!name) {
792
- warn("no items")
793
- } else {
794
- let path = _home + '/' + name
795
- let text =trim(trim(str.substring(1)).replace(/^\+\d+/, ''))
796
- if (!text) {
797
- text = await getCbText()
642
+ return result
643
+ },
644
+ 'ab=': (aSpace, bSpace, a, b, as, bs) => {
645
+ let result = []
646
+ for (let a of as) {
647
+ if (bs.indexOf(a) !== -1) {
648
+ result.push(aSpace + '/' + a)
649
+ result.push(bSpace + '/' + a)
798
650
  }
799
- if (text) {
800
- _fs.appendFileSync(path, '\n' + text)
651
+ }
652
+ return result
653
+ },
654
+ 'a+': (aSpace, bSpace, as, bs) => {
655
+ let result = []
656
+ for(let a of as) {
657
+ if (bs.indexOf(a) === -1) {
658
+ result.push(aSpace + '/' + a)
801
659
  }
802
660
  }
803
- } else if (/^v\d*$/.test(fstr)) {
804
- let name = _cmdMap[trim(fstr.replace(/^v/, ''))]
805
- if (!name) {
806
- warn("no items")
807
- } else {
808
- let path = _home + '/' + _cmdMap[trim(fstr.replace(/^v/, ''))]
809
- let text =trim(trim(str.substring(1)).replace(/^v\d+/, ''))
810
- if (!text) {
811
- text = await getCbText()
661
+ return result
662
+ },
663
+ 'b+': (aSpace, bSpace, as, bs) => {
664
+ let result = []
665
+ for(let b of bs) {
666
+ if (as.indexOf(b) === -1) {
667
+ result.push(bSpace + '/' + b)
812
668
  }
813
- if (text) {
814
- _fs.writeFileSync(path, text)
669
+ }
670
+ return result
671
+ },
672
+ 'ab+': (aSpace, bSpace, as, bs) => {
673
+ let result = []
674
+ for(let a of as) {
675
+ if (bs.indexOf(a) === -1) {
676
+ result.push(aSpace + '/' + a)
815
677
  }
816
678
  }
817
- } else if (/^r\d*$/.test(fstr)) {
818
- let name = _cmdMap[trim(fstr.replace(/^r/, ''))]
819
- if (!name) {
820
- warn("no items")
821
- } else {
822
- let newName =trim(ostr.join(" "))
823
- if (newName) {
824
- newName = toJsirFileName(newName)
825
- let jsLibDir = trim(getConfig("jsLibSource"))
826
- if (jsLibDir && _fs.existsSync(jsLibDir)) {
827
- if (_fs.existsSync(jsLibDir + '/' + name)) {
828
- rename(jsLibDir, name, newName)
829
- }
830
- }
831
- rename(_home, name, newName, true)
679
+ for(let b of bs) {
680
+ if (as.indexOf(b) === -1) {
681
+ result.push(bSpace + '/' + b)
832
682
  }
833
683
  }
834
- } else if (/^s\d*$/.test(fstr)) {
835
- let name = _cmdMap[trim(fstr.replace(/^s/, ''))]
836
- if (!name) {
837
- warn("no items")
838
- } else {
839
- let jsLibDir = trim(getConfig("jsLibSource"))
840
- if (jsLibDir && _fs.existsSync(jsLibDir)) {
841
- let sFile = jsLibDir + "/" + name
842
- if (_fs.existsSync(sFile)) {
843
- let sourceStr = String(_fs.readFileSync(sFile))
844
- console.log(sourceStr)
684
+ return result
685
+ }
686
+ }
687
+
688
+ const keywordDef = {
689
+ help: {
690
+ comment: '帮助文档',
691
+ exeFn: (args) => {
692
+ help()
693
+ },
694
+ short: 'H'
695
+ },
696
+ list: {
697
+ comment: '查看文件列表',
698
+ exeFn: (args) => {
699
+ _cmdMap = arrayToCmdMap(filterCmd(args.length > 0 ? args.join(' '):[',']))
700
+ listCmd()
701
+ },
702
+ args: {
703
+ queryParams: '条件参数(param1,param2 param3 ...)'
704
+ },
705
+ short: 'l'
706
+ },
707
+ clear: {
708
+ comment: '清除任务',
709
+ exeFn: (args) => {
710
+ delTipsByIndex(args.filter(i => i))
711
+ },
712
+ args: {
713
+ tipIndex: '左侧提示符下标,可以多个用空格隔开'
714
+ },
715
+ short: 'C'
716
+ },
717
+ see: {
718
+ comment: '查看文件',
719
+ exeFn: (args) => {
720
+ let uniqueName = _cmdMap[args[0]]
721
+ if (!uniqueName) {
722
+ warn("no items")
723
+ } else {
724
+ let path = getFullPath(uniqueName)
725
+ let sourceStr = String(_fs.readFileSync(path))
726
+ console.log(sourceStr)
727
+ }
728
+ },
729
+ args: {
730
+ fileIndex: '文件下标'
731
+ },
732
+ short: 's'
733
+ },
734
+ rm: {
735
+ comment: '删除文件',
736
+ exeFn: (args) => {
737
+ let uniqueName = _cmdMap[args[0]]
738
+ if (args[0] === 'ALL') {
739
+ for (let value of Object.values(_cmdMap)) {
740
+ let path = getFullPath(value)
741
+ _fs.unlinkSync(path)
742
+ info(`${path} removed`)
845
743
  }
744
+ } else if (!uniqueName) {
745
+ warn("no items")
846
746
  } else {
847
- warn('require config.jsLibSource')
747
+ let path = getFullPath(uniqueName)
748
+ _fs.unlinkSync(path)
749
+ info(`${path} removed`)
848
750
  }
849
- }
850
- } else if (/^\*\d*$/.test(fstr)) {
851
- let name = _cmdMap[trim(fstr.replace(/^\*/, ''))]
852
- if (fstr === '*') {
853
- listCmd('*')
854
- } else if (!name) {
855
- warn("no items")
856
- } else {
857
- let jsLibDir = trim(getConfig("jsLibSource"))
858
- if (jsLibDir && _fs.existsSync(jsLibDir)) {
859
- let sFile = jsLibDir + "/" + name
860
- if (_fs.existsSync(sFile)) {
861
- let sourceStr = String(_fs.readFileSync(sFile))
862
- let path = _home + '/' + _cmdMap[trim(fstr.replace(/^\*/, ''))]
863
- if (sourceStr) {
864
- _fs.writeFileSync(path, sourceStr)
865
- }
751
+ },
752
+ args: {
753
+ fileIndex: '文件下标, ALL代表全部'
754
+ },
755
+ short: 'R'
756
+ },
757
+ get: {
758
+ comment: '获取文件',
759
+ exeFn: (args) => {
760
+ let uniqueName = _cmdMap[args[0]]
761
+ if (args[0] === 'ALL') {
762
+ for (let value of Object.values(_cmdMap)) {
763
+ copyToSpace(value)
866
764
  }
867
- info(`${name} pulled`)
765
+ } else if (!uniqueName) {
766
+ warn("no items")
868
767
  } else {
869
- warn('require config.jsLibSource')
768
+ copyToSpace(uniqueName)
870
769
  }
871
- }
872
- } else if (/^#\d*$/.test(fstr)) {
873
- let name = _cmdMap[trim(fstr.replace(/^#/, ''))]
874
- if (fstr === '#') {
875
- listCmd('#')
876
- } else if (!name) {
877
- warn("no items")
878
- } else {
879
- let jsLibDir = trim(getConfig("jsLibSource"))
880
- if (jsLibDir && _fs.existsSync(jsLibDir)) {
881
- _fs.writeFileSync(jsLibDir + "/" + name, String(_fs.readFileSync(_home + '/' + name)))
882
- info(`${name} pushed`)
770
+ },
771
+ args: {
772
+ fileIndex: '文件下标, ALL代表全部'
773
+ },
774
+ short: 'g'
775
+ },
776
+ rename: {
777
+ comment: '重命名文件',
778
+ exeFn: (args) => {
779
+ let uniqueName = _cmdMap[args[0]]
780
+ if (!uniqueName) {
781
+ warn("no items")
883
782
  } else {
884
- warn('require config.jsLibSource')
783
+ let pair = parseUniqueName(uniqueName)
784
+ let newName =trim(args.slice(1).join(" "))
785
+ rename($workspaceMap[pair[0]], pair[1], toJsirFileName(newName), true)
885
786
  }
886
- }
887
- }else if (fstr === '!') {
888
- listCmd('')
889
- } else if (/^w\d*$/.test(fstr)) {
890
- let name = _cmdMap[trim(fstr.replace(/^w/, ''))]
891
- if (!name) {
892
- warn("no items")
893
- } else {
894
- let path = _home + '/' + name
895
- await e(`"${getFileOpenExe(name)}" "${path}"`)
896
- }
897
- } else if (/^c\d*$/.test(fstr)) {
898
- let name = _cmdMap[trim(fstr.replace(/^c/, ''))]
899
- if (!name) {
900
- warn("no items")
901
- } else {
902
- let path = _home + '/' + name
903
- let jsLibDir = trim(getConfig("jsLibSource"))
904
- if (jsLibDir && _fs.existsSync(jsLibDir)) {
905
- let sPath = jsLibDir + "/" + name
906
- await e(`idea diff "${sPath}" "${path}"`)
787
+ },
788
+ args: {
789
+ fileIndex: '文件下标',
790
+ newName: '新名字'
791
+ },
792
+ short: 'r'
793
+ },
794
+ edit: {
795
+ comment: '编辑文件',
796
+ exeFn: async (args) => {
797
+ let uniqueName = _cmdMap[args[0]]
798
+ if (!uniqueName) {
799
+ warn("no items")
907
800
  } else {
908
- warn('require config.jsLibSource')
801
+ let path = getFullPath(uniqueName)
802
+ await e(`"${getFileOpenExe(parseUniqueName(uniqueName)[1])}" "${path}"`)
909
803
  }
910
- }
911
- } else if (/^\^\d*$/.test(fstr)) {
912
- let name = _cmdMap[trim(fstr.replace(/^\^/, ''))]
913
- if (!name) {
914
- warn("no items")
915
- } else {
916
- let md5Keys = getScriptRequires(name);
917
- _cmdMap = filterCmd(md5Keys)
804
+ },
805
+ args: {
806
+ fileIndex: '文件下标'
807
+ },
808
+ short: 'e'
809
+ },
810
+ compare: {
811
+ comment: '比较文件',
812
+ exeFn: async (args) => {
813
+ let aUniqueName = _cmdMap[args[0]]
814
+ let bUniqueName = _cmdMap[args[1]]
815
+ let aSpace = args[0]
816
+ let bSpace = args[1]
817
+
818
+ if (aUniqueName && bUniqueName) {
819
+ await e(`idea diff "${getFullPath(aUniqueName)}" "${getFullPath(bUniqueName)}"`)
820
+ } else if (aSpace && bSpace) {
821
+ if (!args[2]) {
822
+ warn('require mode')
823
+ return
824
+ }
825
+
826
+ let mode = args[2]
827
+ if (Object.keys(compareMode).indexOf(mode) === -1) {
828
+ warn('invalid mode')
829
+ return;
830
+ }
831
+
832
+ let aFiles = _fs.readdirSync($workspaceMap[aSpace]).filter(isJsirFileName)
833
+ let bFiles = _fs.readdirSync($workspaceMap[bSpace]).filter(isJsirFileName)
834
+
835
+ let result = compareMode[mode](aSpace, bSpace, aFiles, bFiles);
836
+ _cmdMap = arrayToCmdMap(result)
837
+ listCmd()
838
+ } else {
839
+ warn('invalid args')
840
+ }
841
+ },
842
+ args: {
843
+ a: '文件/工作空间',
844
+ b: '文件/工作空间',
845
+ mode: 'a=, b=, ab=, a+, b+, ab+'
846
+ },
847
+ short: 'c'
848
+ },
849
+ // deps: {
850
+ // comment: '查看文件依赖',
851
+ // exeFn: (args) => {
852
+ // let uniqueName = _cmdMap[args[0]]
853
+ // if (!uniqueName) {
854
+ // warn("no items")
855
+ // } else {
856
+ // let md5Keys = getScriptRequires(uniqueName);
857
+ // _cmdMap = arrayToCmdMap(filterCmd(md5Keys))
858
+ // listCmd()
859
+ // }
860
+ // },
861
+ // args: {
862
+ // fileIndex: '文件下标'
863
+ // },
864
+ // short: 'd'
865
+ // },
866
+ history: {
867
+ comment: '查看执行记录',
868
+ exeFn: (args) => {
869
+ hisToCmdMap()
918
870
  listCmd()
919
- }
920
- } else if (/^e\d+$/.test(fstr)) {
921
- await runCmd(trim(str.substring(1)).replace(/^e/, ''))
922
- } else if (fstr === 'e' && ostr.length === 0) {
923
- hisToCmdMap()
924
- listCmd()
925
- } else if (/^f\d*$/.test(fstr)) {
926
- if (fstr === 'f' ) {
927
- await workFile(trim(ostr.join(' ')))
928
- return;
929
- }
930
- let name = _cmdMap[trim(fstr.replace(/^f/, ''))]
931
- if (!name) {
932
- warn("no items")
933
- } else {
934
- await watchFile(name)
935
- }
936
- } else if (fstr === '%') {
937
- let newRepo = trim(ostr[0])
938
- let currRepo = getConfig('jsLibSource');
939
- if (!newRepo) {
940
- console.log(`current: ${currRepo}`)
941
- _repos = _repos.filter(i => _fs.existsSync(i))
942
- for(let i = 0; i<_repos.length; i++) {
943
- console.log(`${i+1}: ${_repos[i]}`)
871
+ },
872
+ short: 'h'
873
+ },
874
+ file: {
875
+ comment: '工作文件模式',
876
+ exeFn: async (args) => {
877
+ if (args.length === 0) {
878
+ await workFile('')
879
+ } else {
880
+ let name = _cmdMap[args[0]]
881
+ if (!name) {
882
+ warn("no items")
883
+ } else {
884
+ await watchFile(name)
885
+ }
944
886
  }
945
- let repoStr = trim(await nextLine(line => line, 'reset(or blank): '))
946
- if (/^\d+$/.test(repoStr)) {
947
- repoStr = _repos[Number(repoStr) - 1]
887
+ },
888
+ args: {
889
+ fileIndex: '文件下标'
890
+ },
891
+ short: 'f'
892
+ },
893
+ workspace: {
894
+ comment: '工作空间管理',
895
+ exeFn: async (args) => {
896
+ let newWorkspace = args.join(' ')
897
+ if (newWorkspace) {
898
+ _workspaces.push(newWorkspace)
948
899
  }
949
- newRepo = repoStr
950
- }
951
- if (newRepo && newRepo !== currRepo) {
952
- if (_fs.existsSync(newRepo)) {
953
- setConfig('jsLibSource', newRepo)
954
- if (_repos.indexOf(newRepo) === -1) {
955
- _repos.push(newRepo)
900
+ checkWorkspaces()
901
+ let items = _workspaces.map((path, index) => {
902
+ return {
903
+ index: ' ' + (index + 1),
904
+ name: getSpaceFromDir(path),
905
+ path
956
906
  }
957
- arrayDataFile('repos.json', () => _repos)
958
- dealSourceCmds()
959
- } else {
960
- warn(`repo ${newRepo} not exist`)
907
+ })
908
+ console.table(items)
909
+ },
910
+ args: {
911
+ workspacePath: '新增工作空间路径'
912
+ },
913
+ short: 'w'
914
+ },
915
+ switch: {
916
+ comment: '切换工作空间',
917
+ exeFn: async (args) => {
918
+ checkWorkspaces()
919
+ let items = _workspaces.map((path, index) => {
920
+ return {
921
+ index: ' ' + (index + 1),
922
+ name: getSpaceFromDir(path),
923
+ path
924
+ }
925
+ })
926
+ console.table(items)
927
+ let index = trim(await nextLine(line => line, "switch workspace: "));
928
+ if (index && _workspaces[index - 1]) {
929
+ let workspace = _workspaces[index - 1];
930
+ initWorkspace(getSpaceFromDir(workspace))
961
931
  }
962
- }
963
- } else if (fstr === 'q') {
964
- console.log("Bye!")
965
- _exit = true;
966
- process.exit(0)
967
- } else {
968
- await save(strs)
969
- }
970
- }
971
-
972
- function getScriptMd5Map() {
973
- let files = _fs.readdirSync(_home)
974
- let md5Map = {}
975
- for (let file of files) {
976
- file = trim(file)
977
- md5Map['0x' + md5(file).substr(0, 8)] = file;
932
+ },
933
+ short: 'S'
934
+ },
935
+ add: {
936
+ comment: '新增文件',
937
+ exeFn: async (args) => {
938
+ await save(args)
939
+ },
940
+ args: {
941
+ fileName: '文件名称(e可执行,i资源文件,f工作文件), 例:.add e test'
942
+ },
943
+ short: 'a'
944
+ },
945
+ quit: {
946
+ comment: '退出',
947
+ exeFn: (args) => {
948
+ console.log(infoStr("Bye!"))
949
+ _exit = true;
950
+ process.exit(0)
951
+ },
952
+ short: 'q'
978
953
  }
979
- return md5Map
980
954
  }
981
955
 
982
- function _getScriptRequires(md5Map, scriptName, md5Keys, links) {
983
- let path = _home + '/' + scriptName;
984
- let text = String(_fs.readFileSync(path))
985
- let temp = []
986
- regEach(text, /(0x[0-9a-f]{8})/g, r=> {
987
- temp.push(r[1])
988
- });
989
- temp = [...new Set(temp)]
990
- temp = temp.filter(i => {
991
- let have = md5Map[i];
992
- if (have && links.indexOf(i) !== -1) {
993
- let items = [...links, i];
994
- let errorStr = items.map(item => item === i ? warnStr(item):item).join("->")
995
- throw `circle deps: ${errorStr}`
956
+ async function dealKeyword(str) {
957
+ let unMatched = true;
958
+ for (let key of Object.keys(keywordDef)) {
959
+ let item = keywordDef[key]
960
+ let currStr = str === key ? item.short : str.replace(new RegExp(`^${key}\\s+`), item.short + ' ')
961
+ let strs = trim(currStr).split(/\s+/)
962
+ let fstr = strs[0]
963
+ let ostr = strs.slice(1)
964
+ if (item.short === fstr) {
965
+ unMatched = false;
966
+ await item.exeFn(ostr);
967
+ break;
996
968
  }
997
- return have;
998
- })
999
- md5Keys.push(...temp)
1000
- for (let md5Key of temp) {
1001
- _getScriptRequires(md5Map, md5Map[md5Key], md5Keys, [...links, md5Key])
969
+ }
970
+ if (unMatched) {
971
+ warn("unknown keyword")
1002
972
  }
1003
973
  }
1004
974
 
1005
- function getScriptRequires(scriptName) {
1006
- let md5Keys = [];
1007
- _getScriptRequires(getScriptMd5Map(), scriptName, md5Keys, ['0x' + md5(scriptName).substr(0, 8)]);
1008
- return md5Keys
1009
- }
975
+ // function getScriptMd5Map() {
976
+ // let md5Map = {}
977
+ // _workspaces.forEach(i => _getScriptMd5Map(i, md5Map))
978
+ // return md5Map
979
+ // }
980
+
981
+ // function _getScriptMd5Map(dir, md5Map) {
982
+ // let files = _fs.readdirSync(dir).filter(isJsirFileName)
983
+ // for (let file of files) {
984
+ // md5Map[getCmdMd5Key(file)] = file;
985
+ // }
986
+ // }
987
+
988
+ // function _getScriptRequires(uniqueName, matchStrs, links) {
989
+ // let path = getFullPath(uniqueName);
990
+ // let text = String(_fs.readFileSync(path))
991
+ // let temp = []
992
+ // regEach(text, /\$require\s*\([^()]+\)/g, r=> {
993
+ // temp.push(r[1])
994
+ // });
995
+ // temp = [...new Set(temp)]
996
+ // temp = temp.filter(i => {
997
+ // let have = md5Map[i];
998
+ // if (have && links.indexOf(i) !== -1) {
999
+ // let items = [...links, i];
1000
+ // let errorStr = items.map(item => item === i ? warnStr(item):item).join("->")
1001
+ // throw `circle deps: ${errorStr}`
1002
+ // }
1003
+ // return have;
1004
+ // })
1005
+ // md5Keys.push(...temp)
1006
+ // for (let md5Key of temp) {
1007
+ // _getScriptRequires(md5Map, md5Map[md5Key], md5Keys, [...links, md5Key])
1008
+ // }
1009
+ // }
1010
+
1011
+ // function getScriptRequires(uniqueName) {
1012
+ // let matchStrs = [];
1013
+ // _getScriptRequires(uniqueName, matchStrs, [getCmdMd5Key(uniqueName)]);
1014
+ // return md5Keys
1015
+ // }
1010
1016
 
1011
1017
  function getComments(i, cmdName, text, cols = [], col) {
1012
- let docLines = [infoStr('0x' + md5(cmdName).substr(0, 8)) + " - " + infoStr(i)]
1018
+ let docLines = [infoStr(getCmdMd5Key(parseUniqueName(cmdName)[1])) + " - " + infoStr(i)]
1013
1019
  text = trim(text)
1014
- if (text.startsWith("/*")) {
1015
- for (let line of text.split("\n")) {
1016
- let trimLine = trim(line)
1017
- if (trimLine.startsWith("/*")) {
1018
- continue
1019
- }
1020
- if (trimLine.endsWith("*/")) {
1021
- break
1022
- }
1023
- if (trimLine) {
1024
- docLines.push(line)
1025
- }
1026
- }
1027
- }
1020
+ docLines.push(...getTextComments(text))
1028
1021
  let argDef = getArgDef(text)
1029
1022
  let comments = getArgComments(argDef)
1030
1023
  if (comments) {
@@ -1042,8 +1035,43 @@ function getComments(i, cmdName, text, cols = [], col) {
1042
1035
  }
1043
1036
  }
1044
1037
 
1038
+ function getFullPath(name) {
1039
+ name = trim(name)
1040
+ if (!name) {
1041
+ return name;
1042
+ }
1043
+ let uniqueName = toUniqueName(name)
1044
+ let pair = parseUniqueName(uniqueName)
1045
+ let space = $workspaceMap[pair[0]]
1046
+ if (!space) {
1047
+ return ''
1048
+ }
1049
+ return `${space}/${pair[1]}`
1050
+ }
1051
+
1052
+ function toUniqueName(name, space) {
1053
+ name = trim(name)
1054
+ if (!name) {
1055
+ throw `invalid name`
1056
+ }
1057
+ let uniqueName
1058
+ if (name.startsWith('/')) {
1059
+ let items = name.split('/').map(trim).filter(i => i).reverse()
1060
+ uniqueName = items[1] + '/' + items[0]
1061
+ } else if (name.indexOf('/') !== -1) {
1062
+ uniqueName = name;
1063
+ } else {
1064
+ uniqueName = (space || $defaultSpace) + '/' + name;
1065
+ }
1066
+ let pair = parseUniqueName(uniqueName);
1067
+ return (pair[0] || space || $defaultSpace) + '/' + toJsirFileName(pair[1])
1068
+ }
1069
+
1045
1070
  function toJsirFileName(name) {
1046
1071
  name = trim(name)
1072
+ if (!name) {
1073
+ throw `invalid name`
1074
+ }
1047
1075
  if (isJsirFileName(name)) {
1048
1076
  return name;
1049
1077
  }
@@ -1055,14 +1083,13 @@ function toJsirFileName(name) {
1055
1083
  }
1056
1084
 
1057
1085
  function isJsirFileName(name) {
1058
- name = trim(name)
1059
- return /^[^.]*[^.\s]\.[^.\s]+$/.test(name)
1086
+ return /^[^./]*[^./\s]\.[^./\s]+$/.test(name)
1060
1087
  }
1061
1088
 
1062
1089
  function trimJsirFileName(name) {
1063
1090
  name = trim(name)
1064
1091
  if (isJsirFileName(name)) {
1065
- return trim(name.replace(/\.[^.\s]+$/, ''))
1092
+ return trim(name.replace(/\.[^./\s]+$/, ''))
1066
1093
  }
1067
1094
  return name
1068
1095
  }
@@ -1075,23 +1102,60 @@ function getJsirFileSuffix(name) {
1075
1102
  return ''
1076
1103
  }
1077
1104
 
1078
- function filterCmd(args){
1105
+ function initWorkspace(space) {
1106
+ let current = getConfig("workspace");
1107
+ if (current && space && current === space) {
1108
+ // 值没有改变
1109
+ return;
1110
+ }
1111
+ let workspace = space || current || 'local'
1112
+ if (workspace) {
1113
+ setConfig("workspace", workspace)
1114
+ global.$defaultSpace = workspace;
1115
+ } else {
1116
+ global.$defaultSpace = workspace;
1117
+ }
1118
+ }
1119
+
1120
+ function filterCmd(arg){
1121
+ arg = trim(arg)
1122
+ let spaceName
1123
+ if (arg.indexOf('/') !== -1) {
1124
+ let index = arg.indexOf('/');
1125
+ spaceName = arg.substring(0, index) || $defaultSpace
1126
+ arg = trim(arg.substring(index + 1))
1127
+ }
1128
+ let cmds = []
1129
+ for (let workspace of _workspaces) {
1130
+ let spaceTmp = getSpaceFromDir(workspace);
1131
+ if (!spaceName || spaceName === spaceTmp) {
1132
+ cmds.push(..._filterCmd(workspace, arg));
1133
+ }
1134
+ }
1135
+ return cmds;
1136
+ }
1137
+
1138
+ function _filterCmd(dirPath, arg) {
1079
1139
  let cmdMap = {}
1080
- let files = _fs.readdirSync(_home)
1081
- let i = 1
1140
+ let files = _fs.readdirSync(dirPath).filter(isJsirFileName)
1082
1141
  for (let file of files) {
1083
1142
  file = trim(file)
1084
- if (!isJsirFileName(file)) {
1085
- continue
1086
- }
1087
- isArgsMatch(file, args, () => {
1088
- if (Object.values(cmdMap).indexOf(file) === -1) {
1089
- cmdMap[i] = file
1090
- i ++
1091
- }
1092
- }, true)
1143
+ let uniqueName = toUniqueName(dirPath + '/' + file)
1144
+ isArgsMatch(file, [arg], () => {
1145
+ cmdMap[uniqueName] = null;
1146
+ }, true, file)
1093
1147
  }
1094
- return cmdMap
1148
+ return Object.keys(cmdMap)
1149
+ }
1150
+
1151
+ function getSpaceFromDir(dirPath) {
1152
+ return trim(trim(dirPath).split('/').map(trim).filter(i => i).reverse()[0])
1153
+ }
1154
+
1155
+ function parseUniqueName(uniqueName) {
1156
+ let pair = uniqueName.split('/').map(trim).filter(i => i)
1157
+ let len = pair.length;
1158
+ return [pair[len - 2], pair[len - 1]]
1095
1159
  }
1096
1160
 
1097
1161
  function getArgComments(argDef) {
@@ -1100,11 +1164,12 @@ function getArgComments(argDef) {
1100
1164
  if (keys.length > 0) {
1101
1165
  let aLine = []
1102
1166
  for (let k of keys) {
1103
- if (aLine.join(', ').length > 64) {
1167
+ let item = warnStr(k) + (argDef[k] ? ` <${argDef[k]}>`:'')
1168
+ if ([...aLine, item].join(', ').length > 64) {
1104
1169
  comments.push(aLine.join(", ") + ", ")
1105
1170
  aLine = []
1106
1171
  }
1107
- aLine.push(warnStr(k) + (argDef[k] ? ` <${argDef[k]}>`:''))
1172
+ aLine.push(item)
1108
1173
  }
1109
1174
  if (aLine.length > 0) {
1110
1175
  comments.push(aLine.join(", "))
@@ -1119,25 +1184,25 @@ function getArgComments(argDef) {
1119
1184
  return comments
1120
1185
  }
1121
1186
 
1122
- async function runCmd(str = '', scriptName = '', text = '') {
1123
- let path = _home + '/' + scriptName;
1124
- if (scriptName || text) {
1187
+ async function runCmd(str = '', uniqueName = '', text = '') {
1188
+ let path = getFullPath(uniqueName);
1189
+ if (uniqueName || text) {
1125
1190
  str = `0 ${str}`
1126
1191
  }
1127
1192
  if (!text) {
1128
1193
  let strs = str.split(/\s+/)
1129
- if (!scriptName) {
1194
+ if (!uniqueName) {
1130
1195
  if (!_cmdMap[strs[0]] && strs[0] !== '0') {
1131
1196
  warn('no items')
1132
1197
  return
1133
1198
  }
1134
1199
  if (_cmdMap[strs[0]]) {
1135
- scriptName = _cmdMap[strs[0]];
1200
+ uniqueName = _cmdMap[strs[0]];
1136
1201
  }
1137
1202
  }
1138
1203
 
1139
- if (scriptName) {
1140
- path = _home + '/' + scriptName;
1204
+ if (uniqueName) {
1205
+ path = getFullPath(uniqueName);
1141
1206
  text = String(_fs.readFileSync(path))
1142
1207
  } else {
1143
1208
  text = await getCbText()
@@ -1218,7 +1283,7 @@ async function runCmd(str = '', scriptName = '', text = '') {
1218
1283
  }
1219
1284
 
1220
1285
  process.argv = [process.argv[0], path, ...scriptArgs]
1221
- return await evalText(text, scriptName, scriptArgs)
1286
+ return await evalText(text, uniqueName, scriptArgs)
1222
1287
  }
1223
1288
 
1224
1289
  // 使用空格作为可执行的标志
@@ -1323,78 +1388,108 @@ function tipsOnRmCallback(key) {
1323
1388
  }
1324
1389
  }
1325
1390
 
1326
- async function _requireSource(cmdMatchStr, ignoreLog = false) {
1391
+ function getCmdMd5Key(str) {
1392
+ return '0x' + md5(str).substr(0, 8);
1393
+ }
1394
+
1395
+ async function _requireSource(currSpace, cmdMatchStr, printLog = false) {
1327
1396
  cmdMatchStr = trim(cmdMatchStr);
1328
1397
  let nullable = false;
1329
1398
  if (cmdMatchStr.startsWith("*")) {
1330
1399
  nullable = true;
1331
1400
  cmdMatchStr = trim(cmdMatchStr.substr(1));
1332
1401
  }
1333
- if (_fs.existsSync(_home + '/' + cmdMatchStr)) {
1334
- cmdMatchStr = '0x' + md5(cmdMatchStr).substr(0, 8);
1335
- }
1336
1402
 
1337
- let cmdMap = filterCmd(cmdMatchStr.split(/\s+/))
1338
- if (Object.keys(cmdMap).length !== 1) {
1403
+ let cmds;
1404
+ let uName = toUniqueName(cmdMatchStr, currSpace)
1405
+ let pr = parseUniqueName(uName)
1406
+ let fullPath;
1407
+ if (!/^[eif]\s+/.test(pr[1])) {
1408
+ uName = pr[0] + "/i " + pr[1]
1409
+ fullPath = getFullPath(uName)
1410
+ }
1411
+ if (fullPath && _fs.existsSync(fullPath)) {
1412
+ cmds = [uName]
1413
+ } else {
1414
+ let appointSpace = parseUniqueName(cmdMatchStr)[0]
1415
+ cmds = filterCmd(cmdMatchStr);
1416
+ if (cmds.length > 0) {
1417
+ cmds = cmds.filter(cmd => parseUniqueName(cmd)[0] === (appointSpace || currSpace))
1418
+ }
1419
+ }
1420
+ if (cmds.length !== 1) {
1339
1421
  if (nullable) {
1340
1422
  return null;
1341
1423
  }
1342
- throw `none matched: ${cmdMatchStr}`
1424
+ throw `none unique match: ${cmdMatchStr}`
1343
1425
  }
1344
- let cmdName = Object.values(cmdMap)[0];
1345
1426
 
1346
1427
  let result
1347
- let path = _home + '/' + cmdName
1428
+ let uniqueName = cmds[0];
1429
+ let path = getFullPath(uniqueName)
1348
1430
  let text = String(_fs.readFileSync(path))
1349
- if (cmdName.startsWith('i ')) {
1350
- result = await evalText(text, cmdName)
1351
- } else if (cmdName.startsWith('e ')) {
1352
- result = async (argsStr) => {
1353
- let oriLog = console.log
1354
- if (ignoreLog) {
1355
- console.log = () => {}
1356
- }
1357
- try {
1358
- return await runCmd(trim(argsStr), cmdName, text)
1359
- } finally {
1360
- if (ignoreLog) {
1361
- console.log = oriLog
1362
- }
1431
+ let pair = parseUniqueName(uniqueName)
1432
+ if (pair[1].startsWith('i ')) {
1433
+ try {
1434
+ result = await evalText(text, uniqueName)
1435
+ } catch (e) {
1436
+ if (nullable) {
1437
+ warn(`require [${cmdMatchStr}] failed`)
1438
+ $log(errorStack(e))
1439
+ return null;
1440
+ } else {
1441
+ throw e
1363
1442
  }
1364
1443
  }
1444
+ } else if (pair[1].startsWith('e ')) {
1445
+ result = async (argsStr) => {
1446
+ return await runCmd(trim(argsStr), uniqueName, text)
1447
+ }
1365
1448
  }
1366
1449
  if (!vl(result)) {
1367
1450
  if (nullable) {
1368
1451
  return null;
1369
1452
  }
1370
- throw `invalid returned: ${cmdMatchStr}`
1453
+ throw `invalid result: ${cmdMatchStr}`
1371
1454
  }
1372
1455
  if (getType(result) === 'Function' || getType(result) === 'AsyncFunction') {
1373
1456
  let tmp = result;
1374
1457
  result = (...args) => {
1375
1458
  let resp
1459
+ let startTime = Date.now();
1460
+ let pl = () => {
1461
+ if (printLog) {
1462
+ info(`${uniqueName} finished in ${Date.now() - startTime}ms`)
1463
+ }
1464
+ }
1376
1465
  try {
1377
1466
  resp = tmp(...args)
1467
+ if (getType(resp) === 'Promise') {
1468
+ return resp.then(result => {
1469
+ pl();
1470
+ return Promise.resolve(result);
1471
+ }).catch(e => {
1472
+ pl();
1473
+ return Promise.reject(errorTag(e, uniqueName))
1474
+ })
1475
+ } else {
1476
+ pl();
1477
+ return resp;
1478
+ }
1378
1479
  } catch (e) {
1379
- throw errorTag(e, cmdName);
1380
- }
1381
- if (getType(resp) === 'Promise') {
1382
- return resp.catch(e => {
1383
- return Promise.reject(errorTag(e, cmdName))
1384
- })
1385
- } else {
1386
- return resp;
1480
+ pl();
1481
+ throw errorTag(e, uniqueName);
1387
1482
  }
1388
1483
  }
1389
1484
  }
1390
1485
  return result
1391
1486
  }
1392
1487
 
1393
- async function _requireSources(...matchItem) {
1488
+ async function _requireSources(currSpace, ...matchItems) {
1394
1489
  let result = []
1395
- for (let i = 0; i < matchItem.length; i++) {
1396
- let curr = matchItem[i]
1397
- let next = matchItem[i + 1]
1490
+ for (let i = 0; i < matchItems.length; i++) {
1491
+ let curr = matchItems[i]
1492
+ let next = matchItems[i + 1]
1398
1493
  if (typeof curr === 'number') {
1399
1494
  curr = '0x' + pad(8, BigNumber(curr).toString(16), '0');
1400
1495
  }
@@ -1402,20 +1497,30 @@ async function _requireSources(...matchItem) {
1402
1497
  next = '0x' + pad(8, BigNumber(next).toString(16), '0');
1403
1498
  }
1404
1499
  if (typeof curr === 'string' && typeof next !== "string") {
1405
- result.push(await _requireSource(curr, next))
1500
+ result.push(await _requireSource(currSpace, curr, next))
1406
1501
  i++
1407
1502
  } else if (typeof curr === 'string') {
1408
- result.push(await _requireSource(curr))
1503
+ result.push(await _requireSource(currSpace, curr))
1409
1504
  }
1410
1505
  }
1411
1506
  return result
1412
1507
  }
1413
1508
 
1414
1509
  async function evalText($text = '', $cmdName = '', $args = []) {
1510
+ let currSpace;
1511
+ if ($cmdName) {
1512
+ let pair = parseUniqueName($cmdName)
1513
+ currSpace = pair[0]
1514
+ } else {
1515
+ currSpace = $defaultSpace
1516
+ }
1517
+ let $require = async (...matchItems) => {
1518
+ return await _requireSources(currSpace, ...matchItems)
1519
+ }
1415
1520
  try {
1416
- return await evalCode($text, $cmdName, $args,
1417
- _home, _cmdMap, _requireSources, $data,
1418
- nextLine, nextText, setTips, delTips, wrapperInput, filterCmd)
1521
+ return await evalCode($text, $cmdName, $args, $require, $data,
1522
+ nextLine, nextText, setTips, delTips, wrapperInput, filterCmd,
1523
+ currSpace, $log, $draft, $config, $homeDir, $lib)
1419
1524
  } catch(e) {
1420
1525
  throw errorTag(e, $cmdName);
1421
1526
  }
@@ -1444,4 +1549,6 @@ process.on('beforeExit', function () {
1444
1549
  if (!_exit) {
1445
1550
  _noAppendNextLine || nextLine();
1446
1551
  }
1447
- });
1552
+ });
1553
+
1554
+ start()