structure Message : sig datatype mode = ALWAYS | AUTO | NEVER val setColors : mode -> unit val exec : string -> unit val error : string -> unit val warn : string -> unit val diag : string -> unit val info : string -> unit val getVerbosity : unit -> int val beMoreVerbose : unit -> unit val setTypeStyle : ANSIStyle.style -> unit val setExecuteStyle : ANSIStyle.style -> unit val setErrorStyle : ANSIStyle.style -> unit val setWarningStyle : ANSIStyle.style -> unit val setDiagnosticStyle : ANSIStyle.style -> unit val setInformationStyle : ANSIStyle.style -> unit end = struct val () = Lua.setGlobal ("CLUTTEX_VERBOSITY", Lua.fromInt 0) fun getVerbosity () : int = Lua.unsafeFromValue (Lua.global "CLUTTEX_VERBOSITY") fun beMoreVerbose () = let val verbosity = Lua.global "CLUTTEX_VERBOSITY" in Lua.setGlobal ("CLUTTEX_VERBOSITY", Lua.+ (verbosity, Lua.fromInt 1)) end datatype mode = ALWAYS | AUTO | NEVER val useColors = ref false fun setColors ALWAYS = let val isatty = Lua.call1 Lua.Lib.require #[Lua.fromString "texrunner.isatty"] val enableVirtualTerminal = Lua.field (isatty, "enable_virtual_terminal") val stderr = Lua.field (Lua.global "io", "stderr") in useColors := true ; if not (Lua.isFalsy enableVirtualTerminal) then let val succ = Lua.call1 enableVirtualTerminal #[stderr] in if Lua.isFalsy succ andalso getVerbosity () >= 2 then TextIO.output (TextIO.stdErr, "ClutTeX: Failed to enable virtual terminal\n") else () end else () end | setColors AUTO = let val isatty = Lua.call1 Lua.Lib.require #[Lua.fromString "texrunner.isatty"] val enableVirtualTerminal = Lua.field (isatty, "enable_virtual_terminal") val stderr = Lua.field (Lua.global "io", "stderr") val u = not (Lua.isFalsy (Lua.call1 (Lua.field (isatty, "isatty")) #[stderr])) in useColors := u ; if u andalso not (Lua.isFalsy enableVirtualTerminal) then let val succ : bool = Lua.unsafeFromValue (Lua.call1 enableVirtualTerminal #[stderr]) in useColors := succ ; if not succ andalso getVerbosity () >= 2 then TextIO.output (TextIO.stdErr, "ClutTeX: Failed to enable virtual terminal\n") else () end else () end | setColors NEVER = useColors := false structure CMD = struct (* ESCAPE: hex 1B = dec 27 = oct 33 *) val reset = "\027[0m" val underline = "\027[4m" val fg_black = "\027[30m" val fg_red = "\027[31m" val fg_green = "\027[32m" val fg_yellow = "\027[33m" val fg_blue = "\027[34m" val fg_magenta = "\027[35m" val fg_cyan = "\027[36m" val fg_white = "\027[37m" val fg_reset = "\027[39m" val bg_black = "\027[40m" val bg_red = "\027[41m" val bg_green = "\027[42m" val bg_yellow = "\027[43m" val bg_blue = "\027[44m" val bg_magenta = "\027[45m" val bg_cyan = "\027[46m" val bg_white = "\027[47m" val bg_reset = "\027[49m" val fg_x_black = "\027[90m" val fg_x_red = "\027[91m" val fg_x_green = "\027[92m" val fg_x_yellow = "\027[93m" val fg_x_blue = "\027[94m" val fg_x_magenta = "\027[95m" val fg_x_cyan = "\027[96m" val fg_x_white = "\027[97m" val bg_x_black = "\027[100m" val bg_x_red = "\027[101m" val bg_x_green = "\027[102m" val bg_x_yellow = "\027[103m" val bg_x_blue = "\027[104m" val bg_x_magenta = "\027[105m" val bg_x_cyan = "\027[106m" val bg_x_white = "\027[107m" end val typeStyle : string ref = ref (ANSIStyle.toString { foreground = SOME ANSIColor.BRIGHT_WHITE , background = SOME ANSIColor.RED , bold = false , dim = false , underline = false , blink = false , reverse = false , italic = false , strike = false } ) val executeStyle : string ref = ref (ANSIStyle.toString { foreground = SOME ANSIColor.CYAN , background = NONE , bold = false , dim = false , underline = false , blink = false , reverse = false , italic = false , strike = false } ) val errorStyle : string ref = ref (ANSIStyle.toString { foreground = SOME ANSIColor.RED , background = NONE , bold = false , dim = false , underline = false , blink = false , reverse = false , italic = false , strike = false } ) val warningStyle : string ref = ref (ANSIStyle.toString { foreground = SOME ANSIColor.BLUE , background = NONE , bold = false , dim = false , underline = false , blink = false , reverse = false , italic = false , strike = false } ) val diagnosticStyle : string ref = ref (ANSIStyle.toString { foreground = SOME ANSIColor.BLUE , background = NONE , bold = false , dim = false , underline = false , blink = false , reverse = false , italic = false , strike = false } ) val informationStyle : string ref = ref (ANSIStyle.toString { foreground = SOME ANSIColor.MAGENTA , background = NONE , bold = false , dim = false , underline = false , blink = false , reverse = false , italic = false , strike = false } ) fun setTypeStyle style = typeStyle := ANSIStyle.toString style fun setExecuteStyle style = executeStyle := ANSIStyle.toString style fun setErrorStyle style = errorStyle := ANSIStyle.toString style fun setWarningStyle style = warningStyle := ANSIStyle.toString style fun setDiagnosticStyle style = diagnosticStyle := ANSIStyle.toString style fun setInformationStyle style = informationStyle := ANSIStyle.toString style fun exec commandline = if !useColors then TextIO.output (TextIO.stdErr, !typeStyle ^ "[EXEC]" ^ ANSIStyle.resetAll ^ " " ^ !executeStyle ^ commandline ^ ANSIStyle.resetAll ^ "\n") else TextIO.output (TextIO.stdErr, "[EXEC] " ^ commandline ^ "\n") fun error message = if !useColors then TextIO.output (TextIO.stdErr, !typeStyle ^ "[ERROR]" ^ ANSIStyle.resetAll ^ " " ^ !errorStyle ^ message ^ ANSIStyle.resetAll ^ "\n") else TextIO.output (TextIO.stdErr, "[ERROR] " ^ message ^ "\n") fun warn message = if !useColors then TextIO.output (TextIO.stdErr, !typeStyle ^ "[WARN]" ^ ANSIStyle.resetAll ^ " " ^ !warningStyle ^ message ^ ANSIStyle.resetAll ^ "\n") else TextIO.output (TextIO.stdErr, "[WARN] " ^ message ^ "\n") fun diag message = if !useColors then TextIO.output (TextIO.stdErr, !typeStyle ^ "[DIAG]" ^ ANSIStyle.resetAll ^ " " ^ !diagnosticStyle ^ message ^ ANSIStyle.resetAll ^ "\n") else TextIO.output (TextIO.stdErr, "[DIAG] " ^ message ^ "\n") fun info message = if !useColors then TextIO.output (TextIO.stdErr, !typeStyle ^ "[INFO]" ^ ANSIStyle.resetAll ^ " " ^ !informationStyle ^ message ^ ANSIStyle.resetAll ^ "\n") else TextIO.output (TextIO.stdErr, "[INFO] " ^ message ^ "\n") end;