@fnndsc/brasa 0.56.2 → 0.56.4
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/buildinfo.json +1 -1
- package/dist/builtins/berth/berth.d.ts +11 -0
- package/dist/builtins/berth/berth.js +53 -22
- package/dist/builtins/berth/berth.js.map +1 -1
- package/dist/builtins/berth/berthCube.d.ts +17 -2
- package/dist/builtins/berth/berthCube.js +22 -10
- package/dist/builtins/berth/berthCube.js.map +1 -1
- package/dist/builtins/debug.d.ts +24 -3
- package/dist/builtins/debug.js +66 -13
- package/dist/builtins/debug.js.map +1 -1
- package/dist/builtins/fs/acl.args.d.ts +5 -38
- package/dist/builtins/fs/acl.args.js +6 -72
- package/dist/builtins/fs/acl.args.js.map +1 -1
- package/dist/builtins/fs/acl.d.ts +100 -10
- package/dist/builtins/fs/acl.js +222 -68
- package/dist/builtins/fs/acl.js.map +1 -1
- package/dist/builtins/fs/cat.args.d.ts +14 -15
- package/dist/builtins/fs/cat.args.js +13 -40
- package/dist/builtins/fs/cat.args.js.map +1 -1
- package/dist/builtins/fs/cat.d.ts +40 -3
- package/dist/builtins/fs/cat.js +89 -10
- package/dist/builtins/fs/cat.js.map +1 -1
- package/dist/builtins/fs/cd.d.ts +24 -6
- package/dist/builtins/fs/cd.js +71 -18
- package/dist/builtins/fs/cd.js.map +1 -1
- package/dist/builtins/fs/configWrite.d.ts +24 -8
- package/dist/builtins/fs/configWrite.js +77 -36
- package/dist/builtins/fs/configWrite.js.map +1 -1
- package/dist/builtins/fs/cp.d.ts +39 -4
- package/dist/builtins/fs/cp.js +120 -55
- package/dist/builtins/fs/cp.js.map +1 -1
- package/dist/builtins/fs/download.d.ts +12 -1
- package/dist/builtins/fs/download.js +24 -4
- package/dist/builtins/fs/download.js.map +1 -1
- package/dist/builtins/fs/du.d.ts +59 -33
- package/dist/builtins/fs/du.js +111 -79
- package/dist/builtins/fs/du.js.map +1 -1
- package/dist/builtins/fs/edit.d.ts +19 -4
- package/dist/builtins/fs/edit.js +77 -16
- package/dist/builtins/fs/edit.js.map +1 -1
- package/dist/builtins/fs/find.d.ts +25 -0
- package/dist/builtins/fs/find.js +76 -5
- package/dist/builtins/fs/find.js.map +1 -1
- package/dist/builtins/fs/mkdir.d.ts +28 -18
- package/dist/builtins/fs/mkdir.js +95 -66
- package/dist/builtins/fs/mkdir.js.map +1 -1
- package/dist/builtins/fs/mv.d.ts +34 -4
- package/dist/builtins/fs/mv.js +129 -64
- package/dist/builtins/fs/mv.js.map +1 -1
- package/dist/builtins/fs/pull.args.d.ts +56 -17
- package/dist/builtins/fs/pull.args.js +16 -66
- package/dist/builtins/fs/pull.args.js.map +1 -1
- package/dist/builtins/fs/pull.d.ts +62 -0
- package/dist/builtins/fs/pull.js +86 -22
- package/dist/builtins/fs/pull.js.map +1 -1
- package/dist/builtins/fs/pwd.d.ts +19 -5
- package/dist/builtins/fs/pwd.js +62 -8
- package/dist/builtins/fs/pwd.js.map +1 -1
- package/dist/builtins/fs/rm.d.ts +58 -21
- package/dist/builtins/fs/rm.js +99 -82
- package/dist/builtins/fs/rm.js.map +1 -1
- package/dist/builtins/fs/rmdir.d.ts +29 -11
- package/dist/builtins/fs/rmdir.js +87 -36
- package/dist/builtins/fs/rmdir.js.map +1 -1
- package/dist/builtins/fs/touch.d.ts +44 -9
- package/dist/builtins/fs/touch.js +91 -27
- package/dist/builtins/fs/touch.js.map +1 -1
- package/dist/builtins/fs/transferJobs.d.ts +64 -0
- package/dist/builtins/fs/transferJobs.js +98 -0
- package/dist/builtins/fs/transferJobs.js.map +1 -0
- package/dist/builtins/fs/tree.d.ts +36 -9
- package/dist/builtins/fs/tree.js +126 -36
- package/dist/builtins/fs/tree.js.map +1 -1
- package/dist/builtins/fs/upload.d.ts +35 -3
- package/dist/builtins/fs/upload.js +99 -14
- package/dist/builtins/fs/upload.js.map +1 -1
- package/dist/builtins/fs/xattr.args.d.ts +12 -33
- package/dist/builtins/fs/xattr.args.js +17 -95
- package/dist/builtins/fs/xattr.args.js.map +1 -1
- package/dist/builtins/fs/xattr.d.ts +98 -8
- package/dist/builtins/fs/xattr.js +163 -24
- package/dist/builtins/fs/xattr.js.map +1 -1
- package/dist/builtins/games/bytes.d.ts +201 -5
- package/dist/builtins/games/bytes.js +255 -54
- package/dist/builtins/games/bytes.js.map +1 -1
- package/dist/builtins/games/chimes.d.ts +180 -3
- package/dist/builtins/games/chimes.js +203 -26
- package/dist/builtins/games/chimes.js.map +1 -1
- package/dist/builtins/games/chrislab.d.ts +101 -3
- package/dist/builtins/games/chrislab.js +117 -17
- package/dist/builtins/games/chrislab.js.map +1 -1
- package/dist/builtins/games/cowsay.d.ts +93 -2
- package/dist/builtins/games/cowsay.js +90 -31
- package/dist/builtins/games/cowsay.js.map +1 -1
- package/dist/builtins/games/figlet.d.ts +70 -2
- package/dist/builtins/games/figlet.js +83 -6
- package/dist/builtins/games/figlet.js.map +1 -1
- package/dist/builtins/games/lab.d.ts +104 -5
- package/dist/builtins/games/lab.js +144 -6
- package/dist/builtins/games/lab.js.map +1 -1
- package/dist/builtins/games/lolcat.d.ts +61 -1
- package/dist/builtins/games/lolcat.js +59 -24
- package/dist/builtins/games/lolcat.js.map +1 -1
- package/dist/builtins/games/morse.d.ts +36 -1
- package/dist/builtins/games/morse.js +50 -2
- package/dist/builtins/games/morse.js.map +1 -1
- package/dist/builtins/games/numbers.d.ts +241 -5
- package/dist/builtins/games/numbers.js +298 -23
- package/dist/builtins/games/numbers.js.map +1 -1
- package/dist/builtins/games/play.d.ts +96 -6
- package/dist/builtins/games/play.js +137 -6
- package/dist/builtins/games/play.js.map +1 -1
- package/dist/builtins/games/qr.d.ts +40 -1
- package/dist/builtins/games/qr.js +51 -2
- package/dist/builtins/games/qr.js.map +1 -1
- package/dist/builtins/games/show.d.ts +131 -6
- package/dist/builtins/games/show.js +208 -20
- package/dist/builtins/games/show.js.map +1 -1
- package/dist/builtins/games/sky.d.ts +178 -4
- package/dist/builtins/games/sky.js +228 -12
- package/dist/builtins/games/sky.js.map +1 -1
- package/dist/builtins/games/text.d.ts +258 -7
- package/dist/builtins/games/text.js +310 -29
- package/dist/builtins/games/text.js.map +1 -1
- package/dist/builtins/games/trek.d.ts +67 -3
- package/dist/builtins/games/trek.js +63 -10
- package/dist/builtins/games/trek.js.map +1 -1
- package/dist/builtins/games/wtf.d.ts +58 -1
- package/dist/builtins/games/wtf.js +67 -6
- package/dist/builtins/games/wtf.js.map +1 -1
- package/dist/builtins/help.d.ts +38 -2
- package/dist/builtins/help.js +76 -769
- package/dist/builtins/help.js.map +1 -1
- package/dist/builtins/helpSections.js +4 -1
- package/dist/builtins/helpSections.js.map +1 -1
- package/dist/builtins/net/connect.d.ts +36 -3
- package/dist/builtins/net/connect.js +84 -26
- package/dist/builtins/net/connect.js.map +1 -1
- package/dist/builtins/net/cubepath.d.ts +49 -5
- package/dist/builtins/net/cubepath.js +69 -27
- package/dist/builtins/net/cubepath.js.map +1 -1
- package/dist/builtins/net/logout.d.ts +13 -4
- package/dist/builtins/net/logout.js +49 -3
- package/dist/builtins/net/logout.js.map +1 -1
- package/dist/builtins/net/netstat.d.ts +29 -4
- package/dist/builtins/net/netstat.js +64 -23
- package/dist/builtins/net/netstat.js.map +1 -1
- package/dist/builtins/net/pacs.d.ts +169 -15
- package/dist/builtins/net/pacs.js +92 -33
- package/dist/builtins/net/pacs.js.map +1 -1
- package/dist/builtins/net/query.args.d.ts +95 -0
- package/dist/builtins/net/query.args.js +26 -0
- package/dist/builtins/net/query.args.js.map +1 -0
- package/dist/builtins/net/query.d.ts +98 -5
- package/dist/builtins/net/query.js +89 -83
- package/dist/builtins/net/query.js.map +1 -1
- package/dist/builtins/net/status.d.ts +5 -3
- package/dist/builtins/net/status.js +5 -12
- package/dist/builtins/net/status.js.map +1 -1
- package/dist/builtins/parametersofplugin.d.ts +82 -3
- package/dist/builtins/parametersofplugin.js +79 -23
- package/dist/builtins/parametersofplugin.js.map +1 -1
- package/dist/builtins/proc.d.ts +210 -3
- package/dist/builtins/proc.js +210 -119
- package/dist/builtins/proc.js.map +1 -1
- package/dist/builtins/res/compute.d.ts +67 -3
- package/dist/builtins/res/compute.js +121 -35
- package/dist/builtins/res/compute.js.map +1 -1
- package/dist/builtins/res/dicom.d.ts +52 -3
- package/dist/builtins/res/dicom.js +82 -34
- package/dist/builtins/res/dicom.js.map +1 -1
- package/dist/builtins/res/expect.d.ts +52 -3
- package/dist/builtins/res/expect.js +92 -29
- package/dist/builtins/res/expect.js.map +1 -1
- package/dist/builtins/res/feed.d.ts +475 -3
- package/dist/builtins/res/feed.js +253 -158
- package/dist/builtins/res/feed.js.map +1 -1
- package/dist/builtins/res/files.d.ts +517 -3
- package/dist/builtins/res/files.js +124 -44
- package/dist/builtins/res/files.js.map +1 -1
- package/dist/builtins/res/gather.d.ts +113 -3
- package/dist/builtins/res/gather.js +153 -44
- package/dist/builtins/res/gather.js.map +1 -1
- package/dist/builtins/res/gather.process.d.ts +27 -19
- package/dist/builtins/res/gather.process.js +29 -59
- package/dist/builtins/res/gather.process.js.map +1 -1
- package/dist/builtins/res/group.d.ts +284 -3
- package/dist/builtins/res/group.js +147 -76
- package/dist/builtins/res/group.js.map +1 -1
- package/dist/builtins/res/image.d.ts +30 -2
- package/dist/builtins/res/image.js +62 -10
- package/dist/builtins/res/image.js.map +1 -1
- package/dist/builtins/res/play.d.ts +71 -9
- package/dist/builtins/res/play.js +124 -82
- package/dist/builtins/res/play.js.map +1 -1
- package/dist/builtins/res/plugininstance.d.ts +307 -2
- package/dist/builtins/res/plugininstance.js +122 -50
- package/dist/builtins/res/plugininstance.js.map +1 -1
- package/dist/builtins/res/pluginmeta.d.ts +244 -2
- package/dist/builtins/res/pluginmeta.js +98 -40
- package/dist/builtins/res/pluginmeta.js.map +1 -1
- package/dist/builtins/res/record.d.ts +37 -3
- package/dist/builtins/res/record.js +127 -57
- package/dist/builtins/res/record.js.map +1 -1
- package/dist/builtins/res/resourceList.d.ts +136 -0
- package/dist/builtins/res/resourceList.js +51 -0
- package/dist/builtins/res/resourceList.js.map +1 -0
- package/dist/builtins/res/tag.d.ts +244 -3
- package/dist/builtins/res/tag.js +97 -41
- package/dist/builtins/res/tag.js.map +1 -1
- package/dist/builtins/res/user.d.ts +122 -3
- package/dist/builtins/res/user.js +83 -21
- package/dist/builtins/res/user.js.map +1 -1
- package/dist/builtins/res/workflow.d.ts +244 -2
- package/dist/builtins/res/workflow.js +97 -40
- package/dist/builtins/res/workflow.js.map +1 -1
- package/dist/builtins/store.d.ts +85 -3
- package/dist/builtins/store.js +135 -68
- package/dist/builtins/store.js.map +1 -1
- package/dist/builtins/sys/apropos.d.ts +80 -5
- package/dist/builtins/sys/apropos.js +121 -15
- package/dist/builtins/sys/apropos.js.map +1 -1
- package/dist/builtins/sys/cal.d.ts +44 -5
- package/dist/builtins/sys/cal.js +57 -10
- package/dist/builtins/sys/cal.js.map +1 -1
- package/dist/builtins/sys/command.d.ts +20 -0
- package/dist/builtins/sys/command.js +31 -0
- package/dist/builtins/sys/command.js.map +1 -1
- package/dist/builtins/sys/context.d.ts +13 -3
- package/dist/builtins/sys/context.js +51 -4
- package/dist/builtins/sys/context.js.map +1 -1
- package/dist/builtins/sys/date.d.ts +56 -5
- package/dist/builtins/sys/date.js +63 -9
- package/dist/builtins/sys/date.js.map +1 -1
- package/dist/builtins/sys/echo.d.ts +63 -2
- package/dist/builtins/sys/echo.js +87 -8
- package/dist/builtins/sys/echo.js.map +1 -1
- package/dist/builtins/sys/fortune.d.ts +27 -2
- package/dist/builtins/sys/fortune.js +44 -2
- package/dist/builtins/sys/fortune.js.map +1 -1
- package/dist/builtins/sys/grep.d.ts +245 -11
- package/dist/builtins/sys/grep.js +418 -131
- package/dist/builtins/sys/grep.js.map +1 -1
- package/dist/builtins/sys/joblets.d.ts +66 -7
- package/dist/builtins/sys/joblets.js +101 -14
- package/dist/builtins/sys/joblets.js.map +1 -1
- package/dist/builtins/sys/motd.d.ts +37 -3
- package/dist/builtins/sys/motd.js +49 -8
- package/dist/builtins/sys/motd.js.map +1 -1
- package/dist/builtins/sys/notes.d.ts +75 -3
- package/dist/builtins/sys/notes.js +90 -29
- package/dist/builtins/sys/notes.js.map +1 -1
- package/dist/builtins/sys/physicalmode.d.ts +24 -3
- package/dist/builtins/sys/physicalmode.js +68 -14
- package/dist/builtins/sys/physicalmode.js.map +1 -1
- package/dist/builtins/sys/tasks.d.ts +74 -5
- package/dist/builtins/sys/tasks.js +102 -14
- package/dist/builtins/sys/tasks.js.map +1 -1
- package/dist/builtins/sys/textFilters.d.ts +673 -41
- package/dist/builtins/sys/textFilters.js +718 -263
- package/dist/builtins/sys/textFilters.js.map +1 -1
- package/dist/builtins/sys/timing.d.ts +24 -3
- package/dist/builtins/sys/timing.js +67 -14
- package/dist/builtins/sys/timing.js.map +1 -1
- package/dist/builtins/sys/variables.d.ts +70 -4
- package/dist/builtins/sys/variables.js +103 -31
- package/dist/builtins/sys/variables.js.map +1 -1
- package/dist/builtins/sys/version.d.ts +27 -2
- package/dist/builtins/sys/version.js +48 -3
- package/dist/builtins/sys/version.js.map +1 -1
- package/dist/builtins/sys/weather.d.ts +92 -15
- package/dist/builtins/sys/weather.js +71 -45
- package/dist/builtins/sys/weather.js.map +1 -1
- package/dist/builtins/sys/whoami.d.ts +38 -18
- package/dist/builtins/sys/whoami.js +112 -8
- package/dist/builtins/sys/whoami.js.map +1 -1
- package/dist/builtins/utils.d.ts +0 -37
- package/dist/builtins/utils.js +0 -86
- package/dist/builtins/utils.js.map +1 -1
- package/dist/chris/chrisCommands.js +58 -152
- package/dist/chris/chrisCommands.js.map +1 -1
- package/dist/chris/commandFallback.d.ts +12 -0
- package/dist/chris/commandFallback.js +47 -0
- package/dist/chris/commandFallback.js.map +1 -1
- package/dist/chris/filesystem.js +7 -5
- package/dist/chris/filesystem.js.map +1 -1
- package/dist/chris/help.js +0 -1018
- package/dist/chris/help.js.map +1 -1
- package/dist/chris/kinds.d.ts +21 -0
- package/dist/chris/kinds.js +114 -2
- package/dist/chris/kinds.js.map +1 -1
- package/dist/chris/mounts.d.ts +4 -4
- package/dist/chris/mounts.js +9 -16
- package/dist/chris/mounts.js.map +1 -1
- package/dist/chris/navigation.d.ts +2 -3
- package/dist/chris/navigation.js +6 -20
- package/dist/chris/navigation.js.map +1 -1
- package/dist/chris/pacsResources.d.ts +259 -0
- package/dist/chris/pacsResources.js +168 -0
- package/dist/chris/pacsResources.js.map +1 -0
- package/dist/core/commandDeclaration.d.ts +97 -7
- package/dist/core/commandDeclaration.js +21 -0
- package/dist/core/commandDeclaration.js.map +1 -1
- package/dist/core/commandParse.js +65 -17
- package/dist/core/commandParse.js.map +1 -1
- package/dist/core/commandRegistry.d.ts +4 -3
- package/dist/core/commandRegistry.js +36 -8
- package/dist/core/commandRegistry.js.map +1 -1
- package/dist/core/commandSchema.js +5 -2
- package/dist/core/commandSchema.js.map +1 -1
- package/dist/core/commandUsage.d.ts +15 -0
- package/dist/core/commandUsage.js +59 -7
- package/dist/core/commandUsage.js.map +1 -1
- package/dist/core/coreCommands.js +63 -212
- package/dist/core/coreCommands.js.map +1 -1
- package/dist/core/paths.d.ts +29 -1
- package/dist/core/paths.js +15 -2
- package/dist/core/paths.js.map +1 -1
- package/dist/core/preprocess.d.ts +3 -4
- package/dist/core/preprocess.js +4 -5
- package/dist/core/preprocess.js.map +1 -1
- package/dist/lib/completer/declared.js +7 -4
- package/dist/lib/completer/declared.js.map +1 -1
- package/dist/lib/completer/index.js +2 -7
- package/dist/lib/completer/index.js.map +1 -1
- package/dist/lib/parser.d.ts +0 -8
- package/dist/lib/parser.js +0 -11
- package/dist/lib/parser.js.map +1 -1
- package/dist/lib/vfs/vfs.d.ts +2 -1
- package/dist/lib/vfs/vfs.js +5 -4
- package/dist/lib/vfs/vfs.js.map +1 -1
- package/dist/notes.json +1 -1
- package/package.json +5 -5
|
@@ -9,111 +9,164 @@
|
|
|
9
9
|
* wore — `@SER41` stays `@SER41`. The kept rows become the held listing, so
|
|
10
10
|
* `gather add @SER41` and `${listing}` read what grep left.
|
|
11
11
|
*
|
|
12
|
-
* It takes grep's
|
|
13
|
-
* and -
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
12
|
+
* It takes grep's flags with grep's meanings: -i -v -w -E -F -c -e, and for
|
|
13
|
+
* text and files -n -l -o -h -r -A -B -C, which a listing (whole rows) has no
|
|
14
|
+
* use for and refuses by name. It is declared in one record, so any other
|
|
15
|
+
* flag is refused by the parser. A file named is a ChRIS path, read through
|
|
16
|
+
* the one store-path resolver (a folder walked under -r) and filtered here,
|
|
17
|
+
* named as typed. Plain text in is the system grep where the surface can run
|
|
18
|
+
* it, its line written back from the typed options, and filtered here where
|
|
19
|
+
* it cannot; `command grep` skips this builtin altogether.
|
|
20
|
+
*
|
|
21
|
+
* Key components:
|
|
22
|
+
* - grepCommand: the declaration.
|
|
23
|
+
* - builtin_grep: the declaration run over words already split.
|
|
24
|
+
* - grepExpression_build, grepMatcher_build: the expression, and the test a line passes.
|
|
25
|
+
* - textSources_grep: the lines a grep over text writes, as GNU grep writes them.
|
|
26
|
+
* - listingRows_grep: the rows a grep keeps of a listing.
|
|
27
|
+
*
|
|
28
|
+
* Typical usage:
|
|
29
|
+
* ```ts
|
|
30
|
+
* await builtin_grep(['-i', 't1']);
|
|
31
|
+
* await builtin_grep(['-c', 'todo', 'notes.txt']);
|
|
32
|
+
* ```
|
|
33
|
+
*
|
|
34
|
+
* Dependencies: the held and piped listings, the session's filesystem (via
|
|
35
|
+
* the text filters' reader), and the surface's system grep.
|
|
17
36
|
*
|
|
18
37
|
* @module
|
|
19
38
|
*/
|
|
20
39
|
import chalk from 'chalk';
|
|
21
40
|
import { envelope_ok, envelope_error } from '@fnndsc/menu';
|
|
22
41
|
import { stdin_take } from '../games/stdin.js';
|
|
42
|
+
import { errorStack, errno_words } from '@fnndsc/fond';
|
|
43
|
+
import { filterFile_read, filterRead_answer, filterSources_read, FILES_OPERAND, lines_join, lines_split, word_quote, } from './textFilters.js';
|
|
44
|
+
import { storePath_resolve } from '../utils.js';
|
|
45
|
+
import { vfsDispatcher_get } from '../../core/filesystem.js';
|
|
46
|
+
import { itemType_isContainer } from '../../core/itemKinds.js';
|
|
47
|
+
import { command_declare } from '../../core/commandDeclaration.js';
|
|
48
|
+
import { declaredCommand_run } from '../../core/commandParse.js';
|
|
23
49
|
import { listingIn_take } from '../../core/listing.js';
|
|
24
50
|
import { answerKinds_get } from '../../core/answerKinds.js';
|
|
25
51
|
import { surface_get } from '../../core/surface.js';
|
|
26
52
|
import { answer_get, answerFilter_apply, answerNumbering_derive, answerOrdinals_attach, answerRow_key, answerRows_derive, handle_word, numberedFooter_render, } from '../../session/answer.js';
|
|
27
53
|
import { exitCode_set } from '../../core/handlerRun.js';
|
|
28
|
-
/**
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
54
|
+
/**
|
|
55
|
+
* The layout of a grep line that asks none: lines as they are.
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* ```ts
|
|
59
|
+
* const layout: GrepLayout = { ...GREP_LAYOUT_PLAIN, onlyMatching: true };
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
export const GREP_LAYOUT_PLAIN = {
|
|
63
|
+
lineNumber: false, filesWithMatches: false, onlyMatching: false, noFilename: false, withFilename: false, recursive: false,
|
|
64
|
+
after: undefined, before: undefined, context: undefined, color: undefined,
|
|
65
|
+
};
|
|
66
|
+
/** The switches of a grep line, as the line writes them back. */
|
|
67
|
+
const GREP_SWITCHES = [
|
|
68
|
+
{ letter: 'i', on: (ask) => ask.insensitive },
|
|
69
|
+
{ letter: 'v', on: (ask) => ask.invert },
|
|
70
|
+
{ letter: 'w', on: (ask) => ask.word },
|
|
71
|
+
{ letter: 'E', on: (ask) => ask.extended },
|
|
72
|
+
{ letter: 'F', on: (ask) => ask.fixed },
|
|
73
|
+
{ letter: 'c', on: (ask) => ask.count },
|
|
74
|
+
{ letter: 'n', on: (_ask, layout) => layout.lineNumber },
|
|
75
|
+
{ letter: 'l', on: (_ask, layout) => layout.filesWithMatches },
|
|
76
|
+
{ letter: 'o', on: (_ask, layout) => layout.onlyMatching },
|
|
77
|
+
{ letter: 'h', on: (_ask, layout) => layout.noFilename },
|
|
78
|
+
{ letter: 'H', on: (_ask, layout) => layout.withFilename },
|
|
79
|
+
{ letter: 'r', on: (_ask, layout) => layout.recursive },
|
|
80
|
+
];
|
|
81
|
+
/** The layout flags a numbered listing has no use for, each with why, as grep says it. */
|
|
82
|
+
const LISTING_REFUSALS = [
|
|
83
|
+
{ flag: '-n', given: (layout) => layout.lineNumber, why: 'a listing\'s rows wear their handles, not line numbers' },
|
|
84
|
+
{ flag: '-l', given: (layout) => layout.filesWithMatches, why: 'a listing is not files to name' },
|
|
85
|
+
{ flag: '-o', given: (layout) => layout.onlyMatching, why: 'a listing keeps whole rows' },
|
|
86
|
+
{ flag: '-h', given: (layout) => layout.noFilename, why: 'a listing has no file names to drop' },
|
|
87
|
+
{ flag: '-H', given: (layout) => layout.withFilename, why: 'a listing has no file names to show' },
|
|
88
|
+
{ flag: '-r', given: (layout) => layout.recursive, why: 'a listing is not a folder to walk' },
|
|
89
|
+
{ flag: '-A', given: (layout) => layout.after !== undefined, why: 'a listing keeps a row with its group, not lines after it' },
|
|
90
|
+
{ flag: '-B', given: (layout) => layout.before !== undefined, why: 'a listing keeps a row with its group, not lines before it' },
|
|
91
|
+
{ flag: '-C', given: (layout) => layout.context !== undefined, why: 'a listing keeps a row with its group, not lines around it' },
|
|
92
|
+
];
|
|
93
|
+
/** What a `grep` line may hold. */
|
|
94
|
+
const GREP_GRAMMAR = {
|
|
95
|
+
operands: [
|
|
96
|
+
{ name: 'pattern', kind: 'word', optional: true, unless: 'regexp', summary: 'The pattern, unless -e gives it' },
|
|
97
|
+
FILES_OPERAND,
|
|
98
|
+
],
|
|
99
|
+
options: {
|
|
100
|
+
insensitive: { short: 'i', long: 'ignore-case', summary: 'Ignore case' },
|
|
101
|
+
invert: { short: 'v', long: 'invert-match', summary: 'Keep what does not match' },
|
|
102
|
+
word: { short: 'w', long: 'word-regexp', summary: 'Whole words' },
|
|
103
|
+
extended: { short: 'E', long: 'extended-regexp', summary: 'Extended regular expressions' },
|
|
104
|
+
fixed: { short: 'F', long: 'fixed-strings', summary: 'Fixed strings' },
|
|
105
|
+
count: { short: 'c', long: 'count', summary: 'Count only' },
|
|
106
|
+
regexp: { short: 'e', long: 'regexp', repeat: true, value: { name: 'pattern', kind: 'word' }, summary: 'A pattern (repeatable: any of them matches)' },
|
|
107
|
+
lineNumber: { short: 'n', long: 'line-number', summary: 'Each line\'s number (text and files)' },
|
|
108
|
+
filesWithMatches: { short: 'l', long: 'files-with-matches', summary: 'Only the names of files with a match' },
|
|
109
|
+
onlyMatching: { short: 'o', long: 'only-matching', summary: 'Only the matching parts, one per line' },
|
|
110
|
+
noFilename: { short: 'h', long: 'no-filename', summary: 'No file-name prefix' },
|
|
111
|
+
withFilename: { short: 'H', long: 'with-filename', summary: 'The file-name prefix, even for one file' },
|
|
112
|
+
color: { long: 'color', value: { name: 'when', kind: 'word', optional: true }, summary: 'Colour the matches (always, never, auto): the system grep colours; the session\'s own grep writes plain text' },
|
|
113
|
+
recursive: { short: 'r', long: 'recursive', summary: 'Walk each folder for files (. when none is named)' },
|
|
114
|
+
after: { short: 'A', long: 'after-context', value: { name: 'N', kind: 'int', min: 0 }, summary: 'N lines after each match' },
|
|
115
|
+
before: { short: 'B', long: 'before-context', value: { name: 'N', kind: 'int', min: 0 }, summary: 'N lines before each match' },
|
|
116
|
+
context: { short: 'C', long: 'context', value: { name: 'N', kind: 'int', min: 0 }, summary: 'N lines around each match' },
|
|
117
|
+
},
|
|
32
118
|
};
|
|
33
119
|
/**
|
|
34
|
-
*
|
|
120
|
+
* `grep [-ivwEFcnlohr] [-A N] [-B N] [-C N] [-e PATTERN]... [PATTERN] [FILE]...`: the declaration.
|
|
35
121
|
*
|
|
36
|
-
* @
|
|
37
|
-
*
|
|
122
|
+
* @example
|
|
123
|
+
* ```ts
|
|
124
|
+
* commands_register({ declarations: [grepCommand] });
|
|
125
|
+
* ```
|
|
38
126
|
*/
|
|
39
|
-
export
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
ask.foreign ??= word;
|
|
83
|
-
continue;
|
|
84
|
-
}
|
|
85
|
-
flag(short);
|
|
86
|
-
continue;
|
|
87
|
-
}
|
|
88
|
-
if (word.startsWith('-') && word.length > 1) {
|
|
89
|
-
// Clustered short flags: -vi. An -e inside a cluster takes the rest.
|
|
90
|
-
const letters = word.slice(1);
|
|
91
|
-
for (let index = 0; index < letters.length; index++) {
|
|
92
|
-
const letter = letters[index] ?? '';
|
|
93
|
-
if (letter === 'e') {
|
|
94
|
-
const rest = letters.slice(index + 1);
|
|
95
|
-
const pattern = rest !== '' ? rest : args[++at];
|
|
96
|
-
if (pattern === undefined)
|
|
97
|
-
ask.foreign ??= word;
|
|
98
|
-
else
|
|
99
|
-
ask.patterns.push(pattern);
|
|
100
|
-
break;
|
|
101
|
-
}
|
|
102
|
-
if (!flag(letter)) {
|
|
103
|
-
ask.foreign ??= `-${letter}`;
|
|
104
|
-
break;
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
continue;
|
|
108
|
-
}
|
|
109
|
-
operands.push(word);
|
|
110
|
-
}
|
|
111
|
-
if (ask.patterns.length === 0 && operands.length > 0)
|
|
112
|
-
ask.patterns.push(operands.shift());
|
|
113
|
-
// A file to read is the system grep's: this one reads a listing or a pipe.
|
|
114
|
-
if (operands.length > 0)
|
|
115
|
-
ask.foreign ??= operands[0] ?? null;
|
|
116
|
-
return ask;
|
|
127
|
+
export const grepCommand = command_declare({
|
|
128
|
+
name: 'grep',
|
|
129
|
+
grammar: GREP_GRAMMAR,
|
|
130
|
+
help: {
|
|
131
|
+
summary: 'Keep the lines, or the rows of a numbered listing, that match',
|
|
132
|
+
description: 'Filters text, or a numbered listing keeping its handles. Fed a numbered listing (piped in, or the held one when nothing is piped), grep keeps rows: a matching row stays with the rows above it, a matched group keeps all of its rows, and every kept row keeps its handle (@SER41 stays @SER41). What it kept becomes the listing @ and ${listing} name; -c counts and changes nothing. A pattern matches a study\'s and a patient\'s own text too: grep -i t1 meant for series descriptions keeps a WHOLE study whose description says t1, and grep -i "mri brain" picking whole studies is the same rule. A file named is a ChRIS path, read here (- is the pipe; a wildcard matches paths); with several, each line or count is under its file\'s name as typed. -r walks each folder named (. when none is) for its files; links met on the way are not followed. -n numbers lines, -l names the files with a match, -o keeps only the matching parts, -h drops the names and -H keeps them for one file, --color colours the matches of the system grep (this one writes plain text), and -A, -B and -C show lines after, before and around each match, groups apart by --; a listing keeps whole rows, so these are refused for one. Text piped in is the system grep where the surface runs one, else filtered here with the same flags. With -e every word after the options is a file. A flag it does not take is refused; command grep runs the system grep.',
|
|
133
|
+
category: 'Files',
|
|
134
|
+
posix: { group: 'Files', differs: 'also filters numbered listings, keeping their handles (help grep)' },
|
|
135
|
+
examples: [
|
|
136
|
+
'query PatientID:1234567,Modality:MR | grep -i t1 | grep -vi gadavist',
|
|
137
|
+
'grep -i -e t1 -e mprage',
|
|
138
|
+
'gather list | grep -i sag | gather remove',
|
|
139
|
+
'cat notes.txt | grep -c todo',
|
|
140
|
+
'grep -c error a.log b.log',
|
|
141
|
+
'grep -rn TODO notes',
|
|
142
|
+
'grep -C 2 error run.log',
|
|
143
|
+
],
|
|
144
|
+
},
|
|
145
|
+
holds: [],
|
|
146
|
+
handler: async (args) => grep_run(args),
|
|
147
|
+
});
|
|
148
|
+
/**
|
|
149
|
+
* A grep line written back from what it asks: its switches, its context
|
|
150
|
+
* counts, then its patterns (each under -e when there are several, or one
|
|
151
|
+
* starts with a dash).
|
|
152
|
+
*
|
|
153
|
+
* @param ask - What the grep line asks of a match.
|
|
154
|
+
* @param layout - How it writes what it kept.
|
|
155
|
+
* @returns The line, `grep -i -v -n -A 2 -e t1 -e t2`.
|
|
156
|
+
*/
|
|
157
|
+
function grepLine_render(ask, layout) {
|
|
158
|
+
const switches = GREP_SWITCHES.filter(({ on }) => on(ask, layout)).map(({ letter }) => `-${letter}`);
|
|
159
|
+
const counts = [
|
|
160
|
+
...(layout.after !== undefined ? ['-A', String(layout.after)] : []),
|
|
161
|
+
...(layout.before !== undefined ? ['-B', String(layout.before)] : []),
|
|
162
|
+
...(layout.context !== undefined ? ['-C', String(layout.context)] : []),
|
|
163
|
+
...(layout.color === undefined ? [] : [layout.color === '' ? '--color' : `--color=${word_quote(layout.color)}`]),
|
|
164
|
+
];
|
|
165
|
+
const lone = ask.patterns.length === 1 ? ask.patterns[0] : undefined;
|
|
166
|
+
const patterns = lone !== undefined && !lone.startsWith('-')
|
|
167
|
+
? [word_quote(lone)]
|
|
168
|
+
: ask.patterns.flatMap((pattern) => ['-e', word_quote(pattern)]);
|
|
169
|
+
return ['grep', ...switches, ...counts, ...patterns].join(' ');
|
|
117
170
|
}
|
|
118
171
|
/**
|
|
119
172
|
* A basic regular expression (grep's default) as a JavaScript one: in a BRE
|
|
@@ -139,24 +192,46 @@ function basic_convertToSource(pattern) {
|
|
|
139
192
|
return out;
|
|
140
193
|
}
|
|
141
194
|
/**
|
|
142
|
-
* Builds the
|
|
195
|
+
* Builds the expression a line (or a row's text) is matched by: any of the
|
|
196
|
+
* patterns, read as grep reads them under -F, -E or neither, -w and -i.
|
|
143
197
|
*
|
|
144
|
-
* @param ask - What the grep line asks.
|
|
145
|
-
* @returns The
|
|
198
|
+
* @param ask - What the grep line asks of a match.
|
|
199
|
+
* @returns The expression (not global), or a refusal when a pattern does not compile.
|
|
200
|
+
*
|
|
201
|
+
* @example
|
|
202
|
+
* ```ts
|
|
203
|
+
* grepExpression_build({ ...ask, patterns: ['t1\\|t2'] }); // /(?:t1|t2)/
|
|
204
|
+
* ```
|
|
146
205
|
*/
|
|
147
|
-
export function
|
|
206
|
+
export function grepExpression_build(ask) {
|
|
148
207
|
const sources = ask.patterns.map((pattern) => {
|
|
149
208
|
const source = ask.fixed ? pattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') : ask.extended ? pattern : basic_convertToSource(pattern);
|
|
150
209
|
return ask.word ? `(?<![\\w])(?:${source})(?![\\w])` : `(?:${source})`;
|
|
151
210
|
});
|
|
152
211
|
try {
|
|
153
|
-
|
|
154
|
-
return (text) => expression.test(text);
|
|
212
|
+
return new RegExp(sources.join('|'), ask.insensitive ? 'i' : '');
|
|
155
213
|
}
|
|
156
214
|
catch (error) {
|
|
157
215
|
return { refused: `grep: ${error instanceof Error ? error.message : String(error)}` };
|
|
158
216
|
}
|
|
159
217
|
}
|
|
218
|
+
/**
|
|
219
|
+
* Builds the test a line (or a row's text) passes.
|
|
220
|
+
*
|
|
221
|
+
* @param ask - What the grep line asks of a match.
|
|
222
|
+
* @returns The test, or a refusal when a pattern does not compile.
|
|
223
|
+
*
|
|
224
|
+
* @example
|
|
225
|
+
* ```ts
|
|
226
|
+
* const matches = grepMatcher_build({ ...ask, patterns: ['T1'], word: true });
|
|
227
|
+
* ```
|
|
228
|
+
*/
|
|
229
|
+
export function grepMatcher_build(ask) {
|
|
230
|
+
const built = grepExpression_build(ask);
|
|
231
|
+
if (!(built instanceof RegExp))
|
|
232
|
+
return built;
|
|
233
|
+
return (text) => built.test(text);
|
|
234
|
+
}
|
|
160
235
|
/**
|
|
161
236
|
* Which rows a grep keeps of a listing: a matching row with its parents, a
|
|
162
237
|
* matched group with all its rows; under -v the matching rows (and a
|
|
@@ -266,63 +341,275 @@ function listing_grep(listing, ask, line) {
|
|
|
266
341
|
return envelope_ok(rendered, { kind: listing.kind, data: filtered });
|
|
267
342
|
}
|
|
268
343
|
/**
|
|
269
|
-
*
|
|
270
|
-
*
|
|
344
|
+
* The lines a grep over text writes for its sources, as GNU grep writes
|
|
345
|
+
* them: `name:` before each line when named, `N:` under -n (`-` for a
|
|
346
|
+
* context line), `--` between groups apart under -A, -B or -C; -l the
|
|
347
|
+
* names with a match, -c a count each, -o the matching parts.
|
|
348
|
+
*
|
|
349
|
+
* @param expression - The match, compiled.
|
|
350
|
+
* @param ask - What the line asks of a match.
|
|
351
|
+
* @param layout - How it writes what it kept.
|
|
352
|
+
* @param sources - The texts, under the names shown.
|
|
353
|
+
* @param named - Whether each line is under its file's name.
|
|
354
|
+
* @returns The output and how many lines were kept.
|
|
355
|
+
*
|
|
356
|
+
* @example
|
|
357
|
+
* ```ts
|
|
358
|
+
* textSources_grep(/b/, ask, GREP_LAYOUT_PLAIN, [{ name: null, text: 'a\nb\n' }], false).text; // 'b\n'
|
|
359
|
+
* ```
|
|
360
|
+
*/
|
|
361
|
+
export function textSources_grep(expression, ask, layout, sources, named) {
|
|
362
|
+
const after = layout.after ?? layout.context ?? 0;
|
|
363
|
+
const before = layout.before ?? layout.context ?? 0;
|
|
364
|
+
const grouped = (after > 0 || before > 0) && !layout.onlyMatching;
|
|
365
|
+
const every = new RegExp(expression.source, `${expression.flags.replace('g', '')}g`);
|
|
366
|
+
const out = [];
|
|
367
|
+
let selected = 0;
|
|
368
|
+
let printedAny = false;
|
|
369
|
+
for (const source of sources) {
|
|
370
|
+
const name = source.name === '-' || source.name === null ? '(standard input)' : source.name;
|
|
371
|
+
const lines = lines_split(source.text);
|
|
372
|
+
const hits = lines.map((line) => expression.test(line) !== ask.invert);
|
|
373
|
+
const kept = hits.filter((hit) => hit).length;
|
|
374
|
+
selected += kept;
|
|
375
|
+
if (layout.filesWithMatches) {
|
|
376
|
+
if (kept > 0)
|
|
377
|
+
out.push(name);
|
|
378
|
+
continue;
|
|
379
|
+
}
|
|
380
|
+
if (ask.count) {
|
|
381
|
+
out.push(named ? `${name}:${kept}` : String(kept));
|
|
382
|
+
continue;
|
|
383
|
+
}
|
|
384
|
+
const prefix = (at, mark) => `${named ? `${name}${mark}` : ''}${layout.lineNumber ? `${at + 1}${mark}` : ''}`;
|
|
385
|
+
if (layout.onlyMatching) {
|
|
386
|
+
// Under -v the kept lines are those with no match: no part to show.
|
|
387
|
+
if (ask.invert)
|
|
388
|
+
continue;
|
|
389
|
+
lines.forEach((line, at) => {
|
|
390
|
+
for (const match of line.matchAll(every))
|
|
391
|
+
if (match[0] !== '')
|
|
392
|
+
out.push(`${prefix(at, ':')}${match[0]}`);
|
|
393
|
+
});
|
|
394
|
+
continue;
|
|
395
|
+
}
|
|
396
|
+
const shown = lines.map(() => false);
|
|
397
|
+
hits.forEach((hit, at) => {
|
|
398
|
+
if (!hit)
|
|
399
|
+
return;
|
|
400
|
+
for (let near = Math.max(0, at - before); near <= Math.min(lines.length - 1, at + after); near++)
|
|
401
|
+
shown[near] = true;
|
|
402
|
+
});
|
|
403
|
+
let last = -2;
|
|
404
|
+
lines.forEach((line, at) => {
|
|
405
|
+
if (!shown[at])
|
|
406
|
+
return;
|
|
407
|
+
if (grouped && printedAny && at !== last + 1)
|
|
408
|
+
out.push('--');
|
|
409
|
+
out.push(`${prefix(at, hits[at] === true ? ':' : '-')}${line}`);
|
|
410
|
+
printedAny = true;
|
|
411
|
+
last = at;
|
|
412
|
+
});
|
|
413
|
+
}
|
|
414
|
+
return { text: lines_join(out), selected };
|
|
415
|
+
}
|
|
416
|
+
/**
|
|
417
|
+
* Walks a folder for its files, depth first: each file read under its name
|
|
418
|
+
* as shown (the folder as typed, then the names below it). A link met on the
|
|
419
|
+
* way is not followed, as grep -r does not.
|
|
420
|
+
*
|
|
421
|
+
* @param store - The folder's store path.
|
|
422
|
+
* @param shown - The folder as the output names it; empty for the working directory unnamed.
|
|
423
|
+
* @param read - Where the files and the errors go.
|
|
424
|
+
*/
|
|
425
|
+
async function folder_walk(store, shown, read) {
|
|
426
|
+
const mark = errorStack.checkpoint_mark();
|
|
427
|
+
const listed = await vfsDispatcher_get().list(store);
|
|
428
|
+
errorStack.checkpoint_drain(mark);
|
|
429
|
+
if (!listed.ok) {
|
|
430
|
+
read.errors += `grep: ${shown || '.'}: cannot list the folder\n`;
|
|
431
|
+
return;
|
|
432
|
+
}
|
|
433
|
+
for (const item of listed.value) {
|
|
434
|
+
const childStore = store === '/' ? `/${item.name}` : `${store}/${item.name}`;
|
|
435
|
+
const childShown = shown === '' ? item.name : `${shown}/${item.name}`;
|
|
436
|
+
if (itemType_isContainer(item.type)) {
|
|
437
|
+
await folder_walk(childStore, childShown, read);
|
|
438
|
+
continue;
|
|
439
|
+
}
|
|
440
|
+
if (item.type === 'link')
|
|
441
|
+
continue;
|
|
442
|
+
const file = await vfsDispatcher_get().read(childStore);
|
|
443
|
+
if (file.ok)
|
|
444
|
+
read.sources.push({ name: childShown, text: file.value });
|
|
445
|
+
else
|
|
446
|
+
read.errors += `grep: ${childShown}: ${file.reason ?? errno_words(file.errno)}\n`;
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
/**
|
|
450
|
+
* Reads what grep -r works on: each operand a file, or a folder walked for
|
|
451
|
+
* its files (`-` is the pipe); no operand walks the working directory, its
|
|
452
|
+
* files named below it.
|
|
453
|
+
*
|
|
454
|
+
* @param operands - The operands, as typed.
|
|
455
|
+
* @returns The files read, under the names shown, and whether a folder was walked.
|
|
456
|
+
*/
|
|
457
|
+
async function recursiveSources_read(operands) {
|
|
458
|
+
const piped = stdin_take();
|
|
459
|
+
const read = { sources: [], errors: '', walked: false };
|
|
460
|
+
if (operands.length === 0) {
|
|
461
|
+
read.walked = true;
|
|
462
|
+
await folder_walk(await storePath_resolve('.'), '', read);
|
|
463
|
+
return read;
|
|
464
|
+
}
|
|
465
|
+
for (const operand of operands) {
|
|
466
|
+
if (operand === '-') {
|
|
467
|
+
read.sources.push({ name: '-', text: piped ?? '' });
|
|
468
|
+
continue;
|
|
469
|
+
}
|
|
470
|
+
const file = await filterFile_read('grep', operand);
|
|
471
|
+
if (!('error' in file)) {
|
|
472
|
+
read.sources.push(file);
|
|
473
|
+
continue;
|
|
474
|
+
}
|
|
475
|
+
const store = await storePath_resolve(operand);
|
|
476
|
+
const mark = errorStack.checkpoint_mark();
|
|
477
|
+
const listed = await vfsDispatcher_get().list(store);
|
|
478
|
+
errorStack.checkpoint_drain(mark);
|
|
479
|
+
if (!listed.ok) {
|
|
480
|
+
read.errors += file.error;
|
|
481
|
+
continue;
|
|
482
|
+
}
|
|
483
|
+
read.walked = true;
|
|
484
|
+
await folder_walk(store, operand.length > 1 ? operand.replace(/\/+$/, '') : operand, read);
|
|
485
|
+
}
|
|
486
|
+
return read;
|
|
487
|
+
}
|
|
488
|
+
/**
|
|
489
|
+
* grep over text it filters itself: ChRIS files (each read through the one
|
|
490
|
+
* store-path resolver, a folder walked under -r) or the piped text, named
|
|
491
|
+
* as typed.
|
|
492
|
+
*
|
|
493
|
+
* @param ask - What the grep line asks of a match.
|
|
494
|
+
* @param layout - How it writes what it kept.
|
|
495
|
+
* @param files - The file operands (`-` is the pipe); none, with text piped, for the pipe alone.
|
|
496
|
+
* @returns The envelope; exit 1 when no line was kept.
|
|
497
|
+
*/
|
|
498
|
+
async function sources_grep(ask, layout, files) {
|
|
499
|
+
const built = grepExpression_build(ask);
|
|
500
|
+
if (!(built instanceof RegExp)) {
|
|
501
|
+
exitCode_set(1);
|
|
502
|
+
return envelope_error('', undefined, `${built.refused}\n`);
|
|
503
|
+
}
|
|
504
|
+
let read;
|
|
505
|
+
if (layout.recursive) {
|
|
506
|
+
read = await recursiveSources_read(files);
|
|
507
|
+
}
|
|
508
|
+
else {
|
|
509
|
+
const plain = await filterSources_read('grep', files);
|
|
510
|
+
if ('refusal' in plain)
|
|
511
|
+
return envelope_error('', undefined, `${plain.refusal}\n`);
|
|
512
|
+
read = { ...plain, walked: false };
|
|
513
|
+
}
|
|
514
|
+
let selected = 0;
|
|
515
|
+
const envelope = filterRead_answer(read, (sources) => {
|
|
516
|
+
const named = layout.withFilename || (!layout.noFilename && (sources.length > 1 || read.walked));
|
|
517
|
+
const answer = textSources_grep(built, ask, layout, sources, named);
|
|
518
|
+
selected = answer.selected;
|
|
519
|
+
return answer.text;
|
|
520
|
+
});
|
|
521
|
+
if (selected === 0)
|
|
522
|
+
exitCode_set(1);
|
|
523
|
+
return envelope;
|
|
524
|
+
}
|
|
525
|
+
/**
|
|
526
|
+
* Plain grep on piped text: the system's, its line written back from the
|
|
527
|
+
* typed options, where the surface runs host programs; otherwise this
|
|
528
|
+
* grep's own filter, with the same flags.
|
|
271
529
|
*
|
|
272
530
|
* @param text - The text piped in.
|
|
273
|
-
* @param ask - What the grep line asks.
|
|
274
|
-
* @param
|
|
531
|
+
* @param ask - What the grep line asks of a match.
|
|
532
|
+
* @param layout - How it writes what it kept.
|
|
275
533
|
* @returns The envelope.
|
|
276
534
|
*/
|
|
277
|
-
async function text_grep(text, ask,
|
|
535
|
+
async function text_grep(text, ask, layout) {
|
|
278
536
|
const surface = surface_get();
|
|
279
537
|
if (surface.capabilities.pipeSegments) {
|
|
280
|
-
const out = await surface.pipeSegment(
|
|
538
|
+
const out = await surface.pipeSegment(grepLine_render(ask, layout), Buffer.from(text, 'utf-8'));
|
|
281
539
|
return envelope_ok(out.toString('utf-8'));
|
|
282
540
|
}
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
const built = grepMatcher_build(ask);
|
|
286
|
-
if (typeof built !== 'function')
|
|
541
|
+
const built = grepExpression_build(ask);
|
|
542
|
+
if (!(built instanceof RegExp))
|
|
287
543
|
return envelope_error('', undefined, `${built.refused}\n`);
|
|
288
|
-
const
|
|
289
|
-
if (
|
|
544
|
+
const answer = textSources_grep(built, ask, layout, [{ name: null, text }], false);
|
|
545
|
+
if (answer.selected === 0)
|
|
290
546
|
exitCode_set(1);
|
|
291
|
-
return envelope_ok(
|
|
547
|
+
return envelope_ok(answer.text);
|
|
292
548
|
}
|
|
293
|
-
/**
|
|
294
|
-
|
|
295
|
-
|
|
549
|
+
/**
|
|
550
|
+
* The refusal of a layout flag a numbered listing has no use for, or null.
|
|
551
|
+
*
|
|
552
|
+
* @param layout - How the line asks to write what it kept.
|
|
553
|
+
* @returns The envelope that says so, or null when the line asks none.
|
|
554
|
+
*/
|
|
555
|
+
function listingLayout_refuse(layout) {
|
|
556
|
+
const refused = LISTING_REFUSALS.find(({ given }) => given(layout));
|
|
557
|
+
if (refused === undefined)
|
|
558
|
+
return null;
|
|
559
|
+
exitCode_set(1);
|
|
560
|
+
return envelope_error('', undefined, `grep ${refused.flag}: ${refused.why}\n`);
|
|
296
561
|
}
|
|
297
562
|
/**
|
|
298
|
-
*
|
|
563
|
+
* The typed grep line run: the files named (or walked under -r), else a
|
|
564
|
+
* piped listing, else piped text, else the held listing.
|
|
299
565
|
*
|
|
300
|
-
* @param args - The
|
|
566
|
+
* @param args - The typed line.
|
|
301
567
|
* @returns The envelope.
|
|
302
568
|
*/
|
|
303
|
-
|
|
304
|
-
const
|
|
305
|
-
const
|
|
306
|
-
const
|
|
307
|
-
const
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
569
|
+
async function grep_run(args) {
|
|
570
|
+
const given = args.options.regexp;
|
|
571
|
+
const pattern = args.operands.pattern;
|
|
572
|
+
const files = args.operands.files;
|
|
573
|
+
const ask = {
|
|
574
|
+
insensitive: args.options.insensitive, invert: args.options.invert, word: args.options.word,
|
|
575
|
+
extended: args.options.extended, fixed: args.options.fixed, count: args.options.count,
|
|
576
|
+
patterns: given.length > 0 ? given : pattern === undefined ? [] : [pattern],
|
|
577
|
+
};
|
|
578
|
+
const layout = {
|
|
579
|
+
lineNumber: args.options.lineNumber, filesWithMatches: args.options.filesWithMatches, onlyMatching: args.options.onlyMatching,
|
|
580
|
+
noFilename: args.options.noFilename, withFilename: args.options.withFilename, recursive: args.options.recursive,
|
|
581
|
+
after: args.options.after, before: args.options.before, context: args.options.context, color: args.options.color,
|
|
582
|
+
};
|
|
316
583
|
if (ask.patterns.length === 0)
|
|
317
584
|
return envelope_error('', undefined, 'grep: a pattern to keep: grep [-ivwEFc] [-e PATTERN] PATTERN\n');
|
|
318
|
-
|
|
319
|
-
|
|
585
|
+
const piped = listingIn_take();
|
|
586
|
+
if (piped !== null && files.length === 0) {
|
|
587
|
+
stdin_take();
|
|
588
|
+
return listingLayout_refuse(layout) ?? listing_grep({ ...piped, source: '' }, ask, grepLine_render(ask, layout));
|
|
589
|
+
}
|
|
590
|
+
if (files.length > 0 || layout.recursive)
|
|
591
|
+
return sources_grep(ask, layout, files);
|
|
592
|
+
const text = stdin_take();
|
|
320
593
|
if (text !== null)
|
|
321
|
-
return text_grep(text, ask,
|
|
594
|
+
return text_grep(text, ask, layout);
|
|
322
595
|
// Nothing piped: the held listing, as an index reads it.
|
|
323
596
|
const held = answer_get();
|
|
324
597
|
if (held === null)
|
|
325
598
|
return envelope_error('', undefined, 'grep: nothing to filter: pipe text or a listing in, or list something first (query, ls, gather list)\n');
|
|
326
|
-
return listing_grep({ kind: held.kind, data: held.data, source: held.source }, ask,
|
|
599
|
+
return listingLayout_refuse(layout) ?? listing_grep({ kind: held.kind, data: held.data, source: held.source }, ask, grepLine_render(ask, layout));
|
|
600
|
+
}
|
|
601
|
+
/**
|
|
602
|
+
* `grep` over words already split: the declaration's parse and handler.
|
|
603
|
+
*
|
|
604
|
+
* @param args - The words after `grep`.
|
|
605
|
+
* @returns The envelope, or the refusal of a bad line.
|
|
606
|
+
*
|
|
607
|
+
* @example
|
|
608
|
+
* ```ts
|
|
609
|
+
* await builtin_grep(['-i', 't1']);
|
|
610
|
+
* ```
|
|
611
|
+
*/
|
|
612
|
+
export async function builtin_grep(args) {
|
|
613
|
+
return declaredCommand_run(grepCommand, args);
|
|
327
614
|
}
|
|
328
615
|
//# sourceMappingURL=grep.js.map
|