From 3ea3e416b482b4ca6400b7640ba0fb008ba81add Mon Sep 17 00:00:00 2001 From: Swoorup Joshi Date: Thu, 3 Dec 2020 19:45:02 +1100 Subject: [PATCH 1/4] Allow moving cursor by prev/next words --- src/fsharp/fsi/console.fs | 43 +++++++++++++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 8 deletions(-) diff --git a/src/fsharp/fsi/console.fs b/src/fsharp/fsi/console.fs index ca73d4e121c..d6e56f0cb7f 100644 --- a/src/fsharp/fsi/console.fs +++ b/src/fsharp/fsi/console.fs @@ -118,6 +118,20 @@ module internal Utils = | None -> failwith "Internal Error: cannot bind to method" | Some methInfo -> methInfo + let rec previousWordFromIdx (line: string) (idx, isInWord) = + if idx < 0 then 0 else + match line.Chars(idx), isInWord with + | ' ', true -> idx + 1 + | ' ', false -> previousWordFromIdx line (idx - 1, false) + | _, _ -> previousWordFromIdx line (idx - 1, true) + + let rec nextWordFromIdx (line: string) (idx, isInWord) = + if idx >= line.Length - 1 then line.Length - 1 else + match line.Chars(idx), isInWord with + | ' ', true -> idx - 1 + | ' ', false -> nextWordFromIdx line (idx + 1, false) + | _, _ -> nextWordFromIdx line (idx + 1, true) + [] type internal Cursor = static member ResetTo(top,left) = @@ -304,6 +318,18 @@ type internal ReadLineConsole() = let c = input.Chars(current) current <- current + 1 Cursor.Move(x.Inset, x.GetCharacterSize(c)) + + let moveWordLeft() = + if (current > 0 && (current - 1 < input.Length)) then + let line = input.ToString() + current <- Utils.previousWordFromIdx line (current - 1, false) + anchor.PlaceAt(x.Inset, current) + + let moveWordRight() = + if (current < input.Length) then + let line = input.ToString() + current <- Utils.nextWordFromIdx line (current + 1, false) + anchor.PlaceAt(x.Inset, current) let setInput(line:string) = input.Length <- 0 @@ -346,14 +372,7 @@ type internal ReadLineConsole() = let deleteWordLeadingToCursor() = if (input.Length > 0 && current > 0) then let line = input.ToString() - let rec prevWord (idx, isInWord) = - if idx < 0 then 0 else - match line.Chars(idx), isInWord with - | ' ', true -> idx + 1 - | ' ', false -> prevWord (idx - 1, false) - | _, _ -> prevWord (idx - 1, true) - - let idx = prevWord (current - 1, false) + let idx = Utils.previousWordFromIdx line (current - 1, false) input.Remove(idx, current - idx) |> ignore current <- idx render() @@ -455,6 +474,14 @@ type internal ReadLineConsole() = | (ConsoleModifiers.Control, ConsoleKey.F) -> moveRight() change () + | (ConsoleModifiers.Control, ConsoleKey.LeftArrow) + | (ConsoleModifiers.Alt, ConsoleKey.B) -> + moveWordLeft() + change () + | (ConsoleModifiers.Control, ConsoleKey.RightArrow) + | (ConsoleModifiers.Alt, ConsoleKey.F) -> + moveWordRight() + change () | (ConsoleModifiers.Control, ConsoleKey.K) -> deleteToEndOfLine() change() From d237e6dfbaef79f267009ede632012962abdad79 Mon Sep 17 00:00:00 2001 From: Swoorup Joshi Date: Thu, 3 Dec 2020 20:12:16 +1100 Subject: [PATCH 2/4] Allow moving to new cursor position at the end of line --- src/fsharp/fsi/console.fs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/fsharp/fsi/console.fs b/src/fsharp/fsi/console.fs index d6e56f0cb7f..4a9231e1cae 100644 --- a/src/fsharp/fsi/console.fs +++ b/src/fsharp/fsi/console.fs @@ -126,7 +126,7 @@ module internal Utils = | _, _ -> previousWordFromIdx line (idx - 1, true) let rec nextWordFromIdx (line: string) (idx, isInWord) = - if idx >= line.Length - 1 then line.Length - 1 else + if idx >= line.Length then line.Length - 1 else match line.Chars(idx), isInWord with | ' ', true -> idx - 1 | ' ', false -> nextWordFromIdx line (idx + 1, false) @@ -328,7 +328,13 @@ type internal ReadLineConsole() = let moveWordRight() = if (current < input.Length) then let line = input.ToString() - current <- Utils.nextWordFromIdx line (current + 1, false) + let idxToMoveTo = Utils.nextWordFromIdx line (current + 1, false) + + // if has reached end of the last word + if idxToMoveTo = current && current < line.Length + then current <- line.Length + else current <- idxToMoveTo + anchor.PlaceAt(x.Inset, current) let setInput(line:string) = From e88fc4ac69fc7615eaba0b269b727a3783ac7ffa Mon Sep 17 00:00:00 2001 From: Swoorup Joshi Date: Fri, 4 Dec 2020 10:59:58 +1100 Subject: [PATCH 3/4] Move cursor to the end of the word --- src/fsharp/fsi/console.fs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fsharp/fsi/console.fs b/src/fsharp/fsi/console.fs index 4a9231e1cae..7d40dfc3952 100644 --- a/src/fsharp/fsi/console.fs +++ b/src/fsharp/fsi/console.fs @@ -128,7 +128,7 @@ module internal Utils = let rec nextWordFromIdx (line: string) (idx, isInWord) = if idx >= line.Length then line.Length - 1 else match line.Chars(idx), isInWord with - | ' ', true -> idx - 1 + | ' ', true -> idx | ' ', false -> nextWordFromIdx line (idx + 1, false) | _, _ -> nextWordFromIdx line (idx + 1, true) From 5740b02a9336a2d8f307b7467231a5ab1a72b856 Mon Sep 17 00:00:00 2001 From: Swoorup Joshi Date: Fri, 4 Dec 2020 11:08:47 +1100 Subject: [PATCH 4/4] Try fixing Ctrl+Left/Right on windows --- src/fsharp/fsi/console.fs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/fsharp/fsi/console.fs b/src/fsharp/fsi/console.fs index 7d40dfc3952..13276b9ced8 100644 --- a/src/fsharp/fsi/console.fs +++ b/src/fsharp/fsi/console.fs @@ -449,10 +449,10 @@ type internal ReadLineConsole() = | ConsoleKey.DownArrow -> setInput(history.Next()) change() - | ConsoleKey.RightArrow -> + | ConsoleKey.RightArrow when key.Modifiers &&& ConsoleModifiers.Control = enum 0 -> moveRight() change() - | ConsoleKey.LeftArrow -> + | ConsoleKey.LeftArrow when key.Modifiers &&& ConsoleModifiers.Control = enum 0 -> moveLeft() change() | ConsoleKey.Escape ->