@lvce-editor/file-search-worker 1.5.0 → 1.7.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.
- package/dist/fileSearchWorkerMain.js +309 -3
- package/package.json +2 -1
|
@@ -18,6 +18,113 @@ const execute = (command, ...args) => {
|
|
|
18
18
|
return fn(...args);
|
|
19
19
|
};
|
|
20
20
|
|
|
21
|
+
const Directory$1 = 3;
|
|
22
|
+
const File$1 = 7;
|
|
23
|
+
|
|
24
|
+
const Slash$1 = '/';
|
|
25
|
+
|
|
26
|
+
const Slash = Slash$1;
|
|
27
|
+
|
|
28
|
+
const state$4 = {
|
|
29
|
+
files: Object.create(null)
|
|
30
|
+
};
|
|
31
|
+
const getDirent = uri => {
|
|
32
|
+
return state$4.files[uri];
|
|
33
|
+
};
|
|
34
|
+
const readFile = uri => {
|
|
35
|
+
const dirent = getDirent(uri);
|
|
36
|
+
if (!dirent) {
|
|
37
|
+
throw new Error(`File not found: ${uri}`);
|
|
38
|
+
}
|
|
39
|
+
if (dirent.type !== File$1) {
|
|
40
|
+
throw new Error('file is a directory');
|
|
41
|
+
}
|
|
42
|
+
return dirent.content;
|
|
43
|
+
};
|
|
44
|
+
const ensureParentDir = uri => {
|
|
45
|
+
const startIndex = 0;
|
|
46
|
+
let endIndex = uri.indexOf(Slash);
|
|
47
|
+
while (endIndex >= 0) {
|
|
48
|
+
const part = uri.slice(startIndex, endIndex + 1);
|
|
49
|
+
state$4.files[part] = {
|
|
50
|
+
type: Directory$1,
|
|
51
|
+
content: ''
|
|
52
|
+
};
|
|
53
|
+
endIndex = uri.indexOf(Slash, endIndex + 1);
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
const writeFile = (uri, content) => {
|
|
57
|
+
const dirent = getDirent(uri);
|
|
58
|
+
if (dirent) {
|
|
59
|
+
dirent.content = content;
|
|
60
|
+
} else {
|
|
61
|
+
ensureParentDir(uri);
|
|
62
|
+
state$4.files[uri] = {
|
|
63
|
+
type: File$1,
|
|
64
|
+
content
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
const mkdir = uri => {
|
|
69
|
+
if (!uri.endsWith(Slash)) {
|
|
70
|
+
uri += Slash;
|
|
71
|
+
}
|
|
72
|
+
ensureParentDir(uri);
|
|
73
|
+
state$4.files[uri] = {
|
|
74
|
+
type: Directory$1,
|
|
75
|
+
content: ''
|
|
76
|
+
};
|
|
77
|
+
};
|
|
78
|
+
const readDirWithFileTypes = uri => {
|
|
79
|
+
if (!uri.endsWith(Slash)) {
|
|
80
|
+
uri += Slash;
|
|
81
|
+
}
|
|
82
|
+
const dirents = [];
|
|
83
|
+
for (const [key, value] of Object.entries(state$4.files)) {
|
|
84
|
+
if (key.startsWith(uri)) {
|
|
85
|
+
// @ts-ignore
|
|
86
|
+
switch (value.type) {
|
|
87
|
+
case Directory$1:
|
|
88
|
+
if (!key.slice(0, -1).includes(Slash, uri.length) && key !== `${uri}/` && key !== uri) {
|
|
89
|
+
dirents.push({
|
|
90
|
+
// @ts-ignore
|
|
91
|
+
type: value.type,
|
|
92
|
+
name: key.slice(uri.length, -1)
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
break;
|
|
96
|
+
case File$1:
|
|
97
|
+
if (!key.includes(Slash, uri.length + 1)) {
|
|
98
|
+
dirents.push({
|
|
99
|
+
// @ts-ignore
|
|
100
|
+
type: value.type,
|
|
101
|
+
name: key.slice(uri.length)
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return dirents;
|
|
109
|
+
};
|
|
110
|
+
const getBlobUrl = uri => {
|
|
111
|
+
const content = readFile(uri);
|
|
112
|
+
const blob = new Blob([content]);
|
|
113
|
+
const url = URL.createObjectURL(blob);
|
|
114
|
+
return url;
|
|
115
|
+
};
|
|
116
|
+
const getBlob = uri => {
|
|
117
|
+
const content = readFile(uri);
|
|
118
|
+
const blob = new Blob([content]);
|
|
119
|
+
return blob;
|
|
120
|
+
};
|
|
121
|
+
const chmod = () => {
|
|
122
|
+
throw new Error('[memfs] chmod not implemented');
|
|
123
|
+
};
|
|
124
|
+
const getFiles = () => {
|
|
125
|
+
return state$4.files;
|
|
126
|
+
};
|
|
127
|
+
|
|
21
128
|
const searchFile$3 = async (workspace, root) => {
|
|
22
129
|
return [];
|
|
23
130
|
};
|
|
@@ -499,6 +606,193 @@ const searchFile$1 = async uri => {
|
|
|
499
606
|
return all;
|
|
500
607
|
};
|
|
501
608
|
|
|
609
|
+
const Diagonal = 1;
|
|
610
|
+
const Left = 2;
|
|
611
|
+
|
|
612
|
+
// based on https://github.com/microsoft/vscode/blob/3059063b805ed0ac10a6d9539e213386bfcfb852/src/vs/base/common/filters.ts by Microsoft (License MIT)
|
|
613
|
+
|
|
614
|
+
const createTable = size => {
|
|
615
|
+
const table = [];
|
|
616
|
+
for (let i = 0; i < size; i++) {
|
|
617
|
+
const row = new Uint8Array(size);
|
|
618
|
+
table.push(row);
|
|
619
|
+
}
|
|
620
|
+
return table;
|
|
621
|
+
};
|
|
622
|
+
const EmptyMatches = [];
|
|
623
|
+
const Dash = '-';
|
|
624
|
+
const Dot = '.';
|
|
625
|
+
const EmptyString = '';
|
|
626
|
+
const Space = ' ';
|
|
627
|
+
const Underline = '_';
|
|
628
|
+
const T = 't';
|
|
629
|
+
const isLowerCase = char => {
|
|
630
|
+
return char === char.toLowerCase();
|
|
631
|
+
};
|
|
632
|
+
const isUpperCase = char => {
|
|
633
|
+
return char === char.toUpperCase();
|
|
634
|
+
};
|
|
635
|
+
|
|
636
|
+
// based on https://github.com/microsoft/vscode/blob/3059063b805ed0ac10a6d9539e213386bfcfb852/src/vs/base/common/filters.ts by Microsoft (License MIT)
|
|
637
|
+
const isGap = (columnCharBefore, columnChar) => {
|
|
638
|
+
switch (columnCharBefore) {
|
|
639
|
+
case Dash:
|
|
640
|
+
case Underline:
|
|
641
|
+
case EmptyString:
|
|
642
|
+
case T:
|
|
643
|
+
case Space:
|
|
644
|
+
case Dot:
|
|
645
|
+
return true;
|
|
646
|
+
}
|
|
647
|
+
if (isLowerCase(columnCharBefore) && isUpperCase(columnChar)) {
|
|
648
|
+
return true;
|
|
649
|
+
}
|
|
650
|
+
return false;
|
|
651
|
+
};
|
|
652
|
+
|
|
653
|
+
// based on https://github.com/microsoft/vscode/blob/3059063b805ed0ac10a6d9539e213386bfcfb852/src/vs/base/common/filters.ts by Microsoft (License MIT)
|
|
654
|
+
const getScore = (rowCharLow, rowChar, columnCharBefore, columnCharLow, columnChar, isDiagonalMatch) => {
|
|
655
|
+
if (rowCharLow !== columnCharLow) {
|
|
656
|
+
return -1;
|
|
657
|
+
}
|
|
658
|
+
const isMatch = rowChar === columnChar;
|
|
659
|
+
if (isMatch) {
|
|
660
|
+
if (isDiagonalMatch) {
|
|
661
|
+
return 8;
|
|
662
|
+
}
|
|
663
|
+
if (isGap(columnCharBefore, columnChar)) {
|
|
664
|
+
return 8;
|
|
665
|
+
}
|
|
666
|
+
return 5;
|
|
667
|
+
}
|
|
668
|
+
if (isGap(columnCharBefore, columnChar)) {
|
|
669
|
+
return 8;
|
|
670
|
+
}
|
|
671
|
+
return 5;
|
|
672
|
+
};
|
|
673
|
+
|
|
674
|
+
// based on https://github.com/microsoft/vscode/blob/3059063b805ed0ac10a6d9539e213386bfcfb852/src/vs/base/common/filters.ts by Microsoft (License MIT)
|
|
675
|
+
|
|
676
|
+
const isPatternInWord = (patternLow, patternPos, patternLen, wordLow, wordPos, wordLen) => {
|
|
677
|
+
while (patternPos < patternLen && wordPos < wordLen) {
|
|
678
|
+
if (patternLow[patternPos] === wordLow[wordPos]) {
|
|
679
|
+
patternPos += 1;
|
|
680
|
+
}
|
|
681
|
+
wordPos += 1;
|
|
682
|
+
}
|
|
683
|
+
return patternPos === patternLen; // pattern must be exhausted
|
|
684
|
+
};
|
|
685
|
+
|
|
686
|
+
// based on https://github.com/microsoft/vscode/blob/3059063b805ed0ac10a6d9539e213386bfcfb852/src/vs/base/common/filters.ts by Microsoft (License MIT)
|
|
687
|
+
const traceHighlights = (table, arrows, patternLength, wordLength) => {
|
|
688
|
+
let row = patternLength;
|
|
689
|
+
let column = wordLength;
|
|
690
|
+
const matches = [];
|
|
691
|
+
while (row >= 1 && column >= 1) {
|
|
692
|
+
const arrow = arrows[row][column];
|
|
693
|
+
if (arrow === Left) {
|
|
694
|
+
column--;
|
|
695
|
+
} else if (arrow === Diagonal) {
|
|
696
|
+
row--;
|
|
697
|
+
column--;
|
|
698
|
+
const start = column + 1;
|
|
699
|
+
while (row >= 1 && column >= 1) {
|
|
700
|
+
const arrow = arrows[row][column];
|
|
701
|
+
if (arrow === Left) {
|
|
702
|
+
break;
|
|
703
|
+
}
|
|
704
|
+
if (arrow === Diagonal) {
|
|
705
|
+
row--;
|
|
706
|
+
column--;
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
const end = column;
|
|
710
|
+
matches.unshift(end, start);
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
matches.unshift(table[patternLength][wordLength - 1]);
|
|
714
|
+
return matches;
|
|
715
|
+
};
|
|
716
|
+
|
|
717
|
+
// based on https://github.com/microsoft/vscode/blob/3059063b805ed0ac10a6d9539e213386bfcfb852/src/vs/base/common/filters.ts by Microsoft (License MIT)
|
|
718
|
+
const gridSize = 128;
|
|
719
|
+
const table = createTable(gridSize);
|
|
720
|
+
const arrows = createTable(gridSize);
|
|
721
|
+
const fuzzySearch = (pattern, word) => {
|
|
722
|
+
const patternLength = Math.min(pattern.length, gridSize - 1);
|
|
723
|
+
const wordLength = Math.min(word.length, gridSize - 1);
|
|
724
|
+
const patternLower = pattern.toLowerCase();
|
|
725
|
+
const wordLower = word.toLowerCase();
|
|
726
|
+
if (!isPatternInWord(patternLower, 0, patternLength, wordLower, 0, wordLength)) {
|
|
727
|
+
return EmptyMatches;
|
|
728
|
+
}
|
|
729
|
+
let strongMatch = false;
|
|
730
|
+
for (let row = 1; row < patternLength + 1; row++) {
|
|
731
|
+
const rowChar = pattern[row - 1];
|
|
732
|
+
const rowCharLow = patternLower[row - 1];
|
|
733
|
+
for (let column = 1; column < wordLength + 1; column++) {
|
|
734
|
+
const columnChar = word[column - 1];
|
|
735
|
+
const columnCharLow = wordLower[column - 1];
|
|
736
|
+
const columnCharBefore = word[column - 2] || '';
|
|
737
|
+
const isDiagonalMatch = arrows[row - 1][column - 1] === Diagonal;
|
|
738
|
+
const score = getScore(rowCharLow, rowChar, columnCharBefore, columnCharLow, columnChar, isDiagonalMatch);
|
|
739
|
+
if (row === 1 && score > 5) {
|
|
740
|
+
strongMatch = true;
|
|
741
|
+
}
|
|
742
|
+
let diagonalScore = score + table[row - 1][column - 1];
|
|
743
|
+
if (isDiagonalMatch && score !== -1) {
|
|
744
|
+
diagonalScore += 2;
|
|
745
|
+
}
|
|
746
|
+
const leftScore = table[row][column - 1];
|
|
747
|
+
if (leftScore > diagonalScore) {
|
|
748
|
+
table[row][column] = leftScore;
|
|
749
|
+
arrows[row][column] = Left;
|
|
750
|
+
} else {
|
|
751
|
+
table[row][column] = diagonalScore;
|
|
752
|
+
arrows[row][column] = Diagonal;
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
if (!strongMatch) {
|
|
757
|
+
return EmptyMatches;
|
|
758
|
+
}
|
|
759
|
+
const highlights = traceHighlights(table, arrows, patternLength, wordLength);
|
|
760
|
+
return highlights;
|
|
761
|
+
};
|
|
762
|
+
|
|
763
|
+
const filterQuickPickItem = (pattern, word) => {
|
|
764
|
+
const matches = fuzzySearch(pattern, word);
|
|
765
|
+
return matches;
|
|
766
|
+
};
|
|
767
|
+
|
|
768
|
+
const getBaseName = path => {
|
|
769
|
+
return path.slice(path.lastIndexOf('/') + 1);
|
|
770
|
+
};
|
|
771
|
+
const emptyMatches = [];
|
|
772
|
+
const convertToPick = item => {
|
|
773
|
+
return {
|
|
774
|
+
pick: item,
|
|
775
|
+
matches: emptyMatches
|
|
776
|
+
};
|
|
777
|
+
};
|
|
778
|
+
const filterQuickPickItems = (items, value) => {
|
|
779
|
+
if (!value) {
|
|
780
|
+
return items.map(convertToPick);
|
|
781
|
+
}
|
|
782
|
+
const results = [];
|
|
783
|
+
for (const item of items) {
|
|
784
|
+
const baseName = getBaseName(item);
|
|
785
|
+
const matches = filterQuickPickItem(value, baseName);
|
|
786
|
+
if (matches.length > 0) {
|
|
787
|
+
results.push({
|
|
788
|
+
pick: item,
|
|
789
|
+
matches
|
|
790
|
+
});
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
return results;
|
|
794
|
+
};
|
|
795
|
+
|
|
502
796
|
const getFileSearchRipGrepArgs = () => {
|
|
503
797
|
const ripGrepArgs = ['--files', '--sort-files'];
|
|
504
798
|
return ripGrepArgs;
|
|
@@ -903,7 +1197,7 @@ const splitLines$1 = lines => {
|
|
|
903
1197
|
|
|
904
1198
|
// TODO create direct connection from electron to file search worker using message ports
|
|
905
1199
|
|
|
906
|
-
const searchFile = async (path, value) => {
|
|
1200
|
+
const searchFile = async (path, value, prepare) => {
|
|
907
1201
|
const ripGrepArgs = getFileSearchRipGrepArgs();
|
|
908
1202
|
const options = {
|
|
909
1203
|
ripGrepArgs,
|
|
@@ -912,14 +1206,26 @@ const searchFile = async (path, value) => {
|
|
|
912
1206
|
};
|
|
913
1207
|
const stdout = await invoke('SearchFile.searchFile', options);
|
|
914
1208
|
const lines = splitLines$1(stdout);
|
|
915
|
-
|
|
1209
|
+
if (!prepare) {
|
|
1210
|
+
return lines;
|
|
1211
|
+
}
|
|
1212
|
+
const filtered = filterQuickPickItems(lines, value);
|
|
1213
|
+
return filtered;
|
|
916
1214
|
};
|
|
917
1215
|
|
|
918
1216
|
const commandMap = {
|
|
919
1217
|
'SearchFile.searchFile': searchFile$3,
|
|
920
1218
|
'SearchFile.searchFileWithRipGrep': searchFile,
|
|
921
1219
|
'SearchFile.searchFileWithHtml': searchFile$1,
|
|
922
|
-
'SearchFile.searchFileWithFetch': searchFile$2
|
|
1220
|
+
'SearchFile.searchFileWithFetch': searchFile$2,
|
|
1221
|
+
'FileSystemMemory.readFile': readFile,
|
|
1222
|
+
'FileSystemMemory.writeFile': writeFile,
|
|
1223
|
+
'FileSystemMemory.mkdir': mkdir,
|
|
1224
|
+
'FileSystemMemory.readDirWithFileTypes': readDirWithFileTypes,
|
|
1225
|
+
'FileSystemMemory.getBlobUrl': getBlobUrl,
|
|
1226
|
+
'FileSystemMemory.getBlob': getBlob,
|
|
1227
|
+
'FileSystemMemory.chmod': chmod,
|
|
1228
|
+
'FileSystemMemory.getFiles': getFiles
|
|
923
1229
|
};
|
|
924
1230
|
|
|
925
1231
|
const requiresSocket = () => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lvce-editor/file-search-worker",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "dist/fileSearchWorkerMain.js",
|
|
6
6
|
"type": "module",
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
"author": "",
|
|
9
9
|
"license": "MIT",
|
|
10
10
|
"dependencies": {
|
|
11
|
+
"@lvce-editor/fuzzy-search": "^1.0.0",
|
|
11
12
|
"idb": "^8.0.0"
|
|
12
13
|
}
|
|
13
14
|
}
|