@moyarich/console-addon-search 0.0.0-stage → 0.2.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/README.md +38 -2
- package/dist/components/ConsoleSearchControls/ConsoleSearchControls.d.cts +8 -0
- package/dist/components/ConsoleSearchControls/ConsoleSearchControls.d.ts +8 -0
- package/dist/components/ConsoleSearchHighlight/ConsoleSearchHighlight.d.cts +6 -0
- package/dist/components/ConsoleSearchHighlight/ConsoleSearchHighlight.d.ts +6 -0
- package/dist/console-addon-search.css +166 -0
- package/dist/index.cjs +523 -0
- package/dist/index.d.cts +50 -0
- package/dist/index.d.ts +50 -0
- package/dist/index.js +523 -0
- package/dist/locales/en.json +14 -0
- package/dist/locales/es.json +14 -0
- package/dist/locales/fr.json +14 -0
- package/dist/locales/pt.json +14 -0
- package/dist/localization.d.cts +4 -0
- package/dist/localization.d.ts +4 -0
- package/dist/styles.css +169 -0
- package/package.json +67 -4
package/dist/index.js
ADDED
|
@@ -0,0 +1,523 @@
|
|
|
1
|
+
import { useSyncExternalStore, useId, createElement } from "react";
|
|
2
|
+
import { createConsoleServiceToken, consoleServices, consoleExtensionPoints } from "@moyarich/console-core";
|
|
3
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
4
|
+
const search$3 = "Console search";
|
|
5
|
+
const searchOutput$3 = "Search output";
|
|
6
|
+
const searchConsoleOutput$3 = "Search console output";
|
|
7
|
+
const caseSensitive$3 = "Case sensitive";
|
|
8
|
+
const wholeWord$3 = "Whole word";
|
|
9
|
+
const regex$3 = "Regex";
|
|
10
|
+
const noMatches$3 = "No matches";
|
|
11
|
+
const matchCount$3 = "{current} of {total} matches";
|
|
12
|
+
const previousResult$3 = "Previous search result";
|
|
13
|
+
const nextResult$3 = "Next search result";
|
|
14
|
+
const previous$3 = "Previous";
|
|
15
|
+
const next$3 = "Next";
|
|
16
|
+
const en = {
|
|
17
|
+
search: search$3,
|
|
18
|
+
searchOutput: searchOutput$3,
|
|
19
|
+
searchConsoleOutput: searchConsoleOutput$3,
|
|
20
|
+
caseSensitive: caseSensitive$3,
|
|
21
|
+
wholeWord: wholeWord$3,
|
|
22
|
+
regex: regex$3,
|
|
23
|
+
noMatches: noMatches$3,
|
|
24
|
+
matchCount: matchCount$3,
|
|
25
|
+
previousResult: previousResult$3,
|
|
26
|
+
nextResult: nextResult$3,
|
|
27
|
+
previous: previous$3,
|
|
28
|
+
next: next$3
|
|
29
|
+
};
|
|
30
|
+
const search$2 = "Buscar en la consola";
|
|
31
|
+
const searchOutput$2 = "Buscar en la salida";
|
|
32
|
+
const searchConsoleOutput$2 = "Buscar en la salida de la consola";
|
|
33
|
+
const caseSensitive$2 = "Distinguir mayúsculas";
|
|
34
|
+
const wholeWord$2 = "Palabra completa";
|
|
35
|
+
const regex$2 = "Expresión regular";
|
|
36
|
+
const noMatches$2 = "Sin resultados";
|
|
37
|
+
const matchCount$2 = "{current} de {total} resultados";
|
|
38
|
+
const previousResult$2 = "Resultado anterior";
|
|
39
|
+
const nextResult$2 = "Resultado siguiente";
|
|
40
|
+
const previous$2 = "Anterior";
|
|
41
|
+
const next$2 = "Siguiente";
|
|
42
|
+
const es = {
|
|
43
|
+
search: search$2,
|
|
44
|
+
searchOutput: searchOutput$2,
|
|
45
|
+
searchConsoleOutput: searchConsoleOutput$2,
|
|
46
|
+
caseSensitive: caseSensitive$2,
|
|
47
|
+
wholeWord: wholeWord$2,
|
|
48
|
+
regex: regex$2,
|
|
49
|
+
noMatches: noMatches$2,
|
|
50
|
+
matchCount: matchCount$2,
|
|
51
|
+
previousResult: previousResult$2,
|
|
52
|
+
nextResult: nextResult$2,
|
|
53
|
+
previous: previous$2,
|
|
54
|
+
next: next$2
|
|
55
|
+
};
|
|
56
|
+
const search$1 = "Recherche dans la console";
|
|
57
|
+
const searchOutput$1 = "Rechercher dans la sortie";
|
|
58
|
+
const searchConsoleOutput$1 = "Rechercher dans la sortie de la console";
|
|
59
|
+
const caseSensitive$1 = "Respecter la casse";
|
|
60
|
+
const wholeWord$1 = "Mot entier";
|
|
61
|
+
const regex$1 = "Expression régulière";
|
|
62
|
+
const noMatches$1 = "Aucun résultat";
|
|
63
|
+
const matchCount$1 = "{current} sur {total} résultats";
|
|
64
|
+
const previousResult$1 = "Résultat précédent";
|
|
65
|
+
const nextResult$1 = "Résultat suivant";
|
|
66
|
+
const previous$1 = "Précédent";
|
|
67
|
+
const next$1 = "Suivant";
|
|
68
|
+
const fr = {
|
|
69
|
+
search: search$1,
|
|
70
|
+
searchOutput: searchOutput$1,
|
|
71
|
+
searchConsoleOutput: searchConsoleOutput$1,
|
|
72
|
+
caseSensitive: caseSensitive$1,
|
|
73
|
+
wholeWord: wholeWord$1,
|
|
74
|
+
regex: regex$1,
|
|
75
|
+
noMatches: noMatches$1,
|
|
76
|
+
matchCount: matchCount$1,
|
|
77
|
+
previousResult: previousResult$1,
|
|
78
|
+
nextResult: nextResult$1,
|
|
79
|
+
previous: previous$1,
|
|
80
|
+
next: next$1
|
|
81
|
+
};
|
|
82
|
+
const search = "Pesquisar no console";
|
|
83
|
+
const searchOutput = "Pesquisar na saída";
|
|
84
|
+
const searchConsoleOutput = "Pesquisar na saída do console";
|
|
85
|
+
const caseSensitive = "Diferenciar maiúsculas de minúsculas";
|
|
86
|
+
const wholeWord = "Palavra inteira";
|
|
87
|
+
const regex = "Expressão regular";
|
|
88
|
+
const noMatches = "Nenhuma correspondência";
|
|
89
|
+
const matchCount = "{current} de {total} correspondências";
|
|
90
|
+
const previousResult = "Resultado anterior";
|
|
91
|
+
const nextResult = "Próximo resultado";
|
|
92
|
+
const previous = "Anterior";
|
|
93
|
+
const next = "Próximo";
|
|
94
|
+
const pt = {
|
|
95
|
+
search,
|
|
96
|
+
searchOutput,
|
|
97
|
+
searchConsoleOutput,
|
|
98
|
+
caseSensitive,
|
|
99
|
+
wholeWord,
|
|
100
|
+
regex,
|
|
101
|
+
noMatches,
|
|
102
|
+
matchCount,
|
|
103
|
+
previousResult,
|
|
104
|
+
nextResult,
|
|
105
|
+
previous,
|
|
106
|
+
next
|
|
107
|
+
};
|
|
108
|
+
const dictionaries = { en, es, fr, pt };
|
|
109
|
+
function resolveAddonMessages(locale = "en", overrides) {
|
|
110
|
+
const tag = locale.replace(/_/g, "-").toLowerCase();
|
|
111
|
+
return {
|
|
112
|
+
...en,
|
|
113
|
+
...dictionaries[tag] ?? dictionaries[tag.split("-")[0]] ?? {},
|
|
114
|
+
...overrides
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
function ConsoleSearchControls({
|
|
118
|
+
controller,
|
|
119
|
+
locale = "en",
|
|
120
|
+
translations
|
|
121
|
+
}) {
|
|
122
|
+
const state = useSyncExternalStore(
|
|
123
|
+
controller.subscribe,
|
|
124
|
+
controller.getState,
|
|
125
|
+
controller.getState
|
|
126
|
+
);
|
|
127
|
+
const errorId = useId();
|
|
128
|
+
const count = state.matches.length;
|
|
129
|
+
const t = resolveAddonMessages(locale, translations);
|
|
130
|
+
const selectFirstMatch = () => {
|
|
131
|
+
const next2 = controller.getState();
|
|
132
|
+
if (next2.matches.length && next2.activeIndex < 0) controller.next();
|
|
133
|
+
};
|
|
134
|
+
return /* @__PURE__ */ jsxs("section", { className: "console-search-controls", "aria-label": t.search, children: [
|
|
135
|
+
/* @__PURE__ */ jsxs("div", { className: "console-search-controls-row", children: [
|
|
136
|
+
/* @__PURE__ */ jsxs("label", { className: "console-search-controls-field", children: [
|
|
137
|
+
/* @__PURE__ */ jsxs(
|
|
138
|
+
"svg",
|
|
139
|
+
{
|
|
140
|
+
"aria-hidden": "true",
|
|
141
|
+
width: "16",
|
|
142
|
+
height: "16",
|
|
143
|
+
viewBox: "0 0 24 24",
|
|
144
|
+
fill: "none",
|
|
145
|
+
stroke: "currentColor",
|
|
146
|
+
strokeWidth: "1.75",
|
|
147
|
+
children: [
|
|
148
|
+
/* @__PURE__ */ jsx("circle", { cx: "10.5", cy: "10.5", r: "6.5" }),
|
|
149
|
+
/* @__PURE__ */ jsx("path", { d: "m16 16 4 4" })
|
|
150
|
+
]
|
|
151
|
+
}
|
|
152
|
+
),
|
|
153
|
+
/* @__PURE__ */ jsx(
|
|
154
|
+
"input",
|
|
155
|
+
{
|
|
156
|
+
type: "search",
|
|
157
|
+
placeholder: t.searchOutput,
|
|
158
|
+
"aria-invalid": !!state.error,
|
|
159
|
+
"aria-describedby": state.error ? errorId : void 0,
|
|
160
|
+
onKeyDown: (event) => {
|
|
161
|
+
if (event.key === "Enter") {
|
|
162
|
+
event.preventDefault();
|
|
163
|
+
event.stopPropagation();
|
|
164
|
+
if (event.shiftKey) controller.previous();
|
|
165
|
+
else controller.next();
|
|
166
|
+
}
|
|
167
|
+
},
|
|
168
|
+
value: state.query,
|
|
169
|
+
onChange: (event) => {
|
|
170
|
+
controller.setQuery(event.target.value);
|
|
171
|
+
selectFirstMatch();
|
|
172
|
+
},
|
|
173
|
+
"aria-label": t.searchConsoleOutput
|
|
174
|
+
}
|
|
175
|
+
)
|
|
176
|
+
] }),
|
|
177
|
+
/* @__PURE__ */ jsx("span", { role: "status", "aria-live": "polite", children: !state.query ? "" : count === 0 ? t.noMatches : t.matchCount.replace("{current}", String(state.activeIndex + 1)).replace("{total}", String(count)) }),
|
|
178
|
+
/* @__PURE__ */ jsx(
|
|
179
|
+
"button",
|
|
180
|
+
{
|
|
181
|
+
type: "button",
|
|
182
|
+
onClick: () => controller.previous(),
|
|
183
|
+
disabled: !count,
|
|
184
|
+
"aria-label": t.previousResult,
|
|
185
|
+
title: t.previousResult,
|
|
186
|
+
children: /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "↑" })
|
|
187
|
+
}
|
|
188
|
+
),
|
|
189
|
+
/* @__PURE__ */ jsx(
|
|
190
|
+
"button",
|
|
191
|
+
{
|
|
192
|
+
type: "button",
|
|
193
|
+
onClick: () => controller.next(),
|
|
194
|
+
disabled: !count,
|
|
195
|
+
"aria-label": t.nextResult,
|
|
196
|
+
title: t.nextResult,
|
|
197
|
+
children: /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "↓" })
|
|
198
|
+
}
|
|
199
|
+
)
|
|
200
|
+
] }),
|
|
201
|
+
/* @__PURE__ */ jsxs("div", { className: "console-search-controls-options", children: [
|
|
202
|
+
/* @__PURE__ */ jsxs("label", { children: [
|
|
203
|
+
/* @__PURE__ */ jsx(
|
|
204
|
+
"input",
|
|
205
|
+
{
|
|
206
|
+
type: "checkbox",
|
|
207
|
+
checked: !!state.options.caseSensitive,
|
|
208
|
+
onChange: (event) => {
|
|
209
|
+
controller.setOptions({
|
|
210
|
+
...state.options,
|
|
211
|
+
caseSensitive: event.target.checked
|
|
212
|
+
});
|
|
213
|
+
selectFirstMatch();
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
),
|
|
217
|
+
" ",
|
|
218
|
+
t.caseSensitive
|
|
219
|
+
] }),
|
|
220
|
+
/* @__PURE__ */ jsxs("label", { children: [
|
|
221
|
+
/* @__PURE__ */ jsx(
|
|
222
|
+
"input",
|
|
223
|
+
{
|
|
224
|
+
type: "checkbox",
|
|
225
|
+
checked: !!state.options.wholeWord,
|
|
226
|
+
onChange: (event) => {
|
|
227
|
+
controller.setOptions({
|
|
228
|
+
...state.options,
|
|
229
|
+
wholeWord: event.target.checked
|
|
230
|
+
});
|
|
231
|
+
selectFirstMatch();
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
),
|
|
235
|
+
" ",
|
|
236
|
+
t.wholeWord
|
|
237
|
+
] }),
|
|
238
|
+
/* @__PURE__ */ jsxs("label", { children: [
|
|
239
|
+
/* @__PURE__ */ jsx(
|
|
240
|
+
"input",
|
|
241
|
+
{
|
|
242
|
+
type: "checkbox",
|
|
243
|
+
checked: !!state.options.regex,
|
|
244
|
+
onChange: (event) => {
|
|
245
|
+
controller.setOptions({
|
|
246
|
+
...state.options,
|
|
247
|
+
regex: event.target.checked
|
|
248
|
+
});
|
|
249
|
+
selectFirstMatch();
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
),
|
|
253
|
+
" ",
|
|
254
|
+
t.regex
|
|
255
|
+
] })
|
|
256
|
+
] }),
|
|
257
|
+
state.error && /* @__PURE__ */ jsx(
|
|
258
|
+
"span",
|
|
259
|
+
{
|
|
260
|
+
className: "console-search-controls-error",
|
|
261
|
+
id: errorId,
|
|
262
|
+
role: "alert",
|
|
263
|
+
children: state.error
|
|
264
|
+
}
|
|
265
|
+
)
|
|
266
|
+
] });
|
|
267
|
+
}
|
|
268
|
+
function ConsoleSearchHighlight({
|
|
269
|
+
controller,
|
|
270
|
+
index
|
|
271
|
+
}) {
|
|
272
|
+
const state = useSyncExternalStore(
|
|
273
|
+
controller.subscribe,
|
|
274
|
+
controller.getState,
|
|
275
|
+
controller.getState
|
|
276
|
+
);
|
|
277
|
+
const matches = state.matches.map((match, matchIndex) => ({ match, matchIndex })).filter(({ match }) => match.index === index);
|
|
278
|
+
if (!matches.length) return null;
|
|
279
|
+
return /* @__PURE__ */ jsx(
|
|
280
|
+
"span",
|
|
281
|
+
{
|
|
282
|
+
className: "console-search-matches",
|
|
283
|
+
"aria-label": `${matches.length} matches in this message`,
|
|
284
|
+
children: matches.map(({ match, matchIndex }) => /* @__PURE__ */ jsx(
|
|
285
|
+
"mark",
|
|
286
|
+
{
|
|
287
|
+
className: "console-search-highlight",
|
|
288
|
+
"data-active": state.activeIndex === matchIndex ? "" : void 0,
|
|
289
|
+
"aria-label": state.activeIndex === matchIndex ? "Current search match" : "Search match",
|
|
290
|
+
children: match.text || "Zero-width match"
|
|
291
|
+
},
|
|
292
|
+
`${match.start}-${match.end}-${matchIndex}`
|
|
293
|
+
))
|
|
294
|
+
}
|
|
295
|
+
);
|
|
296
|
+
}
|
|
297
|
+
const CONSOLE_SEARCH_ADDON_ID = "@moyarich/console-addon-search";
|
|
298
|
+
const consoleSearchService = createConsoleServiceToken(
|
|
299
|
+
`${CONSOLE_SEARCH_ADDON_ID}.controller`
|
|
300
|
+
);
|
|
301
|
+
function findConsoleSearchMatches(entries, query, options = {}) {
|
|
302
|
+
if (!query) return { matches: [] };
|
|
303
|
+
let pattern;
|
|
304
|
+
try {
|
|
305
|
+
pattern = new RegExp(
|
|
306
|
+
options.regex ? query : query.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"),
|
|
307
|
+
options.caseSensitive ? "g" : "gi"
|
|
308
|
+
);
|
|
309
|
+
} catch (error) {
|
|
310
|
+
return {
|
|
311
|
+
matches: [],
|
|
312
|
+
error: error instanceof Error ? error.message : "Invalid pattern"
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
const matches = [];
|
|
316
|
+
for (const [index, entry] of entries.entries()) {
|
|
317
|
+
pattern.lastIndex = 0;
|
|
318
|
+
let hit;
|
|
319
|
+
while ((hit = pattern.exec(entry.text)) !== null) {
|
|
320
|
+
const before = entry.text[hit.index - 1] ?? "";
|
|
321
|
+
const after = entry.text[hit.index + hit[0].length] ?? "";
|
|
322
|
+
if (!options.wholeWord || !/\w/.test(before) && !/\w/.test(after)) {
|
|
323
|
+
matches.push({
|
|
324
|
+
id: entry.id ?? String(index),
|
|
325
|
+
index,
|
|
326
|
+
text: hit[0],
|
|
327
|
+
start: hit.index,
|
|
328
|
+
end: hit.index + hit[0].length
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
if (hit[0].length === 0) pattern.lastIndex++;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
return { matches };
|
|
335
|
+
}
|
|
336
|
+
function valueSearchText(value) {
|
|
337
|
+
if (typeof value === "string") return value;
|
|
338
|
+
if (value instanceof Error) return value.stack || value.message;
|
|
339
|
+
if (typeof value === "object" && value !== null) {
|
|
340
|
+
try {
|
|
341
|
+
return JSON.stringify(value) ?? String(value);
|
|
342
|
+
} catch {
|
|
343
|
+
return String(value);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
return String(value);
|
|
347
|
+
}
|
|
348
|
+
function visibleTerminalText(value) {
|
|
349
|
+
return value.replace(
|
|
350
|
+
new RegExp(String.raw`\x1b\[[0-?]*[ -/]*[@-~]`, "g"),
|
|
351
|
+
""
|
|
352
|
+
);
|
|
353
|
+
}
|
|
354
|
+
function createConsoleSearchAddon(options = {}) {
|
|
355
|
+
let data;
|
|
356
|
+
let viewport;
|
|
357
|
+
let state = {
|
|
358
|
+
query: "",
|
|
359
|
+
options: {},
|
|
360
|
+
matches: [],
|
|
361
|
+
activeIndex: -1
|
|
362
|
+
};
|
|
363
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
364
|
+
const emit = () => {
|
|
365
|
+
for (const listener of listeners) listener();
|
|
366
|
+
};
|
|
367
|
+
const controller = {
|
|
368
|
+
getState: () => state,
|
|
369
|
+
subscribe(listener) {
|
|
370
|
+
listeners.add(listener);
|
|
371
|
+
return () => {
|
|
372
|
+
listeners.delete(listener);
|
|
373
|
+
};
|
|
374
|
+
},
|
|
375
|
+
setQuery(query) {
|
|
376
|
+
state = { ...state, query };
|
|
377
|
+
controller.refresh();
|
|
378
|
+
},
|
|
379
|
+
setOptions(options2) {
|
|
380
|
+
state = { ...state, options: options2 };
|
|
381
|
+
controller.refresh();
|
|
382
|
+
},
|
|
383
|
+
refresh() {
|
|
384
|
+
const snapshot = data?.getSnapshot();
|
|
385
|
+
const entries = snapshot?.mode === "console" ? snapshot.visible.map((message, index) => ({
|
|
386
|
+
id: message.id ?? `console-${index}`,
|
|
387
|
+
text: [
|
|
388
|
+
message.method,
|
|
389
|
+
message.source,
|
|
390
|
+
...message.data.map(valueSearchText)
|
|
391
|
+
].join(" ")
|
|
392
|
+
})) : snapshot?.mode === "terminal" ? snapshot.visible.map((entry, index) => ({
|
|
393
|
+
id: entry.entry.id ?? `terminal-${index}`,
|
|
394
|
+
text: visibleTerminalText(entry.output.data)
|
|
395
|
+
})) : [];
|
|
396
|
+
const result = findConsoleSearchMatches(
|
|
397
|
+
entries,
|
|
398
|
+
state.query,
|
|
399
|
+
state.options
|
|
400
|
+
);
|
|
401
|
+
const activeMatch = state.matches[state.activeIndex];
|
|
402
|
+
const nextIndex = result.matches.findIndex(
|
|
403
|
+
(match) => match.id === activeMatch?.id && match.index === activeMatch.index && match.text === activeMatch.text && match.start === activeMatch.start
|
|
404
|
+
);
|
|
405
|
+
state = {
|
|
406
|
+
...state,
|
|
407
|
+
...result,
|
|
408
|
+
error: result.error,
|
|
409
|
+
activeIndex: nextIndex
|
|
410
|
+
};
|
|
411
|
+
emit();
|
|
412
|
+
},
|
|
413
|
+
next() {
|
|
414
|
+
controller.refresh();
|
|
415
|
+
if (!state.matches.length) return void 0;
|
|
416
|
+
const activeIndex = (state.activeIndex + 1) % state.matches.length;
|
|
417
|
+
state = { ...state, activeIndex };
|
|
418
|
+
emit();
|
|
419
|
+
const match = state.matches[activeIndex];
|
|
420
|
+
viewport?.scrollToMessage(match.id);
|
|
421
|
+
return match;
|
|
422
|
+
},
|
|
423
|
+
previous() {
|
|
424
|
+
controller.refresh();
|
|
425
|
+
if (!state.matches.length) return void 0;
|
|
426
|
+
const activeIndex = (state.activeIndex + state.matches.length - 1) % state.matches.length;
|
|
427
|
+
state = { ...state, activeIndex };
|
|
428
|
+
emit();
|
|
429
|
+
const match = state.matches[activeIndex];
|
|
430
|
+
viewport?.scrollToMessage(match.id);
|
|
431
|
+
return match;
|
|
432
|
+
}
|
|
433
|
+
};
|
|
434
|
+
return {
|
|
435
|
+
id: CONSOLE_SEARCH_ADDON_ID,
|
|
436
|
+
controller,
|
|
437
|
+
activate(host) {
|
|
438
|
+
data = host.services.get(consoleServices.data);
|
|
439
|
+
viewport = host.services.get(consoleServices.viewport);
|
|
440
|
+
host.services.provide(consoleSearchService, controller);
|
|
441
|
+
const textHighlightProvider = {
|
|
442
|
+
subscribe: controller.subscribe,
|
|
443
|
+
getSnapshot: controller.getState,
|
|
444
|
+
getRanges(text, context) {
|
|
445
|
+
if (!state.query) return [];
|
|
446
|
+
const matches = findConsoleSearchMatches(
|
|
447
|
+
[{ id: context.id ?? "local", text }],
|
|
448
|
+
state.query,
|
|
449
|
+
state.options
|
|
450
|
+
).matches;
|
|
451
|
+
const active = state.matches[state.activeIndex];
|
|
452
|
+
return matches.filter((match) => match.end > match.start).map((match, index) => ({
|
|
453
|
+
start: match.start,
|
|
454
|
+
end: match.end,
|
|
455
|
+
active: active?.id === context.id && active?.text === match.text && state.matches.filter(
|
|
456
|
+
(item) => item.id === active?.id && item.text === active?.text
|
|
457
|
+
).findIndex((item) => item.start === active?.start) === index
|
|
458
|
+
}));
|
|
459
|
+
}
|
|
460
|
+
};
|
|
461
|
+
host.extensions.register(
|
|
462
|
+
consoleExtensionPoints.textHighlightProvider,
|
|
463
|
+
textHighlightProvider,
|
|
464
|
+
{ id: CONSOLE_SEARCH_ADDON_ID + ":inline" }
|
|
465
|
+
);
|
|
466
|
+
const highlight = {
|
|
467
|
+
id: CONSOLE_SEARCH_ADDON_ID + ":highlight",
|
|
468
|
+
placement: "badge",
|
|
469
|
+
render: ({ index }) => createElement(ConsoleSearchHighlight, { controller, index })
|
|
470
|
+
};
|
|
471
|
+
host.extensions.register(
|
|
472
|
+
consoleExtensionPoints.messageDecoration,
|
|
473
|
+
highlight,
|
|
474
|
+
{ id: highlight.id }
|
|
475
|
+
);
|
|
476
|
+
const panel = {
|
|
477
|
+
id: CONSOLE_SEARCH_ADDON_ID + ":controls",
|
|
478
|
+
placement: "before-output",
|
|
479
|
+
render: () => createElement(ConsoleSearchControls, { controller, ...options })
|
|
480
|
+
};
|
|
481
|
+
host.extensions.register(consoleExtensionPoints.panelElement, panel, {
|
|
482
|
+
id: panel.id
|
|
483
|
+
});
|
|
484
|
+
for (const shortcut of [
|
|
485
|
+
{
|
|
486
|
+
id: CONSOLE_SEARCH_ADDON_ID + ":next",
|
|
487
|
+
key: "F3",
|
|
488
|
+
onTrigger: () => {
|
|
489
|
+
controller.next();
|
|
490
|
+
}
|
|
491
|
+
},
|
|
492
|
+
{
|
|
493
|
+
id: CONSOLE_SEARCH_ADDON_ID + ":previous",
|
|
494
|
+
key: "F3",
|
|
495
|
+
shiftKey: true,
|
|
496
|
+
onTrigger: () => {
|
|
497
|
+
controller.previous();
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
])
|
|
501
|
+
host.extensions.register(
|
|
502
|
+
consoleExtensionPoints.keyboardShortcut,
|
|
503
|
+
shortcut,
|
|
504
|
+
{ id: shortcut.id }
|
|
505
|
+
);
|
|
506
|
+
const subscription = data?.subscribe(() => controller.refresh());
|
|
507
|
+
return () => {
|
|
508
|
+
subscription?.dispose();
|
|
509
|
+
data = void 0;
|
|
510
|
+
viewport = void 0;
|
|
511
|
+
};
|
|
512
|
+
}
|
|
513
|
+
};
|
|
514
|
+
}
|
|
515
|
+
export {
|
|
516
|
+
CONSOLE_SEARCH_ADDON_ID,
|
|
517
|
+
ConsoleSearchControls,
|
|
518
|
+
ConsoleSearchHighlight,
|
|
519
|
+
consoleSearchService,
|
|
520
|
+
createConsoleSearchAddon,
|
|
521
|
+
findConsoleSearchMatches,
|
|
522
|
+
resolveAddonMessages as resolveConsoleSearchMessages
|
|
523
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"search": "Console search",
|
|
3
|
+
"searchOutput": "Search output",
|
|
4
|
+
"searchConsoleOutput": "Search console output",
|
|
5
|
+
"caseSensitive": "Case sensitive",
|
|
6
|
+
"wholeWord": "Whole word",
|
|
7
|
+
"regex": "Regex",
|
|
8
|
+
"noMatches": "No matches",
|
|
9
|
+
"matchCount": "{current} of {total} matches",
|
|
10
|
+
"previousResult": "Previous search result",
|
|
11
|
+
"nextResult": "Next search result",
|
|
12
|
+
"previous": "Previous",
|
|
13
|
+
"next": "Next"
|
|
14
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"search": "Buscar en la consola",
|
|
3
|
+
"searchOutput": "Buscar en la salida",
|
|
4
|
+
"searchConsoleOutput": "Buscar en la salida de la consola",
|
|
5
|
+
"caseSensitive": "Distinguir mayúsculas",
|
|
6
|
+
"wholeWord": "Palabra completa",
|
|
7
|
+
"regex": "Expresión regular",
|
|
8
|
+
"noMatches": "Sin resultados",
|
|
9
|
+
"matchCount": "{current} de {total} resultados",
|
|
10
|
+
"previousResult": "Resultado anterior",
|
|
11
|
+
"nextResult": "Resultado siguiente",
|
|
12
|
+
"previous": "Anterior",
|
|
13
|
+
"next": "Siguiente"
|
|
14
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"search": "Recherche dans la console",
|
|
3
|
+
"searchOutput": "Rechercher dans la sortie",
|
|
4
|
+
"searchConsoleOutput": "Rechercher dans la sortie de la console",
|
|
5
|
+
"caseSensitive": "Respecter la casse",
|
|
6
|
+
"wholeWord": "Mot entier",
|
|
7
|
+
"regex": "Expression régulière",
|
|
8
|
+
"noMatches": "Aucun résultat",
|
|
9
|
+
"matchCount": "{current} sur {total} résultats",
|
|
10
|
+
"previousResult": "Résultat précédent",
|
|
11
|
+
"nextResult": "Résultat suivant",
|
|
12
|
+
"previous": "Précédent",
|
|
13
|
+
"next": "Suivant"
|
|
14
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"search": "Pesquisar no console",
|
|
3
|
+
"searchOutput": "Pesquisar na saída",
|
|
4
|
+
"searchConsoleOutput": "Pesquisar na saída do console",
|
|
5
|
+
"caseSensitive": "Diferenciar maiúsculas de minúsculas",
|
|
6
|
+
"wholeWord": "Palavra inteira",
|
|
7
|
+
"regex": "Expressão regular",
|
|
8
|
+
"noMatches": "Nenhuma correspondência",
|
|
9
|
+
"matchCount": "{current} de {total} correspondências",
|
|
10
|
+
"previousResult": "Resultado anterior",
|
|
11
|
+
"nextResult": "Próximo resultado",
|
|
12
|
+
"previous": "Anterior",
|
|
13
|
+
"next": "Próximo"
|
|
14
|
+
}
|