{"id":28051469,"url":"https://github.com/raphamorim/myst","last_synced_at":"2025-05-12T01:03:09.955Z","repository":{"id":291170705,"uuid":"970278013","full_name":"raphamorim/myst","owner":"raphamorim","description":"mystical shell parser, formatter, and interpreter with Bash support","archived":false,"fork":false,"pushed_at":"2025-05-02T20:28:25.000Z","size":193,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-05-02T21:30:52.001Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/raphamorim.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,"zenodo":null}},"created_at":"2025-04-21T19:03:40.000Z","updated_at":"2025-05-02T21:25:57.000Z","dependencies_parsed_at":"2025-05-02T21:30:53.915Z","dependency_job_id":"c38b0ae9-40c0-47de-a97d-c49c90cd880d","html_url":"https://github.com/raphamorim/myst","commit_stats":null,"previous_names":["raphamorim/myst"],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/raphamorim%2Fmyst","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/raphamorim%2Fmyst/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/raphamorim%2Fmyst/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/raphamorim%2Fmyst/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/raphamorim","download_url":"https://codeload.github.com/raphamorim/myst/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253655955,"owners_count":21943081,"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":"2025-05-12T01:03:08.915Z","updated_at":"2025-05-12T01:03:09.942Z","avatar_url":"https://github.com/raphamorim.png","language":"Rust","funding_links":[],"categories":["Rust"],"sub_categories":[],"readme":"# myst (work in progress)\n\n*A mystical shell parser, formatter, and interpreter written in Rust.*\n\nMyst is a fast, extensible, and hackable toolkit for working with POSIX-style shell scripts. It includes a parser, formatter, and interpreter built from scratch in Rust. Myst understands real-world shell syntax and provides structured AST access for static analysis, tooling, and transformation.\n\n\u003e Inspired by [mvdan/sh](https://pkg.go.dev/mvdan.cc/sh/v3/syntax), but engineered from the ground up with performance and extensibility in mind.\n\n## Motivation\n\nMyst was created to serve two main purposes: as a learning project to better understand shell parsing and syntax, and as a tool for testing and embedding within the [Rio terminal emulator](https://github.com/raphamorim/rio/), a GPU-accelerated terminal written in Rust.\n\n## Install as your shell\n\n\u003e ⚠️ Myst is still under development. Use it with caution in production environments.\n\nOption 1:\n\n```bash\ncargo install mystsh\n```\n\nOption 2:\n\n```bash\ngit clone https://github.com/raphamorim/myst.git\ncd myst \u0026\u0026 cargo install --path .\n```\n\nOption 3:\n\n```bash\ngit clone https://github.com/raphamorim/myst.git\ncd myst\ncargo build --release\n\n# MacOS/BSD: Change /bin/ to /usr/local/bin/\nsudo cp target/release/myst /bin/\nmyst\n```\n\n#### Interpreter readline support\n\n- ✅ Kill Ring: Text deleted with Ctrl+K, Ctrl+U, or Ctrl+W is saved to a kill ring, allowing it to be yanked (pasted) with Ctrl+Y.\n- ✅ Ability to transpose characters with Ctrl+T.\n- ✅ Incremental History Search: Pressing Ctrl+R initiates a search through command history. Pressing Ctrl+R again searches for the next occurrence of the same pattern.\n- ✅ Bidirectional character and word movement keys.\n- ✅ Ctrl+A: Move cursor to the beginning of the line.\n- ✅ Ctrl+E: Move cursor to the end of the line.\n- ✅ Ctrl+B: Move backward one character (same as left arrow).\n- ✅ Ctrl+F: Move forward one character (same as right arrow).\n- ✅ Ctrl+K: Cut text from cursor to end of line (kill).\n- ✅ Ctrl+U: Cut text from beginning of line to cursor (kill).\n- ✅ Ctrl+Y: Paste (yank) previously killed text.\n- ✅ Ctrl+P: Previous history entry (same as up arrow).\n- ✅ Ctrl+N: Next history entry (same as down arrow).\n- ✅ Ctrl+T: Transpose (swap) characters at cursor.\n- ✅ Ctrl+D: Delete character under cursor (or exit if line is empty).\n- ✅ Ctrl+R: Reverse incremental search through history.\n- ✅ Ctrl+W: Delete word backward.\n- ✅ Ctrl+L: Clear screen and redraw prompt.\n- ✅ Ctrl+C: Cancel/interrupt.\n- ✅ Arrow keys for navigation and history.\n\n## 🔌 Embed in Your Rust Project\n\n#### As an Interpreter\n\n```rust\nuse mystsh::interpreter::Interpreter;\nuse std::io;\n\nfn main() -\u003e io::Result\u003c()\u003e {\n    let mut interpreter = Interpreter::new();\n    interpreter.run_interactive()?;\n    Ok(())\n}\n```\n\n#### As a Lexer/Tokenizer\n\n```rust\nfn test_tokens(input: \u0026str, expected_tokens: Vec\u003cTokenKind\u003e) {\n    let mut lexer = Lexer::new(input);\n    for expected in expected_tokens {\n        let token = lexer.next_token();\n        assert_eq!(\n            token.kind, expected,\n            \"Expected {:?} but got {:?} for input: {}\",\n            expected, token.kind, input\n        );\n    }\n\n    // Ensure we've consumed all tokens\n    let final_token = lexer.next_token();\n    assert_eq!(\n        final_token.kind,\n        TokenKind::EOF,\n        \"Expected EOF but got {:?}\",\n        final_token.kind\n    );\n}\n\n#[test]\nfn test_function_declaration() {\n    let input = \"function greet() { echo hello; }\";\n    let expected = vec![\n        TokenKind::Function,\n        TokenKind::Word(\"greet\".to_string()),\n        TokenKind::LParen,\n        TokenKind::RParen,\n        TokenKind::LBrace,\n        TokenKind::Word(\"echo\".to_string()),\n        TokenKind::Word(\"hello\".to_string()),\n        TokenKind::Semicolon,\n        TokenKind::RBrace,\n    ];\n    test_tokens(input, expected);\n}\n```\n\n#### As a Parser\n\n```rust\nuse mystsh::lexer::Lexer;\nuse mystsh::parser::Parser;\n\n#[test]\nfn test_simple_command() {\n    let input = \"echo hello world\";\n    let lexer = Lexer::new(input);\n    let mut parser = Parser::new(lexer);\n    let result = parser.parse_script();\n\n    match result {\n        Node::List {\n            statements,\n            operators,\n        } =\u003e {\n            assert_eq!(statements.len(), 1);\n            assert_eq!(operators.len(), 0);\n\n            match \u0026statements[0] {\n                Node::Command {\n                    name,\n                    args,\n                    redirects,\n                } =\u003e {\n                    assert_eq!(name, \"echo\");\n                    assert_eq!(args, \u0026[\"hello\", \"world\"]);\n                    assert_eq!(redirects.len(), 0);\n                }\n                _ =\u003e panic!(\"Expected Command node\"),\n            }\n        }\n        _ =\u003e panic!(\"Expected List node\"),\n    }\n}\n```\n\n## Myst Feature Coverage\n\nThis table outlines the supported features of POSIX Shell and Bash. Use it to track what your **Myst** parser and interpreter implementation in Rust supports.\n\nLegends:\n\n- ✅ fully supported.\n- ⚠️ only supported in parser and formatter.\n- ❌ not supported.\n\n| Category              | Functionality / Feature                         | POSIX Shell | Bash | Myst | Notes |\n|-----------------------|--------------------------------------------------|-------------|------|------|-------|\n| **Basic Syntax**      | Variable assignment                             | ✅          | ✅   | ✅  | `VAR=value` |\n|                       | Command substitution                            | ✅          | ✅   | [ ]  | `$(cmd)` and `` `cmd` `` |\n|                       | Arithmetic substitution                         | ❌          | ✅   | [ ]  | `$((expr))` |\n|                       | Comments (`#`)                                  | ✅          | ✅   | ✅  | |\n|                       | Quoting (`'`, \"\", `\\`)                          | ✅          | ✅   | [ ]  | |\n|                       | Globbing (`*`, `?`, `[...]`)                    | ✅          | ✅   | [ ]  | |\n| **Control Structures**| `if` / `else` / `elif`                          | ✅          | ✅   | [ ]  | |\n|                       | `case` / `esac`                                 | ✅          | ✅   | [ ]  | |\n|                       | `for` loops                                     | ✅          | ✅   | [ ]  | |\n|                       | `while`, `until` loops                          | ✅          | ✅   | [ ]  | |\n|                       | `select` loop                                   | ❌          | ✅   | [ ]  | |\n|                       | `[[ ... ]]` test command                        | ❌          | ✅   | [ ]  | Extended test |\n| **Functions**         | Function definition (`name() {}`)               | ✅          | ✅   | [ ]  | |\n|                       | `function` keyword                              | ❌          | ✅   | [ ]  | Bash-specific |\n| **I/O Redirection**   | Output/input redirection (`\u003e`, `\u003c`, `\u003e\u003e`)       | ✅          | ✅   | [ ]  | |\n|                       | Here documents (`\u003c\u003c`, `\u003c\u003c-`)                    | ✅          | ✅   | [ ]  | |\n|                       | Here strings (`\u003c\u003c\u003c`)                            | ❌          | ✅   | [ ]  | |\n|                       | File descriptor duplication (`\u003e\u0026`, `\u003c\u0026`)        | ✅          | ✅   | [ ]  | |\n| **Job Control**       | Background execution (`\u0026`)                      | ✅          | ✅   | [ ]  | |\n|                       | Job control commands (`fg`, `bg`, `jobs`)       | ✅          | ✅   | [ ]  | May be interactive-only |\n|                       | Process substitution (`\u003c(...)`, `\u003e(...)`)       | ❌          | ✅   | [ ]  | |\n| **Arrays**            | Indexed arrays                                  | ❌          | ✅   | [ ]  | `arr=(a b c)` |\n|                       | Associative arrays                              | ❌          | ✅   | [ ]  | `declare -A` |\n| **Parameter Expansion** | `${var}` basic expansion                    | ✅          | ✅   | [ ]  | |\n|                       | `${var:-default}`, `${var:=default}`            | ✅          | ✅   | [ ]  | |\n|                       | `${#var}`, `${var#pattern}`                     | ✅          | ✅   | [ ]  | |\n|                       | `${!var}` indirect expansion                    | ❌          | ✅   | [ ]  | |\n|                       | `${var[@]}` / `${var[*]}` array expansion       | ❌          | ✅   | [ ]  | |\n| **Command Execution** | Pipelines (`|`)                                 | ✅          | ✅   | [ ]  | |\n|                       | Logical AND / OR (`\u0026\u0026`, `||`)                   | ✅          | ✅   | [ ]  | |\n|                       | Grouping (`( )`, `{ }`)                         | ✅          | ✅   | [ ]  | |\n|                       | Subshell (`( )`)                                | ✅          | ✅   | [ ]  | |\n|                       | Coprocesses (`coproc`)                          | ❌          | ✅   | [ ]  | |\n| **Builtins**          | `cd`, `echo`, `test`, `read`, `eval`, etc.      | ✅          | ✅   | [ ]  | |\n|                       | `shopt`, `declare`, `typeset`                   | ❌          | ✅   | [ ]  | Bash-only |\n|                       | `let`, `local`, `export`                        | ✅          | ✅   | [ ]  | |\n| **Debugging**         | `set -x`, `set -e`, `trap`                      | ✅          | ✅   | [ ]  | |\n|                       | `BASH_SOURCE`, `FUNCNAME` arrays                | ❌          | ✅   | [ ]  | |\n| **Miscellaneous**     | Brace expansion (`{1..5}`)                      | ❌          | ✅   | [ ]  | |\n|                       | Extended globbing (`extglob`)                   | ❌          | ✅   | [ ]  | Requires `shopt` |\n|                       | Bash version variables (`$BASH_VERSION`)        | ❌          | ✅   | [ ]  | |\n|                       | Source other scripts (`.` or `source`)          | ✅          | ✅   | [ ]  | `source` is Bash synonym |\n\n\n## 📦 Crate Info\n\nAdd Myst to your Cargo.toml:\n\n```toml\nmystsh = \"0.x\"\n```\n\n## TODO\n\n- [ ] If for parser and interop.\n- [ ] Functions for parser and interop.\n- [ ] Loops for parser and interop.\n- [ ] Array for parser and interop.\n\n## License\n\n[GPL-3.0 License](LICENSE) © [Raphael Amorim](https://github.com/raphamorim/)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fraphamorim%2Fmyst","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fraphamorim%2Fmyst","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fraphamorim%2Fmyst/lists"}