Pudu programming language
Menu
Package

@chrismichaelps / pudu-lang-log

Structured event logging for Pudu: message templates, enrichment, filtering, formatting, and sinks

0.1.0Apache-2.01

InstallClose

Theme.pudu

Pudu162 lines4.7 KB

GitHub ↗
1/** @Log.Sinks.Theme.Palette — terminal colours for each kind of text */2module PuduLangLog.Sinks.Theme34import PuduLangLog.Domain.Display as Display5import PuduLangLog as Log67/** @Log.Sinks.Theme.Palette — the escape sequence that starts each style */8export type Theme = {9  text: Str,10  secondary: Str,11  tertiary: Str,12  invalid: Str,13  nullValue: Str,14  name: Str,15  string: Str,16  number: Str,17  boolean: Str,18  scalar: Str,19  verbose: Str,20  debug: Str,21  information: Str,22  warning: Str,23  error: Str,24  fatal: Str25}2627/// The sequence that ends a styled piece.28const RESET: Str = "\u{1b}[0m"2930/// A theme that writes no escape sequences.31export fn none() -> Theme {32  Theme{text: "", secondary: "", tertiary: "", invalid: "", nullValue: "", name: "", string: "", number: "", boolean: "", scalar: "", verbose: "", debug: "", information: "", warning: "", error: "", fatal: ""}33}3435/// Bright text on a dark terminal, with values coloured by kind: the default console theme.36export fn literate() -> Theme {37  Theme {38    text: "\u{1b}[38;5;0015m",39    secondary: "\u{1b}[38;5;0007m",40    tertiary: "\u{1b}[38;5;0008m",41    invalid: "\u{1b}[38;5;0011m",42    nullValue: "\u{1b}[38;5;0027m",43    name: "\u{1b}[38;5;0007m",44    string: "\u{1b}[38;5;0045m",45    number: "\u{1b}[38;5;0200m",46    boolean: "\u{1b}[38;5;0027m",47    scalar: "\u{1b}[38;5;0085m",48    verbose: "\u{1b}[38;5;0007m",49    debug: "\u{1b}[38;5;0007m",50    information: "\u{1b}[38;5;0015m",51    warning: "\u{1b}[38;5;0011m",52    error: "\u{1b}[38;5;0015m\u{1b}[48;5;0196m",53    fatal: "\u{1b}[38;5;0015m\u{1b}[48;5;0196m"54  }55}5657/// Shades of grey only, with warnings and errors inverted.58export fn grayscale() -> Theme {59  Theme {60    text: "\u{1b}[37;1m",61    secondary: "\u{1b}[37m",62    tertiary: "\u{1b}[30;1m",63    invalid: "\u{1b}[37;1m\u{1b}[47m",64    nullValue: "\u{1b}[1m\u{1b}[37;1m",65    name: "\u{1b}[37m",66    string: "\u{1b}[1m\u{1b}[37;1m",67    number: "\u{1b}[1m\u{1b}[37;1m",68    boolean: "\u{1b}[1m\u{1b}[37;1m",69    scalar: "\u{1b}[1m\u{1b}[37;1m",70    verbose: "\u{1b}[30;1m",71    debug: "\u{1b}[30;1m",72    information: "\u{1b}[37;1m",73    warning: "\u{1b}[37;1m\u{1b}[47m",74    error: "\u{1b}[30m\u{1b}[47m",75    fatal: "\u{1b}[30m\u{1b}[47m"76  }77}7879/// Muted colours in the manner of a code editor.80export fn code() -> Theme {81  Theme {82    text: "\u{1b}[38;5;0253m",83    secondary: "\u{1b}[38;5;0246m",84    tertiary: "\u{1b}[38;5;0242m",85    invalid: "\u{1b}[33;1m",86    nullValue: "\u{1b}[38;5;0038m",87    name: "\u{1b}[38;5;0081m",88    string: "\u{1b}[38;5;0216m",89    number: "\u{1b}[38;5;151m",90    boolean: "\u{1b}[38;5;0038m",91    scalar: "\u{1b}[38;5;0079m",92    verbose: "\u{1b}[37m",93    debug: "\u{1b}[37m",94    information: "\u{1b}[37;1m",95    warning: "\u{1b}[38;5;0229m",96    error: "\u{1b}[38;5;0197m\u{1b}[48;5;0238m",97    fatal: "\u{1b}[38;5;0197m\u{1b}[48;5;0238m"98  }99}100101/// The sixteen basic colours, for terminals without a 256-colour palette.102export fn sixteen() -> Theme {103  Theme {104    text: "",105    secondary: "",106    tertiary: "",107    invalid: "\u{1b}[33m",108    nullValue: "\u{1b}[34m",109    name: "",110    string: "\u{1b}[36m",111    number: "\u{1b}[35m",112    boolean: "\u{1b}[34m",113    scalar: "\u{1b}[32m",114    verbose: "",115    debug: "\u{1b}[1m",116    information: "\u{1b}[36;1m",117    warning: "\u{1b}[33;1m",118    error: "\u{1b}[31;1m",119    fatal: "\u{1b}[31;1m"120  }121}122123/// The escape sequence that starts a style.124fn startOf(theme: &Theme, style: &Display.Style) -> Str {125  match style {126    case Display.Plain => theme.text127    case Display.Secondary => theme.secondary128    case Display.Tertiary => theme.tertiary129    case Display.Invalid => theme.invalid130    case Display.NullStyle => theme.nullValue131    case Display.NameStyle => theme.name132    case Display.StringStyle => theme.string133    case Display.NumberStyle => theme.number134    case Display.BooleanStyle => theme.boolean135    case Display.ScalarStyle => theme.scalar136    case Display.LevelStyle(level) => match level {137      case Log.Verbose => theme.verbose138      case Log.Debug => theme.debug139      case Log.Information => theme.information140      case Log.Warning => theme.warning141      case Log.Error => theme.error142      case Log.Fatal => theme.fatal143    }144  }145}146147/// The pieces joined, each styled piece wrapped in its escape sequence and a reset. Line breaks148/// stay outside the escapes so a terminal never carries colour onto the next line.149export fn paint(theme: &Theme, pieces: &Array[Display.Piece]) -> Str {150  var out: Array[Str] = []151  for piece in pieces {152    let start = startOf(theme, &piece.style)153    if start.isEmpty() || piece.text.isEmpty() {154      out = out.push(piece.text)155    } else {156      let body = piece.text.split("\n").map(|line: Str| if line.isEmpty() { line } else { start + line + RESET })157      out = out.push(body.join("\n"))158    }159  }160  out.join("")161}162