diff --git a/Fake.sln b/Fake.sln
index 7f3bb45d9a1..5d5de8a67c8 100644
--- a/Fake.sln
+++ b/Fake.sln
@@ -154,7 +154,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "template", "template", "{87
EndProject
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "fake-template", "src\template\fake-template\fake-template.fsproj", "{29B66A06-1A45-4D65-AC31-7D746449E5D6}"
EndProject
-Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Fake.DotNet.Cli.IntegrationTests", "src\test\Fake.DotNet.Cli.IntegrationTests\Fake.DotNet.Cli.IntegrationTests.fsproj", "{48ECC58D-468C-4D44-98B3-854C21EB0D40}"
+Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "Fake.DotNet.Cli.IntegrationTests", "src\test\Fake.DotNet.Cli.IntegrationTests\Fake.DotNet.Cli.IntegrationTests.fsproj", "{48ECC58D-468C-4D44-98B3-854C21EB0D40}"
+EndProject
+Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "Fake.Core.UserInput", "src\app\Fake.Core.UserInput\Fake.Core.UserInput.fsproj", "{3B0A5EE3-6696-4EBA-BCF9-8136C7F17040}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -958,6 +960,18 @@ Global
{48ECC58D-468C-4D44-98B3-854C21EB0D40}.Release|x64.Build.0 = Release|Any CPU
{48ECC58D-468C-4D44-98B3-854C21EB0D40}.Release|x86.ActiveCfg = Release|Any CPU
{48ECC58D-468C-4D44-98B3-854C21EB0D40}.Release|x86.Build.0 = Release|Any CPU
+ {3B0A5EE3-6696-4EBA-BCF9-8136C7F17040}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {3B0A5EE3-6696-4EBA-BCF9-8136C7F17040}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {3B0A5EE3-6696-4EBA-BCF9-8136C7F17040}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {3B0A5EE3-6696-4EBA-BCF9-8136C7F17040}.Debug|x64.Build.0 = Debug|Any CPU
+ {3B0A5EE3-6696-4EBA-BCF9-8136C7F17040}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {3B0A5EE3-6696-4EBA-BCF9-8136C7F17040}.Debug|x86.Build.0 = Debug|Any CPU
+ {3B0A5EE3-6696-4EBA-BCF9-8136C7F17040}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {3B0A5EE3-6696-4EBA-BCF9-8136C7F17040}.Release|Any CPU.Build.0 = Release|Any CPU
+ {3B0A5EE3-6696-4EBA-BCF9-8136C7F17040}.Release|x64.ActiveCfg = Release|Any CPU
+ {3B0A5EE3-6696-4EBA-BCF9-8136C7F17040}.Release|x64.Build.0 = Release|Any CPU
+ {3B0A5EE3-6696-4EBA-BCF9-8136C7F17040}.Release|x86.ActiveCfg = Release|Any CPU
+ {3B0A5EE3-6696-4EBA-BCF9-8136C7F17040}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -1031,6 +1045,7 @@ Global
{872B282D-8A3E-459A-B63D-C43C5D73506D} = {539D7B9A-18A1-4D79-86AB-C8B48090CA84}
{29B66A06-1A45-4D65-AC31-7D746449E5D6} = {872B282D-8A3E-459A-B63D-C43C5D73506D}
{48ECC58D-468C-4D44-98B3-854C21EB0D40} = {E09B72E4-D890-46A8-8D14-7367C2E23E9D}
+ {3B0A5EE3-6696-4EBA-BCF9-8136C7F17040} = {7BFFAE76-DEE9-417A-A79B-6A6644C4553A}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {058A0C5E-2216-4306-8AFB-0AE28320C26A}
diff --git a/build.fsx b/build.fsx
index a5d9c996319..824aff04f14 100644
--- a/build.fsx
+++ b/build.fsx
@@ -346,6 +346,7 @@ let dotnetAssemblyInfos =
"Fake.Core.Target", "Defining and running Targets"
"Fake.Core.Tasks", "Repeating and managing Tasks"
"Fake.Core.Trace", "Core Logging functionality"
+ "Fake.Core.UserInput", "User input helpers"
"Fake.Core.Xml", "Core Xml functionality"
"Fake.Documentation.DocFx", "Documentation with DocFx"
"Fake.DotNet.AssemblyInfoFile", "Writing AssemblyInfo files"
diff --git a/help/templates/template.cshtml b/help/templates/template.cshtml
index 4ce5242b6cd..5d066a0ee35 100644
--- a/help/templates/template.cshtml
+++ b/help/templates/template.cshtml
@@ -114,6 +114,7 @@
Tasks
ReleaseNotes
ChangeLog
+ UserInput
diff --git a/src/app/Fake.Core.UserInput/AssemblyInfo.fs b/src/app/Fake.Core.UserInput/AssemblyInfo.fs
new file mode 100644
index 00000000000..64cbeba6324
--- /dev/null
+++ b/src/app/Fake.Core.UserInput/AssemblyInfo.fs
@@ -0,0 +1,17 @@
+// Auto-Generated by FAKE; do not edit
+namespace System
+open System.Reflection
+
+[]
+[]
+[]
+[]
+[]
+do ()
+
+module internal AssemblyVersionInformation =
+ let [] AssemblyTitle = "FAKE - F# Make User input helpers"
+ let [] AssemblyProduct = "FAKE - F# Make"
+ let [] AssemblyVersion = "5.1"
+ let [] AssemblyInformationalVersion = "5.1.0-alpha.1"
+ let [] AssemblyFileVersion = "5.1.0"
diff --git a/src/app/Fake.Core.UserInput/Fake.Core.UserInput.fsproj b/src/app/Fake.Core.UserInput/Fake.Core.UserInput.fsproj
new file mode 100644
index 00000000000..9b190f196a2
--- /dev/null
+++ b/src/app/Fake.Core.UserInput/Fake.Core.UserInput.fsproj
@@ -0,0 +1,18 @@
+
+
+ net46;netstandard1.6;netstandard2.0
+ Fake.Core.UserInput
+ Library
+
+
+ $(DefineConstants);DOTNETCORE
+
+
+ $(DefineConstants);RELEASE
+
+
+
+
+
+
+
diff --git a/src/app/Fake.Core.UserInput/UserInput.fs b/src/app/Fake.Core.UserInput/UserInput.fs
new file mode 100644
index 00000000000..24f62835a28
--- /dev/null
+++ b/src/app/Fake.Core.UserInput/UserInput.fs
@@ -0,0 +1,63 @@
+namespace Fake.Core
+open System
+
+/// Helpers for capturing user input
+///
+/// ## Sample
+///
+/// UserInput.getUserInput prompt
+[]
+module UserInput =
+ let internal erasePreviousChar () =
+ try
+ let left = if Console.CursorLeft <> 0 then Console.CursorLeft-1 else Console.BufferWidth-1
+ let top = if Console.CursorLeft <> 0 then Console.CursorTop else Console.CursorTop-1
+
+ Console.SetCursorPosition(left, top)
+ Console.Write(' ')
+ Console.SetCursorPosition(left, top)
+ with
+ | :? IO.IOException ->
+ // Console is dumb, might be redirected. We don't care,
+ // if it isn't a screen the visual feedback isn't required
+ ()
+
+ let internal readString (echo: bool) : string =
+ let rec loop cs =
+ let key = Console.ReadKey(true)
+ match (key.Key, cs) with
+ | (ConsoleKey.Backspace, []) -> loop []
+ | (ConsoleKey.Backspace, _::cs) ->
+ erasePreviousChar ()
+ loop cs
+ | (ConsoleKey.Enter, _) -> cs
+ | _ ->
+ if echo then Console.Write(key.KeyChar) else Console.Write('*')
+ loop (key.KeyChar :: cs)
+
+ loop []
+ |> List.rev
+ |> Array.ofList
+ |> fun cs -> new String(cs)
+
+ let internal color (color: ConsoleColor) (code : unit -> _) =
+ let before = Console.ForegroundColor
+ try
+ Console.ForegroundColor <- color
+ code ()
+ finally
+ Console.ForegroundColor <- before
+
+
+ let getUserInput prompt =
+ color ConsoleColor.White (fun _ -> printf "%s" prompt)
+ let s = readString true
+ printfn ""
+ s
+
+
+ let getUserPassword prompt =
+ color ConsoleColor.White (fun _ -> printf "%s" prompt)
+ let s = readString false
+ printfn ""
+ s
diff --git a/src/app/Fake.Core.UserInput/paket.references b/src/app/Fake.Core.UserInput/paket.references
new file mode 100644
index 00000000000..33b67482336
--- /dev/null
+++ b/src/app/Fake.Core.UserInput/paket.references
@@ -0,0 +1,3 @@
+group netcore
+
+NETStandard.Library
\ No newline at end of file
diff --git a/src/legacy/FakeLib/FakeLib.fsproj b/src/legacy/FakeLib/FakeLib.fsproj
index 7a75e8688f8..47594a742de 100644
--- a/src/legacy/FakeLib/FakeLib.fsproj
+++ b/src/legacy/FakeLib/FakeLib.fsproj
@@ -209,6 +209,9 @@
Fake.Core.Target/TargetOperators.fs
+
+ Fake.Core.UserInput/UserInput.fs
+
Fake.DotNet.MSBuild/MSBuildLogger.fs
@@ -3393,4 +3396,4 @@
-
+
\ No newline at end of file
diff --git a/src/legacy/FakeLib/UserInputHelper.fs b/src/legacy/FakeLib/UserInputHelper.fs
index 73908d25ec4..7ac0a7f4b26 100644
--- a/src/legacy/FakeLib/UserInputHelper.fs
+++ b/src/legacy/FakeLib/UserInputHelper.fs
@@ -1,5 +1,5 @@
[]
-[]
+[]
/// This module contains functions which allow to interactively input values
module Fake.UserInputHelper
@@ -46,7 +46,7 @@ let internal color (color: ConsoleColor) (code : unit -> _) =
Console.ForegroundColor <- before
/// Return a string entered by the user followed by enter. The input is echoed to the screen.
-[]
+[]
let getUserInput prompt =
color ConsoleColor.White (fun _ -> printf "%s" prompt)
let s = readString true
@@ -54,7 +54,7 @@ let getUserInput prompt =
s
/// Return a string entered by the user followed by enter. The input is replaced by '*' on the screen.
-[]
+[]
let getUserPassword prompt =
color ConsoleColor.White (fun _ -> printf "%s" prompt)
let s = readString false