{"id":19858500,"url":"https://github.com/matjam/mecca","last_synced_at":"2026-05-12T11:40:22.771Z","repository":{"id":204019918,"uuid":"697428272","full_name":"matjam/mecca","owner":"matjam","description":"A template language loosely based on Maximus BBS MECCA","archived":false,"fork":false,"pushed_at":"2025-02-16T09:04:55.000Z","size":15,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-02-16T09:26:57.915Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/matjam.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-09-27T17:55:16.000Z","updated_at":"2025-02-16T09:04:58.000Z","dependencies_parsed_at":null,"dependency_job_id":"5e23c363-c9da-4901-b095-5b21eab4ed46","html_url":"https://github.com/matjam/mecca","commit_stats":null,"previous_names":["matjam/mecca"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/matjam%2Fmecca","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/matjam%2Fmecca/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/matjam%2Fmecca/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/matjam%2Fmecca/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/matjam","download_url":"https://codeload.github.com/matjam/mecca/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":241255130,"owners_count":19934815,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-12T14:23:44.214Z","updated_at":"2026-05-12T11:40:22.746Z","avatar_url":"https://github.com/matjam.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# MECCA Language Reference\n\n\u003e **⚠️ Beta Notice:** This package is currently in beta phase. The API should remain stable, but we want to get at least one BBS server working using it before promoting it to version 1.0.0. We welcome feedback and contributions!\n\n\u003e **Note:** Parts of this document are based on the original MECCA documentation by Scott J. Dudley, and have been adapted for the Go interpretation of the MECCA language. The original documentation can be found in [max300.txt](./max300.txt) in this repository.\n\n## Introduction\n\nMECCA is a simple, easy-to-learn templating language originally designed for the Maximus BBS software by Scott J. Dudley. It was created to allow non-programmers to create interactive content for BBS systems.\n\nThis Go implementation provides a subset of the original MECCA language, adapted for modern terminal-based applications. It's designed to work with the [bubbletea](https://github.com/charmbracelet/bubbletea) framework and uses the [lipgloss](https://github.com/charmbracelet/lipgloss) library for rendering, enabling beautiful terminal user interfaces in modern Go BBS software.\n\n## Usage\n\n### Basic Usage\n\nThe simplest way to use the MECCA interpreter is to create a new interpreter and process a string:\n\n```go\npackage main\n\nimport (\n\t\"github.com/matjam/mecca\"\n)\n\nfunc main() {\n\t// Create a new interpreter with default settings\n\tinterpreter := mecca.NewInterpreter()\n\t\n\t// Process and display a MECCA template\n\tinterpreter.ExecString(\"[bold][red]Hello, World![reset]\", nil)\n}\n```\n\n### Using Variables\n\nYou can pass variables at execution time to substitute values in templates:\n\n```go\ninterpreter := mecca.NewInterpreter()\n\ntemplate := \"Hello, [name]! You have [count] new messages.\"\n\ninterpreter.ExecString(template, map[string]any{\n\t\"name\":  \"Alice\",\n\t\"count\": 42,\n})\n```\n\n### Registering Custom Tokens\n\nYou can register custom tokens that will be called when encountered in templates. This allows you to create dynamic content based on your application's state.\n\nHere's a complete example showing how to register and use custom tokens:\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/matjam/mecca\"\n)\n\n// ServerContext holds application state\ntype ServerContext struct {\n\tuser     string\n\tmsgCount int\n}\n\n// userToken returns the current user's name\nfunc (ctx ServerContext) userToken(_ []string) string {\n\treturn ctx.user\n}\n\n// msgCountToken returns the number of new messages\nfunc (ctx ServerContext) msgCountToken(args []string) string {\n\treturn fmt.Sprintf(\"%d\", ctx.msgCount)\n}\n\n// repeatToken repeats a string a specified number of times\nfunc (ctx ServerContext) repeatToken(args []string) string {\n\tif len(args) \u003c 2 {\n\t\treturn \"\"\n\t}\n\t// Parse count from args[0]\n\tcount := 0\n\tfor _, c := range args[0] {\n\t\tcount = count*10 + int(c-'0')\n\t}\n\treturn strings.Repeat(args[1], count)\n}\n\nfunc main() {\n\t// Create application context\n\tctx := ServerContext{\n\t\tuser:     \"Bob\",\n\t\tmsgCount: 3,\n\t}\n\n\t// Create interpreter\n\tinterpreter := mecca.NewInterpreter()\n\n\t// Register custom tokens\n\tinterpreter.RegisterToken(\"user\", ctx.userToken, 0)        // Takes 0 arguments\n\tinterpreter.RegisterToken(\"msgcount\", ctx.msgCountToken, 1) // Takes 1 argument (unused in this example)\n\tinterpreter.RegisterToken(\"repeat\", ctx.repeatToken, 2)     // Takes 2 arguments: count and string\n\n\t// Use the tokens in a template\n\ttemplate := `[bold yellow]Welcome, [user]![reset]\nYou have [lightblue][msgcount][reset] new messages.\n\n[bold][repeat 5 =][reset] Separator [repeat 5 =][reset]\nThis is a custom token demonstration.\n`\n\n\tinterpreter.ExecString(template, nil)\n}\n```\n\n### Using Type Methods as Token Functions\n\nAs shown in the example above, you can use methods on types as token functions. This allows tokens to access application state naturally:\n\n```go\ntype MyApp struct {\n\tcurrentUser string\n}\n\nfunc (app *MyApp) userToken(_ []string) string {\n\treturn app.currentUser\n}\n\nfunc main() {\n\tapp := \u0026MyApp{currentUser: \"Alice\"}\n\tinterpreter := mecca.NewInterpreter()\n\t\n\t// Register a method as a token function\n\tinterpreter.RegisterToken(\"user\", app.userToken, 0)\n\t\n\tinterpreter.ExecString(\"Hello, [user]!\", nil)\n}\n```\n\n### Working with Files\n\nYou can also process template files:\n\n```go\n// Set a template root directory\ninterpreter := mecca.NewInterpreter(mecca.WithTemplateRoot(\"./templates\"))\n\n// Execute a template file (returns the rendered string)\noutput, err := interpreter.ExecTemplate(\"welcome.mec\", map[string]any{\n\t\"user\": \"Alice\",\n})\nif err != nil {\n\tlog.Fatal(err)\n}\n\n// Or render directly to the output writer\nerr = interpreter.RenderTemplate(\"welcome.mec\", map[string]any{\n\t\"user\": \"Alice\",\n})\n```\n\n## Language Reference\n\n### Basic Syntax\n\nMECCA templates are plain UTF-8 text files, typically with a `.mec` extension. The interpreter processes tokens enclosed in square brackets and renders everything else as literal text.\n\n**Token Format:** Tokens are delimited by square brackets: `[token]`\n\n- Tokens can contain commands and arguments: `[token arg1 arg2]`\n- Multiple tokens can be combined: `[red bold]Hello[reset]`\n- Arguments can be quoted if they contain spaces: `[greet \"hello world\"]`\n- To include a literal `[` in your text, use `[[`: `[[Y,n]?` renders as `[Y,n]?`\n\n**Token Rules:**\n\n- **Case-insensitive:** `[user]`, `[USER]`, and `[UsEr]` are equivalent\n- **Spaces are ignored:** `[  user  ]`, `[user]`, and `[    user]` are equivalent\n- **Multiple tokens per bracket:** `[lightblue blink user]` is equivalent to `[lightblue][blink][user]`\n\n**Special Character Codes:**\n\n- ASCII codes: `[65]` renders as the character 'A'\n- UTF-8 codes: `[U+00A9]` renders as the copyright symbol ©\n\nIf you need to include CP437 characters, convert them to UTF-8 first:\n\n```bash\niconv -f CP437 -t UTF-8 input.mec \u003e output.mec\n```\n\n### Variables\n\nVariables can be passed at execution time to substitute values in templates. Variables are passed as a `map[string]any` where keys match token names.\n\n```go\ntemplate := \"Hello, [name]! You have [count] messages.\"\ninterpreter.ExecString(template, map[string]any{\n\t\"name\":  \"Alice\",\n\t\"count\": 42,\n})\n```\n\n**Variable Priority:** Variables passed at execution time override registered tokens with the same name. This allows you to provide runtime values that take precedence over static token implementations.\n\n### Color Tokens\n\nMECCA supports multiple color modes for text coloring.\n\n**Basic Colors (4-bit ANSI):**\n\nSet foreground color: `[red]text[reset]`  \nSet background color: `[red on white]text[reset]`\n\nAvailable colors for both foreground and background:\n- `black`, `red`, `green`, `yellow`, `blue`, `magenta`, `cyan`, `white`\n\nAdditional foreground-only colors (light variants):\n- `lightblack`, `lightred`, `lightgreen`, `lightyellow`, `lightblue`, `lightmagenta`, `lightcyan`, `lightwhite`\n\n**256-Color Mode:**\n\nUse a color number prefixed with `#`: `[#202]text[reset]` (orange)\n\n**True Color (RGB):**\n\nUse a 6-digit hex color code: `[#FF0000]text[reset]` (red)\n\n**Background Colors:**\n\nSet background using `on`: `[red on white]`, `[lightblue on #00008B]`\n\nYou can also use the `[ON \u003ccolor\u003e]` token to set background only: `[ON blue]text[reset]`\n\n### Text Style Tokens\n\nMECCA provides various tokens to control text appearance:\n\n**Text Styles:**\n- `[bold]` or `[bright]` - Bold text\n- `[dim]` - Dim/faint text\n- `[underline]` - Underlined text\n- `[italic]` - Italic text\n- `[strike]` - Strikethrough text\n- `[reverse]` - Reverse foreground and background colors\n- `[blink]` - Blinking text (use `[steady]` to cancel)\n- `[reset]` - Reset all styling\n\n**Style Management:**\n- `[save]` - Save current color and style state\n- `[load]` - Restore previously saved color and style state\n\n### Cursor Control Tokens\n\nMECCA provides tokens for cursor movement and screen control:\n\n**Screen Clearing:**\n- `[cls]` - Clear the entire screen\n- `[cleos]` - Clear to end of screen\n- `[cleol]` - Clear to end of line\n\n**Cursor Movement:**\n- `[up]` - Move cursor up one line\n- `[down]` - Move cursor down one line\n- `[left]` - Move cursor left one column\n- `[right]` - Move cursor right one column\n- `[cr]` - Carriage return (move to beginning of line)\n- `[lf]` - Line feed (move to next line)\n- `[locate \u003crow\u003e \u003ccolumn\u003e]` - Move cursor to specific position (0-indexed)\n\n**Cursor Position:**\n- `[savecursor]` - Save current cursor position\n- `[restorecursor]` - Restore saved cursor position\n\n**Drawing:**\n- `[line \u003clength\u003e \u003cchar\u003e]` - Draw a line using the specified character (e.g., `[line 40 -]`)\n\n### File Inclusion\n\nMECCA supports including other files in templates:\n\n```\n[include filename.mec]\n```\n\nThe included file path is resolved relative to the template root directory. Included files can contain any valid MECCA tokens, including other `[include]` directives (circular includes are detected and prevented).\n\n**Other File Tokens:**\n\n- `[ansi \u003cfilename\u003e]` - Include an ANSI art file directly\n- `[ansiconvert \u003cfilename\u003e \u003ccharset\u003e]` - Convert and include a file from a specific character encoding (e.g., `cp437`)\n\n### Custom Tokens\n\nYou can extend MECCA by registering custom tokens that execute Go functions when encountered in templates.\n\n**Token Function Signature:**\n\n```go\ntype TokenFunc func(args []string) string\n```\n\nThe function receives a slice of string arguments and returns the substitution string. For example, `[repeat 3 hello]` with `argCount: 2` would call the function with `args = [\"3\", \"hello\"]`.\n\n**Registering Tokens:**\n\n```go\ninterpreter.RegisterToken(\"name\", function, argCount)\n```\n\n- **name**: Token name (case-insensitive)\n- **function**: The function to call\n- **argCount**: Number of expected arguments\n\n**Example:**\n\n```go\n// Token with no arguments\ninterpreter.RegisterToken(\"user\", func(args []string) string {\n\treturn \"John Doe\"\n}, 0)\n\n// Token with one argument\ninterpreter.RegisterToken(\"greet\", func(args []string) string {\n\tif len(args) \u003e 0 {\n\t\treturn \"Hello, \" + args[0] + \"!\"\n\t}\n\treturn \"Hello!\"\n}, 1)\n```\n\n**Important Notes:**\n\n- Token names are case-insensitive\n- Registered tokens can be overridden by variables passed at execution time\n- Registering a token with an existing name will cause a panic\n- Token functions should return plain strings; styling is applied by the interpreter\n- If a token is called with fewer arguments than specified, the function receives an empty slice\n\n## License\n\nThis implementation of the MECCA language is released under the MIT license. See the LICENSE file for more information.\n\n## Acknowledgements\n\nThe original MECCA language was designed by Scott J. Dudley for the Maximus BBS software. This implementation is based on the original MECCA language and has been adapted for the Go programming language.\n\nI thank Scott J. Dudley for creating the original MECCA language and for making it available to the public. When I was a teenager, I spent many hours creating interactive content for my BBS using the MECCA language, and I have fond memories of those days. I hope that this implementation will allow others to create similar content for modern BBS systems.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmatjam%2Fmecca","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmatjam%2Fmecca","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmatjam%2Fmecca/lists"}