{"id":15061146,"url":"https://github.com/wllfaria/terml","last_synced_at":"2025-04-10T06:36:58.603Z","repository":{"id":229382140,"uuid":"776258135","full_name":"wllfaria/terml","owner":"wllfaria","description":"Terminal manipulation library in pure Ocaml. Make text-based terminal applications with ease","archived":false,"fork":false,"pushed_at":"2024-03-29T20:37:17.000Z","size":671,"stargazers_count":9,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-02-02T21:37:30.290Z","etag":null,"topics":["cli","ocaml","terminal","terminal-ui","tui"],"latest_commit_sha":null,"homepage":"","language":"OCaml","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/wllfaria.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGES.md","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}},"created_at":"2024-03-23T02:34:12.000Z","updated_at":"2024-12-07T18:41:14.000Z","dependencies_parsed_at":"2024-03-29T21:39:04.688Z","dependency_job_id":null,"html_url":"https://github.com/wllfaria/terml","commit_stats":null,"previous_names":["wllfaria/terml"],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wllfaria%2Fterml","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wllfaria%2Fterml/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wllfaria%2Fterml/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wllfaria%2Fterml/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wllfaria","download_url":"https://codeload.github.com/wllfaria/terml/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239194325,"owners_count":19598015,"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":["cli","ocaml","terminal","terminal-ui","tui"],"created_at":"2024-09-24T23:09:50.588Z","updated_at":"2025-02-16T20:31:05.218Z","avatar_url":"https://github.com/wllfaria.png","language":"OCaml","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ch1 align=\"center\"\u003e\u003cimg height=\"350px\" src=\"./.github/logo.png\"/\u003e\u003c/h1\u003e\n\n# Terminal Manipulation Library\n\nTerml is a pure-ocaml library for manipulating terminal output. Making\npossible to write text-based interfaces with ease.\n\nThe library is designed to be simple and easy to use. Inspired by the\nrust [Crossterm](https://github.com/crossterm-rs/crossterm) library.\n\n\n## Tutorial\nCheck out the [examples](./examples) directory to see examples that range \nfrom basic applications to more complex ones.\n\n### Getting started\nIn this tutorial, we will print a colored text prompting the user to type\nsomething.\n\nWe will start by adding terml as a library dependency to our project.\n\n```ocaml\n(executable\n  (name my_terml_app)\n  (libraries terml))\n```\n\nNow we need to install the library using `opam`.\n\n```bash\nopam install terml\n```\n\nOpam will install the library and its dependencies, and after that, we can run\n`dune build` to check if everything went well.\n\nAwesome, now we can start writing our application. Start by creating a new\n`main.ml` file and open the `Terml` module.\n\n```ocaml\nopen Terml\n```\n\nIn this tutorial, we will start by setting the terminal to `raw mode`, this will\nallow us to read input without the need of pressing enter.\n\n```ocaml\nlet () =\n  let restore = Terminal.enable_raw_mode () in\n```\n\n`enable_raw_mode` returns the previous state of the terminal, so we can restore\nit later.\n\nNow we can make our colored text. This is done by using the `Style` module.\n\n```ocaml\nlet () =\n  let restore = Terminal.enable_raw_mode () in\n  let greeting =\n    Style.(\n      styled ()\n      |\u003e bg (Color.from \"#c1121f\")\n      |\u003e fg (Color.from \"#fdf0d5\")\n      |\u003e bold\n      |\u003e make \"Type anything below: \")\n  in\n```\n\nWe are using the `styled` function to create a new styled type, then we are\napplying styles to it. And finally, we are applying the styles to text \nusing the `make` function.\n\nGreat, now we will print the text to the terminal, and also enter the alternate\nscreen mode. This is done by the `Command` module.\n\n```ocaml\nlet () =\n  let restore = Terminal.enable_raw_mode () in\n  let greeting =\n    Style.(\n      styled ()\n      |\u003e bg (Color.from \"#c1121f\")\n      |\u003e fg (Color.from \"#fdf0d5\")\n      |\u003e bold\n      |\u003e make \"Type anything below, use 'q' to exit: \")\n  in\n  Command.execute\n    [\n      Command.Terminal Terminal.EnterAlternateScreen;\n      Command.Terminal Terminal.(ClearScreen All);\n      Command.Cursor Cursor.(MoveTo (1, 1));\n      Command.Print greeting;\n      Command.Cursor Cursor.(MoveTo (2, 1));\n    ]\n```\n\nHere we are using the `execute` function to run a list of commands. We are\nentering the alternate screen mode, clearing the screen, moving the cursor to\nthe top-left corner, printing the greeting, and moving the cursor to the second\nline, where the user will type.\n\nAwesome, now we just need to read the user input and print it to the terminal.\nThis is easily done by the `Events` module.\n\n```ocaml\nlet () =\n  let restore = Terminal.enable_raw_mode () in\n  let greeting =\n    Style.(\n      styled ()\n      |\u003e bg (Color.from \"#c1121f\")\n      |\u003e fg (Color.from \"#fdf0d5\")\n      |\u003e bold\n      |\u003e make \"Type anything below, use 'q' to exit: \")\n  in\n  Command.execute\n    [\n      Command.Terminal Terminal.EnterAlternateScreen;\n      Command.Terminal Terminal.(ClearScreen All);\n      Command.Cursor Cursor.(MoveTo (1, 1));\n      Command.Print greeting;\n      Command.Cursor Cursor.(MoveTo (2, 1));\n    ];\n  let should_quit = ref false in\n  let channel = Events.poll () in\n  while not !should_quit do\n    let event = Event.sync (Event.receive channel) in\n    match event with\n    | Events.Key { code = Char \"q\"; _ } -\u003e should_quit := true\n    | Events.Key { code = Char c; _ } -\u003e Command.execute [ Command.Print c ]\n    | _ -\u003e ()\n  done;\n  Command.execute [ Command.Terminal Terminal.LeaveAlternateScreen ];\n  Terminal.disable_raw_mode restore\n```\n\nOk, we just did a lot of things, let's break it down.\n\nWe are creating a boolean reference to define when to quit the application.\nThen, we are using `Events.poll`. This function returns a channel that we can\nuse to receive events.\n\nWe are using a while loop to keep the application running until the user types\n`q`. Inside the loop, we receive events from the channel and match them.\n\nEvents can be of different types, in this case, we are only interested in the\n`Key` variant. Also, for simplicity, we ignore all other fields of the event.\n\nIf the user types `q`, we set the `should_quit` reference to `true`, and the\napplication will exit the loop.\n\nIf the user types any other character, we print it to the terminal.\n\nFinally, we leave the alternate screen mode and disable the raw mode.\n\nWow, that was a lot. But we did it! We created our first Terml application,\nlets run it.\n\n```bash\ndune exec my_terml_app\n```\n\nAnd that's it! You should see a colored text prompting you to type something, \nLike this:\n\n![Tutorial](./.github/tutorial.gif)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwllfaria%2Fterml","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwllfaria%2Fterml","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwllfaria%2Fterml/lists"}