{"id":17942631,"url":"https://github.com/petercamilleri/mini_term","last_synced_at":"2026-01-21T15:33:30.297Z","repository":{"id":56883918,"uuid":"154154505","full_name":"PeterCamilleri/mini_term","owner":"PeterCamilleri","description":"A portable abstraction of the console for creating interactive character mode applications.","archived":false,"fork":false,"pushed_at":"2021-05-19T15:11:35.000Z","size":101,"stargazers_count":1,"open_issues_count":2,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-14T08:39:13.071Z","etag":null,"topics":["console","cross-platform","ruby","rubygem"],"latest_commit_sha":null,"homepage":"","language":"Ruby","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/PeterCamilleri.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-10-22T14:03:30.000Z","updated_at":"2023-03-05T04:20:47.000Z","dependencies_parsed_at":"2022-08-20T13:10:53.702Z","dependency_job_id":null,"html_url":"https://github.com/PeterCamilleri/mini_term","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PeterCamilleri%2Fmini_term","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PeterCamilleri%2Fmini_term/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PeterCamilleri%2Fmini_term/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PeterCamilleri%2Fmini_term/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/PeterCamilleri","download_url":"https://codeload.github.com/PeterCamilleri/mini_term/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247809992,"owners_count":20999821,"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":["console","cross-platform","ruby","rubygem"],"created_at":"2024-10-29T03:06:32.252Z","updated_at":"2026-01-21T15:33:30.289Z","avatar_url":"https://github.com/PeterCamilleri.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# MiniTerm\n\nThe MiniTerm gem is a simple bit of code that seeks to smooth over the bumps\nand pot holes encountered when interacting with the console terminal to create\nconsole based CLI applications. More than most it also seeks to eliminate\nworries about the nasty cross-platform issues encountered between Windows,\nLinux, and MAC OS-X systems.\n\nThis code started out its life buried deep within the code of the mini readline\ngem where it helped that gem do its job. A while ago it was realized that the\nservices provided were invaluable for a much wider range of development. I was\nincreasingly frustrated by my need to \"go-around\" mini readline to get at some\nof its lower level features. When that happens it is a clear sign that a gem is\ndoing too much and has too many responsibilities.\n\nThat's why the low level terminal functionality was split out into the mini\nterm gem contained in this code repository. At the same time, the lessons\nlearned from the earlier version of the code have been applied to make this\ncode better and also not any more incompatible than needed. Since mini readline\nwas the only \"user\" of the old code, moving out in some new directions should\nnot pose a migration issue except for me.\n\nFinally, this gem would not be possible without the excellent insight into the\ngnarly world of win_32_api, dl, and fiddle I gained reading and copying the\ncode in the [ConnorAtherton/rb-readline](https://github.com/ConnorAtherton/rb-readline)\nproject and gem. *Thank You!*\n\nSo, what hurdles do we expect the mini term gem to overcome? What cross-platform\nissues vex us? After all, it's not as if Ruby ignores the issue of low-level\nconsole access. It has the io/console and io/wait code libraries. They are\nsupposed to give low level access right?\n\nAnd this is the point where the wheels start falling off.\n\n* The io/console library has truly awful documentation. Many methods lack any\nsort of description or meaningful parameter names. The developer is left to\nreverse engineering the behavior of the code. The programming process borders\non the tribal. In this regard, io/wait is OK. Too bad it only plays a limited\nrole.\n\n* The io/console library does not work correctly under Windows. And before we\nhear a chorus of \"Switch to Linux\", the anti-windows squad are reminded that\nthis is a cross-platform tool, just like Ruby is supposed to be. The issue is\nthat raw mode is not so raw under windows. In fact it's so cooked that it more\nresembles a chunk of charcoal! It just plain does not work. Fortunately there\nis an answer. Ruby has access to the various APIs though the 'fiddle' gem.\nThis gem is used to emulate the deprecated 'win32api' gem.\n\n* Under JRuby, the situation is even worse. The io/console facility is\nincapable of manipulating the tty or console at all. A true non-starter. Only\nhere's where things take a twist for the weird. Under Windows, JRuby *does*\nsupport the 'win32api' gem. It even works! I'm not at all sure how to support\nJRuby under Linux or Mac OS-X.\n\n* Working with Rubinius is perhaps the worst of all. Rubinius *still* does not\nrun under Windows. Until such time as I am able to develop under a supported\nplatform, or can collaborate with someone who can, this is a non-starter. Don't\nstay tuned, don't hold your breath; This problem is *not* going away any time\nsoon.\n\n#### So! What do we have?\n\nThis is a matrix of language versions and environments that have are tested or\nhave been tested at one time or another.\n\nRuby           | Win32   | Win64   | Cygwin  | Linux   | Mac\n---------------|---------|---------|---------|---------|---------\nruby 2.1.6p336 | Yes?    | Yes??   | Yes??   | Yes??   | Yes??\nruby 2.2.3p173 | Yes??   | Yes??   | Yes?    | Yes??   | Yes??\nruby 2.3.3p222 | Yes??   | Yes     | Yes??   | Yes??   | Yes??\njruby 9.1.5.0  | Yes?    | Yes??   | Maybe?  | Maybe?  | Maybe?\n\nThis table will be updated as more information becomes available. Check the\n[github  repository](https://github.com/PeterCamilleri/mini_term) for the\nlatest info.\n\nNotes:\n* Mini term uses keyword parameters so Ruby 2.0 or later is required. This is\nwhy older versions of Ruby have been removed from this table.\n* Yes? means that this combination was once tested with very similar code and\nshould be OK, we hope. Testing would be nice.\n* Yes?? means that this combination *should* work but needs testing.\n\n## Installation\n\nAdd this line to your application's Gemfile:\n\n```ruby\ngem 'mini_term'\n```\n\nAnd then execute:\n\n    $ bundle\n\nOr install it yourself as:\n\n    $ gem install mini_term\n\n## Usage\n\nThe mini term can be used in a project with:\n\n```ruby\nrequire 'mini_term'\n```\n\n### Interface Summary\n\nThe following is a brief summary of the public interface of the MiniTerm module:\n\n**Constants**\n\n    VERSION       -- A version string of the form \"9.9.9\"\n    DESCRIPTION   -- A descriptive string.\n    VALID_OPTIONS -- An array of the supported option symbols.\n    TERM_TYPE     -- Either :windows or :ansi\n    TERM_PLATFORM -- One of :windows, :cygwin, :macosx, :linux, or :unix\n\n**Methods**\n\n    open(options), close, open?\n    term_info, width, height, ansi?, windows?, java?\n    set_posn(row: the_current_row, column:)\n    raw {}, raw?, begin_raw_input, end_raw_input\n    get_raw_char, has_raw_char? flush\n    get_mapped_char, add_map(type) {}, map_types\n    print(text), clear_screen\n\n\n*MiniTerm.open* - Before it can be used, the mini term should be opened. This\nis done with:\n\n```ruby\nMiniTerm.open(options)\n```\n\nThe open method can take some optional arguments:\n\n    pass_ctrl_c: true   # The control+c character is passed through to the application.\n    pass_ctrl_c: false  # (Default) The control+c character is used by the OS.\n\n    pass_ctrl_s: true   # The control+s character is passed through to the application.\n    pass_ctrl_s: false  # (Default) The control+s character is used by the OS.\n\n    quiet: true         # Suppress various warning messages.\n    quiet: false        # (Default) Display warning message.\n\n    strict: true        # Invalid options raise an exception.\n    strict: false       # (Default) Invalid options cause no such fuss.\n\n\nIf an unsupported or invalid option is detected, a warning message is displayed\nunless the quiet option is active. Alternatively, if the strict option is\nenabled, the MiniTermStrict exception is raised in that case.\n\n*MiniTerm.close* - The converse to open is close. It takes no arguments.\n\n```ruby\nMiniTerm.close\n```\n\nRest assured that if your program should forget to close MiniTerm, the gem will\nclose itself automatically when your program exits. This ensures that the\nterminal will not be left in a unworkable state. It will also tell you that it\nhad to \"Force MiniTerm.close\" unless it was opened with the quiet: true option.\n\n*MiniTerm.terminfo, etc* - These methods return information about the current\nMiniTerm operating environment.\n\n```ruby\nMiniTerm.terminfo   # Returns the console's number of [rows, columns]\nMiniTerm.width      # Returns the console's number of columns.\nMiniTerm.height     # Returns the console's number of rows.\nMiniTerm.ansi?      # Is ANSI mode active?\nMiniTerm.windows?   # Is Windows mode active?\nMiniTerm.java?      # Is Java active?\n```\n\n*MiniTerm.set_posn* - This method is used to place the cursor anywhere on the\nscreen or anywhere in the current line.\n\n```ruby\nset_posn(row: the_current_row, column:)\n```\nNote: If the row parameter is omitted, the row remains on the current row. The\ncolumn parameter is always required.\n\n*MiniTerm.raw, etc* - These methods controll the use of raw console input, one\nof the major features provided by the MiniTerm gem. These methods are:\n\n```ruby\nMiniTerm.raw {|self|  }   # Execute the block with raw mode active.\nMiniTerm.raw?             # Is raw mode active now?\n```\n\nNote that raw blocks may be nested to any depth without undesirable\nside-effects. Infinite recursion is, however, strongly discouraged.\n\n*MiniTerm.get_raw_char, etc* - These methods deal with the keyboard in a raw\nmode. They do not echo or wait for the user to press enter or any of those\nother cooked mode things. Keyboard data in the raw!\n\n```ruby\nMiniTerm.get_raw_char     # Wait for a keystroke in raw mode.\nMiniTerm.has_raw_char?    # Are there any keys waiting?\nMiniTerm.flush            # Flush any keys in the buffer.\n```\n\nNote that the get_raw_char method needs to be run with raw mode in effect. See\nthe raw methods above for more on that. Also, in raw mode, some keys, especially\nextended keys may be composed of more than one byte. These methods only return\none byte at a time.\n\n*MiniTerm.get_mapped_char, etc* - A mapped character is one or more raw\ncharacters that are mapped to an array containing a symbol and the characters\nthat pathed the mapping to that sysmbol. For example:\n\n```ruby\n[:go_left, \"\\e[D\"]\n```\n\nThe conversion process from a stream of raw bytes to commands is done with a\nmap. The method MiniTerm.add_map(type) {} takes one argument, the type, and a\nblock. The type is currently one of the two terminal types: :windows or :ansi.\nThe block also takes one argument, the newly created map. The code can then\ndefine entries in the map as follows:\n\n```ruby\nMiniTerm.add_map(:ansi) do |map|\n  map[\"\\e[D\"] = :go_left        # First\n  map[\" \"..\"~\"] = :insert_text  # Second\n  # etc etc etc\nend\n```\n\nThe \\[\\]= operator of the map object can accept two sorts of indexes.\n* A string in which case an entry for keys defined by that string is created.\nThis is the first example line above.\n* A range of characters, in which case an entry is created for each string\nin the specified range. This is the second example line above.\n\nNow, the index for each entry represents a sort of path to the command. This\npath must not be ambiguous. For example, the following will generate an error:\n\n```ruby\nMiniTerm.add_map(:ansi) do |map|\n  map[\"\\e\"]   = :cancel\n  map[\"\\e[D\"] = :go_left\n  # etc etc etc\nend\n```\n\nTo understand this, imagine that this map were allowed. The user presses the\nleft arrow key. This generates the sequence \"\\e[D\". The \"\\e\" is received first\nand mapped to a :cancel command by the first rule. Then the \"[D\" characters are\nreceived and most likely inserted as these are printable characters. That is\nnot what is wanted because the left arrow key was mapped to the wrong actions.\nThis map is ambiguous mapping error is why MiniTerm signals a MiniTermKME error\nwhen the map is created.\n\nThe method MiniTerm.map_types list the types for key maps that have been added.\nIn most cases this will be [:ansi, :windows]. A map should be defined for each\nof the two term types, unless the application is only intended for one type.\n\n#### Exceptions:\n\nThe mini term gem uses the following exception classes:\n\n    Exception              # From Ruby.\n      StandardError        # From Ruby.\n        MiniTermError      # The abstract base exception for mini term.\n          MiniTermKME      # A keyboard mapping error was detected.\n          MiniTermNoMap    # No map can be found for the current terminal type.\n          MiniTermNotRaw   # Raw mode is required for this operation.\n          MiniTermStrict   # An exception raised due to strictness.\n          MiniTermWTF      # An internal error happened. This shouldn't happen.\n\n## Contributing\n\n1. Fork it\n2. Create your feature branch (`git checkout -b my-new-feature`)\n3. Commit your changes (`git commit -am 'Add some feature'`)\n4. Push to the branch (`git push origin my-new-feature`)\n5. Create new Pull Request\n\nOR...\n\n* Make a suggestion by raising an\n [issue](https://github.com/PeterCamilleri/mini_term/issues)\n. All ideas and comments are welcome.\n\n## License\n\nThe gem is available as open source under the terms of the\n[MIT License](./LICENSE.txt).\n\n## Code of Conduct\n\nEveryone interacting in the mini_term project’s codebases, issue trackers,\nchat rooms and mailing lists is expected to follow the\n[code of conduct](./CODE_OF_CONDUCT.md).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpetercamilleri%2Fmini_term","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpetercamilleri%2Fmini_term","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpetercamilleri%2Fmini_term/lists"}