# grc colouriser for the log files of the monitor family # # Covers spotify_monitor, spotify_profile_monitor, lastfm_monitor, github_monitor, # instagram_monitor, xbox_monitor, psn_monitor, steam_monitor and lol_monitor. # # The colours mirror the built-in COLOR_THEME of the tools, so a saved log replayed through # grc looks like the live terminal output. Theme part to colour: # # username bright_cyan underline id bright_magenta # track, artist, game, champion, commit, story, proxy_ip bright_yellow # album, playlist, game_mode yellow platform blue # repository green event, post, trophy, achievement, rank bright_green # branch, reel bright_magenta date, date_range magenta # timestamp_value cyan info cyan link blue underline # warning, signal, status_change, status_away yellow error red # email bright_cyan webhook bright_blue # boolean_true, count_up, duration, status_active green # boolean_false, count_down, status_inactive, status_offline red # # grc runs every rule in file order and the last rule to paint a character wins, so this file # runs from the widest match to the narrowest. Rows the tools colour before they stop reading # the line use count=stop here, in the same order the code checks them. # # Two things a saved log cannot carry. The tools compare the two numbers in "from N to M" and # paint a drop red, which needs both values at once, so both are green here. They also know # whether a monitored target is a handle or an opaque identifier, so here a target is read as a # handle unless it has the shape of a Spotify URI ID or a Steam64 ID. # # The padded listing tables have no rule here. Their columns are positional, so a rule wide enough # to read one tool's table reads across the column boundaries of another's. The tools colour those # rows at the point they print them instead. - # ---------------------------------------------------------------------------- # Rows the tools colour and then stop reading. A label sits behind a - or * bullet or behind nothing # --------------------------------------------------------------------------- regexp=^(\* Notifications \((?:email|webhook)\):[\t ]+)(On) colours=unchanged, unchanged, green count=stop - regexp=^(\* Notifications \((?:email|webhook)\):[\t ]+)(Off) colours=unchanged, unchanged, red count=stop - # A heading names what follows instead of reporting a value regexp=^(?:Doctor|Summary|Next steps)$ colours=bright_cyan count=stop - regexp=^(?:Environment|Configuration|Authentication|Connectivity|Target|Notifications|Ranked Information|Banned champions|User last played match):?$ colours=bright_white count=stop - regexp=^(\* TLS verification:[\t ]+)(On) colours=unchanged, unchanged, green count=stop - regexp=^(\* TLS verification:[\t ]+)(Off) colours=unchanged, unchanged, red count=stop - # Doctor status markers keep the rest of their line plain so long labels stay readable regexp=^\[PASS\] colours=green count=stop - regexp=^\[WARN\] colours=yellow count=stop - regexp=^\[FAIL\] colours=red count=stop - regexp=^\[SKIP\] colours=cyan count=stop - regexp=^[\t ]*(?:[-*][\t ]+)?(?:Timestamp:|Liveness check, timestamp:)[\t ]+(\S.*?)[\t ]*$ colours=unchanged, cyan count=stop - # Any " URL:" row carries a link, checked before the label table so "Album URL:" # is not read as "Album:". A proxy row is the exception, since it names the proxy rather than a page regexp=(?]*(?:[\s\]]|$)) colours=unchanged, blue underline count=stop - regexp=(?i)^[\t ]*(?:[-*][\t ]+)?STATUS:[\t ]+(online|available|active|playing|private mode)[\t ]*$ colours=unchanged, green count=stop - regexp=(?i)^[\t ]*(?:[-*][\t ]+)?STATUS:[\t ]+(away)[\t ]*$ colours=unchanged, yellow count=stop - regexp=(?i)^[\t ]*(?:[-*][\t ]+)?STATUS:[\t ]+(snooze)[\t ]*$ colours=unchanged, magenta count=stop - regexp=(?i)^[\t ]*(?:[-*][\t ]+)?STATUS:[\t ]+(offline|invisible|inactive|standby)[\t ]*$ colours=unchanged, red count=stop - regexp=(?i)^[\t ]*(?:[-*][\t ]+)?STATUS:[\t ]+(\S.*?)[\t ]*$ colours=unchanged, white count=stop - regexp=(?i)^[\t ]*(?:[-*][\t ]+)?Victory:[\t ]+(yes|active|in game)[\t ]*$ colours=unchanged, green count=stop - regexp=(?i)^[\t ]*(?:[-*][\t ]+)?Victory:[\t ]+(no|inactive|offline)[\t ]*$ colours=unchanged, red count=stop - # The monitored target is a handle in most tools and an opaque identifier in spotify_monitor # and steam_monitor, which a saved log can only tell apart by the shape of the value regexp=^[\t ]*(?:[-*][\t ]+)?Targets?:[\t ]+([A-Za-z0-9]{20,}|\d{17})[\t ]*$ colours=unchanged, bright_magenta count=stop - regexp=^[\t ]*(?:[-*][\t ]+)?Targets?:[\t ]+(\S.*?)[\t ]*$ colours=unchanged, bright_cyan underline count=stop - regexp=^[\t ]*(?:[-*][\t ]+)?(?:Username|Display name|Spotify user|Owner|Last\.fm user|Token belongs to|Event actor login|Event actor name|Published by|Commit author|Issue author|Comment author|Discussion comment by|Member added|Assignee|Requested reviewer|Author|Gamertag|PlayStation ID|PSN ID|Riot ID \(name#tag\)|Summoner name):[\t ]+(\S.*?)[\t ]*$ colours=unchanged, bright_cyan underline count=stop - regexp=^[\t ]*(?:[-*][\t ]+)?(?:User URI ID|Spotify user ID|User URI|Playlist ID|Event ID|Review ID|Commit SHA reviewed|Commit SHA|XUID|PSN account ID|Account ID|User ID|Steam64 ID|Riot PUUID|Match ID):[\t ]+(\S.*?)[\t ]*$ colours=unchanged, bright_magenta count=stop - regexp=^[\t ]*(?:[-*][\t ]+)?(?:Last played|Last track|Track|Context \(Artist\)|Artist|Champion):[\t ]+(\S.*?)[\t ]*$ colours=unchanged, bright_yellow count=stop - regexp=^[\t ]*(?:[-*][\t ]+)?(?:Context \(Album\)|Last album|Album|Playlist|Game mode):[\t ]+(\S.*?)[\t ]*$ colours=unchanged, yellow count=stop - regexp=^[\t ]*(?:[-*][\t ]+)?(?:Last track duration|Match duration|Match finished|Duration):[\t ]+(\S.*?)[\t ]*$ colours=unchanged, green count=stop - regexp=^[\t ]*(?:[-*][\t ]+)?(?:Current game|Title name|User is currently in-game|In-game|Game|Commit message|IP Address|Proxy IP Address|Proxy URL|Proxy Certificate|Proxy for Webhooks):[\t ]+(\S.*?)(?:[\t ]*\((PS[A-Z0-9_]*|MOBILE_APP|Xbox One Series X/S|Android Phone/Tablet|Xbox One X/S|iPhone/iPad|Xbox 360|Xbox One|Windows|Android|XONEX|X360|XONE|XSX)\))?[\t ]*$ colours=unchanged, bright_yellow, blue count=stop - # A proxy line the tools paint whole rather than reading a label out of it regexp=^[\t ]*\*[\t ]+Proxy\b.*$ colours=bright_yellow count=stop - regexp=^[\t ]*(?:[-*][\t ]+)?Platform:[\t ]+(\S.*?)[\t ]*$ colours=unchanged, blue count=stop - regexp=^[\t ]*(?:[-*][\t ]+)?(?:Gamerscore|Trophies earned|Trophy level):[\t ]+(\S.*?)[\t ]*$ colours=unchanged, bright_green count=stop - regexp=^[\t ]*(?:[-*][\t ]+)?(?:Repo name|Forked to repo):[\t ]+(\S.*?)[\t ]*$ colours=unchanged, green count=stop - regexp=^[\t ]*(?:[-*][\t ]+)?(?:Event type|Release name|Release tag name|Issue title|Discussion title):[\t ]+(\S.*?)[\t ]*$ colours=unchanged, bright_green count=stop - regexp=^[\t ]*(?:[-*][\t ]+)?(?:Object name|Target commitish|Branch \(default\)):[\t ]+(\S.*?)[\t ]*$ colours=unchanged, bright_magenta count=stop - regexp=^[\t ]*(?:[-*][\t ]+)?Email:[\t ]+(\S.*?)[\t ]*$ colours=unchanged, bright_cyan count=stop - # A roster entry names a player and what they played regexp=^(-[\t ]+)([^:(\n]+?)([\t ]+\()([^()]+)(\)[\t ]*)$ colours=unchanged, unchanged, bright_cyan underline, unchanged, bright_yellow, unchanged count=stop - # A friends list row names one player and the presence Xbox reports for them. The state word is mixed case # here, unlike the capitalised keyword an event line prints, so these rules do not reach a presence report regexp=^([^\s:*-][^:\n]*?)([\t ]{2,})(Online)([\t ]+\()([^()\n]+)(\))[\t ]*$ colours=unchanged, bright_cyan underline, unchanged, green, unchanged, bright_yellow, unchanged count=stop - regexp=^([^\s:*-][^:\n]*?)([\t ]{2,})(Online)[\t ]*$ colours=unchanged, bright_cyan underline, unchanged, green count=stop - regexp=^([^\s:*-][^:\n]*?)([\t ]{2,})(Away)[\t ]*$ colours=unchanged, bright_cyan underline, unchanged, yellow count=stop - regexp=^([^\s:*-][^:\n]*?)([\t ]{2,})(Offline)[\t ]*$ colours=unchanged, bright_cyan underline, unchanged, red count=stop - # ---------------------------------------------------------------------------- # Whole-line highlights, painted first so the values inside keep their own colour # --------------------------------------------------------------------------- regexp=(?i)^[\t ]*\*[\t ]*info\b.*$ colours=cyan count=once - regexp=(?i)^.*(?:\bsending webhook\b|\bwebhook sent successfully\b).*$ colours=bright_blue count=once - regexp=(?i)^.*(?:\bsending email\b|\bemail sent successfully\b).*$ colours=bright_cyan count=once - regexp=(?i)^[\t ]*(?:[-*][\t ]+)?(?:error\b|critical:|failure\b).*$ colours=red count=once - # A problem word used as a key in a "key=value" detail names a setting or a counter, not a failure regexp=(?i)^[^'\n]*\b(?:failures?|failed|forbidden|timeout|disappeared)\b(?![\t ]*=).*$ colours=red count=once - # A change notice is painted whole, the way instagram_monitor reports one regexp=(?i)^.*(?:story for user|newest post|new post for user|bio changed for|changed profile picture|removed profile picture|set profile picture|has new story item|story items:|has[\t ]+\d+[\t ]+story[\t ]+items?).*$ colours=yellow count=once - # A startup row whose label happens to contain a problem word reports a setting regexp=(?i)^[\t ]*\*[\t ]+(?!error\b|warning\b|critical\b|failure\b)[\w()/-]+[\t ]+[\w()/ -]*:[\t ]+\S.*$ colours=default count=once - # A startup row whose label names a timer reports a setting, not a failure regexp=(?i)^\*[\t ]+(?:disappeared|error retry)[\t ]+timer:.*$ colours=default count=once - # A backend fallback notice reports a recovery that worked, not the failure that caused it regexp=(?i)^.*\bswitched to\b.*$ colours=default count=once - # A debug trace records what was tried, including attempts that fail and are then handled regexp=(?i)^\[debug \d\d:\d\d:\d\d\].*$ colours=default count=once - regexp=(?i)^.*\[errors =.*$ colours=default count=once - regexp=(?i)^[\t ]*to fix:.*$ colours=cyan count=once - # ---------------------------------------------------------------------------- # Presence and playback words # --------------------------------------------------------------------------- regexp=\b(ACTIVE|ONLINE|PRIVATE MODE)\b colours=green - regexp=\b(INACTIVE|OFFLINE|STANDBY)\b colours=red - regexp=\b(AWAY)\b colours=yellow - regexp=\b(SNOOZE)\b colours=magenta - regexp=\b(RESUMED|LOOP|PLAYING)\b colours=green - regexp=\b(SKIPPED|PAUSED)\b colours=red - regexp=\b(CONT)\b colours=yellow - regexp=\bstarted playing\b colours=green - regexp=\bstopped playing\b|\bis not in game currently\b colours=red - regexp=\bis in game now\b colours=green - # A ranked standing regexp=\b(?:IRON|BRONZE|SILVER|GOLD|PLATINUM|EMERALD|DIAMOND|MASTER|GRANDMASTER|CHALLENGER)(?:[\t ]+(?:I|II|III|IV))?\b|\bUnranked\b colours=bright_green - # A champion mastery entry names the champion before the level it reports regexp=^([\t ]+\d+\.[\t ]+)([^:\n]+)(:[\t ]+Level[\t ]+\d+) colours=unchanged, unchanged, bright_yellow, unchanged - regexp=\b(?:changed status|changed game)\b colours=yellow - # A status named in prose rather than in a Status: row, read through the same table that row uses. The # value between "from" and "to" may be two words, so the middle is not matched as a single word regexp=(?i)changed status from[\t ]+(online|available|active|playing|private mode)\b colours=unchanged, green - regexp=(?i)changed status from[\t ]+(away)\b colours=unchanged, yellow - regexp=(?i)changed status from[\t ]+(snooze)\b colours=unchanged, magenta - regexp=(?i)changed status from[\t ]+(offline|invisible|inactive|standby)\b colours=unchanged, red - regexp=(?i)changed status from[\t ]+[\w ]+?[\t ]+to[\t ]+(online|available|active|playing|private mode)\b colours=unchanged, green - regexp=(?i)changed status from[\t ]+[\w ]+?[\t ]+to[\t ]+(away)\b colours=unchanged, yellow - regexp=(?i)changed status from[\t ]+[\w ]+?[\t ]+to[\t ]+(snooze)\b colours=unchanged, magenta - regexp=(?i)changed status from[\t ]+[\w ]+?[\t ]+to[\t ]+(offline|invisible|inactive|standby)\b colours=unchanged, red - # The console a game was launched on. Only the names the tools print are listed, so a bracketed word in # ordinary prose is not read as a platform regexp=\((PS[A-Z0-9_]*|MOBILE_APP|Xbox One Series X/S|Android Phone/Tablet|Xbox One X/S|iPhone/iPad|Xbox 360|Xbox One|Windows|Android|XONEX|X360|XONE|XSX)\) colours=unchanged, blue - # ---------------------------------------------------------------------------- # Warnings and signals mark their opening word instead of painting the line # --------------------------------------------------------------------------- regexp=^[\t ]*\*+[\t ]*(Warning:|Caution:) colours=unchanged, yellow - regexp=^\* Signal (\w+) received$ colours=unchanged, yellow - # ---------------------------------------------------------------------------- # Values inside a line # --------------------------------------------------------------------------- regexp=\bTrue\b|\bEnabled\b colours=green - regexp=:[\t ]+(Yes)[\t ]*$ colours=unchanged, green - regexp=\bFalse\b|\bDisabled\b colours=red - regexp=:[\t ]+(No)[\t ]*$ colours=unchanged, red - # A quoted value takes the colour of what the line is about regexp='(?!(?:[~.]?[\\/]|[A-Za-z]:[\\/]|<|-|[?&]|[^'\n]*://|[^'\n]*\.[A-Za-z0-9]{1,12}'))([^'\n]*\w[^'\n]*)'(?![\t ]*-[\t ]*(?:modified|added|removed|renamed|deleted|changed)\b)(?=[\s.,;:!?)\]]|$) colours=unchanged, bright_yellow - regexp=(?i)\bplaylist\b.*'(?!(?:[~.]?[\\/]|[A-Za-z]:[\\/]|<|-|[?&]|[^'\n]*://|[^'\n]*\.[A-Za-z0-9]{1,12}'))([^'\n]*\w[^'\n]*)'(?![\t ]*-[\t ]*(?:modified|added|removed|renamed|deleted|changed)\b)(?=[\s.,;:!?)\]]|$) colours=unchanged, yellow - regexp=(?i)\busername\b.*'(?!(?:[~.]?[\\/]|[A-Za-z]:[\\/]|<|-|[?&]|[^'\n]*://|[^'\n]*\.[A-Za-z0-9]{1,12}'))([^'\n]*\w[^'\n]*)'(?![\t ]*-[\t ]*(?:modified|added|removed|renamed|deleted|changed)\b)(?=[\s.,;:!?)\]]|$) colours=unchanged, bright_cyan underline - regexp=^[\t ]*-[\t ]+'(?!(?:[~.]?[\\/]|[A-Za-z]:[\\/]|<|-|[?&]|[^'\n]*://|[^'\n]*\.[A-Za-z0-9]{1,12}'))([^'\n]*\w[^'\n]*)'(?![\t ]*-[\t ]*(?:modified|added|removed|renamed|deleted|changed)\b)(?=[\s.,;:!?)\]]|$) colours=unchanged, yellow - regexp=^[\t ]*-[\t ]+'.*'(?!(?:[~.]?[\\/]|[A-Za-z]:[\\/]|<|-|[?&]|[^'\n]*://|[^'\n]*\.[A-Za-z0-9]{1,12}'))([^'\n]*\w[^'\n]*)'(?![\t ]*-[\t ]*(?:modified|added|removed|renamed|deleted|changed)\b)[^'\n]*$ colours=unchanged, yellow - # A quoted value right after the word it belongs to takes that word's colour, whichever # quote on the line it is regexp=(?i)\bplaylist\b[^'\n]*'(?!(?:[~.]?[\\/]|[A-Za-z]:[\\/]|<|-|[?&]|[^'\n]*://|[^'\n]*\.[A-Za-z0-9]{1,12}'))([^'\n]*\w[^'\n]*)'(?![\t ]*-[\t ]*(?:modified|added|removed|renamed|deleted|changed)\b) colours=unchanged, yellow - regexp=(?i)\bplaylist\b.*'(?!(?:[~.]?[\\/]|[A-Za-z]:[\\/]|<|-|[?&]|[^'\n]*://|[^'\n]*\.[A-Za-z0-9]{1,12}'))([^'\n]*\w[^'\n]*)'(?![\t ]*-[\t ]*(?:modified|added|removed|renamed|deleted|changed)\b)[^'\n]*$ colours=unchanged, yellow - regexp=(?i)\busername\b[^'\n]*'(?!(?:[~.]?[\\/]|[A-Za-z]:[\\/]|<|-|[?&]|[^'\n]*://|[^'\n]*\.[A-Za-z0-9]{1,12}'))([^'\n]*\w[^'\n]*)'(?![\t ]*-[\t ]*(?:modified|added|removed|renamed|deleted|changed)\b) colours=unchanged, bright_cyan underline - regexp=(?i)\busername\b.*'(?!(?:[~.]?[\\/]|[A-Za-z]:[\\/]|<|-|[?&]|[^'\n]*://|[^'\n]*\.[A-Za-z0-9]{1,12}'))([^'\n]*\w[^'\n]*)'(?![\t ]*-[\t ]*(?:modified|added|removed|renamed|deleted|changed)\b)[^'\n]*$ colours=unchanged, bright_cyan underline - regexp=(?i)\b(?:user|owner|username|owned by|added by|listened by|tracks of)[\t ]+'(?!(?:[~.]?[\\/]|[A-Za-z]:[\\/]|<|-|[?&]|[^'\n]*://|[^'\n]*\.[A-Za-z0-9]{1,12}'))([^'\n]*\w[^'\n]*)'(?![\t ]*-[\t ]*(?:modified|added|removed|renamed|deleted|changed)\b) colours=unchanged, bright_cyan underline - # Only the Spotify tools print "user ID", and that value is an identifier regexp=(?i)\buser[\t ]+ID[\t ]+'(?!(?:[~.]?[\\/]|[A-Za-z]:[\\/]|<|-|[?&]|[^'\n]*://|[^'\n]*\.[A-Za-z0-9]{1,12}'))([^'\n]*\w[^'\n]*)'(?![\t ]*-[\t ]*(?:modified|added|removed|renamed|deleted|changed)\b) colours=unchanged, bright_magenta - # A quoted value with the shape of a Spotify URI ID or a Steam64 ID names an account regexp=(?i)\buser(?:[\t ]+id)?[\t ]+'([A-Za-z0-9]{20,}|\d{17})' colours=unchanged, bright_magenta - # Listing rows that name one item and then its details in brackets regexp=^-[\t ]+([^\[\n:*]{1,80}?)[\t ]+\[[\t ] colours=unchanged, bright_yellow - regexp=^-[\t ]+[^|\n]+\|[\t ]*([^|\n]+?)[\t ]*\|[\t ]*([A-Z]+)[\t ]*\|[\t ]*(\S.*?)[\t ]*$ colours=unchanged, bright_yellow, bright_green, bright_green - regexp=^-[\t ]+([^\[\n:*]{1,80}?)[\t ]+\[[\t ]*https?:// colours=unchanged, bright_cyan underline - regexp=,[\t ]+([\w.-]+)[\t ]+\][\t ]*$ colours=unchanged, bright_cyan underline - regexp=\[[\t ]*owner:[\t ]+([^\]\n]+?)[\t ]*\] colours=unchanged, bright_cyan underline - regexp=(https?://[^\s\]]+?)(?=[.,;:!?'")>]*(?:[\s\]]|$)) colours=blue underline - regexp=(?