diff --git a/src/BlackFox.ColoredPrintf/BlackFox.ColoredPrintf.fsproj b/src/BlackFox.ColoredPrintf/BlackFox.ColoredPrintf.fsproj
index 49078dd..1591cb0 100644
--- a/src/BlackFox.ColoredPrintf/BlackFox.ColoredPrintf.fsproj
+++ b/src/BlackFox.ColoredPrintf/BlackFox.ColoredPrintf.fsproj
@@ -57,9 +57,10 @@
-
+
+
diff --git a/src/BlackFox.ColoredPrintf/ColoredPrintf.fs b/src/BlackFox.ColoredPrintf/ColoredPrintf.fs
index c3db0ce..6397ba7 100644
--- a/src/BlackFox.ColoredPrintf/ColoredPrintf.fs
+++ b/src/BlackFox.ColoredPrintf/ColoredPrintf.fs
@@ -1,120 +1,61 @@
-[]
-module BlackFox.ColoredPrintf.ColoredWriter
+[]
+[]
+module BlackFox.ColoredPrintf.ColoredPrintf
open System
-open System.Text
-
-type IColoredPrinterEnv =
- abstract Write : string -> unit
- abstract Foreground : ConsoleColor with get,set
- abstract Background : ConsoleColor with get,set
-
-type WriterStatus = | Normal | Foreground | Background | Escaping
-type WriterState = {
- mutable Colors: (ConsoleColor * ConsoleColor) list
- mutable Status: WriterStatus
- CurrentText: StringBuilder
- mutable WipForeground: ConsoleColor option
-}
-
-let getEmptyState (foreground: ConsoleColor) (background: ConsoleColor) = {
- Colors = [foreground, background]
- Status = WriterStatus.Normal
- CurrentText = StringBuilder()
- WipForeground = None
-}
-
-module private StateHelpers =
- open ColorStrings
- let inline clearText (state: WriterState) = ignore(state.CurrentText.Clear())
- let inline appendChar (c: char) (state: WriterState) = ignore(state.CurrentText.Append(c))
-
- let inline writeCurrentTextToEnv (env: IColoredPrinterEnv) (state: WriterState) =
- if state.CurrentText.Length > 0 then
- env.Write (state.CurrentText.ToString())
- state |> clearText
-
- let inline getColor (state: WriterState) =
- let colorText = state.CurrentText.ToString()
- state |> clearText
- colorNameToColor colorText
-
-open StateHelpers
-
-let inline writeChar (env: IColoredPrinterEnv) (c: char) (state: WriterState) =
- match state.Status with
- | WriterStatus.Normal when c = '$' ->
- writeCurrentTextToEnv env state
- state.Status <- WriterStatus.Foreground
- | WriterStatus.Normal when c = ']' ->
- match state.Colors with
- | [] -> failwith "Unexpected, no colors in stack"
- | [_] -> state |> appendChar c
- | (currentFg, currentBg) :: (previousFg, previousBg) :: rest ->
- writeCurrentTextToEnv env state
- state.Colors <- (previousFg, previousBg) :: rest
- if currentFg <> previousFg then env.Foreground <- previousFg
- if currentBg <> previousBg then env.Background <- previousBg
- | WriterStatus.Normal when c = '\\' -> state.Status <- WriterStatus.Escaping
- | WriterStatus.Normal -> state |> appendChar c
- | WriterStatus.Escaping when c = '$' || c = ']' ->
- state |> appendChar c
- state.Status <- WriterStatus.Normal
- | WriterStatus.Escaping ->
- state |> appendChar '\\'
- state |> appendChar c
- state.Status <- WriterStatus.Normal
- | WriterStatus.Foreground when c = ';' ->
- match getColor state with
- | Some c -> state.WipForeground <- Some c
- | None -> ()
- state.Status <- WriterStatus.Background
- | WriterStatus.Foreground when c = '[' ->
- let (currentFg, currentBg) = state.Colors.Head
- match getColor state with
- | Some c ->
- if currentFg <> c then env.Foreground <- c
- state.Colors <- (c, currentBg) :: state.Colors
- | None ->
- state.Colors <- state.Colors.Head :: state.Colors
- state.Status <- WriterStatus.Normal
- | WriterStatus.Foreground -> state |> appendChar c
- | WriterStatus.Background when c = '[' ->
- let (currentFg, currentBg) = state.Colors.Head
-
- let fg = defaultArg state.WipForeground currentFg
- let bg = defaultArg (getColor state) currentBg
-
- state.WipForeground <- None
+open BlackFox.MasterOfFoo
+open BlackFox.ColoredPrintf.ColoredWriter
+
+type private ConsoleColoredPrinterEnv() =
+ let mutable fg = ConsoleColor.White
+ let mutable bg = ConsoleColor.Black
+ let mutable colorDisabled = false
+ let wrap f =
+ if not colorDisabled then
+ try f()
+ with | _ -> colorDisabled <- true
+
+ do
+ wrap (fun _ ->
+ fg <- Console.ForegroundColor
+ bg <- Console.BackgroundColor)
+
+ interface ColoredWriter.IColoredPrinterEnv with
+ member __.Write (s: string) = Console.Write(s)
+ member __.Foreground
+ with get () = fg
+ and set c =
+ fg <- c
+ wrap(fun _ -> Console.ForegroundColor <- c)
+ member __.Background
+ with get () = bg
+ and set c =
+ bg <- c
+ wrap(fun _ -> Console.BackgroundColor <- c)
+
+type private ColoredConsolePrintEnv<'Result>(k) =
+ inherit PrintfEnv()
+
+ let env = ConsoleColoredPrinterEnv() :> ColoredWriter.IColoredPrinterEnv
+ let state = getEmptyState env.Foreground env.Background
+
+ override __.Finalize() : 'Result =
+ state |> finish env
+ k()
+
+ override __.Write(s : PrintableElement) =
+ match s.ElementType with
+ | PrintableElementType.FromFormatSpecifier -> env.Write(s.FormatAsPrintF())
+ | _ -> state |> writeString env (s.FormatAsPrintF())
+
+ override __.WriteT(s : string) =
+ env.Write(s)
- if currentFg <> fg then env.Foreground <- fg
- if currentBg <> bg then env.Background <- bg
+type ColorPrintFormat<'T> = Format<'T, unit, string, unit>
- state.Colors <- (fg, bg) :: state.Colors
- state.Status <- WriterStatus.Normal
- | WriterStatus.Background -> state |> appendChar c
-
-let inline writeString (env: IColoredPrinterEnv) (s: string) (state: WriterState) =
- for i in 0..s.Length-1 do
- state |> writeChar env (s.[i])
+let colorprintf<'T> (format: ColorPrintFormat<'T>) =
+ doPrintfFromEnv format (ColoredConsolePrintEnv(id))
-let inline finish (env: IColoredPrinterEnv) (state: WriterState) =
- match state.Status with
- | WriterStatus.Normal ->
- writeCurrentTextToEnv env state
- | WriterStatus.Escaping ->
- state |> appendChar '\\'
- writeCurrentTextToEnv env state
- | WriterStatus.Foreground -> ()
- | WriterStatus.Background -> ()
-
-let writeCompleteString (env: IColoredPrinterEnv) (s: string) =
- let initialFg = env.Foreground
- let initialBg = env.Background
-
- let state = getEmptyState initialFg initialBg
- state |> writeString env s
-
- state |> finish env
- if initialFg <> env.Foreground then env.Foreground <- initialFg
- if initialBg <> env.Background then env.Background <- initialBg
+let colorprintfn<'T> (format: ColorPrintFormat<'T>) =
+ let writeLine () = Console.WriteLine()
+ doPrintfFromEnv format (ColoredConsolePrintEnv(writeLine))
diff --git a/src/BlackFox.ColoredPrintf/ColoredWriter.fs b/src/BlackFox.ColoredPrintf/ColoredWriter.fs
new file mode 100644
index 0000000..77d0ee8
--- /dev/null
+++ b/src/BlackFox.ColoredPrintf/ColoredWriter.fs
@@ -0,0 +1,117 @@
+module BlackFox.ColoredPrintf.ColoredWriter
+
+open System
+open System.Text
+
+type IColoredPrinterEnv =
+ abstract Write : string -> unit
+ abstract Foreground : ConsoleColor with get,set
+ abstract Background : ConsoleColor with get,set
+
+type WriterStatus = | Normal | Foreground | Background | Escaping
+type WriterState = {
+ mutable Colors: (ConsoleColor * ConsoleColor) list
+ mutable Status: WriterStatus
+ CurrentText: StringBuilder
+ mutable WipForeground: ConsoleColor option
+}
+
+let getEmptyState (foreground: ConsoleColor) (background: ConsoleColor) = {
+ Colors = [foreground, background]
+ Status = WriterStatus.Normal
+ CurrentText = StringBuilder()
+ WipForeground = None
+}
+
+module private StateHelpers =
+ open ColorStrings
+ let inline clearText (state: WriterState) = ignore(state.CurrentText.Clear())
+ let inline appendChar (c: char) (state: WriterState) = ignore(state.CurrentText.Append(c))
+
+ let inline writeCurrentTextToEnv (env: IColoredPrinterEnv) (state: WriterState) =
+ if state.CurrentText.Length > 0 then
+ env.Write (state.CurrentText.ToString())
+ state |> clearText
+
+ let inline getColor (state: WriterState) =
+ let colorText = state.CurrentText.ToString()
+ state |> clearText
+ colorNameToColor colorText
+
+open StateHelpers
+
+let inline writeChar (env: IColoredPrinterEnv) (c: char) (state: WriterState) =
+ match state.Status with
+ | WriterStatus.Normal when c = '$' ->
+ writeCurrentTextToEnv env state
+ state.Status <- WriterStatus.Foreground
+ | WriterStatus.Normal when c = ']' ->
+ match state.Colors with
+ | [] -> failwith "Unexpected, no colors in stack"
+ | [_] -> state |> appendChar c
+ | (currentFg, currentBg) :: (previousFg, previousBg) :: rest ->
+ writeCurrentTextToEnv env state
+ state.Colors <- (previousFg, previousBg) :: rest
+ if currentFg <> previousFg then env.Foreground <- previousFg
+ if currentBg <> previousBg then env.Background <- previousBg
+ | WriterStatus.Normal when c = '\\' -> state.Status <- WriterStatus.Escaping
+ | WriterStatus.Normal -> state |> appendChar c
+ | WriterStatus.Escaping when c = '$' || c = ']' ->
+ state |> appendChar c
+ state.Status <- WriterStatus.Normal
+ | WriterStatus.Escaping ->
+ state |> appendChar '\\'
+ state |> appendChar c
+ state.Status <- WriterStatus.Normal
+ | WriterStatus.Foreground when c = ';' ->
+ match getColor state with
+ | Some c -> state.WipForeground <- Some c
+ | None -> ()
+ state.Status <- WriterStatus.Background
+ | WriterStatus.Foreground when c = '[' ->
+ let (currentFg, currentBg) = state.Colors.Head
+ match getColor state with
+ | Some c ->
+ if currentFg <> c then env.Foreground <- c
+ state.Colors <- (c, currentBg) :: state.Colors
+ | None ->
+ state.Colors <- state.Colors.Head :: state.Colors
+ state.Status <- WriterStatus.Normal
+ | WriterStatus.Foreground -> state |> appendChar c
+ | WriterStatus.Background when c = '[' ->
+ let (currentFg, currentBg) = state.Colors.Head
+
+ let fg = defaultArg state.WipForeground currentFg
+ let bg = defaultArg (getColor state) currentBg
+
+ state.WipForeground <- None
+
+ if currentFg <> fg then env.Foreground <- fg
+ if currentBg <> bg then env.Background <- bg
+
+ state.Colors <- (fg, bg) :: state.Colors
+ state.Status <- WriterStatus.Normal
+ | WriterStatus.Background -> state |> appendChar c
+
+let inline writeString (env: IColoredPrinterEnv) (s: string) (state: WriterState) =
+ for i in 0..s.Length-1 do
+ state |> writeChar env (s.[i])
+
+let inline finish (env: IColoredPrinterEnv) (state: WriterState) =
+ match state.Status with
+ | WriterStatus.Normal ->
+ writeCurrentTextToEnv env state
+ | WriterStatus.Escaping ->
+ state |> appendChar '\\'
+ writeCurrentTextToEnv env state
+ | WriterStatus.Foreground -> ()
+ | WriterStatus.Background -> ()
+
+ let (initialFg, initialBg) = state.Colors |> List.last
+ if initialFg <> env.Foreground then env.Foreground <- initialFg
+ if initialBg <> env.Background then env.Background <- initialBg
+
+let writeCompleteString (env: IColoredPrinterEnv) (s: string) =
+ let state = getEmptyState (env.Foreground) (env.Background)
+ state |> writeString env s
+ state |> finish env
\ No newline at end of file
diff --git a/src/TestApp/Program.fs b/src/TestApp/Program.fs
index 2bcf7f9..a533f14 100644
--- a/src/TestApp/Program.fs
+++ b/src/TestApp/Program.fs
@@ -1,7 +1,8 @@
-// Learn more about F# at http://fsharp.org
-// See the 'F# Tutorial' project for more help.
+open System
+open BlackFox.ColoredPrintf
[]
let main argv =
- printfn "%A" argv
+ colorprintfn "$white;blue[%s ]$black;white[%s ]$white;red[%s]" "La vie" "est" "belle"
+ ignore(Console.ReadLine())
0 // return an integer exit code
diff --git a/src/TestApp/TestApp.fsproj b/src/TestApp/TestApp.fsproj
index dba095d..ed78392 100644
--- a/src/TestApp/TestApp.fsproj
+++ b/src/TestApp/TestApp.fsproj
@@ -52,6 +52,13 @@
+
+
+ BlackFox.ColoredPrintf
+ {860e1cc6-a7f8-4bc2-9a6c-ebe93360ece1}
+ True
+
+
11