|
| 1 | +# Text Formatting |
| 2 | + |
| 3 | +This document describes a custom text formatting syntax used in both shell scripts, module configuration files, and Jetpack Compose UI development. This syntax allows you to add color and style to your text output using simple tags. |
| 4 | + |
| 5 | +## Overview |
| 6 | + |
| 7 | +The formatting system uses tags enclosed in square brackets `[]` to define styles. These tags can control text color, background color, and text attributes like bold, italic, and underline. |
| 8 | + |
| 9 | +## Supported Tags |
| 10 | + |
| 11 | +The following tags are supported: |
| 12 | + |
| 13 | +- **`[color=<value>]` / `[color]`**: |
| 14 | + |
| 15 | + - Sets the foreground color of the text. |
| 16 | + - `<value>` can be a predefined color name (see [Supported Colors](#supported-colors) below). |
| 17 | + - Using `[color]` without a value (or with an unrecognized value) typically resets the color to the default or `Color.Unspecified` in Compose. |
| 18 | + |
| 19 | +- **`[bg=<value>]` / `[bg]`**: |
| 20 | + |
| 21 | + - Sets the background color of the text. |
| 22 | + - `<value>` can be a predefined color name (see [Supported Colors](#supported-colors) below). |
| 23 | + - Using `[bg]` without a value (or with an unrecognized value) typically resets the background color to the default or `Color.Unspecified` in Compose. |
| 24 | + |
| 25 | +- **`[bold]`**: |
| 26 | + |
| 27 | + - Applies bold styling to the text. |
| 28 | + - In Compose, this sets `FontWeight.Bold`. |
| 29 | + - In the shell script, this tag is stripped if `MMRL` is not "true". To actually render bold in a terminal, you'd typically need ANSI escape codes, which this script doesn't explicitly add (it only strips the custom tags). |
| 30 | + |
| 31 | +- **`[italic]`**: |
| 32 | + |
| 33 | + - Applies italic styling to the text. |
| 34 | + - In Compose, this sets `FontStyle.Italic`. |
| 35 | + - In the shell script, this tag is stripped if `MMRL` is not "true". |
| 36 | + |
| 37 | +- **`[underline]`**: |
| 38 | + - Applies underline styling to the text. |
| 39 | + - In Compose, this sets `TextDecoration.Underline`. |
| 40 | + - In the shell script, this tag is stripped if `MMRL` is not "true". |
| 41 | + |
| 42 | +## Usage |
| 43 | + |
| 44 | +### Shell Script (`echo` function) |
| 45 | + |
| 46 | +The provided `echo` shell function processes these tags: |
| 47 | + |
| 48 | +```shell |
| 49 | +echo() { |
| 50 | + local msg="$*" |
| 51 | + if [ "$MMRL" = "true" ]; then |
| 52 | + command echo "$msg" |
| 53 | + else |
| 54 | + # Remove all custom formatting tags before printing |
| 55 | + command echo "$msg" | sed -E 's/\[(color|bg|bold|italic|underline)(=[^]]+)?]//g' |
| 56 | + fi |
| 57 | +} |
| 58 | +``` |
| 59 | + |
| 60 | +**Behavior (Shell Script):** |
| 61 | + |
| 62 | +- If the environment variable `MMRL` is set to `"true"`, the `echo` command will print the message as-is, including all formatting tags. This might be useful for debugging or for systems that can interpret these tags directly. |
| 63 | +- If `MMRL` is not set to `"true"` (or is set to any other value), the function strips out all custom formatting tags using `sed` before printing the message. The output will be plain text. |
| 64 | + |
| 65 | +**Example (Shell Script):** |
| 66 | + |
| 67 | +```shell |
| 68 | +# With MMRL not "true" (default behavior) |
| 69 | +echo "This is a [color=red]red[color] message with [bold]bold text[bold]." |
| 70 | +# Output: This is a red message with bold text. |
| 71 | + |
| 72 | +# With MMRL="true" |
| 73 | +MMRL="true" echo "This is a [color=red]red[color] message with [bold]bold text[bold]." |
| 74 | +# Output: This is a [color=red]red[color] message with [bold]bold text[bold]. |
| 75 | +``` |
| 76 | + |
| 77 | +### Module Config (`config.json` in module root) |
| 78 | + |
| 79 | +The custom formatting tags can be used within the `description` field of a module's `config.json` file. |
| 80 | + |
| 81 | +**Note:** Only the `description` field supports this formatting API. It cannot be used with other fields like those in `module.prop`. |
| 82 | + |
| 83 | +```json |
| 84 | +{ |
| 85 | + "name": { |
| 86 | + "en": "Systemless module", |
| 87 | + "de": "Systemloses Modul" |
| 88 | + }, |
| 89 | + "description": { |
| 90 | + "en": "[bg=red]Hello[bg], [color=primary]World[color]!", |
| 91 | + "de": "Hallo, [color=green]Welt[color]!" |
| 92 | + } |
| 93 | +} |
| 94 | +``` |
| 95 | + |
| 96 | +When an application (like a module manager that supports this format) reads this `config.json`, it would be responsible for parsing the `description` string and rendering the formatted text in its UI, likely using a mechanism similar to the Jetpack Compose `toStyleMarkup()` function. |
| 97 | + |
| 98 | +### Jetpack Compose (`String.toStyleMarkup()`) |
| 99 | + |
| 100 | +The Kotlin extension function `toStyleMarkup()` converts a string containing these formatting tags into an `AnnotatedString`, which can be used to display styled text in Jetpack Compose. |
| 101 | + |
| 102 | +```kotlin |
| 103 | +// Simplified conceptual usage |
| 104 | +@Composable |
| 105 | +fun MyStyledText(text: String) { |
| 106 | + Text(text = text.toStyleMarkup()) |
| 107 | +} |
| 108 | + |
| 109 | +// Example |
| 110 | +MyStyledText(text = "Hello [color=blue]Blue World[color] with [bg=yellow]yellow background[bg] and [bold]bold[bold] text!") |
| 111 | +``` |
| 112 | + |
| 113 | +This will render "Hello " in the default style, "Blue World" in blue, " with " in default style, "yellow background" with a yellow background, " and " in default style, and "bold" in bold text. The styling is cumulative within the parsed segments. |
| 114 | + |
| 115 | +## Supported Colors |
| 116 | + |
| 117 | +The `colorFromName` Composable function in Kotlin defines the mapping from color names to `Color` objects. These names can be used in `[color=<name>]` and `[bg=<name>]` tags. |
| 118 | + |
| 119 | +| Color Name | Mapped To (Jetpack Compose) | |
| 120 | +| -------------------- | -------------------------------------------- | |
| 121 | +| `black` | `Color.Black` | |
| 122 | +| `red` | `Color.Red` | |
| 123 | +| `green` | `Color.Green` | |
| 124 | +| `yellow` | `Color.Yellow` | |
| 125 | +| `blue` | `Color.Blue` | |
| 126 | +| `magenta` | `Color.Magenta` | |
| 127 | +| `cyan` | `Color.Cyan` | |
| 128 | +| `white` | `Color.White` | |
| 129 | +| `gray`, `grey` | `Color.Gray` | |
| 130 | +| `lightgray` | `Color.LightGray` | |
| 131 | +| `primary` | `MaterialTheme.colorScheme.primary` | |
| 132 | +| `secondary` | `MaterialTheme.colorScheme.secondary` | |
| 133 | +| `tertiary` | `MaterialTheme.colorScheme.tertiary` | |
| 134 | +| `background` | `MaterialTheme.colorScheme.background` | |
| 135 | +| `surface` | `MaterialTheme.colorScheme.surface` | |
| 136 | +| `error` | `MaterialTheme.colorScheme.error` | |
| 137 | +| `outline` | `MaterialTheme.colorScheme.outline` | |
| 138 | +| `inverse_surface` | `MaterialTheme.colorScheme.inverseSurface` | |
| 139 | +| `inverse_on_surface` | `MaterialTheme.colorScheme.inverseOnSurface` | |
| 140 | +| `inverse_primary` | `MaterialTheme.colorScheme.inversePrimary` | |
| 141 | +| `surface_variant` | `MaterialTheme.colorScheme.surfaceVariant` | |
| 142 | +| `on_surface_variant` | `MaterialTheme.colorScheme.onSurfaceVariant` | |
| 143 | +| `surface_tint` | `MaterialTheme.colorScheme.surfaceTint` | |
| 144 | +| `on_surface` | `MaterialTheme.colorScheme.onSurface` | |
| 145 | +| `on_primary` | `MaterialTheme.colorScheme.onPrimary` | |
| 146 | +| `on_secondary` | `MaterialTheme.colorScheme.onSecondary` | |
| 147 | +| `on_tertiary` | `MaterialTheme.colorScheme.onTertiary` | |
| 148 | +| `on_background` | `MaterialTheme.colorScheme.onBackground` | |
| 149 | +| `on_error` | `MaterialTheme.colorScheme.onError` | |
| 150 | +| _(any other value)_ | `Color.Unspecified` | |
| 151 | + |
| 152 | +**Note:** Color names are case-insensitive (e.g., `Red`, `red`, `RED` are all treated the same). |
| 153 | + |
| 154 | +## Tag Nesting and Behavior |
| 155 | + |
| 156 | +In the Jetpack Compose implementation (`toStyleMarkup`): |
| 157 | + |
| 158 | +- Styles are applied segment by segment. When a tag is encountered, the style it defines (e.g., `currentColor`, `isBold`) is set and applied to subsequent text until another relevant tag changes it or the string ends. |
| 159 | +- There isn't explicit "closing" tag logic like `[/bold]`. Instead, a new tag like `[color=green]` would change the current color from whatever it was previously. For boolean styles like `bold`, `italic`, `underline`, the provided Kotlin code currently only sets them to `true`. To turn them _off_, you would need to modify the parsing logic to handle specific "off" tags (e.g., `[bold=false]`) or a general reset tag if that functionality is desired. The current parser only activates these styles. |
| 160 | + |
| 161 | +For the shell script, the `sed` command simply removes any recognized tag pattern. It does not interpret nesting or apply styles. The same applies to how an application might parse the `config.json`'s `description` field – it would depend on its specific parsing implementation, but would likely follow the Jetpack Compose behavior if aiming for consistency. |
0 commit comments