Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement property completion. #93

Merged
merged 8 commits into from
Dec 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions src/pocof.Test/PocofAction.fs
Original file line number Diff line number Diff line change
Expand Up @@ -39,18 +39,18 @@ module ``toKeyPattern should returns`` =

module ``get should returns`` =
[<Fact>]
let ``PocofData.AddChar if no modifier is specified.`` () =
let ``PocofData.AddQuery if no modifier is specified.`` () =
let key = [ new ConsoleKeyInfo('a', ConsoleKey.A, false, false, false) ]
let actual = PocofAction.get Map.empty key

actual |> shouldEqual (PocofData.AddChar "a")
actual |> shouldEqual (PocofData.AddQuery "a")

[<Fact>]
let ``PocofData.AddChar if symbol with shift.`` () =
let ``PocofData.AddQuery if symbol with shift.`` () =
let getKey = [ new ConsoleKeyInfo(':', ConsoleKey.Oem1, true, false, false) ]
let actual = PocofAction.get Map.empty getKey

actual |> shouldEqual (PocofData.AddChar ":")
actual |> shouldEqual (PocofData.AddQuery ":")

[<Fact>]
let ``user-defined Action if matched.`` () =
Expand Down Expand Up @@ -99,14 +99,14 @@ module ``get should returns`` =
actual |> shouldEqual PocofData.BeginningOfLine

[<Fact>]
let ``PocofData.AddChar if not match the keymap.`` () =
let ``PocofData.AddQuery if not match the keymap.`` () =
let keyMap: Map<PocofData.KeyPattern, PocofData.Action> =
Map [ ({ Modifier = 1; Key = ConsoleKey.U }, PocofData.KillBeginningOfLine) ]

let key = [ new ConsoleKeyInfo('u', ConsoleKey.U, false, true, true) ]
let actual = PocofAction.get keyMap key

actual |> shouldEqual (PocofData.AddChar "u")
actual |> shouldEqual (PocofData.AddQuery "u")

[<Fact>]
let ``PocofData.None if the control character not match the keymap.`` () =
Expand Down
190 changes: 170 additions & 20 deletions src/pocof.Test/PocofData.fs
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@ module ``Action fromString should returns`` =
|> shouldEqual (Error "Unknown case 'XXX'.")

[<Fact>]
let ``Error when AddChar.`` () =
Action.fromString "AddChar"
|> shouldEqual (Error "Unknown case 'AddChar'.")
let ``Error when AddQuery.`` () =
Action.fromString "AddQuery"
|> shouldEqual (Error "Unknown case 'AddQuery'.")

[<Fact>]
let ``known actions excluding AddChar.`` () =
let ``known actions excluding AddQuery.`` () =
FSharpType.GetUnionCases(typeof<Action>)
|> Seq.filter (fun a -> a.Name <> "AddChar")
|> Seq.filter (fun a -> a.Name <> "AddQuery")
|> Seq.iter (fun a ->
[ a.Name
String.lower a.Name
Expand Down Expand Up @@ -235,10 +235,10 @@ module invokeAction =

let position: Position = { X = 0; Y = 0 }

module ``with AddChar`` =
module ``with AddQuery`` =
[<Fact>]
let ``should return a property search state and position.x = 1 when the char is colon.`` () =
invokeAction state { X = 0; Y = 0 } (AddChar ":")
invokeAction state { X = 0; Y = 0 } [] (AddQuery ":")
|> shouldEqual (
{ state with
Query = ":"
Expand All @@ -254,7 +254,8 @@ module invokeAction =
Query = ":name"
PropertySearch = Search "name" }
{ X = 5; Y = 0 }
(AddChar " ")
[]
(AddQuery " ")
|> shouldEqual (
{ state with
Query = ":name "
Expand All @@ -273,7 +274,7 @@ module invokeAction =

let position: Position = { X = 0; Y = 0 }

invokeAction state position BackwardChar
invokeAction state position [] BackwardChar
|> shouldEqual (state, position, NotRequired)

[<Fact>]
Expand All @@ -283,6 +284,7 @@ module invokeAction =
Query = ":name"
PropertySearch = Search "name" }
{ X = 5; Y = 0 }
[]
BackwardChar
|> shouldEqual (
{ state with
Expand All @@ -300,6 +302,7 @@ module invokeAction =
Query = ":name"
PropertySearch = Search "" }
{ X = 1; Y = 0 }
[]
ForwardChar
|> shouldEqual (
{ state with
Expand All @@ -318,6 +321,7 @@ module invokeAction =
Query = ":name"
PropertySearch = Search "name" }
{ X = 5; Y = 0 }
[]
ForwardChar
|> shouldEqual (
{ state with
Expand All @@ -335,6 +339,7 @@ module invokeAction =
Query = ":name"
PropertySearch = Search "name" }
{ X = 5; Y = 0 }
[]
BeginningOfLine
|> shouldEqual (
{ state with
Expand All @@ -351,6 +356,7 @@ module invokeAction =
Query = ":name"
PropertySearch = Search "name" }
{ X = 0; Y = 0 }
[]
BeginningOfLine
|> shouldEqual (
{ state with
Expand All @@ -367,6 +373,7 @@ module invokeAction =
Query = "query"
PropertySearch = NonSearch }
{ X = 5; Y = 0 }
[]
BeginningOfLine
|> (shouldEqual (
{ state with
Expand All @@ -384,6 +391,7 @@ module invokeAction =
Query = ":name"
PropertySearch = Search "n" }
{ X = 2; Y = 0 }
[]
EndOfLine
|> shouldEqual (
{ state with
Expand All @@ -400,6 +408,7 @@ module invokeAction =
Query = ":name"
PropertySearch = Search "name" }
{ X = 5; Y = 0 }
[]
EndOfLine
|> shouldEqual (
{ state with
Expand All @@ -416,6 +425,7 @@ module invokeAction =
Query = "query"
PropertySearch = NonSearch }
{ X = 0; Y = 0 }
[]
EndOfLine
|> shouldEqual (
{ state with
Expand All @@ -433,6 +443,7 @@ module invokeAction =
Query = ":name "
PropertySearch = NonSearch }
{ X = 6; Y = 0 }
[]
DeleteBackwardChar
|> shouldEqual (
{ state with
Expand All @@ -449,6 +460,7 @@ module invokeAction =
Query = ":name"
PropertySearch = NonSearch }
{ X = 0; Y = 0 }
[]
DeleteBackwardChar
|> shouldEqual (
{ state with
Expand All @@ -466,6 +478,7 @@ module invokeAction =
Query = ":name "
PropertySearch = Search "name" }
{ X = 0; Y = 0 }
[]
DeleteForwardChar
|> shouldEqual (
{ state with
Expand All @@ -482,6 +495,7 @@ module invokeAction =
Query = ":name"
PropertySearch = Search "name" }
{ X = 5; Y = 0 }
[]
DeleteForwardChar
|> shouldEqual (
{ state with
Expand All @@ -494,27 +508,27 @@ module invokeAction =
module ``with KillBeginningOfLine`` =
[<Fact>]
let ``should remove all characters before the specified position.`` () =
invokeAction { state with Query = "examplequery" } { X = 7; Y = 0 } KillBeginningOfLine
invokeAction { state with Query = "examplequery" } { X = 7; Y = 0 } [] KillBeginningOfLine
|> shouldEqual ({ state with Query = "query" }, { X = 0; Y = 0 }, Required)

[<Fact>]
let ``should not change state if the cursor position is at the begin of line.`` () =
invokeAction { state with Query = "query" } { X = 0; Y = 0 } KillBeginningOfLine
invokeAction { state with Query = "query" } { X = 0; Y = 0 } [] KillBeginningOfLine
|> shouldEqual ({ state with Query = "query" }, { X = 0; Y = 0 }, NotRequired)

module ``with KillEndOfLine`` =
[<Fact>]
let ``should remove characters after the current cursor position.`` () =
invokeAction { state with Query = "examplequery" } { X = 7; Y = 0 } KillEndOfLine
invokeAction { state with Query = "examplequery" } { X = 7; Y = 0 } [] KillEndOfLine
|> shouldEqual ({ state with Query = "example" }, { X = 7; Y = 0 }, Required)

[<Fact>]
let ``should not change state if the cursor position is at the end of line.`` () =
invokeAction { state with Query = "example" } { X = 7; Y = 0 } KillEndOfLine
invokeAction { state with Query = "example" } { X = 7; Y = 0 } [] KillEndOfLine
|> shouldEqual ({ state with Query = "example" }, { X = 7; Y = 0 }, NotRequired)

let testStateOnly action state expected =
invokeAction state position action
invokeAction state position [] action
|> shouldEqual (expected, position, Required)

module ``with RotateMatcher`` =
Expand Down Expand Up @@ -589,25 +603,161 @@ module invokeAction =
let ``should return a disabled suppress property.`` () = test true false

let noop action =
invokeAction state position action
invokeAction state position [] action
|> shouldEqual (state, position, NotRequired) // TODO: change to false when the action is implemented.

module ``with SelectUp`` =
[<Fact>]
let ``should return any difference when a up-arrow is entered.`` () = noop SelectUp
let ``shouldn't return any difference when a up-arrow is entered.`` () = noop SelectUp

module ``with SelectDown`` =
[<Fact>]
let ``should return any difference when a down-arrow is entered.`` () = noop SelectDown
let ``shouldn't return any difference when a down-arrow is entered.`` () = noop SelectDown

module ``with ScrollPageUp`` =
[<Fact>]
let ``should return any difference when a page-up is entered.`` () = noop ScrollPageUp
let ``shouldn't return any difference when a page-up is entered.`` () = noop ScrollPageUp

module ``with ScrollPageDown`` =
[<Fact>]
let ``should return any difference when a page-down is entered.`` () = noop ScrollPageDown
let ``shouldn't return any difference when a page-down is entered.`` () = noop ScrollPageDown

module ``with TabExpansion`` =
[<Fact>]
let ``should return any difference when a tab is entered.`` () = noop TabExpansion
let ``shouldn't return any difference when a tab is entered with non search mode.`` () =
invokeAction state position [ "name"; "path" ] CompleteProperty
|> shouldEqual (state, position, NotRequired)

[<Fact>]
let ``shouldn't return any difference when a tab is entered with empty properties list.`` () =
let state =
{ state with
Query = ":"
PropertySearch = Search "" }

invokeAction state position [] CompleteProperty
|> shouldEqual (state, position, NotRequired)

[<Fact>]
let ``shouldn't return any difference when a tab is entered and found no property completion.`` () =
let state =
{ state with
Query = ":a"
PropertySearch = Search "a" }

invokeAction state position [ "name"; "path" ] CompleteProperty
|> shouldEqual (state, position, NotRequired)

[<Fact>]
let ``should return completion when a property is found.`` () =
let state =
{ state with
Query = ":p"
PropertySearch = Search "p" }

let position = { position with X = 2 }

invokeAction state position [ "name"; "path" ] CompleteProperty
|> shouldEqual (
{ state with
Query = ":path"
PropertySearch = Rotate("p", 0, [ "path" ]) },
{ position with X = 5 },
Required
)

[<Fact>]
let ``should return completion when some properties are found.`` () =
let state =
{ state with
Query = ":n"
PropertySearch = Search "n" }

let position = { position with X = 2 }

invokeAction state position [ "name"; "path"; "number" ] CompleteProperty
|> shouldEqual (
{ state with
Query = ":name"
PropertySearch = Rotate("n", 0, [ "name"; "number" ]) },
{ position with X = 5 },
Required
)

[<Fact>]
let ``should insert completion to mid of query when a property is found.`` () =
let state =
{ state with
Query = ":n foo"
PropertySearch = Search "n" }

let position = { position with X = 2 }

invokeAction state position [ "name"; "path" ] CompleteProperty
|> shouldEqual (
{ state with
Query = ":name foo"
PropertySearch = Rotate("n", 0, [ "name" ]) },
{ position with X = 5 },
Required
)

[<Fact>]
let ``shouldn't return any difference when a property is already completed.`` () =
let state =
{ state with
Query = ":name"
PropertySearch = Search "name" }

let position = { position with X = 5 }

invokeAction state position [ "name"; "path" ] CompleteProperty
|> shouldEqual ({ state with PropertySearch = Rotate("name", 0, [ "name" ]) }, position, Required)

[<Fact>]
let ``shouldn't return any difference when a property is already completed to mid of query.`` () =
let state =
{ state with
Query = ":name a"
PropertySearch = Search "name" }

let position = { position with X = 5 }

invokeAction state position [ "name"; "path" ] CompleteProperty
|> shouldEqual ({ state with PropertySearch = Rotate("name", 0, [ "name" ]) }, position, Required)

[<Fact>]
let ``should return next property when rotation.`` () =
let state =
{ state with
Query = ":name"
PropertySearch = Rotate("n", 0, [ "name"; "number" ]) }

let position = { position with X = 5 }

invokeAction state position [ "name"; "path"; "number" ] CompleteProperty
|> shouldEqual (
{ state with
Query = ":number"
PropertySearch = Rotate("n", 1, [ "name"; "number" ]) },
{ position with X = 7 },
Required
)

[<Fact>]
let ``should return first property when next rotation not found.`` () =
let state =
{ state with
Query = ":number"
PropertySearch = Rotate("n", 1, [ "name"; "number" ]) }

let position = { position with X = 7 }

invokeAction state position [ "name"; "path"; "number" ] CompleteProperty
|> shouldEqual (
{ state with
Query = ":name"
PropertySearch = Rotate("n", 0, [ "name"; "number" ]) },
{ position with X = 5 },
Required
)
Loading