jsir 1.3.2 → 2.0.1

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
3
  getLibDataDir, trim, regEach, getConfig, mkdir, reget,
4
- getCbText, e, sleep, objDataFile, setConfig, vl, md5, BigNumber,
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,38 +17,31 @@ 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
23
  const readline = require("readline");
24
24
  const _fileWatcherMap = {}
25
-
25
+ const setting = require('../setting')
26
+ let _cmdMapFile = setting.name + 'CmdMap.json'
26
27
  let _cmdMap = {}
27
28
  let _rl
28
29
  let _rlHistory = []
29
30
  let _haveWrapperInput = true
30
- let _repos = arrayDataFile('repos.json')
31
+ let _workspaceConfigFile = 'workspace.json';
31
32
  let _exit = false
32
33
 
33
34
  const $data = {}
35
+ const $homeDir = getLibDataDir()
36
+ const $lib = {...require('../util')}
34
37
 
35
- global.$lib = {}
36
38
  global.$tips = {}
37
39
  global.$newInput = false
38
-
39
- try {
40
- getConfig("jsLibSource")
41
- } catch (e) {
42
- error(e)
43
- }
40
+ global.$workspaceMap = {}
41
+ global.$defaultSpace = 'local'
44
42
 
45
43
  let _noAppendNextLine = true
46
44
 
47
- function initRuntime() {
48
- global.$lib = {...require('../util')}
49
- }
50
-
51
45
  function getFileOpenExe(fileName) {
52
46
  fileName = trim(fileName);
53
47
  let strs = fileName.split('.')
@@ -63,17 +57,32 @@ function getFileOpenExe(fileName) {
63
57
  return exe || 'idea';
64
58
  }
65
59
 
60
+ function checkWorkspaces() {
61
+ let localWorkspace = _libDataDir + '/local';
62
+ global.$workspaceMap = {
63
+ 'local': localWorkspace
64
+ }
65
+ mkdir(localWorkspace)
66
+ for (let workspace of arrayDataFile(_workspaceConfigFile)) {
67
+ workspace = workspace.replace(/\/+$/, '')
68
+ let space = getSpaceFromDir(workspace);
69
+ if (space === 'local') {
70
+ continue
71
+ }
72
+ if (_fs.existsSync(workspace)) {
73
+ $workspaceMap[space] = workspace;
74
+ }
75
+ }
76
+ arrayDataFile(_workspaceConfigFile, () => Object.values($workspaceMap))
77
+ initWorkspace()
78
+ }
79
+
66
80
  async function start() {
67
- mkdir(_home)
68
- dealSourceCmds()
81
+ checkWorkspaces()
69
82
 
70
- if (_args[0] === '--repl') {
71
- initRuntime()
72
- _noAppendNextLine = false
73
- console.log(warnStr("You can start with .help"))
74
- } else if (_args[0]) {
83
+ if (_args[0]) {
75
84
  if (_noAppendNextLine) {
76
- _cmdMap = objDataFile('ooaCmdMap.json')
85
+ _cmdMap = objDataFile(_cmdMapFile)
77
86
  }
78
87
  let line = _args.map(i => {
79
88
  if (/\s+/.test(i) || !i) {
@@ -81,21 +90,14 @@ async function start() {
81
90
  }
82
91
  return i
83
92
  }).join(' ')
84
- if (/^\d+$/.test(_args[0])) {
85
- if (_args[0] === '0' || (_cmdMap[_args[0]] && ['e ', 'f '].filter(i => _cmdMap[_args[0]].startsWith(i)).length > 0)) {
86
- initRuntime()
87
- }
88
- }
89
93
  await wrapperInput(line)
90
94
  } else {
91
- if (_noAppendNextLine) {
92
- _cmdMap = objDataFile('ooaCmdMap.json')
93
- }
94
- listCmd();
95
+ _noAppendNextLine = false
96
+ console.log(warnStr("You can start with .help, use * to expand context"))
95
97
  }
96
98
  }
97
99
 
98
- async function getFileWatcher(fileName, workFilePath, text) {
100
+ async function getFileWatcher(workFilePath, text) {
99
101
  info("workFile open " + workFilePath)
100
102
  if (!_fileWatcherMap[workFilePath]) {
101
103
  _fs.unlinkSync(workFilePath)
@@ -118,22 +120,21 @@ function closeFileWatcher(workFilePath) {
118
120
  delete _fileWatcherMap[workFilePath]
119
121
  }
120
122
 
121
- async function workFile(name) {
122
- name = trim(name)
123
- if (!name) {
124
- name = 'workFile'
123
+ async function workFile(uniqueName) {
124
+ uniqueName = trim(uniqueName)
125
+ if (!uniqueName) {
126
+ uniqueName = toUniqueName('f workFile')
125
127
  }
126
- let fileName = `f ${toJsirFileName(name)}`
127
- await watchFile(fileName)
128
+ await watchFile(uniqueName)
128
129
  }
129
130
 
130
- async function watchFile(fileName) {
131
- let workFilePath = `${_home}/${fileName}`;
131
+ async function watchFile(uniqueName) {
132
+ let workFilePath = getFullPath(uniqueName);
132
133
  if (!_fs.existsSync(workFilePath)) {
133
134
  _fs.writeFileSync(workFilePath, '');
134
135
  }
135
136
  let text = String(_fs.readFileSync(workFilePath))
136
- let watcher = await getFileWatcher(fileName, workFilePath, text)
137
+ let watcher = await getFileWatcher(workFilePath, text)
137
138
 
138
139
  if (watcher) {
139
140
  watcher.on('change', async () => {
@@ -152,7 +153,7 @@ async function watchFile(fileName) {
152
153
  closeFileWatcher(workFilePath);
153
154
  });
154
155
  }
155
- await e(`"${getFileOpenExe(fileName)}" "${workFilePath}"`)
156
+ await e(`"${getFileOpenExe(parseUniqueName(uniqueName)[1])}" "${workFilePath}"`)
156
157
  }
157
158
 
158
159
  function getExeStr(oldText, newText) {
@@ -227,12 +228,11 @@ function initRl(callback, preStr, hidden) {
227
228
  _rl.history = _rlHistory
228
229
  }
229
230
 
230
- let repoTip = trim(trim(getConfig("jsLibSource")).split('/').map(trim).reverse().filter(i => i)[0])
231
231
  let promptStr = preStr
232
232
  if (promptStr !== '') {
233
233
  promptStr = (preStr
234
234
  || ((callback && callback !== wrapperInput) ? "-> ":"")
235
- || [Object.values(global.$tips).filter(i => String(i)).join(','), repoTip].filter(i => i).join(':') + `> `)
235
+ || [Object.values(global.$tips).filter(i => String(i)).join(','), $defaultSpace].filter(i => i).join(':') + `> `)
236
236
  promptStr = infoStr(promptStr)
237
237
  }
238
238
  if (hidden) {
@@ -318,24 +318,13 @@ async function nextText(callback, end, hidden) {
318
318
  })
319
319
  }
320
320
 
321
- function dealSourceCmds() {
322
- let source = trim(getConfig("jsLibSource"));
323
- if (source && _fs.existsSync(source)) {
324
- _fs.readdirSync(source).filter(isJsirFileName).forEach(item => {
325
- if (!_fs.existsSync(_home + "/" + item)) {
326
- _fs.writeFileSync(_home + "/" + item, String(_fs.readFileSync(source + "/" + item)))
327
- }
328
- })
329
- }
330
- }
331
-
332
321
  async function save(args) {
333
- let name = toJsirFileName(args.join(' '))
334
- let path = `${_home}/${name}`
322
+ let uniqueName = toUniqueName(toJsirFileName(args.join(' ')))
323
+ let path = getFullPath(uniqueName)
335
324
  if (_fs.existsSync(path)) {
336
325
  warn(`${path} already exist`)
337
326
  _cmdMap = {
338
- 1: name
327
+ 1: uniqueName
339
328
  }
340
329
  listCmd()
341
330
  return
@@ -374,32 +363,24 @@ return {}
374
363
  _fs.writeFileSync(path, resp)
375
364
  info(`${path} created`)
376
365
  _cmdMap = {
377
- 1: name
366
+ 1: uniqueName
378
367
  }
379
368
  listCmd()
380
369
  }
381
370
 
382
- function rename(dir, oldName, newName, isOoa) {
371
+ function rename(dir, oldName, newName) {
383
372
  let old = dir + '/' + oldName;
384
373
  let _new = dir + '/' + newName;
385
374
  if (_fs.existsSync(_new)) {
386
- if (isOoa) {
387
- warn(`${_new} already exist`)
388
- _cmdMap = {
389
- 1: newName
390
- }
391
- listCmd()
392
- }
393
- return
394
- }
395
- _fs.rename(old, _new, ()=>{})
396
- if (isOoa) {
375
+ warn(`${_new} already exist`)
376
+ } else {
377
+ _fs.rename(old, _new, ()=>{})
397
378
  info(`${_new} renamed`)
398
- _cmdMap = {
399
- 1: newName
400
- }
401
- listCmd()
402
379
  }
380
+ _cmdMap = {
381
+ 1: toUniqueName(newName)
382
+ }
383
+ listCmd()
403
384
  }
404
385
 
405
386
  function putHis(x) {
@@ -422,85 +403,57 @@ function hisToCmdMap() {
422
403
  _cmdMap = cmdMap
423
404
  }
424
405
 
425
- function listCmd(prefixKey, inputCmdMap) {
426
- let currCmdMap = _cmdMap
427
- if (inputCmdMap) {
428
- currCmdMap =inputCmdMap;
429
- }
430
- let newCmdMap = {}
431
- let prefixMap = {}
432
- for (let i of Object.keys(currCmdMap)) {
433
- let jsLib = trim(getConfig("jsLibSource"))
434
- let sourceFile = jsLib + "/" + currCmdMap[i]
435
- let prefix = [' ', ' ']
436
- prefixMap[currCmdMap[i]] = prefix;
437
- if (jsLib && _fs.existsSync(sourceFile)) {
438
- prefix[1] = '#'
439
- let text1 = String(_fs.readFileSync(_home + "/" + currCmdMap[i]))
440
- let text2 = String(_fs.readFileSync(sourceFile))
441
- if (text1 !== text2) {
442
- prefix[0] = '*'
443
- }
444
- }
445
- }
446
- let items = Object.values(currCmdMap)
447
- .filter(item => _fs.existsSync(_home + "/" + item)
448
- && ((prefixKey === '' && prefixMap[item].filter(i => trim(i)).length <= 0)
449
- || (trim(prefixKey) && prefixMap[item].indexOf(trim(prefixKey)) !== -1)
450
- || (!prefixKey && prefixKey !== '')))
406
+ function listCmd() {
407
+ let items = Object.values(_cmdMap)
408
+ .filter(item => _fs.existsSync(getFullPath(item)))
451
409
  .sort((a,b) => {
410
+ a = parseUniqueName(a)[1];
411
+ b = parseUniqueName(b)[1];
452
412
  let typeKeys = Object.keys(_types);
453
413
  let orderA = typeKeys.indexOf(a.split(/\s+/)[0]);
454
414
  let orderB = typeKeys.indexOf(b.split(/\s+/)[0]);
455
- orderA = orderA === -1 ? 999:orderA;
456
- orderB = orderB === -1 ? 999:orderB;
415
+ orderA = orderA === -1 ? 999999:orderA;
416
+ orderB = orderB === -1 ? 999999:orderB;
457
417
  return orderA - orderB
458
418
  })
459
- for(let i = 0; i< items.length; i++) {
460
- newCmdMap[i + 1] =items[i]
461
- }
462
419
 
463
- currCmdMap = newCmdMap
464
- if (!inputCmdMap) {
465
- _cmdMap = newCmdMap
466
- if (_noAppendNextLine) {
467
- objDataFile('ooaCmdMap.json', () => _cmdMap)
468
- }
469
- } else {
470
- for (let key of Object.keys(inputCmdMap)) {
471
- delete inputCmdMap[key]
472
- }
473
- Object.assign(inputCmdMap, newCmdMap)
420
+ _cmdMap = arrayToCmdMap(items)
421
+ if (_noAppendNextLine) {
422
+ objDataFile(_cmdMapFile, () => _cmdMap)
474
423
  }
475
424
 
476
425
  items = []
477
- for (let i of Object.keys(currCmdMap)) {
478
- let prefix = prefixMap[currCmdMap[i]]
479
- let text = String(_fs.readFileSync(_home + "/" + currCmdMap[i]))
480
- let name = trimJsirFileName(currCmdMap[i])
481
- let suffix = getJsirFileSuffix(currCmdMap[i])
426
+ for (let i of Object.keys(_cmdMap)) {
427
+ let text = String(_fs.readFileSync(getFullPath(_cmdMap[i])))
428
+ let pair = parseUniqueName(_cmdMap[i])
429
+ let name = trimJsirFileName(pair[1])
430
+ let suffix = getJsirFileSuffix(pair[1])
482
431
  let item = {
483
- key: prefix.join('') + i,
484
- name: name.replace(/^[eif]\s+/, ''),
432
+ key: ' ' + i,
433
+ name: pair[0] + '/' + name.replace(/^[eif]\s+/, ''),
485
434
  type: [_types[name.split(/\s+/)[0]] || 'note', suffix].map(trim).join(".")
486
435
  }
487
436
  items.push(item)
488
437
 
489
438
  if (!text) {
490
- text = String(_fs.readFileSync(_home + "/" + currCmdMap[i]))
439
+ text = String(_fs.readFileSync(getFullPath(_cmdMap[i])))
491
440
  }
492
- getComments(i, currCmdMap[i], text, items, item)
441
+ getComments(i, _cmdMap[i], text, items, item)
493
442
  }
494
443
  if (Object.keys(items).length === 0) {
495
444
  warn("no items")
496
445
  } else {
497
446
  items.forEach(item => {
498
447
  if (item.type) {
448
+ let pair = parseUniqueName(item.name);
499
449
  if (item.type.startsWith('exe.')) {
500
- item.name = infoStr(item.name)
450
+ item.name = infoStr(pair[1])
501
451
  } else if (item.type.startsWith('init.')) {
502
- item.name = msgStr(item.name)
452
+ item.name = msgStr(pair[1])
453
+ } else {
454
+ item.name = pair[1]
503
455
  }
456
+ item.name = pair[0] + '/' + item.name
504
457
  }
505
458
  })
506
459
  console.table(items)
@@ -527,7 +480,7 @@ async function _wrapperInput(str) {
527
480
  let cmdStr = trim(str.substr(1));
528
481
  if (/^\d+$/.test(cmdStr) && _cmdMap[cmdStr]) {
529
482
  if (_cmdMap[cmdStr]) {
530
- ei('vi', [getLibDataDir() + '/ooa/' + _cmdMap[cmdStr]])
483
+ ei('vi', [getFullPath(_cmdMap[cmdStr])])
531
484
  } else {
532
485
  warn("no items")
533
486
  }
@@ -558,6 +511,9 @@ async function _wrapperInput(str) {
558
511
  if (is$) {
559
512
  console.log(await evalText('return ' + text))
560
513
  } else if (isStar) {
514
+ if (!text) {
515
+ text = '$context';
516
+ }
561
517
  let items = text.split(/\s+/).map(trim).filter(i => i)
562
518
  let result = await evalText('return ' + items[0])
563
519
  if (!result || typeof result === 'string' || Object.keys(result).length === 0) {
@@ -567,7 +523,7 @@ async function _wrapperInput(str) {
567
523
  let rows = []
568
524
  let matchs = items.slice(1)
569
525
  for (let key of Object.keys(result)) {
570
- if (matchs.length === 0 || isArgsMatch(key, matchs)){
526
+ if (matchs.length === 0 || isArgsMatch(key, [matchs.join(' ')])){
571
527
  rows.push(getInfo(result[key], key))
572
528
  }
573
529
  }
@@ -587,17 +543,18 @@ async function _wrapperInput(str) {
587
543
  help()
588
544
  }
589
545
  } else if (!str.split(/\s+/)[0].match(/^\d+$/)) {
590
- _cmdMap = filterCmd(str.split(/\s+/))
546
+ _cmdMap = arrayToCmdMap(filterCmd(str))
591
547
  listCmd()
592
548
  } else {
593
549
  let strs = str.split(/\s+/)
594
550
  if (_cmdMap[strs[0]]) {
595
551
  putHis(_cmdMap[strs[0]])
596
- let path = _home + '/' + _cmdMap[strs[0]]
597
- let fileName = trim(_cmdMap[strs[0]]);
552
+ let path = getFullPath(_cmdMap[strs[0]])
553
+ let uniqueName = trim(_cmdMap[strs[0]]);
554
+ let fileName = parseUniqueName(uniqueName)[1]
598
555
  let firstName = fileName.split(/\s+/)[0]
599
556
  if (firstName === 'f') {
600
- await workFile(fileName.replace(/^\s*f\s*/, ''))
557
+ await workFile(uniqueName)
601
558
  } else if (firstName !== 'e') {
602
559
  console.log(String(_fs.readFileSync(path)));
603
560
  } else {
@@ -609,6 +566,13 @@ async function _wrapperInput(str) {
609
566
  }
610
567
  }
611
568
 
569
+ function arrayToCmdMap(cmds) {
570
+ let cmdMap = {}
571
+ for (let i = 0; i < cmds.length; i++) {
572
+ cmdMap[i + 1] = cmds[i];
573
+ }
574
+ return cmdMap
575
+ }
612
576
 
613
577
  function help() {
614
578
  console.nable(Object.keys(keywordDef).map(key => {
@@ -640,6 +604,82 @@ function delTipsByIndex(idxs) {
640
604
  delTips(...params)
641
605
  }
642
606
 
607
+ function copyToSpace(uniqueName) {
608
+ let path = getFullPath(uniqueName)
609
+ let text = String(_fs.readFileSync(path))
610
+ let fileName = parseUniqueName(uniqueName)[1];
611
+ let targetPath = $workspaceMap[$defaultSpace] + '/' + fileName;
612
+ if (_fs.existsSync(targetPath)) {
613
+ warn(`${fileName} already exist in ${$defaultSpace}`)
614
+ } else {
615
+ _fs.writeFileSync(targetPath, text)
616
+ info(`get ${uniqueName} to ${$defaultSpace}`)
617
+ }
618
+ }
619
+
620
+ let compareMode = {
621
+ 'a=': (aSpace, bSpace, as, bs) => {
622
+ let result = []
623
+ for (let a of as) {
624
+ if (bs.indexOf(a) !== -1) {
625
+ result.push(aSpace + '/' + a)
626
+ }
627
+ }
628
+ return result
629
+ },
630
+ 'b=': (aSpace, bSpace, as, bs) => {
631
+ let result = []
632
+ for (let a of as) {
633
+ if (bs.indexOf(a) !== -1) {
634
+ result.push(bSpace + '/' + a)
635
+ }
636
+ }
637
+ return result
638
+ },
639
+ 'ab=': (aSpace, bSpace, a, b, as, bs) => {
640
+ let result = []
641
+ for (let a of as) {
642
+ if (bs.indexOf(a) !== -1) {
643
+ result.push(aSpace + '/' + a)
644
+ result.push(bSpace + '/' + a)
645
+ }
646
+ }
647
+ return result
648
+ },
649
+ 'a+': (aSpace, bSpace, as, bs) => {
650
+ let result = []
651
+ for(let a of as) {
652
+ if (bs.indexOf(a) === -1) {
653
+ result.push(aSpace + '/' + a)
654
+ }
655
+ }
656
+ return result
657
+ },
658
+ 'b+': (aSpace, bSpace, as, bs) => {
659
+ let result = []
660
+ for(let b of bs) {
661
+ if (as.indexOf(b) === -1) {
662
+ result.push(bSpace + '/' + b)
663
+ }
664
+ }
665
+ return result
666
+ },
667
+ 'ab+': (aSpace, bSpace, as, bs) => {
668
+ let result = []
669
+ for(let a of as) {
670
+ if (bs.indexOf(a) === -1) {
671
+ result.push(aSpace + '/' + a)
672
+ }
673
+ }
674
+ for(let b of bs) {
675
+ if (as.indexOf(b) === -1) {
676
+ result.push(bSpace + '/' + b)
677
+ }
678
+ }
679
+ return result
680
+ }
681
+ }
682
+
643
683
  const keywordDef = {
644
684
  help: {
645
685
  comment: '帮助文档',
@@ -649,13 +689,15 @@ const keywordDef = {
649
689
  short: 'H'
650
690
  },
651
691
  list: {
652
- comment: '查看本地文件列表',
692
+ comment: '查看文件列表',
653
693
  exeFn: (args) => {
654
- _cmdMap = filterCmd(args.length > 0 ? args:[','])
694
+ if (args.length > 0) {
695
+ _cmdMap = arrayToCmdMap(filterCmd(args.length > 0 ? args.join(' '):[',']))
696
+ }
655
697
  listCmd()
656
698
  },
657
699
  args: {
658
- queryParams: '条件参数(param1,param2 param3 ...)'
700
+ queryParams: '条件参数(param1,param2 param3 ...), [,]代表全部'
659
701
  },
660
702
  short: 'l'
661
703
  },
@@ -670,13 +712,13 @@ const keywordDef = {
670
712
  short: 'C'
671
713
  },
672
714
  see: {
673
- comment: '查看本地文件',
715
+ comment: '查看文件',
674
716
  exeFn: (args) => {
675
- let name = _cmdMap[args[0]]
676
- if (!name) {
717
+ let uniqueName = _cmdMap[args[0]]
718
+ if (!uniqueName) {
677
719
  warn("no items")
678
720
  } else {
679
- let path = _home + '/' + name
721
+ let path = getFullPath(uniqueName)
680
722
  let sourceStr = String(_fs.readFileSync(path))
681
723
  console.log(sourceStr)
682
724
  }
@@ -687,147 +729,74 @@ const keywordDef = {
687
729
  short: 's'
688
730
  },
689
731
  rm: {
690
- comment: '删除本地文件以及其源文件',
732
+ comment: '删除文件',
691
733
  exeFn: (args) => {
692
- let name = _cmdMap[args[0]]
693
- if (!name) {
734
+ let uniqueName = _cmdMap[args[0]]
735
+ if (args[0] === 'ALL') {
736
+ for (let value of Object.values(_cmdMap)) {
737
+ let path = getFullPath(value)
738
+ _fs.unlinkSync(path)
739
+ info(`${path} removed`)
740
+ }
741
+ } else if (!uniqueName) {
694
742
  warn("no items")
695
743
  } else {
696
- let path = _home + '/' + name
744
+ let path = getFullPath(uniqueName)
697
745
  _fs.unlinkSync(path)
698
- let jsLibDir = trim(getConfig("jsLibSource"))
699
- if (jsLibDir && _fs.existsSync(jsLibDir)) {
700
- if (_fs.existsSync(jsLibDir + '/' + name)) {
701
- _fs.unlinkSync(jsLibDir + '/' + name)
702
- }
703
- }
704
746
  info(`${path} removed`)
705
747
  }
706
748
  },
707
749
  args: {
708
- fileIndex: '文件下标'
750
+ fileIndex: '文件下标, ALL代表全部'
709
751
  },
710
752
  short: 'R'
711
753
  },
712
- rename: {
713
- comment: '重命名本地文件以及其源文件',
714
- exeFn: (args) => {
715
- let name = _cmdMap[args[0]]
716
- if (!name) {
717
- warn("no items")
718
- } else {
719
- let newName =trim(args.slice(1).join(" "))
720
- if (newName) {
721
- newName = toJsirFileName(newName)
722
- let jsLibDir = trim(getConfig("jsLibSource"))
723
- if (jsLibDir && _fs.existsSync(jsLibDir)) {
724
- if (_fs.existsSync(jsLibDir + '/' + name)) {
725
- rename(jsLibDir, name, newName)
726
- }
727
- }
728
- rename(_home, name, newName, true)
729
- }
730
- }
731
- },
732
- args: {
733
- fileIndex: '文件下标',
734
- newName: '新名字'
735
- },
736
- short: 'r'
737
- },
738
- source: {
739
- comment: '查看源文件',
740
- exeFn: (args) => {
741
- let name = _cmdMap[args[0]]
742
- if (!name) {
743
- warn("no items")
744
- } else {
745
- let jsLibDir = trim(getConfig("jsLibSource"))
746
- if (jsLibDir && _fs.existsSync(jsLibDir)) {
747
- let sFile = jsLibDir + "/" + name
748
- if (_fs.existsSync(sFile)) {
749
- let sourceStr = String(_fs.readFileSync(sFile))
750
- console.log(sourceStr)
751
- }
752
- } else {
753
- warn('require origin workspace')
754
- }
755
- }
756
- },
757
- args: {
758
- fileIndex: '文件下标'
759
- },
760
- short: 'S'
761
- },
762
754
  get: {
763
- comment: '将源文件内容覆盖到本地文件',
755
+ comment: '获取文件',
764
756
  exeFn: (args) => {
765
- let name = _cmdMap[args[0]]
766
- if (!args[0]) {
767
- listCmd('*')
768
- } else if (!name) {
757
+ let uniqueName = _cmdMap[args[0]]
758
+ if (args[0] === 'ALL') {
759
+ for (let value of Object.values(_cmdMap)) {
760
+ copyToSpace(value)
761
+ }
762
+ } else if (!uniqueName) {
769
763
  warn("no items")
770
764
  } else {
771
- let jsLibDir = trim(getConfig("jsLibSource"))
772
- if (jsLibDir && _fs.existsSync(jsLibDir)) {
773
- let sFile = jsLibDir + "/" + name
774
- if (_fs.existsSync(sFile)) {
775
- let sourceStr = String(_fs.readFileSync(sFile))
776
- let path = _home + '/' + name
777
- if (sourceStr) {
778
- _fs.writeFileSync(path, sourceStr)
779
- }
780
- }
781
- info(`${name} pulled`)
782
- } else {
783
- warn('require origin workspace')
784
- }
765
+ copyToSpace(uniqueName)
785
766
  }
786
767
  },
787
768
  args: {
788
- fileIndex: '文件下标'
769
+ fileIndex: '文件下标, ALL代表全部'
789
770
  },
790
771
  short: 'g'
791
772
  },
792
- push: {
793
- comment: '将本地文件内容覆盖到源文件',
773
+ rename: {
774
+ comment: '重命名文件',
794
775
  exeFn: (args) => {
795
- let name = _cmdMap[args[0]]
796
- if (!args[0]) {
797
- listCmd('#')
798
- } else if (!name) {
776
+ let uniqueName = _cmdMap[args[0]]
777
+ if (!uniqueName) {
799
778
  warn("no items")
800
779
  } else {
801
- let jsLibDir = trim(getConfig("jsLibSource"))
802
- if (jsLibDir && _fs.existsSync(jsLibDir)) {
803
- _fs.writeFileSync(jsLibDir + "/" + name, String(_fs.readFileSync(_home + '/' + name)))
804
- info(`${name} pushed`)
805
- } else {
806
- warn('require origin workspace')
807
- }
780
+ let pair = parseUniqueName(uniqueName)
781
+ let newName =trim(args.slice(1).join(" "))
782
+ rename($workspaceMap[pair[0]], pair[1], toJsirFileName(newName), true)
808
783
  }
809
784
  },
810
785
  args: {
811
- fileIndex: '文件下标'
812
- },
813
- short: 'p'
814
- },
815
- unsync: {
816
- comment: '查看未同步源文件的本地文件列表',
817
- exeFn: (args) => {
818
- listCmd('')
786
+ fileIndex: '文件下标',
787
+ newName: '新名字'
819
788
  },
820
- short: 'u'
789
+ short: 'n'
821
790
  },
822
791
  edit: {
823
- comment: '编辑本地文件',
792
+ comment: '编辑文件',
824
793
  exeFn: async (args) => {
825
- let name = _cmdMap[args[0]]
826
- if (!name) {
794
+ let uniqueName = _cmdMap[args[0]]
795
+ if (!uniqueName) {
827
796
  warn("no items")
828
797
  } else {
829
- let path = _home + '/' + name
830
- await e(`"${getFileOpenExe(name)}" "${path}"`)
798
+ let path = getFullPath(uniqueName)
799
+ await e(`"${getFileOpenExe(parseUniqueName(uniqueName)[1])}" "${path}"`)
831
800
  }
832
801
  },
833
802
  args: {
@@ -836,44 +805,61 @@ const keywordDef = {
836
805
  short: 'e'
837
806
  },
838
807
  compare: {
839
- comment: '比较本地文件和源文件',
808
+ comment: '比较文件',
840
809
  exeFn: async (args) => {
841
- let name = _cmdMap[args[0]]
842
- if (!name) {
843
- warn("no items")
844
- } else {
845
- let path = _home + '/' + name
846
- let jsLibDir = trim(getConfig("jsLibSource"))
847
- if (jsLibDir && _fs.existsSync(jsLibDir)) {
848
- let sPath = jsLibDir + "/" + name
849
- await e(`idea diff "${sPath}" "${path}"`)
850
- } else {
851
- warn('require origin workspace')
810
+ let aUniqueName = _cmdMap[args[0]]
811
+ let bUniqueName = _cmdMap[args[1]]
812
+ let aSpace = args[0]
813
+ let bSpace = args[1]
814
+
815
+ if (aUniqueName && bUniqueName) {
816
+ await e(`idea diff "${getFullPath(aUniqueName)}" "${getFullPath(bUniqueName)}"`)
817
+ } else if (aSpace && bSpace) {
818
+ if (!args[2]) {
819
+ warn('require mode')
820
+ return
852
821
  }
853
- }
854
- },
855
- args: {
856
- fileIndex: '文件下标',
857
- },
858
- short: 'c'
859
- },
860
- deps: {
861
- comment: '查看文件依赖',
862
- exeFn: (args) => {
863
- let name = _cmdMap[args[0]]
864
- if (!name) {
865
- warn("no items")
866
- } else {
867
- let md5Keys = getScriptRequires(name);
868
- _cmdMap = filterCmd(md5Keys)
822
+
823
+ let mode = args[2]
824
+ if (Object.keys(compareMode).indexOf(mode) === -1) {
825
+ warn('invalid mode')
826
+ return;
827
+ }
828
+
829
+ let aFiles = _fs.readdirSync($workspaceMap[aSpace]).filter(isJsirFileName)
830
+ let bFiles = _fs.readdirSync($workspaceMap[bSpace]).filter(isJsirFileName)
831
+
832
+ let result = compareMode[mode](aSpace, bSpace, aFiles, bFiles);
833
+ _cmdMap = arrayToCmdMap(result)
869
834
  listCmd()
835
+ } else {
836
+ warn('invalid args')
870
837
  }
871
838
  },
872
839
  args: {
873
- fileIndex: '文件下标'
840
+ a: '文件/工作空间',
841
+ b: '文件/工作空间',
842
+ mode: 'a=, b=, ab=, a+, b+, ab+'
874
843
  },
875
- short: 'd'
844
+ short: 'c'
876
845
  },
846
+ // deps: {
847
+ // comment: '查看文件依赖',
848
+ // exeFn: (args) => {
849
+ // let uniqueName = _cmdMap[args[0]]
850
+ // if (!uniqueName) {
851
+ // warn("no items")
852
+ // } else {
853
+ // let md5Keys = getScriptRequires(uniqueName);
854
+ // _cmdMap = arrayToCmdMap(filterCmd(md5Keys))
855
+ // listCmd()
856
+ // }
857
+ // },
858
+ // args: {
859
+ // fileIndex: '文件下标'
860
+ // },
861
+ // short: 'd'
862
+ // },
877
863
  history: {
878
864
  comment: '查看执行记录',
879
865
  exeFn: (args) => {
@@ -902,36 +888,76 @@ const keywordDef = {
902
888
  short: 'f'
903
889
  },
904
890
  workspace: {
905
- comment: '源空间管理',
891
+ comment: '工作空间管理',
906
892
  exeFn: async (args) => {
907
- let newRepo = args.join(' ')
908
- let currRepo = getConfig('jsLibSource');
909
- if (!newRepo) {
910
- console.log(`current: ${currRepo}`)
911
- _repos = _repos.filter(i => _fs.existsSync(i))
912
- for(let i = 0; i<_repos.length; i++) {
913
- console.log(`${i+1}: ${_repos[i]}`)
893
+ let newWorkspace = args.join(' ')
894
+ if (newWorkspace) {
895
+ let workspaces = Object.values($workspaceMap)
896
+ workspaces.push(newWorkspace)
897
+ arrayDataFile(_workspaceConfigFile, () => workspaces)
898
+ }
899
+ checkWorkspaces()
900
+ let workspaces = Object.values($workspaceMap)
901
+ let items = workspaces.map((path, index) => {
902
+ return {
903
+ index: ' ' + (index + 1),
904
+ name: getSpaceFromDir(path),
905
+ path
914
906
  }
915
- let repoStr = trim(await nextLine(line => line, 'reset(or blank): '))
916
- if (/^\d+$/.test(repoStr)) {
917
- repoStr = _repos[Number(repoStr) - 1]
907
+ })
908
+ console.table(items)
909
+ },
910
+ args: {
911
+ workspacePath: '新增工作空间路径'
912
+ },
913
+ short: 'w'
914
+ },
915
+ uninstall: {
916
+ comment: '卸载工作空间',
917
+ exeFn: async (args) => {
918
+ let workspaces = Object.values($workspaceMap)
919
+ let items = workspaces.map((path, index) => {
920
+ return {
921
+ index: ' ' + (index + 1),
922
+ name: getSpaceFromDir(path),
923
+ path
918
924
  }
919
- newRepo = repoStr
925
+ })
926
+ console.table(items)
927
+ let index = await nextLine(line => line, "index: ")
928
+ let workspace = workspaces[index - 1]
929
+ if (workspace) {
930
+ workspaces = workspaces.filter(i => i !== workspace);
931
+ arrayDataFile(_workspaceConfigFile, () => workspaces);
932
+ checkWorkspaces()
933
+ } else {
934
+ warn('invalid args')
920
935
  }
921
- if (newRepo && newRepo !== currRepo) {
922
- if (_fs.existsSync(newRepo)) {
923
- setConfig('jsLibSource', newRepo)
924
- if (_repos.indexOf(newRepo) === -1) {
925
- _repos.push(newRepo)
926
- }
927
- arrayDataFile('repos.json', () => _repos)
928
- dealSourceCmds()
929
- } else {
930
- warn(`repo ${newRepo} not exist`)
936
+ },
937
+ short: 'u'
938
+ },
939
+ switch: {
940
+ comment: '切换工作空间',
941
+ exeFn: async (args) => {
942
+ checkWorkspaces()
943
+ let workspaces = Object.values($workspaceMap)
944
+ let items = workspaces.map((path, index) => {
945
+ return {
946
+ index: ' ' + (index + 1),
947
+ name: getSpaceFromDir(path),
948
+ path
931
949
  }
950
+ })
951
+ console.table(items)
952
+ let index = trim(await nextLine(line => line, "switch workspace: "));
953
+ if (index && workspaces[index - 1]) {
954
+ let workspace = workspaces[index - 1];
955
+ initWorkspace(getSpaceFromDir(workspace))
956
+ } else {
957
+ warn('no items')
932
958
  }
933
959
  },
934
- short: 'w'
960
+ short: 'S'
935
961
  },
936
962
  add: {
937
963
  comment: '新增文件',
@@ -943,6 +969,25 @@ const keywordDef = {
943
969
  },
944
970
  short: 'a'
945
971
  },
972
+ run: {
973
+ comment: '快捷执行',
974
+ exeFn: async (args) => {
975
+ if (!args[0]) {
976
+ warn('invalid args')
977
+ return
978
+ }
979
+ let cmds = filterCmd('^e ' + toJsirFileName(args[0]).replace(/^[eif]\s+/, '') + '$')
980
+ _cmdMap = arrayToCmdMap(cmds)
981
+ listCmd()
982
+ if (cmds.length === 1) {
983
+ await runCmd('1 ' + args.slice(1).join(' '))
984
+ }
985
+ },
986
+ args: {
987
+ fileNameReg: '文件名称匹配'
988
+ },
989
+ short: 'r'
990
+ },
946
991
  quit: {
947
992
  comment: '退出',
948
993
  exeFn: (args) => {
@@ -973,62 +1018,52 @@ async function dealKeyword(str) {
973
1018
  }
974
1019
  }
975
1020
 
976
- function getScriptMd5Map() {
977
- let files = _fs.readdirSync(_home)
978
- let md5Map = {}
979
- for (let file of files) {
980
- file = trim(file)
981
- md5Map['0x' + md5(file).substr(0, 8)] = file;
982
- }
983
- return md5Map
984
- }
985
-
986
- function _getScriptRequires(md5Map, scriptName, md5Keys, links) {
987
- let path = _home + '/' + scriptName;
988
- let text = String(_fs.readFileSync(path))
989
- let temp = []
990
- regEach(text, /(0x[0-9a-f]{8})/g, r=> {
991
- temp.push(r[1])
992
- });
993
- temp = [...new Set(temp)]
994
- temp = temp.filter(i => {
995
- let have = md5Map[i];
996
- if (have && links.indexOf(i) !== -1) {
997
- let items = [...links, i];
998
- let errorStr = items.map(item => item === i ? warnStr(item):item).join("->")
999
- throw `circle deps: ${errorStr}`
1000
- }
1001
- return have;
1002
- })
1003
- md5Keys.push(...temp)
1004
- for (let md5Key of temp) {
1005
- _getScriptRequires(md5Map, md5Map[md5Key], md5Keys, [...links, md5Key])
1006
- }
1007
- }
1008
-
1009
- function getScriptRequires(scriptName) {
1010
- let md5Keys = [];
1011
- _getScriptRequires(getScriptMd5Map(), scriptName, md5Keys, ['0x' + md5(scriptName).substr(0, 8)]);
1012
- return md5Keys
1013
- }
1021
+ // function getScriptMd5Map() {
1022
+ // let md5Map = {}
1023
+ // _workspaces.forEach(i => _getScriptMd5Map(i, md5Map))
1024
+ // return md5Map
1025
+ // }
1026
+
1027
+ // function _getScriptMd5Map(dir, md5Map) {
1028
+ // let files = _fs.readdirSync(dir).filter(isJsirFileName)
1029
+ // for (let file of files) {
1030
+ // md5Map[getCmdMd5Key(file)] = file;
1031
+ // }
1032
+ // }
1033
+
1034
+ // function _getScriptRequires(uniqueName, matchStrs, links) {
1035
+ // let path = getFullPath(uniqueName);
1036
+ // let text = String(_fs.readFileSync(path))
1037
+ // let temp = []
1038
+ // regEach(text, /\$require\s*\([^()]+\)/g, r=> {
1039
+ // temp.push(r[1])
1040
+ // });
1041
+ // temp = [...new Set(temp)]
1042
+ // temp = temp.filter(i => {
1043
+ // let have = md5Map[i];
1044
+ // if (have && links.indexOf(i) !== -1) {
1045
+ // let items = [...links, i];
1046
+ // let errorStr = items.map(item => item === i ? warnStr(item):item).join("->")
1047
+ // throw `circle deps: ${errorStr}`
1048
+ // }
1049
+ // return have;
1050
+ // })
1051
+ // md5Keys.push(...temp)
1052
+ // for (let md5Key of temp) {
1053
+ // _getScriptRequires(md5Map, md5Map[md5Key], md5Keys, [...links, md5Key])
1054
+ // }
1055
+ // }
1056
+
1057
+ // function getScriptRequires(uniqueName) {
1058
+ // let matchStrs = [];
1059
+ // _getScriptRequires(uniqueName, matchStrs, [getCmdMd5Key(uniqueName)]);
1060
+ // return md5Keys
1061
+ // }
1014
1062
 
1015
1063
  function getComments(i, cmdName, text, cols = [], col) {
1016
- let docLines = [infoStr('0x' + md5(cmdName).substr(0, 8)) + " - " + infoStr(i)]
1064
+ let docLines = [infoStr(getCmdMd5Key(parseUniqueName(cmdName)[1])) + " - " + infoStr(i)]
1017
1065
  text = trim(text)
1018
- if (text.startsWith("/*")) {
1019
- for (let line of text.split("\n")) {
1020
- let trimLine = trim(line)
1021
- if (trimLine.startsWith("/*")) {
1022
- continue
1023
- }
1024
- if (trimLine.endsWith("*/")) {
1025
- break
1026
- }
1027
- if (trimLine) {
1028
- docLines.push(line)
1029
- }
1030
- }
1031
- }
1066
+ docLines.push(...getTextComments(text))
1032
1067
  let argDef = getArgDef(text)
1033
1068
  let comments = getArgComments(argDef)
1034
1069
  if (comments) {
@@ -1046,8 +1081,43 @@ function getComments(i, cmdName, text, cols = [], col) {
1046
1081
  }
1047
1082
  }
1048
1083
 
1084
+ function getFullPath(name) {
1085
+ name = trim(name)
1086
+ if (!name) {
1087
+ return name;
1088
+ }
1089
+ let uniqueName = toUniqueName(name)
1090
+ let pair = parseUniqueName(uniqueName)
1091
+ let space = $workspaceMap[pair[0]]
1092
+ if (!space) {
1093
+ return ''
1094
+ }
1095
+ return `${space}/${pair[1]}`
1096
+ }
1097
+
1098
+ function toUniqueName(name, space) {
1099
+ name = trim(name)
1100
+ if (!name) {
1101
+ throw `invalid name`
1102
+ }
1103
+ let uniqueName
1104
+ if (name.startsWith('/')) {
1105
+ let items = name.split('/').map(trim).filter(i => i).reverse()
1106
+ uniqueName = items[1] + '/' + items[0]
1107
+ } else if (name.indexOf('/') !== -1) {
1108
+ uniqueName = name;
1109
+ } else {
1110
+ uniqueName = (space || $defaultSpace) + '/' + name;
1111
+ }
1112
+ let pair = parseUniqueName(uniqueName);
1113
+ return (pair[0] || space || $defaultSpace) + '/' + toJsirFileName(pair[1])
1114
+ }
1115
+
1049
1116
  function toJsirFileName(name) {
1050
1117
  name = trim(name)
1118
+ if (!name) {
1119
+ throw `invalid name`
1120
+ }
1051
1121
  if (isJsirFileName(name)) {
1052
1122
  return name;
1053
1123
  }
@@ -1059,14 +1129,13 @@ function toJsirFileName(name) {
1059
1129
  }
1060
1130
 
1061
1131
  function isJsirFileName(name) {
1062
- name = trim(name)
1063
- return /^[^.]*[^.\s]\.[^.\s]+$/.test(name)
1132
+ return /^[^./]*[^./\s]\.[^./\s]+$/.test(name)
1064
1133
  }
1065
1134
 
1066
1135
  function trimJsirFileName(name) {
1067
1136
  name = trim(name)
1068
1137
  if (isJsirFileName(name)) {
1069
- return trim(name.replace(/\.[^.\s]+$/, ''))
1138
+ return trim(name.replace(/\.[^./\s]+$/, ''))
1070
1139
  }
1071
1140
  return name
1072
1141
  }
@@ -1079,23 +1148,55 @@ function getJsirFileSuffix(name) {
1079
1148
  return ''
1080
1149
  }
1081
1150
 
1082
- function filterCmd(args){
1151
+ function initWorkspace(space) {
1152
+ let current = getConfig("workspace");
1153
+ let workspace = space || current || 'local'
1154
+ if (!$workspaceMap[current]) {
1155
+ workspace = 'local'
1156
+ }
1157
+ setConfig("workspace", workspace)
1158
+ global.$defaultSpace = workspace;
1159
+ }
1160
+
1161
+ function filterCmd(arg){
1162
+ arg = trim(arg)
1163
+ let spaceName
1164
+ if (arg.indexOf('/') !== -1) {
1165
+ let index = arg.indexOf('/');
1166
+ spaceName = trim(arg.substring(0, index)) || $defaultSpace
1167
+ arg = trim(arg.substring(index + 1))
1168
+ }
1169
+ let cmds = []
1170
+ for (let workspace of Object.values($workspaceMap)) {
1171
+ let spaceTmp = getSpaceFromDir(workspace);
1172
+ if (!spaceName || spaceName === spaceTmp) {
1173
+ cmds.push(..._filterCmd(workspace, arg));
1174
+ }
1175
+ }
1176
+ return cmds;
1177
+ }
1178
+
1179
+ function _filterCmd(dirPath, arg) {
1083
1180
  let cmdMap = {}
1084
- let files = _fs.readdirSync(_home)
1085
- let i = 1
1181
+ let files = _fs.readdirSync(dirPath).filter(isJsirFileName)
1086
1182
  for (let file of files) {
1087
1183
  file = trim(file)
1088
- if (!isJsirFileName(file)) {
1089
- continue
1090
- }
1091
- isArgsMatch(file, args, () => {
1092
- if (Object.values(cmdMap).indexOf(file) === -1) {
1093
- cmdMap[i] = file
1094
- i ++
1095
- }
1096
- }, true)
1184
+ let uniqueName = toUniqueName(dirPath + '/' + file)
1185
+ isArgsMatch(file, [arg], () => {
1186
+ cmdMap[uniqueName] = null;
1187
+ }, true, file)
1097
1188
  }
1098
- return cmdMap
1189
+ return Object.keys(cmdMap)
1190
+ }
1191
+
1192
+ function getSpaceFromDir(dirPath) {
1193
+ return trim(trim(dirPath).split('/').map(trim).filter(i => i).reverse()[0])
1194
+ }
1195
+
1196
+ function parseUniqueName(uniqueName) {
1197
+ let pair = uniqueName.split('/').map(trim).filter(i => i)
1198
+ let len = pair.length;
1199
+ return [pair[len - 2], pair[len - 1]]
1099
1200
  }
1100
1201
 
1101
1202
  function getArgComments(argDef) {
@@ -1124,25 +1225,25 @@ function getArgComments(argDef) {
1124
1225
  return comments
1125
1226
  }
1126
1227
 
1127
- async function runCmd(str = '', scriptName = '', text = '') {
1128
- let path = _home + '/' + scriptName;
1129
- if (scriptName || text) {
1228
+ async function runCmd(str = '', uniqueName = '', text = '') {
1229
+ let path = getFullPath(uniqueName);
1230
+ if (uniqueName || text) {
1130
1231
  str = `0 ${str}`
1131
1232
  }
1132
1233
  if (!text) {
1133
1234
  let strs = str.split(/\s+/)
1134
- if (!scriptName) {
1235
+ if (!uniqueName) {
1135
1236
  if (!_cmdMap[strs[0]] && strs[0] !== '0') {
1136
1237
  warn('no items')
1137
1238
  return
1138
1239
  }
1139
1240
  if (_cmdMap[strs[0]]) {
1140
- scriptName = _cmdMap[strs[0]];
1241
+ uniqueName = _cmdMap[strs[0]];
1141
1242
  }
1142
1243
  }
1143
1244
 
1144
- if (scriptName) {
1145
- path = _home + '/' + scriptName;
1245
+ if (uniqueName) {
1246
+ path = getFullPath(uniqueName);
1146
1247
  text = String(_fs.readFileSync(path))
1147
1248
  } else {
1148
1249
  text = await getCbText()
@@ -1223,7 +1324,7 @@ async function runCmd(str = '', scriptName = '', text = '') {
1223
1324
  }
1224
1325
 
1225
1326
  process.argv = [process.argv[0], path, ...scriptArgs]
1226
- return await evalText(text, scriptName, scriptArgs)
1327
+ return await evalText(text, uniqueName, scriptArgs)
1227
1328
  }
1228
1329
 
1229
1330
  // 使用空格作为可执行的标志
@@ -1328,32 +1429,50 @@ function tipsOnRmCallback(key) {
1328
1429
  }
1329
1430
  }
1330
1431
 
1331
- async function _requireSource(cmdMatchStr, printLog = false) {
1432
+ function getCmdMd5Key(str) {
1433
+ return '0x' + md5(str).substr(0, 8);
1434
+ }
1435
+
1436
+ async function _requireSource(currSpace, cmdMatchStr, printLog = false) {
1332
1437
  cmdMatchStr = trim(cmdMatchStr);
1333
1438
  let nullable = false;
1334
1439
  if (cmdMatchStr.startsWith("*")) {
1335
1440
  nullable = true;
1336
1441
  cmdMatchStr = trim(cmdMatchStr.substr(1));
1337
1442
  }
1338
- if (_fs.existsSync(_home + '/' + cmdMatchStr)) {
1339
- cmdMatchStr = '0x' + md5(cmdMatchStr).substr(0, 8);
1340
- }
1341
1443
 
1342
- let cmdMap = filterCmd(cmdMatchStr.split(/\s+/))
1343
- if (Object.keys(cmdMap).length !== 1) {
1444
+ let cmds;
1445
+ let uName = toUniqueName(cmdMatchStr, currSpace)
1446
+ let pr = parseUniqueName(uName)
1447
+ let fullPath;
1448
+ if (!/^[eif]\s+/.test(pr[1])) {
1449
+ uName = pr[0] + "/i " + pr[1]
1450
+ fullPath = getFullPath(uName)
1451
+ }
1452
+ if (fullPath && _fs.existsSync(fullPath)) {
1453
+ cmds = [uName]
1454
+ } else {
1455
+ let appointSpace = parseUniqueName(cmdMatchStr)[0]
1456
+ cmds = filterCmd(cmdMatchStr);
1457
+ if (cmds.length > 0) {
1458
+ cmds = cmds.filter(cmd => parseUniqueName(cmd)[0] === (appointSpace || currSpace))
1459
+ }
1460
+ }
1461
+ if (cmds.length !== 1) {
1344
1462
  if (nullable) {
1345
1463
  return null;
1346
1464
  }
1347
- throw `none match: ${cmdMatchStr}`
1465
+ throw `none unique match: ${cmdMatchStr}`
1348
1466
  }
1349
- let cmdName = Object.values(cmdMap)[0];
1350
1467
 
1351
1468
  let result
1352
- let path = _home + '/' + cmdName
1469
+ let uniqueName = cmds[0];
1470
+ let path = getFullPath(uniqueName)
1353
1471
  let text = String(_fs.readFileSync(path))
1354
- if (cmdName.startsWith('i ')) {
1472
+ let pair = parseUniqueName(uniqueName)
1473
+ if (pair[1].startsWith('i ')) {
1355
1474
  try {
1356
- result = await evalText(text, cmdName)
1475
+ result = await evalText(text, uniqueName)
1357
1476
  } catch (e) {
1358
1477
  if (nullable) {
1359
1478
  warn(`require [${cmdMatchStr}] failed`)
@@ -1363,9 +1482,9 @@ async function _requireSource(cmdMatchStr, printLog = false) {
1363
1482
  throw e
1364
1483
  }
1365
1484
  }
1366
- } else if (cmdName.startsWith('e ')) {
1485
+ } else if (pair[1].startsWith('e ')) {
1367
1486
  result = async (argsStr) => {
1368
- return await runCmd(trim(argsStr), cmdName, text)
1487
+ return await runCmd(trim(argsStr), uniqueName, text)
1369
1488
  }
1370
1489
  }
1371
1490
  if (!vl(result)) {
@@ -1381,7 +1500,7 @@ async function _requireSource(cmdMatchStr, printLog = false) {
1381
1500
  let startTime = Date.now();
1382
1501
  let pl = () => {
1383
1502
  if (printLog) {
1384
- info(`${cmdName} finished in ${Date.now() - startTime}ms`)
1503
+ info(`${uniqueName} finished in ${Date.now() - startTime}ms`)
1385
1504
  }
1386
1505
  }
1387
1506
  try {
@@ -1392,7 +1511,7 @@ async function _requireSource(cmdMatchStr, printLog = false) {
1392
1511
  return Promise.resolve(result);
1393
1512
  }).catch(e => {
1394
1513
  pl();
1395
- return Promise.reject(errorTag(e, cmdName))
1514
+ return Promise.reject(errorTag(e, uniqueName))
1396
1515
  })
1397
1516
  } else {
1398
1517
  pl();
@@ -1400,18 +1519,18 @@ async function _requireSource(cmdMatchStr, printLog = false) {
1400
1519
  }
1401
1520
  } catch (e) {
1402
1521
  pl();
1403
- throw errorTag(e, cmdName);
1522
+ throw errorTag(e, uniqueName);
1404
1523
  }
1405
1524
  }
1406
1525
  }
1407
1526
  return result
1408
1527
  }
1409
1528
 
1410
- async function _requireSources(...matchItem) {
1529
+ async function _requireSources(currSpace, ...matchItems) {
1411
1530
  let result = []
1412
- for (let i = 0; i < matchItem.length; i++) {
1413
- let curr = matchItem[i]
1414
- let next = matchItem[i + 1]
1531
+ for (let i = 0; i < matchItems.length; i++) {
1532
+ let curr = matchItems[i]
1533
+ let next = matchItems[i + 1]
1415
1534
  if (typeof curr === 'number') {
1416
1535
  curr = '0x' + pad(8, BigNumber(curr).toString(16), '0');
1417
1536
  }
@@ -1419,20 +1538,30 @@ async function _requireSources(...matchItem) {
1419
1538
  next = '0x' + pad(8, BigNumber(next).toString(16), '0');
1420
1539
  }
1421
1540
  if (typeof curr === 'string' && typeof next !== "string") {
1422
- result.push(await _requireSource(curr, next))
1541
+ result.push(await _requireSource(currSpace, curr, next))
1423
1542
  i++
1424
1543
  } else if (typeof curr === 'string') {
1425
- result.push(await _requireSource(curr))
1544
+ result.push(await _requireSource(currSpace, curr))
1426
1545
  }
1427
1546
  }
1428
1547
  return result
1429
1548
  }
1430
1549
 
1431
1550
  async function evalText($text = '', $cmdName = '', $args = []) {
1551
+ let currSpace;
1552
+ if ($cmdName) {
1553
+ let pair = parseUniqueName($cmdName)
1554
+ currSpace = pair[0]
1555
+ } else {
1556
+ currSpace = $defaultSpace
1557
+ }
1558
+ let $require = async (...matchItems) => {
1559
+ return await _requireSources(currSpace, ...matchItems)
1560
+ }
1432
1561
  try {
1433
- return await evalCode($text, $cmdName, $args,
1434
- _home, _cmdMap, _requireSources, $data,
1435
- nextLine, nextText, setTips, delTips, wrapperInput, filterCmd)
1562
+ return await evalCode($text, $cmdName, $args, $require, $data,
1563
+ nextLine, nextText, setTips, delTips, wrapperInput, filterCmd,
1564
+ currSpace, $log, $draft, $config, $homeDir, $lib)
1436
1565
  } catch(e) {
1437
1566
  throw errorTag(e, $cmdName);
1438
1567
  }