Skip to content

Commit 187576f

Browse files
author
⚙︎ Greg
committed
bugfix to *grep commands - inverse inverted. ranges are numbers and allow for negative numbers to index from end
1 parent ff22879 commit 187576f

File tree

14 files changed

+156
-88
lines changed

14 files changed

+156
-88
lines changed

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ These commands are NOT intended for projects with a long life. It is recommended
99
## Usage
1010
```F#
1111
#r "nuget:FsShell"
12-
open FsShell
12+
1313
man "";;
1414
```
1515

@@ -40,9 +40,9 @@ Data Manipulation
4040
cut Split lines at tabs
4141
cut_d Split lines at delimeter
4242
cut_c Cut character range options
43-
cut_c2 Cut character ranges
44-
cut_x Splits data file into columns; detects quotes and commas
45-
xjoin Join columns into data
43+
cut_x Splits data file into columns
44+
paste Join files into single file; line-to-line
45+
xpaste Join columns into data
4646
sort Sorting
4747
sort_k Sorting by a substring
4848
sort_kn Sorting by a substring as a number

src/FsShell.Testing/Command/CutTests.fs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,53 +23,53 @@ let ``Test Cut_d - spaces`` () =
2323
let ``Test Cut_c - None to 4`` () =
2424
let input = "Quick brown,fox,jumps\tover the lazy dog "
2525
let expect = "Quick"
26-
let actual = Utility.AsSingleton (cut_c [(None, Some 4)]) input
26+
let actual = Utility.AsSingleton (cut_c [(0, 4)]) input
2727
Assert.Equal(expect, actual);
2828

2929
[<Fact>]
3030
let ``Test Cut_c - 0 to 4, 11 to 14`` () =
3131
let input = "Quick brown fox jumps over the lazy dog"
3232
let expect = "Quick fox"
33-
let actual = Utility.AsSingleton (cut_c [(Some 0, Some 4); (Some 11, Some 14)]) input
33+
let actual = Utility.AsSingleton (cut_c [(0, 4); (11, 14)]) input
3434
Assert.Equal(expect, actual);
3535

3636
[<Fact>]
3737
let ``Test Cut_c - 31 to None`` () =
3838
let input = "Quick brown fox jumps over the lazy dog"
3939
let expect = "lazy dog"
40-
let actual = Utility.AsSingleton (cut_c [(Some 31, None)]) input
40+
let actual = Utility.AsSingleton (cut_c [(31, -1)]) input
4141
Assert.Equal(expect, actual);
4242

4343
[<Fact>]
4444
let ``Test Cut_c - None to None`` () =
4545
let input = "Quick brown fox jumps over the lazy dog"
4646
let expect = input
47-
let actual = Utility.AsSingleton (cut_c [(None, None)]) input
47+
let actual = Utility.AsSingleton (cut_c [(0, -1)]) input
4848
Assert.Equal(expect, actual);
4949

5050
[<Fact>]
51-
let ``Test Cut_c - None to 500`` () =
51+
let ``Test Cut_c - 0 to 500`` () =
5252
let input = "Quick brown fox jumps over the lazy dog"
5353
let expect = input
54-
let actual = Utility.AsSingleton (cut_c [(None, Some 500)]) input
54+
let actual = Utility.AsSingleton (cut_c [(0, 500)]) input
5555
Assert.Equal(expect, actual);
5656

5757
[<Fact>]
58-
let ``Test Cut_c - -5 to None`` () =
58+
let ``Test Cut_c - -5 to -1`` () =
5959
let input = "Quick brown fox jumps over the lazy dog"
60-
let expect = input
61-
let actual = Utility.AsSingleton (cut_c [(Some -5, None)]) input
60+
let expect = "y dog"
61+
let actual = Utility.AsSingleton (cut_c [(-5, -1)]) input
6262
Assert.Equal(expect, actual);
6363

6464
[<Fact>]
6565
let ``Test Cut_c - 500 to 505`` () =
6666
let input = "Quick brown fox jumps over the lazy dog"
6767
let expect = ""
68-
let actual = Utility.AsSingleton (cut_c [(Some 500, Some 505)]) input
68+
let actual = Utility.AsSingleton (cut_c [(500, 505)]) input
6969
Assert.Equal(expect, actual);
7070

7171
[<Fact>]
72-
let ``Test Cutx`` () =
72+
let ``Test Cut_x`` () =
7373
let expect = [
7474
[ "Col 1"; "Col 2"; "Col 3" ]
7575
[ "Val 1-1"; "Val 2-1"; "Val 3-1" ]

src/FsShell.Testing/Command/GrepTests.fs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ let ``Test XGrep`` () =
7878
[| "Do Not Find Me"; "Val 2-3"; "Val 3-3" |]
7979
}
8080
let expect = 2
81-
let actual = xgrep' false false "Find Me" ([ (1, 2) ]) input |> Seq.length
81+
let actual = xgrep false false "Find Me" ([ (1, 2) ]) input |> Seq.length
8282
Assert.Equal(expect, actual)
8383

8484
[<Fact>]
@@ -90,7 +90,7 @@ let ``Test XGrep 2`` () =
9090
[| "Do Not Find Me"; "Val 2-3"; "Val 3-3" |]
9191
}
9292
let expect = 2
93-
let actual = xgrep false false "Find Me" ([ (Some 1, None) ]) input |> Seq.length
93+
let actual = xgrep false false "Find Me" ([ (1, -1) ]) input |> Seq.length
9494
Assert.Equal(expect, actual)
9595

9696
[<Fact>]
@@ -103,7 +103,7 @@ let ``Test XGrep Inverse`` () =
103103
[| "Do Not Find Me"; "Val 2-4"; "Val 3-4" |]
104104
}
105105
let expect = 3
106-
let actual = xgrep false true "Find Me" ([ (Some 1, None) ]) input |> Seq.length
106+
let actual = xgrep false true "Find Me" ([ (1, -1) ]) input |> Seq.length
107107
Assert.Equal(expect, actual)
108108

109109
[<Fact>]
@@ -115,7 +115,7 @@ let ``Test XGrep Ignore Case`` () =
115115
[| "Do Not Find Me"; "Val 2-3"; "Val 3-3" |]
116116
}
117117
let expect = 2
118-
let actual = xgrep true false "Find Me" ([ (Some 1, None) ]) input |> Seq.length
118+
let actual = xgrep true false "Find Me" ([ (1, -1) ]) input |> Seq.length
119119
Assert.Equal(expect, actual)
120120

121121
[<Fact>]
@@ -127,7 +127,7 @@ let ``Test XEGrep`` () =
127127
[| "Do Not Find Me"; "Val 2-3"; "Val 3-3" |]
128128
}
129129
let expect = 2
130-
let actual = xegrep' false false "^Find Me$" ([ (0, 1); (2, 2) ]) input |> Seq.length
130+
let actual = xegrep false false "^Find Me$" ([ (0, 1); (2, 2) ]) input |> Seq.length
131131
Assert.Equal(expect, actual)
132132

133133
[<Fact>]
@@ -139,5 +139,5 @@ let ``Test XEGrep Inverse`` () =
139139
[| "Do Not Find Me"; "Val 2-3"; "Val 3-3" |]
140140
}
141141
let expect = 2
142-
let actual = xegrep' false false "^Find Me$" ([ (0, 1); (2, 2) ]) input |> Seq.length
142+
let actual = xegrep false false "^Find Me$" ([ (0, 1); (2, 2) ]) input |> Seq.length
143143
Assert.Equal(expect, actual)

src/FsShell.Testing/Command/SortTests.fs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,21 +22,21 @@ let ``Test Sort Ignore Case`` () =
2222
let ``Test Sort Range`` () =
2323
let input = seq { "AC"; "BB"; "CA" }
2424
let expect = seq { "CA"; "BB"; "AC" }
25-
let actual = sort_k (Some 1, Some 1) input
25+
let actual = sort_k (1, 1) input
2626
Assert.True(expect.SequenceEqual(actual))
2727

2828
[<Fact>]
2929
let ``Test Sort Range Ignore Case`` () =
3030
let input = seq { "AC"; "Bb"; "Ca" }
3131
let expect = seq { "Ca"; "Bb"; "AC" }
32-
let actual = sort_k (Some 1, Some 1) input
32+
let actual = sort_k (1, 1) input
3333
Assert.True(expect.SequenceEqual(actual))
3434

3535
[<Fact>]
3636
let ``Test Sort Number Range`` () =
3737
let input = seq { "A31"; "B21"; "C11" }
3838
let expect = seq { "C11"; "B21"; "A31" }
39-
let actual = sort_kn (Some 1, Some 2) input
39+
let actual = sort_kn (1, 2) input
4040
Assert.True(expect.SequenceEqual(actual))
4141

4242
[<Fact>]
@@ -91,7 +91,6 @@ let ``Test XSort Ignore Case`` () =
9191
]
9292
let actual = xsort [ 1 ] input |> Seq.toList
9393
for (expectRow, actualRow) in (expect |> Seq.zip actual) do
94-
//printfn "YES:%A %A" expectRow actualRow
9594
Assert.True(expectRow.SequenceEqual(actualRow))
9695

9796
[<Fact>]

src/FsShell.Testing/FsShell.Testing.fsproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
</ItemGroup>
1111
<ItemGroup>
1212
<Compile Include="Infrastructure/Utility.fs" />
13-
<Compile Include="Infrastructure/Seq.fs" />
13+
<Compile Include="Infrastructure/UtilityTests.fs" />
14+
<Compile Include="Infrastructure/SeqTests.fs" />
1415
<Compile Include="Infrastructure/DataReaderTests.fs" />
1516
<Compile Include="Command/CatTests.fs" />
1617
<Compile Include="Command/CdTests.fs" />

src/FsShell.Testing/Infrastructure/DataReaderTests.fs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,5 +78,4 @@ let samplesDetermineSeparatorAndQuantifier : obj[] list =
7878
[<MemberData(nameof(samplesDetermineSeparatorAndQuantifier))>]
7979
let ``Test determineSeparatorAndQuantifier`` expect input =
8080
let actual = DataReader.determineSpAndQt input
81-
printfn "Expect = %A; Actual = %A" expect actual
8281
Assert.Equal(expect, actual)
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
module SpiralOSS.FsShell.Testing.Infrastructure.UtilityTests
2+
3+
open Xunit
4+
open System.Linq
5+
open SpiralOSS.FsShell.Infrastructure.Utility
6+
7+
let rangesToCursorsTests = seq {
8+
[| 5 :> obj; [ ( 0, 5) ] :> obj; [ (Within 0, Within 5) ] :> obj |]
9+
[| 5 :> obj; [ ( 0, 6) ] :> obj; [ (Within 0, After ) ] :> obj |]
10+
[| 5 :> obj; [ ( 0, 3) ] :> obj; [ (Within 0, Within 3) ] :> obj |]
11+
[| 5 :> obj; [ ( 0, -1) ] :> obj; [ (Within 0, Within 5) ] :> obj |]
12+
[| 5 :> obj; [ ( 0, -5) ] :> obj; [ (Within 0, Within 1) ] :> obj |]
13+
[| 5 :> obj; [ ( 0, -6) ] :> obj; [ (Within 0, Within 0) ] :> obj |]
14+
[| 5 :> obj; [ ( 0, -6) ] :> obj; [ (Within 0, Within 0) ] :> obj |]
15+
[| 5 :> obj; [ (-1, -6) ] :> obj; [ (Within 5, Within 5) ] :> obj |]
16+
[| 5 :> obj; [ (-3, -1) ] :> obj; [ (Within 3, Within 5) ] :> obj |]
17+
[| 5 :> obj; [ (-7, -1) ] :> obj; [ (Before, Within 5) ] :> obj |]
18+
[| 5 :> obj; [ (-7, 6) ] :> obj; [ (Before, After ) ] :> obj |]
19+
}
20+
21+
[<Theory>]
22+
[<MemberData(nameof(rangesToCursorsTests))>]
23+
let ``Test rangesToCursors`` inputLastPosition inputRanges (expect:((CursorPosition*CursorPosition) list)) =
24+
let actual = rangesToCursors inputLastPosition inputRanges
25+
Assert.True(expect.SequenceEqual(actual))
26+
27+
let rangeSpliceTests = seq {
28+
[| [ ( 0, 6) ] :> obj; "0123456789" :> obj; "0123456" :> obj |]
29+
[| [ ( 0, -1) ] :> obj; "0123456789" :> obj; "0123456789" :> obj |]
30+
[| [ ( 0, -2) ] :> obj; "0123456789" :> obj; "012345678" :> obj |]
31+
[| [ ( 5, 0) ] :> obj; "0123456789" :> obj; "5" :> obj |]
32+
[| [ ( 5,100) ] :> obj; "0123456789" :> obj; "56789" :> obj |]
33+
[| [ ( 1, 3); ( 5, 6); (-1, -1) ] :> obj; "0123456789" :> obj; "123569" :> obj |]
34+
}
35+
36+
[<Theory>]
37+
[<MemberData(nameof(rangeSpliceTests))>]
38+
let ``Test stringRangeSplice`` (ranges:(int*int) list) (input:string) (expect:string) =
39+
let actual =
40+
stringRangeSplice' ranges input
41+
|> String.concat ""
42+
Assert.Equal(expect, actual)
43+
44+
[<Theory>]
45+
[<MemberData(nameof(rangeSpliceTests))>]
46+
let ``Test arrayRangeSpliceTests`` (ranges:(int*int) list) (input:string) (expect:string) =
47+
let inputArr = input.ToCharArray() |> Array.map string
48+
let actual =
49+
arrayRangeSplice' ranges inputArr
50+
|> Array.concat
51+
|> String.concat ""
52+
Assert.Equal(expect, actual)

src/FsShell/Command/Cut.fs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@ let cut_d (delimiter:char seq) (contents:string seq) =
88
content.Split ((Seq.toArray delimiter), System.StringSplitOptions.RemoveEmptyEntries) |> Seq.toList
99
)
1010

11-
let cut_c (ranges:(int option*int option) list) (contents:string seq) =
11+
let cut_c (ranges:(int*int) list) (contents:string seq) =
1212
contents
1313
|> Seq.map (fun content ->
14-
stringSplice ranges content
14+
stringRangeSplice' ranges content
1515
|> String.concat ""
1616
)
1717

src/FsShell/Command/Grep.fs

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,28 +23,24 @@ let egrep (ignoreCase:bool) (inverse:bool) (pattern:string) (contents:string seq
2323
| true -> fun (content:string) -> not (compiledRegex.IsMatch(content))
2424
Seq.filter filterMethod contents
2525

26-
let xgrep (ignoreCase:bool) (inverse:bool) (pattern:string) (ranges:(int option*int option) list) (contents:string[] seq) =
26+
let xgrep (ignoreCase:bool) (inverse:bool) (pattern:string) (ranges:(int*int) list) (contents:string[] seq) =
2727
let filterMethod =
2828
let containsPattern (ignoreCase:bool) (value:string) = value.Contains(pattern, (if ignoreCase then System.StringComparison.CurrentCultureIgnoreCase else System.StringComparison.CurrentCulture))
2929
match (ignoreCase, inverse) with
30-
| (false, false) -> fun (content:string[]) -> content |> rangeSplice ranges |> List.exists (containsPattern false)
31-
| (false, true) -> fun (content:string[]) -> content |> rangeSplice ranges |> List.filter (containsPattern false) |> List.isEmpty
32-
| (true, false) -> fun (content:string[]) -> content |> rangeSplice ranges |> List.exists (containsPattern true)
33-
| (true, true) -> fun (content:string[]) -> content |> rangeSplice ranges |> List.filter (containsPattern true) |> List.isEmpty
30+
| (false, false) -> fun (content:string[]) -> content |> arrayRangeSplice' ranges |> Array.concat |> Array.exists (containsPattern false)
31+
| (false, true) -> fun (content:string[]) -> content |> arrayRangeSplice' ranges |> Array.concat |> Array.filter (containsPattern false) |> Array.isEmpty
32+
| (true, false) -> fun (content:string[]) -> content |> arrayRangeSplice' ranges |> Array.concat |> Array.exists (containsPattern true)
33+
| (true, true) -> fun (content:string[]) -> content |> arrayRangeSplice' ranges |> Array.concat |> Array.filter (containsPattern true) |> Array.isEmpty
3434
Seq.filter filterMethod contents
35-
let xgrep' (ignoreCase:bool) (inverse:bool) (pattern:string) (ranges:(int*int) list) (contents:string[] seq) =
36-
xgrep ignoreCase inverse pattern (ranges |> List.map (fun (ss,ee) -> (Some ss, Some ee))) contents
3735

38-
let xegrep (ignoreCase:bool) (inverse:bool) (pattern:string) (ranges:(int option*int option) list) (contents:string[] seq) =
36+
let xegrep (ignoreCase:bool) (inverse:bool) (pattern:string) (ranges:(int*int) list) (contents:string[] seq) =
3937
let compiledRegex =
4038
match ignoreCase with
4139
| false -> Regex(pattern, RegexOptions.Compiled)
4240
| true -> Regex(pattern, RegexOptions.Compiled + RegexOptions.IgnoreCase)
4341
let filterMethod =
4442
let isMatch (value:string) = compiledRegex.IsMatch(value)
4543
match inverse with
46-
| false -> fun (content:string[]) -> content |> rangeSplice ranges |> List.exists isMatch
47-
| true -> fun (content:string[]) -> content |> rangeSplice ranges |> List.filter isMatch |> List.isEmpty
48-
Seq.filter filterMethod contents
49-
let xegrep' (ignoreCase:bool) (inverse:bool) (pattern:string) (ranges:(int*int) list) (contents:string[] seq) =
50-
xegrep ignoreCase inverse pattern (ranges |> List.map (fun (ss,ee) -> (Some ss, Some ee))) contents
44+
| false -> fun (content:string[]) -> content |> arrayRangeSplice' ranges |> Array.concat |> Array.exists isMatch
45+
| true -> fun (content:string[]) -> content |> arrayRangeSplice' ranges |> Array.concat |> Array.filter isMatch |> Array.isEmpty
46+
Seq.filter filterMethod contents

src/FsShell/Command/Sort.fs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@ open System.Linq
55

66
let sort (contents:string seq) = seq { yield! contents.OrderBy(fun it -> it) }
77

8-
let sort_k (ranges:(int option*int option)) (contents:string seq) =
9-
seq { yield! contents.OrderBy (fun content -> (stringSplice [ ranges ] content) |> String.concat "") }
8+
let sort_k (ranges:(int*int)) (contents:string seq) =
9+
seq { yield! contents.OrderBy (fun content -> (stringRangeSplice' [ ranges ] content) |> String.concat "") }
1010

11-
let sort_kn (ranges:(int option*int option)) (contents:string seq) =
11+
let sort_kn (ranges:(int*int)) (contents:string seq) =
1212
contents |> Seq.sortBy (fun content ->
13-
let sortNum = stringSplice [ ranges ] content |> String.concat ""
13+
let sortNum = stringRangeSplice' [ ranges ] content |> String.concat ""
1414
let (success, number) = System.Int64.TryParse(sortNum)
1515
if success then number else 0L
1616
)

0 commit comments

Comments
 (0)