summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThijs Schreijer <thijs@thijsschreijer.nl>2024-06-20 23:16:29 +0200
committerGitHub <noreply@github.com>2024-06-20 23:16:29 +0200
commitbb4fd73c317cc88beb5e58c1abf52138abed107f (patch)
tree35b774efc97d820a908424a5bc2452e0d6bf12a8
parentc1a64c1b75f97cef97965b3bd9a941564a6270bd (diff)
downloadluasystem-bb4fd73c317cc88beb5e58c1abf52138abed107f.zip
Release v0.4.0 (#24)v0.4.0
-rw-r--r--CHANGELOG.md14
-rw-r--r--LICENSE.md2
-rw-r--r--docs/classes/bitflags.html305
-rw-r--r--docs/examples/compat.lua.html119
-rw-r--r--docs/examples/flag_debugging.lua.html87
-rw-r--r--docs/examples/password_input.lua.html139
-rw-r--r--docs/examples/read.lua.html150
-rw-r--r--docs/examples/readline.lua.html552
-rw-r--r--docs/examples/spinner.lua.html144
-rw-r--r--docs/examples/spiral_snake.lua.html152
-rw-r--r--docs/examples/terminalsize.lua.html117
-rw-r--r--docs/index.html369
-rw-r--r--docs/modules/system.html1418
-rw-r--r--docs/topics/01-introduction.md.html27
-rw-r--r--docs/topics/02-development.md.html91
-rw-r--r--docs/topics/03-terminal.md.html225
-rw-r--r--docs/topics/CHANGELOG.md.html55
-rw-r--r--docs/topics/LICENSE.md.html29
-rw-r--r--rockspecs/luasystem-0.4.0-1.rockspec85
-rw-r--r--src/core.c5
20 files changed, 3774 insertions, 311 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index eb85c94..a3544ea 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -28,6 +28,20 @@ The scope of what is covered by the version number excludes:
## Version history
+### Version 0.4.0, released 20-Jun-2024
+
+- Feat: `getconsoleflags` and `setconsoleflags` for getting/setting the current console configuration flags on Windows
+- Feat: `getconsolecp` and `setconsolecp` for getting/setting the console codepage on Windows
+- Feat: `getconsoleoutputcp` and `setconsoleoutputcp` for getting/setting the console output codepage on Windows
+- Feat: `tcgetattr` and `tcsetattr` for getting/setting the current console configuration flags on Posix
+- Feat: `getnonblock` and `setnonblock` for getting/setting the non-blocking flag on Posix
+- Feat: `bitflags`: a support feature for the above flag type controls to facilitate bit manipulation without resorting to binary operations (to also support PuC Lua 5.1)
+- Feat: `readkey` reads a keyboard input from `stdin` in a non-blocking way (utf8, also on Windows)
+- Feat: `readansi` reads a keyboard input from `stdin` in a non-blocking way, parses ansi and utf8 sequences
+- Feat: `termsize` gets the current terminal size in rows and columns
+- Feat: `utf8cwidth` and `utf8swidth` for getting the display width (in columns) of respectively a single utf8 character, or a utf8 string
+- Feat: helpers; `termbackup`, `termrestore`, `autotermrestore`, and `termwrap` for managing the many terminal settings on all platforms.
+
### Version 0.3.0, released 15-Dec-2023
- Feat: on Windows `sleep` now has a precision parameter
diff --git a/LICENSE.md b/LICENSE.md
index df2befb..16c86d0 100644
--- a/LICENSE.md
+++ b/LICENSE.md
@@ -1,6 +1,6 @@
# MIT License
-### Copyright (c) 2016-2023 Oscar Lim
+### Copyright (c) 2016-2024 Oscar Lim
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
diff --git a/docs/classes/bitflags.html b/docs/classes/bitflags.html
new file mode 100644
index 0000000..f063149
--- /dev/null
+++ b/docs/classes/bitflags.html
@@ -0,0 +1,305 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+<head>
+ <title>Lua-System docs</title>
+ <link rel="stylesheet" href="../ldoc.css" type="text/css" />
+</head>
+<body>
+
+<div id="container">
+
+<div id="product">
+ <div id="product_logo"></div>
+ <div id="product_name"><big><b></b></big></div>
+ <div id="product_description"></div>
+</div> <!-- id="product" -->
+
+
+<div id="main">
+
+
+<!-- Menu -->
+
+<div id="navigation">
+<br/>
+<h1>Lua-System</h1>
+
+
+<ul>
+ <li><a href="../index.html">Index</a></li>
+</ul>
+
+<h2>Contents</h2>
+<ul>
+<li><a href="#Bit_flags">Bit flags </a></li>
+</ul>
+
+
+<h2>Classes</h2>
+<ul class="nowrap">
+ <li><strong>bitflags</strong></li>
+</ul>
+<h2>Modules</h2>
+<ul class="nowrap">
+ <li><a href="../modules/system.html">system</a></li>
+</ul>
+<h2>Topics</h2>
+<ul class="">
+ <li><a href="../topics/01-introduction.md.html">1. Introduction</a></li>
+ <li><a href="../topics/02-development.md.html">2. Development</a></li>
+ <li><a href="../topics/03-terminal.md.html">3. Terminal functionality</a></li>
+ <li><a href="../topics/CHANGELOG.md.html">CHANGELOG</a></li>
+ <li><a href="../topics/LICENSE.md.html">MIT License</a></li>
+</ul>
+<h2>Examples</h2>
+<ul class="nowrap">
+ <li><a href="../examples/compat.lua.html">compat.lua</a></li>
+ <li><a href="../examples/flag_debugging.lua.html">flag_debugging.lua</a></li>
+ <li><a href="../examples/password_input.lua.html">password_input.lua</a></li>
+ <li><a href="../examples/read.lua.html">read.lua</a></li>
+ <li><a href="../examples/readline.lua.html">readline.lua</a></li>
+ <li><a href="../examples/spinner.lua.html">spinner.lua</a></li>
+ <li><a href="../examples/spiral_snake.lua.html">spiral_snake.lua</a></li>
+ <li><a href="../examples/terminalsize.lua.html">terminalsize.lua</a></li>
+</ul>
+
+</div>
+
+<div id="content">
+
+<h1>Class <code>bitflags</code></h1>
+<p>Bitflags module.</p>
+<p> The bitflag object makes it easy to manipulate flags in a bitmask.</p>
+
+<p> It has metamethods that do the hard work, adding flags sets them, substracting
+ unsets them. Comparing flags checks if all flags in the second set are also set
+ in the first set. The <code>has</code> method checks if all flags in the second set are
+ also set in the first set, but behaves slightly different.</p>
+
+<p> Indexing allows checking values or setting them by bit index (eg. 0-7 for flags
+ in the first byte).</p>
+
+<p> <em>NOTE</em>: unavailable flags (eg. Windows flags on a Posix system) should not be
+ omitted, but be assigned a value of 0. This is because the <code>has</code> method will
+ return <code>false</code> if the flags are checked and the value is 0.</p>
+
+<p> See <a href="../classes/bitflags.html#system.bitflag">system.bitflag</a> (the constructor) for extensive examples on usage.</p>
+
+
+<h2><a href="#Bit_flags">Bit flags </a></h2>
+<table class="function_list">
+ <tr>
+ <td class="name" nowrap><a href="#bitflag:has_all_of">bitflag:has_all_of (subset)</a></td>
+ <td class="summary">Checks if all the flags in the given subset are set.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#bitflag:has_any_of">bitflag:has_any_of (subset)</a></td>
+ <td class="summary">Checks if any of the flags in the given subset are set.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#bitflag:value">bitflag:value ()</a></td>
+ <td class="summary">Retrieves the numeric value of the bitflag object.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#system.bitflag">system.bitflag ([value=0])</a></td>
+ <td class="summary">Creates a new bitflag object from the given value.</td>
+ </tr>
+</table>
+
+<br/>
+<br/>
+
+
+ <h2 class="section-header has-description"><a name="Bit_flags"></a>Bit flags </h2>
+
+ <div class="section-description">
+ Bitflag objects can be used to easily manipulate and compare bit flags.
+ These are primarily for use with the terminal functions, but can be used
+ in other places as well.
+ </div>
+ <dl class="function">
+ <dt>
+ <a name = "bitflag:has_all_of"></a>
+ <strong>bitflag:has_all_of (subset)</strong>
+ </dt>
+ <dd>
+ Checks if all the flags in the given subset are set.
+If the flags to check has a value <code>0</code>, it will always return <code>false</code>. So if there are flags that are
+unsupported on a platform, they can be set to 0 and the <a href="../classes/bitflags.html#bitflag:has_all_of">has_all_of</a> function will
+return <code>false</code> if the flags are checked.
+
+
+ <h3>Parameters:</h3>
+ <ul>
+ <li><span class="parameter">subset</span>
+ <span class="types"><a class="type" href="../classes/bitflags.html#system.bitflag">bitflag</a></span>
+ the flags to check for.
+ </li>
+ </ul>
+
+ <h3>Returns:</h3>
+ <ol>
+
+ <span class="types"><span class="type">boolean</span></span>
+ true if all the flags are set, false otherwise.
+ </ol>
+
+
+
+ <h3>Usage:</h3>
+ <ul>
+ <pre class="example"><span class="keyword">local</span> sys = <span class="global">require</span> <span class="string">'system'</span>
+<span class="keyword">local</span> flags = sys.<span class="function-name">bitflag</span>(<span class="number">12</span>) <span class="comment">-- b1100
+</span><span class="keyword">local</span> myflags = sys.<span class="function-name">bitflag</span>(<span class="number">15</span>) <span class="comment">-- b1111
+</span><span class="global">print</span>(flags:<span class="function-name">has_all_of</span>(myflags)) <span class="comment">-- false, not all bits in myflags are set in flags
+</span><span class="global">print</span>(myflags:<span class="function-name">has_all_of</span>(flags)) <span class="comment">-- true, all bits in flags are set in myflags</span></pre>
+ </ul>
+
+</dd>
+ <dt>
+ <a name = "bitflag:has_any_of"></a>
+ <strong>bitflag:has_any_of (subset)</strong>
+ </dt>
+ <dd>
+ Checks if any of the flags in the given subset are set.
+If the flags to check has a value <code>0</code>, it will always return <code>false</code>. So if there are flags that are
+unsupported on a platform, they can be set to 0 and the <a href="../classes/bitflags.html#bitflag:has_any_of">has_any_of</a> function will
+return <code>false</code> if the flags are checked.
+
+
+ <h3>Parameters:</h3>
+ <ul>
+ <li><span class="parameter">subset</span>
+ <span class="types"><a class="type" href="../classes/bitflags.html#system.bitflag">bitflag</a></span>
+ the flags to check for.
+ </li>
+ </ul>
+
+ <h3>Returns:</h3>
+ <ol>
+
+ <span class="types"><span class="type">boolean</span></span>
+ true if any of the flags are set, false otherwise.
+ </ol>
+
+
+
+ <h3>Usage:</h3>
+ <ul>
+ <pre class="example"><span class="keyword">local</span> sys = <span class="global">require</span> <span class="string">'system'</span>
+<span class="keyword">local</span> flags = sys.<span class="function-name">bitflag</span>(<span class="number">12</span>) <span class="comment">-- b1100
+</span><span class="keyword">local</span> myflags = sys.<span class="function-name">bitflag</span>(<span class="number">7</span>) <span class="comment">-- b0111
+</span><span class="global">print</span>(flags:<span class="function-name">has_any_of</span>(myflags)) <span class="comment">-- true, some bits in myflags are set in flags
+</span><span class="global">print</span>(myflags:<span class="function-name">has_any_of</span>(flags)) <span class="comment">-- true, some bits in flags are set in myflags</span></pre>
+ </ul>
+
+</dd>
+ <dt>
+ <a name = "bitflag:value"></a>
+ <strong>bitflag:value ()</strong>
+ </dt>
+ <dd>
+ Retrieves the numeric value of the bitflag object.
+
+
+
+ <h3>Returns:</h3>
+ <ol>
+
+ <span class="types"><span class="type">number</span></span>
+ the numeric value of the bitflags.
+ </ol>
+
+
+
+ <h3>Usage:</h3>
+ <ul>
+ <pre class="example"><span class="keyword">local</span> sys = <span class="global">require</span> <span class="string">'system'</span>
+<span class="keyword">local</span> flags = sys.<span class="function-name">bitflag</span>() <span class="comment">-- b0000
+</span>flags[<span class="number">0</span>] = <span class="keyword">true</span> <span class="comment">-- b0001
+</span>flags[<span class="number">2</span>] = <span class="keyword">true</span> <span class="comment">-- b0101
+</span><span class="global">print</span>(flags:<span class="function-name">value</span>()) <span class="comment">-- 5</span></pre>
+ </ul>
+
+</dd>
+ <dt>
+ <a name = "system.bitflag"></a>
+ <strong>system.bitflag ([value=0])</strong>
+ </dt>
+ <dd>
+ Creates a new bitflag object from the given value.
+
+
+ <h3>Parameters:</h3>
+ <ul>
+ <li><span class="parameter">value</span>
+ <span class="types"><span class="type">number</span></span>
+ the value to create the bitflag object from.
+ (<em>default</em> 0)
+ </li>
+ </ul>
+
+ <h3>Returns:</h3>
+ <ol>
+
+ <span class="types"><a class="type" href="../classes/bitflags.html#system.bitflag">bitflag</a></span>
+ bitflag object with the given values set.
+ </ol>
+
+
+
+ <h3>Usage:</h3>
+ <ul>
+ <pre class="example"><span class="keyword">local</span> sys = <span class="global">require</span> <span class="string">'system'</span>
+<span class="keyword">local</span> flags = sys.<span class="function-name">bitflag</span>(<span class="number">2</span>) <span class="comment">-- b0010
+</span>
+<span class="comment">-- get state of individual bits
+</span><span class="global">print</span>(flags[<span class="number">0</span>]) <span class="comment">-- false
+</span><span class="global">print</span>(flags[<span class="number">1</span>]) <span class="comment">-- true
+</span>
+<span class="comment">-- set individual bits
+</span>flags[<span class="number">0</span>] = <span class="keyword">true</span> <span class="comment">-- b0011
+</span><span class="global">print</span>(flags:<span class="function-name">value</span>()) <span class="comment">-- 3
+</span><span class="global">print</span>(flags) <span class="comment">-- "bitflags: 3"
+</span>
+<span class="comment">-- adding flags (bitwise OR)
+</span><span class="keyword">local</span> flags1 = sys.<span class="function-name">bitflag</span>(<span class="number">1</span>) <span class="comment">-- b0001
+</span><span class="keyword">local</span> flags2 = sys.<span class="function-name">bitflag</span>(<span class="number">2</span>) <span class="comment">-- b0010
+</span><span class="keyword">local</span> flags3 = flags1 + flags2 <span class="comment">-- b0011
+</span>
+<span class="comment">-- substracting flags (bitwise AND NOT)
+</span><span class="global">print</span>(flags3:<span class="function-name">value</span>()) <span class="comment">-- 3
+</span>flag3 = flag3 - flag3 <span class="comment">-- b0000
+</span><span class="global">print</span>(flags3:<span class="function-name">value</span>()) <span class="comment">-- 0
+</span>
+<span class="comment">-- comparing flags
+</span><span class="keyword">local</span> flags4 = sys.<span class="function-name">bitflag</span>(<span class="number">7</span>) <span class="comment">-- b0111
+</span><span class="keyword">local</span> flags5 = sys.<span class="function-name">bitflag</span>(<span class="number">255</span>) <span class="comment">-- b11111111
+</span><span class="global">print</span>(flags5 ~= flags4) <span class="comment">-- true, not the same flags
+</span><span class="keyword">local</span> flags6 = sys.<span class="function-name">bitflag</span>(<span class="number">7</span>) <span class="comment">-- b0111
+</span><span class="global">print</span>(flags6 == flags4) <span class="comment">-- true, same flags
+</span>
+<span class="comment">-- comparison of subsets
+</span><span class="keyword">local</span> flags7 = sys.<span class="function-name">bitflag</span>(<span class="number">0</span>) <span class="comment">-- b0000
+</span><span class="keyword">local</span> flags8 = sys.<span class="function-name">bitflag</span>(<span class="number">3</span>) <span class="comment">-- b0011
+</span><span class="keyword">local</span> flags9 = sys.<span class="function-name">bitflag</span>(<span class="number">7</span>) <span class="comment">-- b0111
+</span><span class="global">print</span>(flags9:<span class="function-name">has_all_of</span>(flags8)) <span class="comment">-- true, flags8 bits are all set in flags9
+</span><span class="global">print</span>(flags8:<span class="function-name">has_any_of</span>(flags9)) <span class="comment">-- true, some of flags9 bits are set in flags8
+</span><span class="global">print</span>(flags8:<span class="function-name">has_all_of</span>(flags7)) <span class="comment">-- false, flags7 (== 0) is not set in flags8</span></pre>
+ </ul>
+
+</dd>
+</dl>
+
+
+</div> <!-- id="content" -->
+</div> <!-- id="main" -->
+<div id="about">
+<i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i>
+<i style="float:right;">Last updated 2024-06-20 23:11:37 </i>
+</div> <!-- id="about" -->
+</div> <!-- id="container" -->
+</body>
+</html>
diff --git a/docs/examples/compat.lua.html b/docs/examples/compat.lua.html
new file mode 100644
index 0000000..a0abafe
--- /dev/null
+++ b/docs/examples/compat.lua.html
@@ -0,0 +1,119 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+<head>
+ <title>Lua-System docs</title>
+ <link rel="stylesheet" href="../ldoc.css" type="text/css" />
+</head>
+<body>
+
+<div id="container">
+
+<div id="product">
+ <div id="product_logo"></div>
+ <div id="product_name"><big><b></b></big></div>
+ <div id="product_description"></div>
+</div> <!-- id="product" -->
+
+
+<div id="main">
+
+
+<!-- Menu -->
+
+<div id="navigation">
+<br/>
+<h1>Lua-System</h1>
+
+
+<ul>
+ <li><a href="../index.html">Index</a></li>
+</ul>
+
+
+
+<h2>Examples</h2>
+<ul class="nowrap">
+ <li><strong>compat.lua</strong></li>
+ <li><a href="../examples/flag_debugging.lua.html">flag_debugging.lua</a></li>
+ <li><a href="../examples/password_input.lua.html">password_input.lua</a></li>
+ <li><a href="../examples/read.lua.html">read.lua</a></li>
+ <li><a href="../examples/readline.lua.html">readline.lua</a></li>
+ <li><a href="../examples/spinner.lua.html">spinner.lua</a></li>
+ <li><a href="../examples/spiral_snake.lua.html">spiral_snake.lua</a></li>
+ <li><a href="../examples/terminalsize.lua.html">terminalsize.lua</a></li>
+</ul>
+<h2>Modules</h2>
+<ul class="nowrap">
+ <li><a href="../modules/system.html">system</a></li>
+</ul>
+<h2>Classes</h2>
+<ul class="nowrap">
+ <li><a href="../classes/bitflags.html">bitflags</a></li>
+</ul>
+<h2>Topics</h2>
+<ul class="">
+ <li><a href="../topics/01-introduction.md.html">1. Introduction</a></li>
+ <li><a href="../topics/02-development.md.html">2. Development</a></li>
+ <li><a href="../topics/03-terminal.md.html">3. Terminal functionality</a></li>
+ <li><a href="../topics/CHANGELOG.md.html">CHANGELOG</a></li>
+ <li><a href="../topics/LICENSE.md.html">MIT License</a></li>
+</ul>
+
+</div>
+
+<div id="content">
+
+ <h2>compat.lua</h2>
+<pre>
+<span class="comment">-- This example shows how to remove platform differences to create a
+</span><span class="comment">-- cross-platform level playing field.
+</span>
+<span class="keyword">local</span> sys = <span class="global">require</span> <span class="string">"system"</span>
+
+
+
+<span class="keyword">if</span> sys.windows <span class="keyword">then</span>
+ <span class="comment">-- Windows holds multiple copies of environment variables, to ensure <code>getenv</code>
+</span> <span class="comment">-- returns what <code>setenv</code> sets we need to use the <a href="../modules/system.html#getenv">system.getenv</a> instead of
+</span> <span class="comment">-- <a href="https://www.lua.org/manual/5.4/manual.html#pdf-os.getenv">os.getenv</a>.
+</span> <span class="global">os</span>.getenv = sys.getenv <span class="comment">-- luacheck: ignore
+</span>
+ <span class="comment">-- Set console output to UTF-8 encoding.
+</span> sys.<span class="function-name">setconsoleoutputcp</span>(sys.CODEPAGE_UTF8)
+
+ <span class="comment">-- Set up the terminal to handle ANSI escape sequences on Windows.
+</span> <span class="keyword">if</span> sys.<span class="function-name">isatty</span>(<span class="global">io</span>.stdout) <span class="keyword">then</span>
+ sys.<span class="function-name">setconsoleflags</span>(<span class="global">io</span>.stdout, sys.<span class="function-name">getconsoleflags</span>(<span class="global">io</span>.stdout) + sys.COF_VIRTUAL_TERMINAL_PROCESSING)
+ <span class="keyword">end</span>
+ <span class="keyword">if</span> sys.<span class="function-name">isatty</span>(<span class="global">io</span>.stderr) <span class="keyword">then</span>
+ sys.<span class="function-name">setconsoleflags</span>(<span class="global">io</span>.stderr, sys.<span class="function-name">getconsoleflags</span>(<span class="global">io</span>.stderr) + sys.COF_VIRTUAL_TERMINAL_PROCESSING)
+ <span class="keyword">end</span>
+ <span class="keyword">if</span> sys.<span class="function-name">isatty</span>(<span class="global">io</span>.stdin) <span class="keyword">then</span>
+ sys.<span class="function-name">setconsoleflags</span>(<span class="global">io</span>.stdin, sys.<span class="function-name">getconsoleflags</span>(<span class="global">io</span>.stdout) + sys.ENABLE_VIRTUAL_TERMINAL_INPUT)
+ <span class="keyword">end</span>
+
+
+<span class="keyword">else</span>
+ <span class="comment">-- On Posix, one can set a variable to an empty string, but on Windows, this
+</span> <span class="comment">-- will remove the variable from the environment. To make this consistent
+</span> <span class="comment">-- across platforms, we will remove the variable from the environment if the
+</span> <span class="comment">-- value is an empty string.
+</span> <span class="keyword">local</span> old_setenv = sys.setenv
+ <span class="keyword">function</span> sys.<span class="function-name">setenv</span>(name, value)
+ <span class="keyword">if</span> value == <span class="string">""</span> <span class="keyword">then</span> value = <span class="keyword">nil</span> <span class="keyword">end</span>
+ <span class="keyword">return</span> <span class="function-name">old_setenv</span>(name, value)
+ <span class="keyword">end</span>
+<span class="keyword">end</span></pre>
+
+
+</div> <!-- id="content" -->
+</div> <!-- id="main" -->
+<div id="about">
+<i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i>
+<i style="float:right;">Last updated 2024-06-20 23:11:37 </i>
+</div> <!-- id="about" -->
+</div> <!-- id="container" -->
+</body>
+</html>
diff --git a/docs/examples/flag_debugging.lua.html b/docs/examples/flag_debugging.lua.html
new file mode 100644
index 0000000..38f506a
--- /dev/null
+++ b/docs/examples/flag_debugging.lua.html
@@ -0,0 +1,87 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+<head>
+ <title>Lua-System docs</title>
+ <link rel="stylesheet" href="../ldoc.css" type="text/css" />
+</head>
+<body>
+
+<div id="container">
+
+<div id="product">
+ <div id="product_logo"></div>
+ <div id="product_name"><big><b></b></big></div>
+ <div id="product_description"></div>
+</div> <!-- id="product" -->
+
+
+<div id="main">
+
+
+<!-- Menu -->
+
+<div id="navigation">
+<br/>
+<h1>Lua-System</h1>
+
+
+<ul>
+ <li><a href="../index.html">Index</a></li>
+</ul>
+
+
+
+<h2>Examples</h2>
+<ul class="nowrap">
+ <li><a href="../examples/compat.lua.html">compat.lua</a></li>
+ <li><strong>flag_debugging.lua</strong></li>
+ <li><a href="../examples/password_input.lua.html">password_input.lua</a></li>
+ <li><a href="../examples/read.lua.html">read.lua</a></li>
+ <li><a href="../examples/readline.lua.html">readline.lua</a></li>
+ <li><a href="../examples/spinner.lua.html">spinner.lua</a></li>
+ <li><a href="../examples/spiral_snake.lua.html">spiral_snake.lua</a></li>
+ <li><a href="../examples/terminalsize.lua.html">terminalsize.lua</a></li>
+</ul>
+<h2>Modules</h2>
+<ul class="nowrap">
+ <li><a href="../modules/system.html">system</a></li>
+</ul>
+<h2>Classes</h2>
+<ul class="nowrap">
+ <li><a href="../classes/bitflags.html">bitflags</a></li>
+</ul>
+<h2>Topics</h2>
+<ul class="">
+ <li><a href="../topics/01-introduction.md.html">1. Introduction</a></li>
+ <li><a href="../topics/02-development.md.html">2. Development</a></li>
+ <li><a href="../topics/03-terminal.md.html">3. Terminal functionality</a></li>
+ <li><a href="../topics/CHANGELOG.md.html">CHANGELOG</a></li>
+ <li><a href="../topics/LICENSE.md.html">MIT License</a></li>
+</ul>
+
+</div>
+
+<div id="content">
+
+ <h2>flag_debugging.lua</h2>
+<pre>
+<span class="keyword">local</span> sys = <span class="global">require</span> <span class="string">"system"</span>
+
+<span class="comment">-- Print the Windows Console flags for stdin
+</span>sys.<span class="function-name">listconsoleflags</span>(<span class="global">io</span>.stdin)
+
+<span class="comment">-- Print the Posix termios flags for stdin
+</span>sys.<span class="function-name">listtermflags</span>(<span class="global">io</span>.stdin)</pre>
+
+
+</div> <!-- id="content" -->
+</div> <!-- id="main" -->
+<div id="about">
+<i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i>
+<i style="float:right;">Last updated 2024-06-20 23:11:37 </i>
+</div> <!-- id="about" -->
+</div> <!-- id="container" -->
+</body>
+</html>
diff --git a/docs/examples/password_input.lua.html b/docs/examples/password_input.lua.html
new file mode 100644
index 0000000..4234fbb
--- /dev/null
+++ b/docs/examples/password_input.lua.html
@@ -0,0 +1,139 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+<head>
+ <title>Lua-System docs</title>
+ <link rel="stylesheet" href="../ldoc.css" type="text/css" />
+</head>
+<body>
+
+<div id="container">
+
+<div id="product">
+ <div id="product_logo"></div>
+ <div id="product_name"><big><b></b></big></div>
+ <div id="product_description"></div>
+</div> <!-- id="product" -->
+
+
+<div id="main">
+
+
+<!-- Menu -->
+
+<div id="navigation">
+<br/>
+<h1>Lua-System</h1>
+
+
+<ul>
+ <li><a href="../index.html">Index</a></li>
+</ul>
+
+
+
+<h2>Examples</h2>
+<ul class="nowrap">
+ <li><a href="../examples/compat.lua.html">compat.lua</a></li>
+ <li><a href="../examples/flag_debugging.lua.html">flag_debugging.lua</a></li>
+ <li><strong>password_input.lua</strong></li>
+ <li><a href="../examples/read.lua.html">read.lua</a></li>
+ <li><a href="../examples/readline.lua.html">readline.lua</a></li>
+ <li><a href="../examples/spinner.lua.html">spinner.lua</a></li>
+ <li><a href="../examples/spiral_snake.lua.html">spiral_snake.lua</a></li>
+ <li><a href="../examples/terminalsize.lua.html">terminalsize.lua</a></li>
+</ul>
+<h2>Modules</h2>
+<ul class="nowrap">
+ <li><a href="../modules/system.html">system</a></li>
+</ul>
+<h2>Classes</h2>
+<ul class="nowrap">
+ <li><a href="../classes/bitflags.html">bitflags</a></li>
+</ul>
+<h2>Topics</h2>
+<ul class="">
+ <li><a href="../topics/01-introduction.md.html">1. Introduction</a></li>
+ <li><a href="../topics/02-development.md.html">2. Development</a></li>
+ <li><a href="../topics/03-terminal.md.html">3. Terminal functionality</a></li>
+ <li><a href="../topics/CHANGELOG.md.html">CHANGELOG</a></li>
+ <li><a href="../topics/LICENSE.md.html">MIT License</a></li>
+</ul>
+
+</div>
+
+<div id="content">
+
+ <h2>password_input.lua</h2>
+<pre>
+<span class="keyword">local</span> sys = <span class="global">require</span> <span class="string">"system"</span>
+
+<span class="global">print</span> <span class="string">[[
+
+This example shows how to disable the "echo" of characters read to the console,
+useful for reading secrets from the user.
+
+]]</span>
+
+<span class="comment">--- Function to read from stdin without echoing the input (for secrets etc).
+</span><span class="comment">-- It will (in a platform agnostic way) disable echo on the terminal, read the
+</span><span class="comment">-- input, and then re-enable echo.
+</span><span class="comment">-- @param ... Arguments to pass to <code>io.stdin:read()</code>
+</span><span class="comment">-- @return the results of <code>io.stdin:read(...)</code>
+</span><span class="keyword">local</span> <span class="keyword">function</span> <span class="function-name">read_secret</span>(...)
+ <span class="keyword">local</span> w_oldflags, p_oldflags
+
+ <span class="keyword">if</span> sys.<span class="function-name">isatty</span>(<span class="global">io</span>.stdin) <span class="keyword">then</span>
+ <span class="comment">-- backup settings, configure echo flags
+</span> w_oldflags = sys.<span class="function-name">getconsoleflags</span>(<span class="global">io</span>.stdin)
+ p_oldflags = sys.<span class="function-name">tcgetattr</span>(<span class="global">io</span>.stdin)
+ <span class="comment">-- set echo off to not show password on screen
+</span> <span class="global">assert</span>(sys.<span class="function-name">setconsoleflags</span>(<span class="global">io</span>.stdin, w_oldflags - sys.CIF_ECHO_INPUT))
+ <span class="global">assert</span>(sys.<span class="function-name">tcsetattr</span>(<span class="global">io</span>.stdin, sys.TCSANOW, { lflag = p_oldflags.lflag - sys.L_ECHO }))
+ <span class="keyword">end</span>
+
+ <span class="keyword">local</span> secret, err = <span class="global">io</span>.stdin:<span class="function-name">read</span>(...)
+
+ <span class="comment">-- restore settings
+</span> <span class="keyword">if</span> sys.<span class="function-name">isatty</span>(<span class="global">io</span>.stdin) <span class="keyword">then</span>
+ <span class="global">io</span>.stdout:<span class="function-name">write</span>(<span class="string">"\n"</span>) <span class="comment">-- Add newline after reading the password
+</span> sys.<span class="function-name">setconsoleflags</span>(<span class="global">io</span>.stdin, w_oldflags)
+ sys.<span class="function-name">tcsetattr</span>(<span class="global">io</span>.stdin, sys.TCSANOW, p_oldflags)
+ <span class="keyword">end</span>
+
+ <span class="keyword">return</span> secret, err
+<span class="keyword">end</span>
+
+
+
+<span class="comment">-- Get username
+</span><span class="global">io</span>.<span class="function-name">write</span>(<span class="string">"Username: "</span>)
+<span class="keyword">local</span> username = <span class="global">io</span>.stdin:<span class="function-name">read</span>(<span class="string">"*l"</span>)
+
+<span class="comment">-- Get the secret
+</span><span class="global">io</span>.<span class="function-name">write</span>(<span class="string">"Password: "</span>)
+<span class="keyword">local</span> password = <span class="function-name">read_secret</span>(<span class="string">"*l"</span>)
+
+<span class="comment">-- Get domainname
+</span><span class="global">io</span>.<span class="function-name">write</span>(<span class="string">"Domain : "</span>)
+<span class="keyword">local</span> domain = <span class="global">io</span>.stdin:<span class="function-name">read</span>(<span class="string">"*l"</span>)
+
+
+<span class="comment">-- Print the results
+</span><span class="global">print</span>(<span class="string">""</span>)
+<span class="global">print</span>(<span class="string">"Here's what we got:"</span>)
+<span class="global">print</span>(<span class="string">" username: "</span> .. username)
+<span class="global">print</span>(<span class="string">" password: "</span> .. password)
+<span class="global">print</span>(<span class="string">" domain : "</span> .. domain)</pre>
+
+
+</div> <!-- id="content" -->
+</div> <!-- id="main" -->
+<div id="about">
+<i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i>
+<i style="float:right;">Last updated 2024-06-20 23:11:37 </i>
+</div> <!-- id="about" -->
+</div> <!-- id="container" -->
+</body>
+</html>
diff --git a/docs/examples/read.lua.html b/docs/examples/read.lua.html
new file mode 100644
index 0000000..c7697d3
--- /dev/null
+++ b/docs/examples/read.lua.html
@@ -0,0 +1,150 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+<head>
+ <title>Lua-System docs</title>
+ <link rel="stylesheet" href="../ldoc.css" type="text/css" />
+</head>
+<body>
+
+<div id="container">
+
+<div id="product">
+ <div id="product_logo"></div>
+ <div id="product_name"><big><b></b></big></div>
+ <div id="product_description"></div>
+</div> <!-- id="product" -->
+
+
+<div id="main">
+
+
+<!-- Menu -->
+
+<div id="navigation">
+<br/>
+<h1>Lua-System</h1>
+
+
+<ul>
+ <li><a href="../index.html">Index</a></li>
+</ul>
+
+
+
+<h2>Examples</h2>
+<ul class="nowrap">
+ <li><a href="../examples/compat.lua.html">compat.lua</a></li>
+ <li><a href="../examples/flag_debugging.lua.html">flag_debugging.lua</a></li>
+ <li><a href="../examples/password_input.lua.html">password_input.lua</a></li>
+ <li><strong>read.lua</strong></li>
+ <li><a href="../examples/readline.lua.html">readline.lua</a></li>
+ <li><a href="../examples/spinner.lua.html">spinner.lua</a></li>
+ <li><a href="../examples/spiral_snake.lua.html">spiral_snake.lua</a></li>
+ <li><a href="../examples/terminalsize.lua.html">terminalsize.lua</a></li>
+</ul>
+<h2>Modules</h2>
+<ul class="nowrap">
+ <li><a href="../modules/system.html">system</a></li>
+</ul>
+<h2>Classes</h2>
+<ul class="nowrap">
+ <li><a href="../classes/bitflags.html">bitflags</a></li>
+</ul>
+<h2>Topics</h2>
+<ul class="">
+ <li><a href="../topics/01-introduction.md.html">1. Introduction</a></li>
+ <li><a href="../topics/02-development.md.html">2. Development</a></li>
+ <li><a href="../topics/03-terminal.md.html">3. Terminal functionality</a></li>
+ <li><a href="../topics/CHANGELOG.md.html">CHANGELOG</a></li>
+ <li><a href="../topics/LICENSE.md.html">MIT License</a></li>
+</ul>
+
+</div>
+
+<div id="content">
+
+ <h2>read.lua</h2>
+<pre>
+<span class="keyword">local</span> sys = <span class="global">require</span> <span class="string">"system"</span>
+
+<span class="global">print</span> <span class="string">[[
+
+This example shows how to do a non-blocking read from the cli.
+
+]]</span>
+
+<span class="comment">-- setup Windows console to handle ANSI processing
+</span><span class="keyword">local</span> of_in = sys.<span class="function-name">getconsoleflags</span>(<span class="global">io</span>.stdin)
+<span class="keyword">local</span> of_out = sys.<span class="function-name">getconsoleflags</span>(<span class="global">io</span>.stdout)
+sys.<span class="function-name">setconsoleflags</span>(<span class="global">io</span>.stdout, sys.<span class="function-name">getconsoleflags</span>(<span class="global">io</span>.stdout) + sys.COF_VIRTUAL_TERMINAL_PROCESSING)
+sys.<span class="function-name">setconsoleflags</span>(<span class="global">io</span>.stdin, sys.<span class="function-name">getconsoleflags</span>(<span class="global">io</span>.stdin) + sys.CIF_VIRTUAL_TERMINAL_INPUT)
+
+<span class="comment">-- setup Posix terminal to use non-blocking mode, and disable line-mode
+</span><span class="keyword">local</span> of_attr = sys.<span class="function-name">tcgetattr</span>(<span class="global">io</span>.stdin)
+<span class="keyword">local</span> of_block = sys.<span class="function-name">getnonblock</span>(<span class="global">io</span>.stdin)
+sys.<span class="function-name">setnonblock</span>(<span class="global">io</span>.stdin, <span class="keyword">true</span>)
+sys.<span class="function-name">tcsetattr</span>(<span class="global">io</span>.stdin, sys.TCSANOW, {
+ lflag = of_attr.lflag - sys.L_ICANON - sys.L_ECHO, <span class="comment">-- disable canonical mode and echo
+</span>})
+
+<span class="comment">-- cursor sequences
+</span><span class="keyword">local</span> get_cursor_pos = <span class="string">"\27[6n"</span>
+
+
+
+<span class="global">print</span>(<span class="string">"Press a key, or 'A' to get cursor position, 'ESC' to exit"</span>)
+<span class="keyword">while</span> <span class="keyword">true</span> <span class="keyword">do</span>
+ <span class="keyword">local</span> key, keytype
+
+ <span class="comment">-- wait for a key
+</span> <span class="keyword">while</span> <span class="keyword">not</span> key <span class="keyword">do</span>
+ key, keytype = sys.<span class="function-name">readansi</span>(<span class="global">math</span>.huge)
+ <span class="keyword">end</span>
+
+ <span class="keyword">if</span> key == <span class="string">"A"</span> <span class="keyword">then</span> <span class="global">io</span>.<span class="function-name">write</span>(get_cursor_pos); <span class="global">io</span>.<span class="function-name">flush</span>() <span class="keyword">end</span>
+
+ <span class="comment">-- check if we got a key or ANSI sequence
+</span> <span class="keyword">if</span> keytype == <span class="string">"char"</span> <span class="keyword">then</span>
+ <span class="comment">-- just a key
+</span> <span class="keyword">local</span> b = key:<span class="function-name">byte</span>()
+ <span class="keyword">if</span> b &lt; <span class="number">32</span> <span class="keyword">then</span>
+ key = <span class="string">"."</span> <span class="comment">-- replace control characters with a simple "." to not mess up the screen
+</span> <span class="keyword">end</span>
+
+ <span class="global">print</span>(<span class="string">"you pressed: "</span> .. key .. <span class="string">" ("</span> .. b .. <span class="string">")"</span>)
+ <span class="keyword">if</span> b == <span class="number">27</span> <span class="keyword">then</span>
+ <span class="global">print</span>(<span class="string">"Escape pressed, exiting"</span>)
+ <span class="keyword">break</span>
+ <span class="keyword">end</span>
+
+ <span class="keyword">elseif</span> keytype == <span class="string">"ansi"</span> <span class="keyword">then</span>
+ <span class="comment">-- we got an ANSI sequence
+</span> <span class="keyword">local</span> seq = { key:<span class="function-name">byte</span>(<span class="number">1</span>, #key) }
+ <span class="global">print</span>(<span class="string">"ANSI sequence received: "</span> .. key:<span class="function-name">sub</span>(<span class="number">2</span>,-<span class="number">1</span>), <span class="string">"(bytes: "</span> .. <span class="global">table</span>.<span class="function-name">concat</span>(seq, <span class="string">", "</span>)..<span class="string">")"</span>)
+
+ <span class="keyword">else</span>
+ <span class="global">print</span>(<span class="string">"unknown key type received: "</span> .. <span class="global">tostring</span>(keytype))
+ <span class="keyword">end</span>
+<span class="keyword">end</span>
+
+
+
+<span class="comment">-- Clean up afterwards
+</span>sys.<span class="function-name">setnonblock</span>(<span class="global">io</span>.stdin, <span class="keyword">false</span>)
+sys.<span class="function-name">setconsoleflags</span>(<span class="global">io</span>.stdout, of_out)
+sys.<span class="function-name">setconsoleflags</span>(<span class="global">io</span>.stdin, of_in)
+sys.<span class="function-name">tcsetattr</span>(<span class="global">io</span>.stdin, sys.TCSANOW, of_attr)
+sys.<span class="function-name">setnonblock</span>(<span class="global">io</span>.stdin, of_block)</pre>
+
+
+</div> <!-- id="content" -->
+</div> <!-- id="main" -->
+<div id="about">
+<i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i>
+<i style="float:right;">Last updated 2024-06-20 23:11:37 </i>
+</div> <!-- id="about" -->
+</div> <!-- id="container" -->
+</body>
+</html>
diff --git a/docs/examples/readline.lua.html b/docs/examples/readline.lua.html
new file mode 100644
index 0000000..7895a81
--- /dev/null
+++ b/docs/examples/readline.lua.html
@@ -0,0 +1,552 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+<head>
+ <title>Lua-System docs</title>
+ <link rel="stylesheet" href="../ldoc.css" type="text/css" />
+</head>
+<body>
+
+<div id="container">
+
+<div id="product">
+ <div id="product_logo"></div>
+ <div id="product_name"><big><b></b></big></div>
+ <div id="product_description"></div>
+</div> <!-- id="product" -->
+
+
+<div id="main">
+
+
+<!-- Menu -->
+
+<div id="navigation">
+<br/>
+<h1>Lua-System</h1>
+
+
+<ul>
+ <li><a href="../index.html">Index</a></li>
+</ul>
+
+
+
+<h2>Examples</h2>
+<ul class="nowrap">
+ <li><a href="../examples/compat.lua.html">compat.lua</a></li>
+ <li><a href="../examples/flag_debugging.lua.html">flag_debugging.lua</a></li>
+ <li><a href="../examples/password_input.lua.html">password_input.lua</a></li>
+ <li><a href="../examples/read.lua.html">read.lua</a></li>
+ <li><strong>readline.lua</strong></li>
+ <li><a href="../examples/spinner.lua.html">spinner.lua</a></li>
+ <li><a href="../examples/spiral_snake.lua.html">spiral_snake.lua</a></li>
+ <li><a href="../examples/terminalsize.lua.html">terminalsize.lua</a></li>
+</ul>
+<h2>Modules</h2>
+<ul class="nowrap">
+ <li><a href="../modules/system.html">system</a></li>
+</ul>
+<h2>Classes</h2>
+<ul class="nowrap">
+ <li><a href="../classes/bitflags.html">bitflags</a></li>
+</ul>
+<h2>Topics</h2>
+<ul class="">
+ <li><a href="../topics/01-introduction.md.html">1. Introduction</a></li>
+ <li><a href="../topics/02-development.md.html">2. Development</a></li>
+ <li><a href="../topics/03-terminal.md.html">3. Terminal functionality</a></li>
+ <li><a href="../topics/CHANGELOG.md.html">CHANGELOG</a></li>
+ <li><a href="../topics/LICENSE.md.html">MIT License</a></li>
+</ul>
+
+</div>
+
+<div id="content">
+
+ <h2>readline.lua</h2>
+<pre>
+<span class="comment">--- An example class for reading a line of input from the user in a non-blocking way.
+</span><span class="comment">-- It uses ANSI escape sequences to move the cursor and handle input.
+</span><span class="comment">-- It can be used to read a line of input from the user, with a prompt.
+</span><span class="comment">-- It can handle double-width UTF-8 characters.
+</span><span class="comment">-- It can be used asynchroneously if <a href="../modules/system.html#sleep">system.sleep</a> is patched to yield to a coroutine scheduler.
+</span>
+<span class="keyword">local</span> sys = <span class="global">require</span>(<span class="string">"system"</span>)
+
+
+<span class="comment">-- Mapping of key-sequences to key-names
+</span><span class="keyword">local</span> key_names = {
+ [<span class="string">"\27[C"</span>] = <span class="string">"right"</span>,
+ [<span class="string">"\27[D"</span>] = <span class="string">"left"</span>,
+ [<span class="string">"\127"</span>] = <span class="string">"backspace"</span>,
+ [<span class="string">"\27[3~"</span>] = <span class="string">"delete"</span>,
+ [<span class="string">"\27[H"</span>] = <span class="string">"home"</span>,
+ [<span class="string">"\27[F"</span>] = <span class="string">"end"</span>,
+ [<span class="string">"\27"</span>] = <span class="string">"escape"</span>,
+ [<span class="string">"\9"</span>] = <span class="string">"tab"</span>,
+ [<span class="string">"\27[Z"</span>] = <span class="string">"shift-tab"</span>,
+}
+
+<span class="keyword">if</span> sys.windows <span class="keyword">then</span>
+ key_names[<span class="string">"\13"</span>] = <span class="string">"enter"</span>
+<span class="keyword">else</span>
+ key_names[<span class="string">"\10"</span>] = <span class="string">"enter"</span>
+<span class="keyword">end</span>
+
+
+<span class="comment">-- Mapping of key-names to key-sequences
+</span><span class="keyword">local</span> key_sequences = {}
+<span class="keyword">for</span> k, v <span class="keyword">in</span> <span class="global">pairs</span>(key_names) <span class="keyword">do</span>
+ key_sequences[v] = k
+<span class="keyword">end</span>
+
+
+<span class="comment">-- bell character
+</span><span class="keyword">local</span> <span class="keyword">function</span> <span class="function-name">bell</span>()
+ <span class="global">io</span>.<span class="function-name">write</span>(<span class="string">"\7"</span>)
+ <span class="global">io</span>.<span class="function-name">flush</span>()
+<span class="keyword">end</span>
+
+
+<span class="comment">-- generate string to move cursor horizontally
+</span><span class="comment">-- positive goes right, negative goes left
+</span><span class="keyword">local</span> <span class="keyword">function</span> <span class="function-name">cursor_move_horiz</span>(n)
+ <span class="keyword">if</span> n == <span class="number">0</span> <span class="keyword">then</span>
+ <span class="keyword">return</span> <span class="string">""</span>
+ <span class="keyword">end</span>
+ <span class="keyword">return</span> <span class="string">"\27["</span> .. (n &gt; <span class="number">0</span> <span class="keyword">and</span> n <span class="keyword">or</span> -n) .. (n &gt; <span class="number">0</span> <span class="keyword">and</span> <span class="string">"C"</span> <span class="keyword">or</span> <span class="string">"D"</span>)
+<span class="keyword">end</span>
+
+
+<span class="comment">-- -- generate string to move cursor vertically
+</span><span class="comment">-- -- positive goes down, negative goes up
+</span><span class="comment">-- local function cursor_move_vert(n)
+</span><span class="comment">-- if n == 0 then
+</span><span class="comment">-- return ""
+</span><span class="comment">-- end
+</span><span class="comment">-- return "\27[" .. (n &gt; 0 and n or -n) .. (n &gt; 0 and "B" or "A")
+</span><span class="comment">-- end
+</span>
+
+<span class="comment">-- -- log to the line above the current line
+</span><span class="comment">-- local function log(...)
+</span><span class="comment">-- local arg = { n = select("#", ...), ...}
+</span><span class="comment">-- for i = 1, arg.n do
+</span><span class="comment">-- arg[i] = tostring(arg[i])
+</span><span class="comment">-- end
+</span><span class="comment">-- arg = " " .. table.concat(arg, " ") .. " "
+</span>
+<span class="comment">-- io.write(cursor_move_vert(-1), arg, cursor_move_vert(1), cursor_move_horiz(-#arg))
+</span><span class="comment">-- end
+</span>
+
+<span class="comment">-- UTF8 character size in bytes
+</span><span class="comment">-- @tparam number b the byte value of the first byte of a UTF8 character
+</span><span class="keyword">local</span> <span class="keyword">function</span> <span class="function-name">utf8size</span>(b)
+ <span class="keyword">return</span> b &lt; <span class="number">128</span> <span class="keyword">and</span> <span class="number">1</span> <span class="keyword">or</span> b &lt; <span class="number">224</span> <span class="keyword">and</span> <span class="number">2</span> <span class="keyword">or</span> b &lt; <span class="number">240</span> <span class="keyword">and</span> <span class="number">3</span> <span class="keyword">or</span> b &lt; <span class="number">248</span> <span class="keyword">and</span> <span class="number">4</span>
+<span class="keyword">end</span>
+
+
+
+<span class="keyword">local</span> utf8parse <span class="keyword">do</span>
+ <span class="keyword">local</span> utf8_value_mt = {
+ __tostring = <span class="keyword">function</span>(self)
+ <span class="keyword">return</span> <span class="global">table</span>.<span class="function-name">concat</span>(self, <span class="string">""</span>)
+ <span class="keyword">end</span>,
+ }
+
+ <span class="comment">-- Parses a UTF8 string into list of individual characters.
+</span> <span class="comment">-- key 'chars' gets the length in UTF8 characters, whilst # returns the length
+</span> <span class="comment">-- for display (to handle double-width UTF8 chars).
+</span> <span class="comment">-- in the list the double-width characters are followed by an empty string.
+</span> <span class="comment">-- @tparam string s the UTF8 string to parse
+</span> <span class="comment">-- @treturn table the list of characters
+</span> <span class="keyword">function</span> <span class="function-name">utf8parse</span>(s)
+ <span class="keyword">local</span> t = <span class="global">setmetatable</span>({ chars = <span class="number">0</span> }, utf8_value_mt)
+ <span class="keyword">local</span> i = <span class="number">1</span>
+ <span class="keyword">while</span> i &lt;= #s <span class="keyword">do</span>
+ <span class="keyword">local</span> b = s:<span class="function-name">byte</span>(i)
+ <span class="keyword">local</span> w = <span class="function-name">utf8size</span>(b)
+ <span class="keyword">local</span> char = s:<span class="function-name">sub</span>(i, i + w - <span class="number">1</span>)
+ t[#t + <span class="number">1</span>] = char
+ t.chars = t.chars + <span class="number">1</span>
+ <span class="keyword">if</span> sys.<span class="function-name">utf8cwidth</span>(char) == <span class="number">2</span> <span class="keyword">then</span>
+ <span class="comment">-- double width character, add empty string to keep the length of the
+</span> <span class="comment">-- list the same as the character width on screen
+</span> t[#t + <span class="number">1</span>] = <span class="string">""</span>
+ <span class="keyword">end</span>
+ i = i + w
+ <span class="keyword">end</span>
+ <span class="keyword">return</span> t
+ <span class="keyword">end</span>
+<span class="keyword">end</span>
+
+
+
+<span class="comment">-- inline tests for utf8parse
+</span><span class="comment">-- do
+</span><span class="comment">-- local t = utf8parse("a你b好c")
+</span><span class="comment">-- assert(t[1] == "a")
+</span><span class="comment">-- assert(t[2] == "ä½ ") -- double width
+</span><span class="comment">-- assert(t[3] == "")
+</span><span class="comment">-- assert(t[4] == "b")
+</span><span class="comment">-- assert(t[5] == "好") -- double width
+</span><span class="comment">-- assert(t[6] == "")
+</span><span class="comment">-- assert(t[7] == "c")
+</span><span class="comment">-- assert(#t == 7) -- size as displayed
+</span><span class="comment">-- end
+</span>
+
+
+<span class="comment">-- readline class
+</span>
+<span class="keyword">local</span> readline = {}
+readline.__index = readline
+
+
+<span class="comment">--- Create a new readline object.
+</span><span class="comment">-- @tparam table opts the options for the readline object
+</span><span class="comment">-- @tparam[opt=""] string opts.prompt the prompt to display
+</span><span class="comment">-- @tparam[opt=80] number opts.max_length the maximum length of the input (in characters, not bytes)
+</span><span class="comment">-- @tparam[opt=""] string opts.value the default value
+</span><span class="comment">-- @tparam[opt=<code>#value</code>] number opts.position of the cursor in the input
+</span><span class="comment">-- @tparam[opt={"\10"/"\13"}] table opts.exit_keys an array of keys that will cause the readline to exit
+</span><span class="comment">-- @treturn readline the new readline object
+</span><span class="keyword">function</span> readline.<span class="function-name">new</span>(opts)
+ <span class="keyword">local</span> value = <span class="function-name">utf8parse</span>(opts.value <span class="keyword">or</span> <span class="string">""</span>)
+ <span class="keyword">local</span> prompt = <span class="function-name">utf8parse</span>(opts.prompt <span class="keyword">or</span> <span class="string">""</span>)
+ <span class="keyword">local</span> pos = <span class="global">math</span>.<span class="function-name">floor</span>(opts.position <span class="keyword">or</span> (#value + <span class="number">1</span>))
+ pos = <span class="global">math</span>.<span class="function-name">max</span>(<span class="global">math</span>.<span class="function-name">min</span>(pos, (#value + <span class="number">1</span>)), <span class="number">1</span>)
+ <span class="keyword">local</span> len = <span class="global">math</span>.<span class="function-name">floor</span>(opts.max_length <span class="keyword">or</span> <span class="number">80</span>)
+ <span class="keyword">if</span> len &lt; <span class="number">1</span> <span class="keyword">then</span>
+ <span class="global">error</span>(<span class="string">"max_length must be at least 1"</span>, <span class="number">2</span>)
+ <span class="keyword">end</span>
+
+ <span class="keyword">if</span> value.chars &gt; len <span class="keyword">then</span>
+ <span class="global">error</span>(<span class="string">"value is longer than max_length"</span>, <span class="number">2</span>)
+ <span class="keyword">end</span>
+
+ <span class="keyword">local</span> exit_keys = {}
+ <span class="keyword">for</span> _, key <span class="keyword">in</span> <span class="global">ipairs</span>(opts.exit_keys <span class="keyword">or</span> {}) <span class="keyword">do</span>
+ exit_keys[key] = <span class="keyword">true</span>
+ <span class="keyword">end</span>
+ <span class="keyword">if</span> exit_keys[<span class="number">1</span>] == <span class="keyword">nil</span> <span class="keyword">then</span>
+ <span class="comment">-- nothing provided, default to Enter-key
+</span> exit_keys[<span class="number">1</span>] = key_sequences.enter
+ <span class="keyword">end</span>
+
+ <span class="keyword">local</span> self = {
+ value = value, <span class="comment">-- the default value
+</span> max_length = len, <span class="comment">-- the maximum length of the input
+</span> prompt = prompt, <span class="comment">-- the prompt to display
+</span> position = pos, <span class="comment">-- the current position in the input
+</span> drawn_before = <span class="keyword">false</span>, <span class="comment">-- if the prompt has been drawn
+</span> exit_keys = exit_keys, <span class="comment">-- the keys that will cause the readline to exit
+</span> }
+
+ <span class="global">setmetatable</span>(self, readline)
+ <span class="keyword">return</span> self
+<span class="keyword">end</span>
+
+
+
+<span class="comment">-- draw the prompt and the input value, and position the cursor.
+</span><span class="keyword">local</span> <span class="keyword">function</span> <span class="function-name">draw</span>(self, redraw)
+ <span class="keyword">if</span> redraw <span class="keyword">or</span> <span class="keyword">not</span> self.drawn_before <span class="keyword">then</span>
+ <span class="comment">-- we are at start of prompt
+</span> self.drawn_before = <span class="keyword">true</span>
+ <span class="keyword">else</span>
+ <span class="comment">-- we are at current cursor position, move to start of prompt
+</span> <span class="global">io</span>.<span class="function-name">write</span>(<span class="function-name">cursor_move_horiz</span>(-(#self.prompt + self.position)))
+ <span class="keyword">end</span>
+ <span class="comment">-- write prompt &amp; value
+</span> <span class="global">io</span>.<span class="function-name">write</span>(<span class="global">tostring</span>(self.prompt) .. <span class="global">tostring</span>(self.value))
+ <span class="comment">-- clear remainder of input size
+</span> <span class="global">io</span>.<span class="function-name">write</span>(<span class="global">string</span>.<span class="function-name">rep</span>(<span class="string">" "</span>, self.max_length - self.value.chars))
+ <span class="global">io</span>.<span class="function-name">write</span>(<span class="function-name">cursor_move_horiz</span>(-(self.max_length - self.value.chars)))
+ <span class="comment">-- move to cursor position
+</span> <span class="global">io</span>.<span class="function-name">write</span>(<span class="function-name">cursor_move_horiz</span>(-(#self.value + <span class="number">1</span> - self.position)))
+ <span class="global">io</span>.<span class="function-name">flush</span>()
+<span class="keyword">end</span>
+
+
+<span class="keyword">local</span> handle_key <span class="keyword">do</span> <span class="comment">-- keyboard input handler
+</span>
+ <span class="keyword">local</span> key_handlers
+ key_handlers = {
+ left = <span class="keyword">function</span>(self)
+ <span class="keyword">if</span> self.position == <span class="number">1</span> <span class="keyword">then</span>
+ <span class="function-name">bell</span>()
+ <span class="keyword">return</span>
+ <span class="keyword">end</span>
+
+ <span class="keyword">local</span> new_pos = self.position - <span class="number">1</span>
+ <span class="keyword">while</span> self.value[new_pos] == <span class="string">""</span> <span class="keyword">do</span> <span class="comment">-- skip empty strings; double width chars
+</span> new_pos = new_pos - <span class="number">1</span>
+ <span class="keyword">end</span>
+
+ <span class="global">io</span>.<span class="function-name">write</span>(<span class="function-name">cursor_move_horiz</span>(-(self.position - new_pos)))
+ <span class="global">io</span>.<span class="function-name">flush</span>()
+ self.position = new_pos
+ <span class="keyword">end</span>,
+
+ right = <span class="keyword">function</span>(self)
+ <span class="keyword">if</span> self.position == #self.value + <span class="number">1</span> <span class="keyword">then</span>
+ <span class="function-name">bell</span>()
+ <span class="keyword">return</span>
+ <span class="keyword">end</span>
+
+ <span class="keyword">local</span> new_pos = self.position + <span class="number">1</span>
+ <span class="keyword">while</span> self.value[new_pos] == <span class="string">""</span> <span class="keyword">do</span> <span class="comment">-- skip empty strings; double width chars
+</span> new_pos = new_pos + <span class="number">1</span>
+ <span class="keyword">end</span>
+
+ <span class="global">io</span>.<span class="function-name">write</span>(<span class="function-name">cursor_move_horiz</span>(new_pos - self.position))
+ <span class="global">io</span>.<span class="function-name">flush</span>()
+ self.position = new_pos
+ <span class="keyword">end</span>,
+
+ backspace = <span class="keyword">function</span>(self)
+ <span class="keyword">if</span> self.position == <span class="number">1</span> <span class="keyword">then</span>
+ <span class="function-name">bell</span>()
+ <span class="keyword">return</span>
+ <span class="keyword">end</span>
+
+ <span class="keyword">while</span> self.value[self.position - <span class="number">1</span>] == <span class="string">""</span> <span class="keyword">do</span> <span class="comment">-- remove empty strings; double width chars
+</span> <span class="global">io</span>.<span class="function-name">write</span>(<span class="function-name">cursor_move_horiz</span>(-<span class="number">1</span>))
+ self.position = self.position - <span class="number">1</span>
+ <span class="global">table</span>.<span class="function-name">remove</span>(self.value, self.position)
+ <span class="keyword">end</span>
+ <span class="comment">-- remove char itself
+</span> <span class="global">io</span>.<span class="function-name">write</span>(<span class="function-name">cursor_move_horiz</span>(-<span class="number">1</span>))
+ self.position = self.position - <span class="number">1</span>
+ <span class="global">table</span>.<span class="function-name">remove</span>(self.value, self.position)
+ self.value.chars = self.value.chars - <span class="number">1</span>
+ <span class="function-name">draw</span>(self)
+ <span class="keyword">end</span>,
+
+ home = <span class="keyword">function</span>(self)
+ <span class="keyword">local</span> new_pos = <span class="number">1</span>
+ <span class="global">io</span>.<span class="function-name">write</span>(<span class="function-name">cursor_move_horiz</span>(new_pos - self.position))
+ self.position = new_pos
+ <span class="keyword">end</span>,
+
+ [<span class="string">"end"</span>] = <span class="keyword">function</span>(self)
+ <span class="keyword">local</span> new_pos = #self.value + <span class="number">1</span>
+ <span class="global">io</span>.<span class="function-name">write</span>(<span class="function-name">cursor_move_horiz</span>(new_pos - self.position))
+ self.position = new_pos
+ <span class="keyword">end</span>,
+
+ delete = <span class="keyword">function</span>(self)
+ <span class="keyword">if</span> self.position &gt; #self.value <span class="keyword">then</span>
+ <span class="function-name">bell</span>()
+ <span class="keyword">return</span>
+ <span class="keyword">end</span>
+
+ key_handlers.<span class="function-name">right</span>(self)
+ key_handlers.<span class="function-name">backspace</span>(self)
+ <span class="keyword">end</span>,
+ }
+
+
+ <span class="comment">-- handles a single input key/ansi-sequence.
+</span> <span class="comment">-- @tparam string key the key or ansi-sequence (from <a href="../modules/system.html#readansi">system.readansi</a>)
+</span> <span class="comment">-- @tparam string keytype the type of the key, either "char" or "ansi" (from <a href="../modules/system.html#readansi">system.readansi</a>)
+</span> <span class="comment">-- @treturn string status the status of the key handling, either "ok", "exit_key" or an error message
+</span> <span class="keyword">function</span> <span class="function-name">handle_key</span>(self, key, keytype)
+ <span class="keyword">if</span> self.exit_keys[key] <span class="keyword">then</span>
+ <span class="comment">-- registered exit key
+</span> <span class="keyword">return</span> <span class="string">"exit_key"</span>
+ <span class="keyword">end</span>
+
+ <span class="keyword">local</span> handler = key_handlers[key_names[key] <span class="keyword">or</span> <span class="keyword">true</span> ]
+ <span class="keyword">if</span> handler <span class="keyword">then</span>
+ <span class="function-name">handler</span>(self)
+ <span class="keyword">return</span> <span class="string">"ok"</span>
+ <span class="keyword">end</span>
+
+ <span class="keyword">if</span> keytype == <span class="string">"ansi"</span> <span class="keyword">then</span>
+ <span class="comment">-- we got an ansi sequence, but dunno how to handle it, ignore
+</span> <span class="comment">-- print("unhandled ansi: ", key:sub(2,-1), string.byte(key, 1, -1))
+</span> <span class="function-name">bell</span>()
+ <span class="keyword">return</span> <span class="string">"ok"</span>
+ <span class="keyword">end</span>
+
+ <span class="comment">-- just a single key
+</span> <span class="keyword">if</span> key &lt; <span class="string">" "</span> <span class="keyword">then</span>
+ <span class="comment">-- control character
+</span> <span class="function-name">bell</span>()
+ <span class="keyword">return</span> <span class="string">"ok"</span>
+ <span class="keyword">end</span>
+
+ <span class="keyword">if</span> self.value.chars &gt;= self.max_length <span class="keyword">then</span>
+ <span class="function-name">bell</span>()
+ <span class="keyword">return</span> <span class="string">"ok"</span>
+ <span class="keyword">end</span>
+
+ <span class="comment">-- insert the key into the value
+</span> <span class="keyword">if</span> sys.<span class="function-name">utf8cwidth</span>(key) == <span class="number">2</span> <span class="keyword">then</span>
+ <span class="comment">-- double width character, insert empty string after it
+</span> <span class="global">table</span>.<span class="function-name">insert</span>(self.value, self.position, <span class="string">""</span>)
+ <span class="global">table</span>.<span class="function-name">insert</span>(self.value, self.position, key)
+ self.position = self.position + <span class="number">2</span>
+ <span class="global">io</span>.<span class="function-name">write</span>(<span class="function-name">cursor_move_horiz</span>(<span class="number">2</span>))
+ <span class="keyword">else</span>
+ <span class="global">table</span>.<span class="function-name">insert</span>(self.value, self.position, key)
+ self.position = self.position + <span class="number">1</span>
+ <span class="global">io</span>.<span class="function-name">write</span>(<span class="function-name">cursor_move_horiz</span>(<span class="number">1</span>))
+ <span class="keyword">end</span>
+ self.value.chars = self.value.chars + <span class="number">1</span>
+ <span class="function-name">draw</span>(self)
+ <span class="keyword">return</span> <span class="string">"ok"</span>
+ <span class="keyword">end</span>
+<span class="keyword">end</span>
+
+
+
+<span class="comment">--- Get_size returns the maximum size of the input box (prompt + input).
+</span><span class="comment">-- The size is in rows and columns. Columns is determined by
+</span><span class="comment">-- the prompt and the <code>max_length * 2</code> (characters can be double-width).
+</span><span class="comment">-- @treturn number the number of rows (always 1)
+</span><span class="comment">-- @treturn number the number of columns
+</span><span class="keyword">function</span> readline:<span class="function-name">get_size</span>()
+ <span class="keyword">return</span> <span class="number">1</span>, #self.prompt + self.max_length * <span class="number">2</span>
+<span class="keyword">end</span>
+
+
+
+<span class="comment">--- Get coordinates of the cursor in the input box (prompt + input).
+</span><span class="comment">-- The coordinates are 1-based. They are returned as row and column, within the
+</span><span class="comment">-- size as reported by <code>get_size</code>.
+</span><span class="comment">-- @treturn number the row of the cursor (always 1)
+</span><span class="comment">-- @treturn number the column of the cursor
+</span><span class="keyword">function</span> readline:<span class="function-name">get_cursor</span>()
+ <span class="keyword">return</span> <span class="number">1</span>, #self.prompt + self.position
+<span class="keyword">end</span>
+
+
+
+<span class="comment">--- Set the coordinates of the cursor in the input box (prompt + input).
+</span><span class="comment">-- The coordinates are 1-based. They are expected to be within the
+</span><span class="comment">-- size as reported by <code>get_size</code>, and beyond the prompt.
+</span><span class="comment">-- If the position is invalid, it will be corrected.
+</span><span class="comment">-- Use the results to check if the position was adjusted.
+</span><span class="comment">-- @tparam number row the row of the cursor (always 1)
+</span><span class="comment">-- @tparam number col the column of the cursor
+</span><span class="comment">-- @return results of get_cursor
+</span><span class="keyword">function</span> readline:<span class="function-name">set_cursor</span>(row, col)
+ <span class="keyword">local</span> l_prompt = #self.prompt
+ <span class="keyword">local</span> l_value = #self.value
+
+ <span class="keyword">if</span> col &lt; l_prompt + <span class="number">1</span> <span class="keyword">then</span>
+ col = l_prompt + <span class="number">1</span>
+ <span class="keyword">elseif</span> col &gt; l_prompt + l_value + <span class="number">1</span> <span class="keyword">then</span>
+ col = l_prompt + l_value + <span class="number">1</span>
+ <span class="keyword">end</span>
+
+ <span class="keyword">while</span> self.value[col - l_prompt] == <span class="string">""</span> <span class="keyword">do</span>
+ col = col - <span class="number">1</span> <span class="comment">-- on an empty string, so move back to start of double-width char
+</span> <span class="keyword">end</span>
+
+ <span class="keyword">local</span> new_pos = col - l_prompt
+
+ <span class="function-name">cursor_move_horiz</span>(self.position - new_pos)
+ <span class="global">io</span>.<span class="function-name">flush</span>()
+
+ self.position = new_pos
+ <span class="keyword">return</span> self:<span class="function-name">get_cursor</span>()
+<span class="keyword">end</span>
+
+
+
+<span class="comment">--- Read a line of input from the user.
+</span><span class="comment">-- It will first print the <code>prompt</code> and then wait for input. Ensure the cursor
+</span><span class="comment">-- is at the correct position before calling this function. This function will
+</span><span class="comment">-- do all cursor movements in a relative way.
+</span><span class="comment">-- Can be called again after an exit-key or timeout has occurred. Just make sure
+</span><span class="comment">-- the cursor is at the same position where is was when it returned the last time.
+</span><span class="comment">-- Alternatively the cursor can be set to the position of the prompt (the position
+</span><span class="comment">-- the cursor was in before the first call), and the parameter <code>redraw</code> can be set
+</span><span class="comment">-- to <code>true</code>.
+</span><span class="comment">-- @tparam[opt=math.huge] number timeout the maximum time to wait for input in seconds
+</span><span class="comment">-- @tparam[opt=false] boolean redraw if <code>true</code> the prompt will be redrawn (cursor must be at prompt position!)
+</span><span class="comment">-- @treturn[1] string the input string as entered the user
+</span><span class="comment">-- @treturn[1] string the exit-key used to exit the readline (see <code>new</code>)
+</span><span class="comment">-- @treturn[2] nil when input is incomplete
+</span><span class="comment">-- @treturn[2] string error message, the reason why the input is incomplete, <code>&quot;timeout&quot;</code>, or an error reading a key
+</span><span class="keyword">function</span> readline:<span class="function-name">__call</span>(timeout, redraw)
+ <span class="function-name">draw</span>(self, redraw)
+ timeout = timeout <span class="keyword">or</span> <span class="global">math</span>.huge
+ <span class="keyword">local</span> timeout_end = sys.<span class="function-name">gettime</span>() + timeout
+
+ <span class="keyword">while</span> <span class="keyword">true</span> <span class="keyword">do</span>
+ <span class="keyword">local</span> key, keytype = sys.<span class="function-name">readansi</span>(timeout_end - sys.<span class="function-name">gettime</span>())
+ <span class="keyword">if</span> <span class="keyword">not</span> key <span class="keyword">then</span>
+ <span class="comment">-- error or timeout
+</span> <span class="keyword">return</span> <span class="keyword">nil</span>, keytype
+ <span class="keyword">end</span>
+
+ <span class="keyword">local</span> status = <span class="function-name">handle_key</span>(self, key, keytype)
+ <span class="keyword">if</span> status == <span class="string">"exit_key"</span> <span class="keyword">then</span>
+ <span class="keyword">return</span> <span class="global">tostring</span>(self.value), key
+
+ <span class="keyword">elseif</span> status ~= <span class="string">"ok"</span> <span class="keyword">then</span>
+ <span class="global">error</span>(<span class="string">"unknown status received: "</span> .. <span class="global">tostring</span>(status))
+ <span class="keyword">end</span>
+ <span class="keyword">end</span>
+<span class="keyword">end</span>
+
+
+
+<span class="comment">-- return readline -- normally we'd return here, but for the example we continue
+</span>
+
+
+
+<span class="keyword">local</span> backup = sys.<span class="function-name">termbackup</span>()
+
+<span class="comment">-- setup Windows console to handle ANSI processing
+</span>sys.<span class="function-name">setconsoleflags</span>(<span class="global">io</span>.stdout, sys.<span class="function-name">getconsoleflags</span>(<span class="global">io</span>.stdout) + sys.COF_VIRTUAL_TERMINAL_PROCESSING)
+sys.<span class="function-name">setconsoleflags</span>(<span class="global">io</span>.stdin, sys.<span class="function-name">getconsoleflags</span>(<span class="global">io</span>.stdin) + sys.CIF_VIRTUAL_TERMINAL_INPUT)
+<span class="comment">-- set output to UTF-8
+</span>sys.<span class="function-name">setconsoleoutputcp</span>(sys.CODEPAGE_UTF8)
+
+<span class="comment">-- setup Posix terminal to disable canonical mode and echo
+</span>sys.<span class="function-name">tcsetattr</span>(<span class="global">io</span>.stdin, sys.TCSANOW, {
+ lflag = sys.<span class="function-name">tcgetattr</span>(<span class="global">io</span>.stdin).lflag - sys.L_ICANON - sys.L_ECHO,
+})
+<span class="comment">-- setup stdin to non-blocking mode
+</span>sys.<span class="function-name">setnonblock</span>(<span class="global">io</span>.stdin, <span class="keyword">true</span>)
+
+
+<span class="keyword">local</span> rl = readline.<span class="function-name">new</span>{
+ prompt = <span class="string">"Enter something: "</span>,
+ max_length = <span class="number">60</span>,
+ value = <span class="string">"Hello, 你-好 World 🚀!"</span>,
+ <span class="comment">-- position = 2,
+</span> exit_keys = {key_sequences.enter, <span class="string">"\27"</span>, <span class="string">"\t"</span>, <span class="string">"\27[Z"</span>}, <span class="comment">-- enter, escape, tab, shift-tab
+</span>}
+
+
+<span class="keyword">local</span> result, key = <span class="function-name">rl</span>()
+<span class="global">print</span>(<span class="string">""</span>) <span class="comment">-- newline after input, to move cursor down from the input line
+</span><span class="global">print</span>(<span class="string">"Result (string): '"</span> .. result .. <span class="string">"'"</span>)
+<span class="global">print</span>(<span class="string">"Result (bytes):"</span>, result:<span class="function-name">byte</span>(<span class="number">1</span>,-<span class="number">1</span>))
+<span class="global">print</span>(<span class="string">"Exit-Key (bytes):"</span>, key:<span class="function-name">byte</span>(<span class="number">1</span>,-<span class="number">1</span>))
+
+
+<span class="comment">-- Clean up afterwards
+</span>sys.<span class="function-name">termrestore</span>(backup)</pre>
+
+
+</div> <!-- id="content" -->
+</div> <!-- id="main" -->
+<div id="about">
+<i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i>
+<i style="float:right;">Last updated 2024-06-20 23:11:37 </i>
+</div> <!-- id="about" -->
+</div> <!-- id="container" -->
+</body>
+</html>
diff --git a/docs/examples/spinner.lua.html b/docs/examples/spinner.lua.html
new file mode 100644
index 0000000..181cbe5
--- /dev/null
+++ b/docs/examples/spinner.lua.html
@@ -0,0 +1,144 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+<head>
+ <title>Lua-System docs</title>
+ <link rel="stylesheet" href="../ldoc.css" type="text/css" />
+</head>
+<body>
+
+<div id="container">
+
+<div id="product">
+ <div id="product_logo"></div>
+ <div id="product_name"><big><b></b></big></div>
+ <div id="product_description"></div>
+</div> <!-- id="product" -->
+
+
+<div id="main">
+
+
+<!-- Menu -->
+
+<div id="navigation">
+<br/>
+<h1>Lua-System</h1>
+
+
+<ul>
+ <li><a href="../index.html">Index</a></li>
+</ul>
+
+
+
+<h2>Examples</h2>
+<ul class="nowrap">
+ <li><a href="../examples/compat.lua.html">compat.lua</a></li>
+ <li><a href="../examples/flag_debugging.lua.html">flag_debugging.lua</a></li>
+ <li><a href="../examples/password_input.lua.html">password_input.lua</a></li>
+ <li><a href="../examples/read.lua.html">read.lua</a></li>
+ <li><a href="../examples/readline.lua.html">readline.lua</a></li>
+ <li><strong>spinner.lua</strong></li>
+ <li><a href="../examples/spiral_snake.lua.html">spiral_snake.lua</a></li>
+ <li><a href="../examples/terminalsize.lua.html">terminalsize.lua</a></li>
+</ul>
+<h2>Modules</h2>
+<ul class="nowrap">
+ <li><a href="../modules/system.html">system</a></li>
+</ul>
+<h2>Classes</h2>
+<ul class="nowrap">
+ <li><a href="../classes/bitflags.html">bitflags</a></li>
+</ul>
+<h2>Topics</h2>
+<ul class="">
+ <li><a href="../topics/01-introduction.md.html">1. Introduction</a></li>
+ <li><a href="../topics/02-development.md.html">2. Development</a></li>
+ <li><a href="../topics/03-terminal.md.html">3. Terminal functionality</a></li>
+ <li><a href="../topics/CHANGELOG.md.html">CHANGELOG</a></li>
+ <li><a href="../topics/LICENSE.md.html">MIT License</a></li>
+</ul>
+
+</div>
+
+<div id="content">
+
+ <h2>spinner.lua</h2>
+<pre>
+<span class="keyword">local</span> sys = <span class="global">require</span>(<span class="string">"system"</span>)
+
+<span class="global">print</span> <span class="string">[[
+
+An example to display a spinner, whilst a long running task executes.
+
+]]</span>
+
+
+<span class="comment">-- start make backup, to auto-restore on exit
+</span>sys.<span class="function-name">autotermrestore</span>()
+<span class="comment">-- configure console
+</span>sys.<span class="function-name">setconsoleflags</span>(<span class="global">io</span>.stdin, sys.<span class="function-name">getconsoleflags</span>(<span class="global">io</span>.stdin) - sys.CIF_ECHO_INPUT - sys.CIF_LINE_INPUT)
+<span class="keyword">local</span> of = sys.<span class="function-name">tcgetattr</span>(<span class="global">io</span>.stdin)
+sys.<span class="function-name">tcsetattr</span>(<span class="global">io</span>.stdin, sys.TCSANOW, { lflag = of.lflag - sys.L_ICANON - sys.L_ECHO })
+sys.<span class="function-name">setnonblock</span>(<span class="global">io</span>.stdin, <span class="keyword">true</span>)
+
+
+
+<span class="keyword">local</span> <span class="keyword">function</span> <span class="function-name">hideCursor</span>()
+ <span class="global">io</span>.<span class="function-name">write</span>(<span class="string">"\27[?25l"</span>)
+ <span class="global">io</span>.<span class="function-name">flush</span>()
+<span class="keyword">end</span>
+
+<span class="keyword">local</span> <span class="keyword">function</span> <span class="function-name">showCursor</span>()
+ <span class="global">io</span>.<span class="function-name">write</span>(<span class="string">"\27[?25h"</span>)
+ <span class="global">io</span>.<span class="function-name">flush</span>()
+<span class="keyword">end</span>
+
+<span class="keyword">local</span> <span class="keyword">function</span> <span class="function-name">left</span>(n)
+ <span class="global">io</span>.<span class="function-name">write</span>(<span class="string">"\27["</span>,n <span class="keyword">or</span> <span class="number">1</span>,<span class="string">"D"</span>)
+ <span class="global">io</span>.<span class="function-name">flush</span>()
+<span class="keyword">end</span>
+
+
+
+<span class="keyword">local</span> spinner <span class="keyword">do</span>
+ <span class="keyword">local</span> spin = <span class="string">[[|/-\]]</span>
+ <span class="keyword">local</span> i = <span class="number">1</span>
+ spinner = <span class="keyword">function</span>()
+ <span class="function-name">hideCursor</span>()
+ <span class="global">io</span>.<span class="function-name">write</span>(spin:<span class="function-name">sub</span>(i, i))
+ <span class="function-name">left</span>()
+ i = i + <span class="number">1</span>
+ <span class="keyword">if</span> i &gt; #spin <span class="keyword">then</span> i = <span class="number">1</span> <span class="keyword">end</span>
+
+ <span class="keyword">if</span> sys.<span class="function-name">readkey</span>(<span class="number">0</span>) ~= <span class="keyword">nil</span> <span class="keyword">then</span>
+ <span class="keyword">while</span> sys.<span class="function-name">readkey</span>(<span class="number">0</span>) ~= <span class="keyword">nil</span> <span class="keyword">do</span> <span class="keyword">end</span> <span class="comment">-- consume keys pressed
+</span> <span class="global">io</span>.<span class="function-name">write</span>(<span class="string">" "</span>);
+ <span class="function-name">left</span>()
+ <span class="function-name">showCursor</span>()
+ <span class="keyword">return</span> <span class="keyword">true</span>
+ <span class="keyword">else</span>
+ <span class="keyword">return</span> <span class="keyword">false</span>
+ <span class="keyword">end</span>
+ <span class="keyword">end</span>
+<span class="keyword">end</span>
+
+<span class="global">io</span>.stdout:<span class="function-name">write</span>(<span class="string">"press any key to stop the spinner... "</span>)
+<span class="keyword">while</span> <span class="keyword">not</span> <span class="function-name">spinner</span>() <span class="keyword">do</span>
+ sys.<span class="function-name">sleep</span>(<span class="number">0.1</span>)
+<span class="keyword">end</span>
+
+<span class="global">print</span>(<span class="string">"Done!"</span>)</pre>
+
+
+</div> <!-- id="content" -->
+</div> <!-- id="main" -->
+<div id="about">
+<i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i>
+<i style="float:right;">Last updated 2024-06-20 23:11:37 </i>
+</div> <!-- id="about" -->
+</div> <!-- id="container" -->
+</body>
+</html>
diff --git a/docs/examples/spiral_snake.lua.html b/docs/examples/spiral_snake.lua.html
new file mode 100644
index 0000000..7ebb838
--- /dev/null
+++ b/docs/examples/spiral_snake.lua.html
@@ -0,0 +1,152 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+<head>
+ <title>Lua-System docs</title>
+ <link rel="stylesheet" href="../ldoc.css" type="text/css" />
+</head>
+<body>
+
+<div id="container">
+
+<div id="product">
+ <div id="product_logo"></div>
+ <div id="product_name"><big><b></b></big></div>
+ <div id="product_description"></div>
+</div> <!-- id="product" -->
+
+
+<div id="main">
+
+
+<!-- Menu -->
+
+<div id="navigation">
+<br/>
+<h1>Lua-System</h1>
+
+
+<ul>
+ <li><a href="../index.html">Index</a></li>
+</ul>
+
+
+
+<h2>Examples</h2>
+<ul class="nowrap">
+ <li><a href="../examples/compat.lua.html">compat.lua</a></li>
+ <li><a href="../examples/flag_debugging.lua.html">flag_debugging.lua</a></li>
+ <li><a href="../examples/password_input.lua.html">password_input.lua</a></li>
+ <li><a href="../examples/read.lua.html">read.lua</a></li>
+ <li><a href="../examples/readline.lua.html">readline.lua</a></li>
+ <li><a href="../examples/spinner.lua.html">spinner.lua</a></li>
+ <li><strong>spiral_snake.lua</strong></li>
+ <li><a href="../examples/terminalsize.lua.html">terminalsize.lua</a></li>
+</ul>
+<h2>Modules</h2>
+<ul class="nowrap">
+ <li><a href="../modules/system.html">system</a></li>
+</ul>
+<h2>Classes</h2>
+<ul class="nowrap">
+ <li><a href="../classes/bitflags.html">bitflags</a></li>
+</ul>
+<h2>Topics</h2>
+<ul class="">
+ <li><a href="../topics/01-introduction.md.html">1. Introduction</a></li>
+ <li><a href="../topics/02-development.md.html">2. Development</a></li>
+ <li><a href="../topics/03-terminal.md.html">3. Terminal functionality</a></li>
+ <li><a href="../topics/CHANGELOG.md.html">CHANGELOG</a></li>
+ <li><a href="../topics/LICENSE.md.html">MIT License</a></li>
+</ul>
+
+</div>
+
+<div id="content">
+
+ <h2>spiral_snake.lua</h2>
+<pre>
+<span class="keyword">local</span> sys = <span class="global">require</span> <span class="string">"system"</span>
+
+<span class="global">print</span> <span class="string">[[
+
+This example will draw a snake like spiral on the screen. Showing ANSI escape
+codes for moving the cursor around.
+
+]]</span>
+
+<span class="comment">-- backup term settings with auto-restore on exit
+</span>sys.<span class="function-name">autotermrestore</span>()
+
+<span class="comment">-- setup Windows console to handle ANSI processing
+</span>sys.<span class="function-name">setconsoleflags</span>(<span class="global">io</span>.stdout, sys.<span class="function-name">getconsoleflags</span>(<span class="global">io</span>.stdout) + sys.COF_VIRTUAL_TERMINAL_PROCESSING)
+
+<span class="comment">-- start drawing the spiral.
+</span><span class="comment">-- start from current pos, then right, then up, then left, then down, and again.
+</span><span class="keyword">local</span> x, y = <span class="number">1</span>, <span class="number">1</span> <span class="comment">-- current position
+</span><span class="keyword">local</span> dx, dy = <span class="number">1</span>, <span class="number">0</span> <span class="comment">-- direction after each step
+</span><span class="keyword">local</span> wx, wy = <span class="number">30</span>, <span class="number">30</span> <span class="comment">-- width and height of the room
+</span><span class="keyword">local</span> mx, my = <span class="number">1</span>, <span class="number">1</span> <span class="comment">-- margin
+</span>
+<span class="comment">-- commands to move the cursor
+</span><span class="keyword">local</span> move_left = <span class="string">"\27[1D"</span>
+<span class="keyword">local</span> move_right = <span class="string">"\27[1C"</span>
+<span class="keyword">local</span> move_up = <span class="string">"\27[1A"</span>
+<span class="keyword">local</span> move_down = <span class="string">"\27[1B"</span>
+
+<span class="comment">-- create room: 30 empty lines
+</span><span class="global">print</span>((<span class="string">"\n"</span>):<span class="function-name">rep</span>(wy))
+<span class="keyword">local</span> move = move_right
+
+<span class="keyword">while</span> wx &gt; <span class="number">0</span> <span class="keyword">and</span> wy &gt; <span class="number">0</span> <span class="keyword">do</span>
+ sys.<span class="function-name">sleep</span>(<span class="number">0.01</span>) <span class="comment">-- slow down the drawing a little
+</span> <span class="global">io</span>.<span class="function-name">write</span>(<span class="string">"*"</span> .. move_left .. move )
+ <span class="global">io</span>.<span class="function-name">flush</span>()
+ x = x + dx
+ y = y + dy
+
+ <span class="keyword">if</span> x &gt; wx <span class="keyword">and</span> move == move_right <span class="keyword">then</span>
+ <span class="comment">-- end of move right
+</span> dx = <span class="number">0</span>
+ dy = <span class="number">1</span>
+ move = move_up
+ wy = wy - <span class="number">1</span>
+ my = my + <span class="number">1</span>
+ <span class="keyword">elseif</span> y &gt; wy <span class="keyword">and</span> move == move_up <span class="keyword">then</span>
+ <span class="comment">-- end of move up
+</span> dx = -<span class="number">1</span>
+ dy = <span class="number">0</span>
+ move = move_left
+ wx = wx - <span class="number">1</span>
+ mx = mx + <span class="number">1</span>
+ <span class="keyword">elseif</span> x &lt; mx <span class="keyword">and</span> move == move_left <span class="keyword">then</span>
+ <span class="comment">-- end of move left
+</span> dx = <span class="number">0</span>
+ dy = -<span class="number">1</span>
+ move = move_down
+ wy = wy - <span class="number">1</span>
+ my = my + <span class="number">1</span>
+ <span class="keyword">elseif</span> y &lt; my <span class="keyword">and</span> move == move_down <span class="keyword">then</span>
+ <span class="comment">-- end of move down
+</span> dx = <span class="number">1</span>
+ dy = <span class="number">0</span>
+ move = move_right
+ wx = wx - <span class="number">1</span>
+ mx = mx + <span class="number">1</span>
+ <span class="keyword">end</span>
+<span class="keyword">end</span>
+
+<span class="global">io</span>.<span class="function-name">write</span>(move_down:<span class="function-name">rep</span>(<span class="number">15</span>))
+<span class="global">print</span>(<span class="string">"\nDone!"</span>)</pre>
+
+
+</div> <!-- id="content" -->
+</div> <!-- id="main" -->
+<div id="about">
+<i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i>
+<i style="float:right;">Last updated 2024-06-20 23:11:37 </i>
+</div> <!-- id="about" -->
+</div> <!-- id="container" -->
+</body>
+</html>
diff --git a/docs/examples/terminalsize.lua.html b/docs/examples/terminalsize.lua.html
new file mode 100644
index 0000000..d7f902d
--- /dev/null
+++ b/docs/examples/terminalsize.lua.html
@@ -0,0 +1,117 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+<head>
+ <title>Lua-System docs</title>
+ <link rel="stylesheet" href="../ldoc.css" type="text/css" />
+</head>
+<body>
+
+<div id="container">
+
+<div id="product">
+ <div id="product_logo"></div>
+ <div id="product_name"><big><b></b></big></div>
+ <div id="product_description"></div>
+</div> <!-- id="product" -->
+
+
+<div id="main">
+
+
+<!-- Menu -->
+
+<div id="navigation">
+<br/>
+<h1>Lua-System</h1>
+
+
+<ul>
+ <li><a href="../index.html">Index</a></li>
+</ul>
+
+
+
+<h2>Examples</h2>
+<ul class="nowrap">
+ <li><a href="../examples/compat.lua.html">compat.lua</a></li>
+ <li><a href="../examples/flag_debugging.lua.html">flag_debugging.lua</a></li>
+ <li><a href="../examples/password_input.lua.html">password_input.lua</a></li>
+ <li><a href="../examples/read.lua.html">read.lua</a></li>
+ <li><a href="../examples/readline.lua.html">readline.lua</a></li>
+ <li><a href="../examples/spinner.lua.html">spinner.lua</a></li>
+ <li><a href="../examples/spiral_snake.lua.html">spiral_snake.lua</a></li>
+ <li><strong>terminalsize.lua</strong></li>
+</ul>
+<h2>Modules</h2>
+<ul class="nowrap">
+ <li><a href="../modules/system.html">system</a></li>
+</ul>
+<h2>Classes</h2>
+<ul class="nowrap">
+ <li><a href="../classes/bitflags.html">bitflags</a></li>
+</ul>
+<h2>Topics</h2>
+<ul class="">
+ <li><a href="../topics/01-introduction.md.html">1. Introduction</a></li>
+ <li><a href="../topics/02-development.md.html">2. Development</a></li>
+ <li><a href="../topics/03-terminal.md.html">3. Terminal functionality</a></li>
+ <li><a href="../topics/CHANGELOG.md.html">CHANGELOG</a></li>
+ <li><a href="../topics/LICENSE.md.html">MIT License</a></li>
+</ul>
+
+</div>
+
+<div id="content">
+
+ <h2>terminalsize.lua</h2>
+<pre>
+<span class="keyword">local</span> sys = <span class="global">require</span>(<span class="string">"system"</span>)
+
+sys.<span class="function-name">autotermrestore</span>() <span class="comment">-- set up auto restore of terminal settings on exit
+</span>
+<span class="comment">-- setup Windows console to handle ANSI processing
+</span>sys.<span class="function-name">setconsoleflags</span>(<span class="global">io</span>.stdout, sys.<span class="function-name">getconsoleflags</span>(<span class="global">io</span>.stdout) + sys.COF_VIRTUAL_TERMINAL_PROCESSING)
+sys.<span class="function-name">setconsoleflags</span>(<span class="global">io</span>.stdin, sys.<span class="function-name">getconsoleflags</span>(<span class="global">io</span>.stdin) + sys.CIF_VIRTUAL_TERMINAL_INPUT)
+
+<span class="comment">-- setup Posix to disable canonical mode and echo
+</span><span class="keyword">local</span> of_attr = sys.<span class="function-name">tcgetattr</span>(<span class="global">io</span>.stdin)
+sys.<span class="function-name">setnonblock</span>(<span class="global">io</span>.stdin, <span class="keyword">true</span>)
+sys.<span class="function-name">tcsetattr</span>(<span class="global">io</span>.stdin, sys.TCSANOW, {
+ lflag = of_attr.lflag - sys.L_ICANON - sys.L_ECHO, <span class="comment">-- disable canonical mode and echo
+</span>})
+
+
+<span class="comment">-- generate string to move cursor horizontally
+</span><span class="comment">-- positive goes right, negative goes left
+</span><span class="keyword">local</span> <span class="keyword">function</span> <span class="function-name">cursor_move_horiz</span>(n)
+ <span class="keyword">if</span> n == <span class="number">0</span> <span class="keyword">then</span>
+ <span class="keyword">return</span> <span class="string">""</span>
+ <span class="keyword">end</span>
+ <span class="keyword">return</span> <span class="string">"\27["</span> .. (n &gt; <span class="number">0</span> <span class="keyword">and</span> n <span class="keyword">or</span> -n) .. (n &gt; <span class="number">0</span> <span class="keyword">and</span> <span class="string">"C"</span> <span class="keyword">or</span> <span class="string">"D"</span>)
+<span class="keyword">end</span>
+
+
+<span class="keyword">local</span> rows, cols
+<span class="global">print</span>(<span class="string">"Change the terminal window size, press any key to exit"</span>)
+<span class="keyword">while</span> <span class="keyword">not</span> sys.<span class="function-name">readansi</span>(<span class="number">0.2</span>) <span class="keyword">do</span> <span class="comment">-- use readansi to not leave stray bytes in the input buffer
+</span> <span class="keyword">local</span> nrows, ncols = sys.<span class="function-name">termsize</span>()
+ <span class="keyword">if</span> rows ~= nrows <span class="keyword">or</span> cols ~= ncols <span class="keyword">then</span>
+ rows, cols = nrows, ncols
+ <span class="keyword">local</span> text = <span class="string">"Terminal size: "</span> .. rows .. <span class="string">"x"</span> .. cols .. <span class="string">" "</span>
+ <span class="global">io</span>.<span class="function-name">write</span>(text .. <span class="function-name">cursor_move_horiz</span>(-#text))
+ <span class="global">io</span>.<span class="function-name">flush</span>()
+ <span class="keyword">end</span>
+<span class="keyword">end</span></pre>
+
+
+</div> <!-- id="content" -->
+</div> <!-- id="main" -->
+<div id="about">
+<i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i>
+<i style="float:right;">Last updated 2024-06-20 23:11:37 </i>
+</div> <!-- id="about" -->
+</div> <!-- id="container" -->
+</body>
+</html>
diff --git a/docs/index.html b/docs/index.html
index cd95fc2..52c93fe 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -27,339 +27,122 @@
<h1>Lua-System</h1>
-<h2>Contents</h2>
-<ul>
-<li><a href="#environment_Functions">environment Functions</a></li>
-<li><a href="#random_Functions">random Functions</a></li>
-<li><a href="#term_Functions">term Functions</a></li>
-<li><a href="#time_Functions">time Functions</a></li>
-</ul>
+
<h2>Modules</h2>
<ul class="nowrap">
- <li><strong>system</strong></li>
+ <li><a href="modules/system.html">system</a></li>
+</ul>
+<h2>Classes</h2>
+<ul class="nowrap">
+ <li><a href="classes/bitflags.html">bitflags</a></li>
</ul>
<h2>Topics</h2>
<ul class="">
<li><a href="topics/01-introduction.md.html">1. Introduction</a></li>
+ <li><a href="topics/02-development.md.html">2. Development</a></li>
+ <li><a href="topics/03-terminal.md.html">3. Terminal functionality</a></li>
<li><a href="topics/CHANGELOG.md.html">CHANGELOG</a></li>
<li><a href="topics/LICENSE.md.html">MIT License</a></li>
</ul>
+<h2>Examples</h2>
+<ul class="nowrap">
+ <li><a href="examples/compat.lua.html">compat.lua</a></li>
+ <li><a href="examples/flag_debugging.lua.html">flag_debugging.lua</a></li>
+ <li><a href="examples/password_input.lua.html">password_input.lua</a></li>
+ <li><a href="examples/read.lua.html">read.lua</a></li>
+ <li><a href="examples/readline.lua.html">readline.lua</a></li>
+ <li><a href="examples/spinner.lua.html">spinner.lua</a></li>
+ <li><a href="examples/spiral_snake.lua.html">spiral_snake.lua</a></li>
+ <li><a href="examples/terminalsize.lua.html">terminalsize.lua</a></li>
+</ul>
</div>
<div id="content">
-<h1>Module <code>system</code></h1>
-<p>Platform independent system calls for Lua.</p>
-<p>
-
-</p>
+ <h2>Platform independent system calls for Lua</h2>
-<h2><a href="#environment_Functions">environment Functions</a></h2>
-<table class="function_list">
+<h2>Modules</h2>
+<table class="module_list">
<tr>
- <td class="name" nowrap><a href="#getenv">getenv (name)</a></td>
- <td class="summary">Gets the value of an environment variable.</td>
+ <td class="name" nowrap><a href="modules/system.html">system</a></td>
+ <td class="summary">Platform independent system calls for Lua.</td>
</tr>
+</table>
+<h2>Classes</h2>
+<table class="module_list">
<tr>
- <td class="name" nowrap><a href="#getenvs">getenvs ()</a></td>
- <td class="summary">Returns a table with all environment variables.</td>
+ <td class="name" nowrap><a href="classes/bitflags.html">bitflags</a></td>
+ <td class="summary">Bitflags module.</td>
</tr>
+</table>
+<h2>Topics</h2>
+<table class="module_list">
<tr>
- <td class="name" nowrap><a href="#setenv">setenv (name[, value])</a></td>
- <td class="summary">Sets an environment variable.</td>
+ <td class="name" nowrap><a href="topics/01-introduction.md.html">01-introduction.md</a></td>
+ <td class="summary"></td>
</tr>
-</table>
-<h2><a href="#random_Functions">random Functions</a></h2>
-<table class="function_list">
<tr>
- <td class="name" nowrap><a href="#random">random ([length=1])</a></td>
- <td class="summary">Generate random bytes.</td>
+ <td class="name" nowrap><a href="topics/02-development.md.html">02-development.md</a></td>
+ <td class="summary"></td>
</tr>
-</table>
-<h2><a href="#term_Functions">term Functions</a></h2>
-<table class="function_list">
<tr>
- <td class="name" nowrap><a href="#isatty">isatty (file)</a></td>
- <td class="summary">Checks if a file-handle is a TTY.</td>
+ <td class="name" nowrap><a href="topics/03-terminal.md.html">03-terminal.md</a></td>
+ <td class="summary"></td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="topics/CHANGELOG.md.html">CHANGELOG.md</a></td>
+ <td class="summary"></td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="topics/LICENSE.md.html">LICENSE.md</a></td>
+ <td class="summary"></td>
</tr>
</table>
-<h2><a href="#time_Functions">time Functions</a></h2>
-<table class="function_list">
+<h2>Examples</h2>
+<table class="module_list">
+ <tr>
+ <td class="name" nowrap><a href="examples/compat.lua.html">compat.lua</a></td>
+ <td class="summary"></td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="examples/flag_debugging.lua.html">flag_debugging.lua</a></td>
+ <td class="summary"></td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="examples/password_input.lua.html">password_input.lua</a></td>
+ <td class="summary"></td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="examples/read.lua.html">read.lua</a></td>
+ <td class="summary"></td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="examples/readline.lua.html">readline.lua</a></td>
+ <td class="summary"></td>
+ </tr>
<tr>
- <td class="name" nowrap><a href="#gettime">gettime ()</a></td>
- <td class="summary">Get system time.</td>
+ <td class="name" nowrap><a href="examples/spinner.lua.html">spinner.lua</a></td>
+ <td class="summary"></td>
</tr>
<tr>
- <td class="name" nowrap><a href="#monotime">monotime ()</a></td>
- <td class="summary">Get monotonic time.</td>
+ <td class="name" nowrap><a href="examples/spiral_snake.lua.html">spiral_snake.lua</a></td>
+ <td class="summary"></td>
</tr>
<tr>
- <td class="name" nowrap><a href="#sleep">sleep (seconds[, precision=16])</a></td>
- <td class="summary">Sleep without a busy loop.</td>
+ <td class="name" nowrap><a href="examples/terminalsize.lua.html">terminalsize.lua</a></td>
+ <td class="summary"></td>
</tr>
</table>
-<br/>
-<br/>
-
-
- <h2 class="section-header "><a name="environment_Functions"></a>environment Functions</h2>
-
- <dl class="function">
- <dt>
- <a name = "getenv"></a>
- <strong>getenv (name)</strong>
- </dt>
- <dd>
- Gets the value of an environment variable. </p>
-
-<p><strong>NOTE</strong>: Windows has multiple copies of environment variables. For this reason,
-the <a href="index.html#setenv">setenv</a> function will not work with Lua's <a href="https://www.lua.org/manual/5.1/manual.html#pdf-os.getenv">os.getenv</a> on Windows. If you want
-to use <a href="index.html#setenv">setenv</a> then consider patching <a href="https://www.lua.org/manual/5.1/manual.html#pdf-os.getenv">os.getenv</a> with this implementation of <a href="index.html#getenv">getenv</a>.
-
-
- <h3>Parameters:</h3>
- <ul>
- <li><span class="parameter">name</span>
- <span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
- name of the environment variable
- </li>
- </ul>
-
- <h3>Returns:</h3>
- <ol>
-
- <span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a> or <span class="type">nil</span></span>
- value of the environment variable, or nil if the variable is not set
- </ol>
-
-
-
-
-</dd>
- <dt>
- <a name = "getenvs"></a>
- <strong>getenvs ()</strong>
- </dt>
- <dd>
- Returns a table with all environment variables.
-
-
-
- <h3>Returns:</h3>
- <ol>
-
- <span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.5">table</a></span>
- table with all environment variables and their values
- </ol>
-
-
-
-
-</dd>
- <dt>
- <a name = "setenv"></a>
- <strong>setenv (name[, value])</strong>
- </dt>
- <dd>
- Sets an environment variable. </p>
-
-<p><strong>NOTE</strong>: Windows has multiple copies of environment variables. For this reason, the
-<a href="index.html#setenv">setenv</a> function will not work with Lua's <a href="https://www.lua.org/manual/5.1/manual.html#pdf-os.getenv">os.getenv</a> on Windows. If you want to use
-it then consider patching <a href="https://www.lua.org/manual/5.1/manual.html#pdf-os.getenv">os.getenv</a> with the implementation of <a href="index.html#getenv">system.getenv</a>.
-
-
- <h3>Parameters:</h3>
- <ul>
- <li><span class="parameter">name</span>
- <span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
- name of the environment variable
- </li>
- <li><span class="parameter">value</span>
- <span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
- value of the environment variable, if <code>nil</code> the variable will be deleted (on
-Windows, setting an empty string, will also delete the variable)
- (<em>optional</em>)
- </li>
- </ul>
-
- <h3>Returns:</h3>
- <ol>
-
- <span class="types"><span class="type">boolean</span></span>
- success
- </ol>
-
-
-
-
-</dd>
-</dl>
- <h2 class="section-header "><a name="random_Functions"></a>random Functions</h2>
-
- <dl class="function">
- <dt>
- <a name = "random"></a>
- <strong>random ([length=1])</strong>
- </dt>
- <dd>
- Generate random bytes.
-This uses <code>CryptGenRandom()</code> on Windows, and <code>/dev/urandom</code> on other platforms. It will return the
-requested number of bytes, or an error, never a partial result.
-
-
- <h3>Parameters:</h3>
- <ul>
- <li><span class="parameter">length</span>
- <span class="types"><span class="type">int</span></span>
- number of bytes to get
- (<em>default</em> 1)
- </li>
- </ul>
-
- <h3>Returns:</h3>
- <ol>
-
- <span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
- string of random bytes
- </ol>
- <h3>Or</h3>
- <ol>
- <li>
- <span class="types"><span class="type">nil</span></span>
-
-
-</li>
- <li>
- <span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
- error message</li>
- </ol>
-
-
-
-
-</dd>
-</dl>
- <h2 class="section-header "><a name="term_Functions"></a>term Functions</h2>
-
- <dl class="function">
- <dt>
- <a name = "isatty"></a>
- <strong>isatty (file)</strong>
- </dt>
- <dd>
- Checks if a file-handle is a TTY.
-
-
- <h3>Parameters:</h3>
- <ul>
- <li><span class="parameter">file</span>
- <span class="types"><span class="type">file</span></span>
- the file-handle to check
- </li>
- </ul>
-
- <h3>Returns:</h3>
- <ol>
-
- <span class="types"><span class="type">boolean</span></span>
- true if the file is a tty
- </ol>
-
-
-
-
-</dd>
-</dl>
- <h2 class="section-header "><a name="time_Functions"></a>time Functions</h2>
-
- <dl class="function">
- <dt>
- <a name = "gettime"></a>
- <strong>gettime ()</strong>
- </dt>
- <dd>
- Get system time.
-The time is returned as the seconds since the epoch (1 January 1970 00:00:00).
-
-
-
- <h3>Returns:</h3>
- <ol>
-
- <span class="types"><span class="type">number</span></span>
- seconds (fractional)
- </ol>
-
-
-
-
-</dd>
- <dt>
- <a name = "monotime"></a>
- <strong>monotime ()</strong>
- </dt>
- <dd>
- Get monotonic time.
-The time is returned as the seconds since system start.
-
-
-
- <h3>Returns:</h3>
- <ol>
-
- <span class="types"><span class="type">number</span></span>
- seconds (fractional)
- </ol>
-
-
-
-
-</dd>
- <dt>
- <a name = "sleep"></a>
- <strong>sleep (seconds[, precision=16])</strong>
- </dt>
- <dd>
- Sleep without a busy loop.
-This function will sleep, without doing a busy-loop and wasting CPU cycles.
-
-
- <h3>Parameters:</h3>
- <ul>
- <li><span class="parameter">seconds</span>
- <span class="types"><span class="type">number</span></span>
- seconds to sleep (fractional).
- </li>
- <li><span class="parameter">precision</span>
- <span class="types"><span class="type">integer</span></span>
- minimum stepsize in milliseconds (Windows only, ignored elsewhere)
- (<em>default</em> 16)
- </li>
- </ul>
-
- <h3>Returns:</h3>
- <ol>
-
- <code>true</code> on success, or <code>nil+err</code> on failure
- </ol>
-
-
-
-
-</dd>
-</dl>
-
-
</div> <!-- id="content" -->
</div> <!-- id="main" -->
<div id="about">
-<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
-<i style="float:right;">Last updated 2023-12-15 13:15:09 </i>
+<i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i>
+<i style="float:right;">Last updated 2024-06-20 23:11:37 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>
diff --git a/docs/modules/system.html b/docs/modules/system.html
new file mode 100644
index 0000000..0423e37
--- /dev/null
+++ b/docs/modules/system.html
@@ -0,0 +1,1418 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+<head>
+ <title>Lua-System docs</title>
+ <link rel="stylesheet" href="../ldoc.css" type="text/css" />
+</head>
+<body>
+
+<div id="container">
+
+<div id="product">
+ <div id="product_logo"></div>
+ <div id="product_name"><big><b></b></big></div>
+ <div id="product_description"></div>
+</div> <!-- id="product" -->
+
+
+<div id="main">
+
+
+<!-- Menu -->
+
+<div id="navigation">
+<br/>
+<h1>Lua-System</h1>
+
+
+<ul>
+ <li><a href="../index.html">Index</a></li>
+</ul>
+
+<h2>Contents</h2>
+<ul>
+<li><a href="#Fields">Fields</a></li>
+<li><a href="#Environment">Environment </a></li>
+<li><a href="#Random">Random </a></li>
+<li><a href="#Terminal">Terminal </a></li>
+<li><a href="#Time">Time </a></li>
+</ul>
+
+
+<h2>Modules</h2>
+<ul class="nowrap">
+ <li><strong>system</strong></li>
+</ul>
+<h2>Classes</h2>
+<ul class="nowrap">
+ <li><a href="../classes/bitflags.html">bitflags</a></li>
+</ul>
+<h2>Topics</h2>
+<ul class="">
+ <li><a href="../topics/01-introduction.md.html">1. Introduction</a></li>
+ <li><a href="../topics/02-development.md.html">2. Development</a></li>
+ <li><a href="../topics/03-terminal.md.html">3. Terminal functionality</a></li>
+ <li><a href="../topics/CHANGELOG.md.html">CHANGELOG</a></li>
+ <li><a href="../topics/LICENSE.md.html">MIT License</a></li>
+</ul>
+<h2>Examples</h2>
+<ul class="nowrap">
+ <li><a href="../examples/compat.lua.html">compat.lua</a></li>
+ <li><a href="../examples/flag_debugging.lua.html">flag_debugging.lua</a></li>
+ <li><a href="../examples/password_input.lua.html">password_input.lua</a></li>
+ <li><a href="../examples/read.lua.html">read.lua</a></li>
+ <li><a href="../examples/readline.lua.html">readline.lua</a></li>
+ <li><a href="../examples/spinner.lua.html">spinner.lua</a></li>
+ <li><a href="../examples/spiral_snake.lua.html">spiral_snake.lua</a></li>
+ <li><a href="../examples/terminalsize.lua.html">terminalsize.lua</a></li>
+</ul>
+
+</div>
+
+<div id="content">
+
+<h1>Module <code>system</code></h1>
+<p>Platform independent system calls for Lua.</p>
+<p>
+
+</p>
+
+
+<h2><a href="#Fields">Fields</a></h2>
+<table class="function_list">
+ <tr>
+ <td class="name" nowrap><a href="#windows">windows</a></td>
+ <td class="summary">Flag to identify Windows.</td>
+ </tr>
+</table>
+<h2><a href="#Environment">Environment </a></h2>
+<table class="function_list">
+ <tr>
+ <td class="name" nowrap><a href="#getenv">getenv (name)</a></td>
+ <td class="summary">Gets the value of an environment variable.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#getenvs">getenvs ()</a></td>
+ <td class="summary">Returns a table with all environment variables.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#setenv">setenv (name[, value])</a></td>
+ <td class="summary">Sets an environment variable.</td>
+ </tr>
+</table>
+<h2><a href="#Random">Random </a></h2>
+<table class="function_list">
+ <tr>
+ <td class="name" nowrap><a href="#random">random ([length=1])</a></td>
+ <td class="summary">Generate random bytes.</td>
+ </tr>
+</table>
+<h2><a href="#Terminal">Terminal </a></h2>
+<table class="function_list">
+ <tr>
+ <td class="name" nowrap><a href="#CODEPAGE_UTF8">CODEPAGE_UTF8</a></td>
+ <td class="summary">UTF8 codepage.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#_readkey">_readkey ()</a></td>
+ <td class="summary">Reads a key from the console non-blocking.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#autotermrestore">autotermrestore ()</a></td>
+ <td class="summary">Backs up terminal settings and restores them on application exit.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#getconsolecp">getconsolecp ()</a></td>
+ <td class="summary">Gets the current console code page (Windows).</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#getconsoleflags">getconsoleflags (file)</a></td>
+ <td class="summary">Gets console flags (Windows).</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#getconsoleoutputcp">getconsoleoutputcp ()</a></td>
+ <td class="summary">Gets the current console output code page (Windows).</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#getnonblock">getnonblock (fd)</a></td>
+ <td class="summary">Gets non-blocking mode status for a file (Posix).</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#isatty">isatty (file)</a></td>
+ <td class="summary">Checks if a file-handle is a TTY.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#listconsoleflags">listconsoleflags (fh)</a></td>
+ <td class="summary">Debug function for console flags (Windows).</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#listtermflags">listtermflags (fh)</a></td>
+ <td class="summary">Debug function for terminal flags (Posix).</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#readansi">readansi (timeout)</a></td>
+ <td class="summary">Reads a single key, if it is the start of ansi escape sequence then it reads
+ the full sequence.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#readkey">readkey (timeout)</a></td>
+ <td class="summary">Reads a single byte from the console, with a timeout.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#setconsolecp">setconsolecp (cp)</a></td>
+ <td class="summary">Sets the current console code page (Windows).</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#setconsoleflags">setconsoleflags (file, bitflags)</a></td>
+ <td class="summary">Sets the console flags (Windows).</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#setconsoleoutputcp">setconsoleoutputcp (cp)</a></td>
+ <td class="summary">Sets the current console output code page (Windows).</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#setnonblock">setnonblock (fd, make_non_block)</a></td>
+ <td class="summary">Enables or disables non-blocking mode for a file (Posix).</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#tcgetattr">tcgetattr (fd)</a></td>
+ <td class="summary">Get termios state (Posix).</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#tcsetattr">tcsetattr (fd, actions, termios)</a></td>
+ <td class="summary">Set termios state (Posix).</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#termbackup">termbackup ()</a></td>
+ <td class="summary">Returns a backup of terminal settings for stdin/out/err.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#termrestore">termrestore (backup)</a></td>
+ <td class="summary">Restores terminal settings from a backup</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#termsize">termsize ()</a></td>
+ <td class="summary">Get the size of the terminal in rows and columns.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#termwrap">termwrap (f)</a></td>
+ <td class="summary">Wraps a function to automatically restore terminal settings upon returning.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#utf8cwidth">utf8cwidth (utf8_char)</a></td>
+ <td class="summary">Get the width of a utf8 character for terminal display.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#utf8swidth">utf8swidth (utf8_string)</a></td>
+ <td class="summary">Get the width of a utf8 string for terminal display.</td>
+ </tr>
+</table>
+<h2><a href="#Time">Time </a></h2>
+<table class="function_list">
+ <tr>
+ <td class="name" nowrap><a href="#gettime">gettime ()</a></td>
+ <td class="summary">Get system time.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#monotime">monotime ()</a></td>
+ <td class="summary">Get monotonic time.</td>
+ </tr>
+ <tr>
+ <td class="name" nowrap><a href="#sleep">sleep (seconds[, precision=16])</a></td>
+ <td class="summary">Sleep without a busy loop.</td>
+ </tr>
+</table>
+
+<br/>
+<br/>
+
+
+ <h2 class="section-header "><a name="Fields"></a>Fields</h2>
+
+ <dl class="function">
+ <dt>
+ <a name = "windows"></a>
+ <strong>windows</strong>
+ </dt>
+ <dd>
+ Flag to identify Windows.
+
+
+ <ul>
+ <li><span class="parameter">windows</span>
+ <code>true</code> if on Windows, <code>false</code> otherwise.
+ </li>
+ </ul>
+
+
+
+
+
+</dd>
+</dl>
+ <h2 class="section-header "><a name="Environment"></a>Environment </h2>
+
+ <dl class="function">
+ <dt>
+ <a name = "getenv"></a>
+ <strong>getenv (name)</strong>
+ </dt>
+ <dd>
+ Gets the value of an environment variable. </p>
+
+<p><strong>NOTE</strong>: Windows has multiple copies of environment variables. For this reason,
+the <a href="../modules/system.html#setenv">setenv</a> function will not work with Lua's <a href="https://www.lua.org/manual/5.4/manual.html#pdf-os.getenv">os.getenv</a> on Windows. If you want
+to use <a href="../modules/system.html#setenv">setenv</a> then consider patching <a href="https://www.lua.org/manual/5.4/manual.html#pdf-os.getenv">os.getenv</a> with this implementation of <a href="../modules/system.html#getenv">getenv</a>.
+
+
+ <h3>Parameters:</h3>
+ <ul>
+ <li><span class="parameter">name</span>
+ <span class="types"><a class="type" href="https://www.lua.org/manual/5.4/manual.html#6.4">string</a></span>
+ name of the environment variable
+ </li>
+ </ul>
+
+ <h3>Returns:</h3>
+ <ol>
+
+ <span class="types"><a class="type" href="https://www.lua.org/manual/5.4/manual.html#6.4">string</a> or <span class="type">nil</span></span>
+ value of the environment variable, or nil if the variable is not set
+ </ol>
+
+
+
+
+</dd>
+ <dt>
+ <a name = "getenvs"></a>
+ <strong>getenvs ()</strong>
+ </dt>
+ <dd>
+ Returns a table with all environment variables.
+
+
+
+ <h3>Returns:</h3>
+ <ol>
+
+ <span class="types"><a class="type" href="https://www.lua.org/manual/5.4/manual.html#6.6">table</a></span>
+ table with all environment variables and their values
+ </ol>
+
+
+
+
+</dd>
+ <dt>
+ <a name = "setenv"></a>
+ <strong>setenv (name[, value])</strong>
+ </dt>
+ <dd>
+ Sets an environment variable. </p>
+
+<p><strong>NOTE</strong>: Windows has multiple copies of environment variables. For this reason, the
+<a href="../modules/system.html#setenv">setenv</a> function will not work with Lua's <a href="https://www.lua.org/manual/5.4/manual.html#pdf-os.getenv">os.getenv</a> on Windows. If you want to use
+it then consider patching <a href="https://www.lua.org/manual/5.4/manual.html#pdf-os.getenv">os.getenv</a> with the implementation of <a href="../modules/system.html#getenv">system.getenv</a>.
+
+
+ <h3>Parameters:</h3>
+ <ul>
+ <li><span class="parameter">name</span>
+ <span class="types"><a class="type" href="https://www.lua.org/manual/5.4/manual.html#6.4">string</a></span>
+ name of the environment variable
+ </li>
+ <li><span class="parameter">value</span>
+ <span class="types"><a class="type" href="https://www.lua.org/manual/5.4/manual.html#6.4">string</a></span>
+ value of the environment variable, if <code>nil</code> the variable will be deleted (on
+Windows, setting an empty string, will also delete the variable)
+ (<em>optional</em>)
+ </li>
+ </ul>
+
+ <h3>Returns:</h3>
+ <ol>
+
+ <span class="types"><span class="type">boolean</span></span>
+ success
+ </ol>
+
+
+
+
+</dd>
+</dl>
+ <h2 class="section-header "><a name="Random"></a>Random </h2>
+
+ <dl class="function">
+ <dt>
+ <a name = "random"></a>
+ <strong>random ([length=1])</strong>
+ </dt>
+ <dd>
+ Generate random bytes.
+This uses <code>CryptGenRandom()</code> on Windows, and <code>/dev/urandom</code> on other platforms. It will return the
+requested number of bytes, or an error, never a partial result.
+
+
+ <h3>Parameters:</h3>
+ <ul>
+ <li><span class="parameter">length</span>
+ <span class="types"><span class="type">int</span></span>
+ number of bytes to get
+ (<em>default</em> 1)
+ </li>
+ </ul>
+
+ <h3>Returns:</h3>
+ <ol>
+
+ <span class="types"><a class="type" href="https://www.lua.org/manual/5.4/manual.html#6.4">string</a></span>
+ string of random bytes
+ </ol>
+ <h3>Or</h3>
+ <ol>
+ <li>
+ <span class="types"><span class="type">nil</span></span>
+
+
+</li>
+ <li>
+ <span class="types"><a class="type" href="https://www.lua.org/manual/5.4/manual.html#6.4">string</a></span>
+ error message</li>
+ </ol>
+
+
+
+
+</dd>
+</dl>
+ <h2 class="section-header has-description"><a name="Terminal"></a>Terminal </h2>
+
+ <div class="section-description">
+ Unix: see https://blog.nelhage.com/2009/12/a-brief-introduction-to-termios-termios3-and-stty/</p>
+
+<p> Windows: see https://learn.microsoft.com/en-us/windows/console/console-reference
+ </div>
+ <dl class="function">
+ <dt>
+ <a name = "CODEPAGE_UTF8"></a>
+ <strong>CODEPAGE_UTF8</strong>
+ </dt>
+ <dd>
+ UTF8 codepage.
+ To be used with <a href="../modules/system.html#setconsoleoutputcp">system.setconsoleoutputcp</a> and <a href="../modules/system.html#setconsolecp">system.setconsolecp</a>.
+
+
+ <ul>
+ <li><span class="parameter">CODEPAGE_UTF8</span>
+ The Windows CodePage for UTF8.
+ </li>
+ </ul>
+
+
+
+
+
+</dd>
+ <dt>
+ <a name = "_readkey"></a>
+ <strong>_readkey ()</strong>
+ </dt>
+ <dd>
+ Reads a key from the console non-blocking. This function should not be called
+directly, but through the <a href="../modules/system.html#readkey">system.readkey</a> or <a href="../modules/system.html#readansi">system.readansi</a> functions. It
+will return the next byte from the input stream, or <code>nil</code> if no key was pressed.</p>
+
+<p>On Posix, <a href="https://www.lua.org/manual/5.4/manual.html#pdf-io.stdin">io.stdin</a> must be set to non-blocking mode using <a href="../modules/system.html#setnonblock">setnonblock</a>
+and canonical mode must be turned off using <a href="../modules/system.html#tcsetattr">tcsetattr</a>,
+before calling this function. Otherwise it will block. No conversions are
+done on Posix, so the byte read is returned as-is.</p>
+
+<p>On Windows this reads a wide character and converts it to UTF-8. Multi-byte
+sequences will be buffered internally and returned one byte at a time.
+
+
+
+ <h3>Returns:</h3>
+ <ol>
+
+ <span class="types"><span class="type">integer</span></span>
+ the byte read from the input stream
+ </ol>
+ <h3>Or</h3>
+ <ol>
+
+ <span class="types"><span class="type">nil</span></span>
+ if no key was pressed
+ </ol>
+ <h3>Or</h3>
+ <ol>
+ <li>
+ <span class="types"><span class="type">nil</span></span>
+ on error</li>
+ <li>
+ <span class="types"><a class="type" href="https://www.lua.org/manual/5.4/manual.html#6.4">string</a></span>
+ error message</li>
+ <li>
+ <span class="types"><span class="type">int</span></span>
+ errnum (on posix)</li>
+ </ol>
+
+
+
+
+</dd>
+ <dt>
+ <a name = "autotermrestore"></a>
+ <strong>autotermrestore ()</strong>
+ </dt>
+ <dd>
+ Backs up terminal settings and restores them on application exit.
+ Calls <a href="../modules/system.html#termbackup">termbackup</a> to back up terminal settings and sets up a GC method to
+ automatically restore them on application exit (also works on Lua 5.1).
+
+
+
+ <h3>Returns:</h3>
+ <ol>
+
+ <span class="types"><span class="type">boolean</span></span>
+ true
+ </ol>
+ <h3>Or</h3>
+ <ol>
+ <li>
+ <span class="types"><span class="type">nil</span></span>
+ if the backup was already created</li>
+ <li>
+ <span class="types"><a class="type" href="https://www.lua.org/manual/5.4/manual.html#6.4">string</a></span>
+ error message</li>
+ </ol>
+
+
+
+
+</dd>
+ <dt>
+ <a name = "getconsolecp"></a>
+ <strong>getconsolecp ()</strong>
+ </dt>
+ <dd>
+ Gets the current console code page (Windows).
+
+
+
+ <h3>Returns:</h3>
+ <ol>
+
+ <span class="types"><span class="type">int</span></span>
+ the current code page (always 65001 on Posix systems)
+ </ol>
+
+
+
+
+</dd>
+ <dt>
+ <a name = "getconsoleflags"></a>
+ <strong>getconsoleflags (file)</strong>
+ </dt>
+ <dd>
+ Gets console flags (Windows).
+The <code>CIF_</code> and <code>COF_</code> constants are available on the module table. Where <code>CIF</code> are the
+input flags (for use with <a href="https://www.lua.org/manual/5.4/manual.html#pdf-io.stdin">io.stdin</a>) and <code>COF</code> are the output flags (for use with
+<a href="https://www.lua.org/manual/5.4/manual.html#pdf-io.stdout">io.stdout</a>/<a href="https://www.lua.org/manual/5.4/manual.html#pdf-io.stderr">io.stderr</a>).</p>
+
+<p><em>Note</em>: See <a href="https://learn.microsoft.com/en-us/windows/console/setconsolemode">setconsolemode documentation</a>
+for more information on the flags.
+
+
+ <h3>Parameters:</h3>
+ <ul>
+ <li><span class="parameter">file</span>
+ <span class="types"><span class="type">file</span></span>
+ file handle to operate on, one of <a href="https://www.lua.org/manual/5.4/manual.html#pdf-io.stdin">io.stdin</a>, <a href="https://www.lua.org/manual/5.4/manual.html#pdf-io.stdout">io.stdout</a>, <a href="https://www.lua.org/manual/5.4/manual.html#pdf-io.stderr">io.stderr</a>
+ </li>
+ </ul>
+
+ <h3>Returns:</h3>
+ <ol>
+
+ <span class="types"><a class="type" href="../classes/bitflags.html#">bitflags</a></span>
+ the current console flags.
+ </ol>
+ <h3>Or</h3>
+ <ol>
+ <li>
+ <span class="types"><span class="type">nil</span></span>
+
+
+</li>
+ <li>
+ <span class="types"><a class="type" href="https://www.lua.org/manual/5.4/manual.html#6.4">string</a></span>
+ error message</li>
+ </ol>
+
+
+
+ <h3>Usage:</h3>
+ <ul>
+ <pre class="example"><span class="keyword">local</span> system = <span class="global">require</span>(<span class="string">'system'</span>)
+
+<span class="keyword">local</span> flags = system.<span class="function-name">getconsoleflags</span>(<span class="global">io</span>.stdout)
+<span class="global">print</span>(<span class="string">"Current stdout flags:"</span>, <span class="global">tostring</span>(flags))
+
+<span class="keyword">if</span> flags:<span class="function-name">has_all_of</span>(system.COF_VIRTUAL_TERMINAL_PROCESSING + system.COF_PROCESSED_OUTPUT) <span class="keyword">then</span>
+ <span class="global">print</span>(<span class="string">"Both flags are set"</span>)
+<span class="keyword">else</span>
+ <span class="global">print</span>(<span class="string">"At least one flag is not set"</span>)
+<span class="keyword">end</span></pre>
+ </ul>
+
+</dd>
+ <dt>
+ <a name = "getconsoleoutputcp"></a>
+ <strong>getconsoleoutputcp ()</strong>
+ </dt>
+ <dd>
+ Gets the current console output code page (Windows).
+
+
+
+ <h3>Returns:</h3>
+ <ol>
+
+ <span class="types"><span class="type">int</span></span>
+ the current code page (always 65001 on Posix systems)
+ </ol>
+
+
+
+
+</dd>
+ <dt>
+ <a name = "getnonblock"></a>
+ <strong>getnonblock (fd)</strong>
+ </dt>
+ <dd>
+ Gets non-blocking mode status for a file (Posix).
+
+
+ <h3>Parameters:</h3>
+ <ul>
+ <li><span class="parameter">fd</span>
+ <span class="types"><span class="type">file</span></span>
+ file handle to operate on, one of <a href="https://www.lua.org/manual/5.4/manual.html#pdf-io.stdin">io.stdin</a>, <a href="https://www.lua.org/manual/5.4/manual.html#pdf-io.stdout">io.stdout</a>, <a href="https://www.lua.org/manual/5.4/manual.html#pdf-io.stderr">io.stderr</a>
+ </li>
+ </ul>
+
+ <h3>Returns:</h3>
+ <ol>
+
+ <span class="types"><span class="type">bool</span></span>
+ <code>true</code> if set to non-blocking, <code>false</code> if not. Always returns <code>false</code> on Windows.
+ </ol>
+ <h3>Or</h3>
+ <ol>
+ <li>
+ <span class="types"><span class="type">nil</span></span>
+
+
+</li>
+ <li>
+ <span class="types"><a class="type" href="https://www.lua.org/manual/5.4/manual.html#6.4">string</a></span>
+ error message</li>
+ <li>
+ <span class="types"><span class="type">int</span></span>
+ errnum</li>
+ </ol>
+
+
+
+
+</dd>
+ <dt>
+ <a name = "isatty"></a>
+ <strong>isatty (file)</strong>
+ </dt>
+ <dd>
+ Checks if a file-handle is a TTY.
+
+
+ <h3>Parameters:</h3>
+ <ul>
+ <li><span class="parameter">file</span>
+ <span class="types"><span class="type">file</span></span>
+ the file-handle to check, one of <a href="https://www.lua.org/manual/5.4/manual.html#pdf-io.stdin">io.stdin</a>, <a href="https://www.lua.org/manual/5.4/manual.html#pdf-io.stdout">io.stdout</a>, <a href="https://www.lua.org/manual/5.4/manual.html#pdf-io.stderr">io.stderr</a>.
+ </li>
+ </ul>
+
+ <h3>Returns:</h3>
+ <ol>
+
+ <span class="types"><span class="type">boolean</span></span>
+ true if the file is a tty
+ </ol>
+
+
+
+ <h3>Usage:</h3>
+ <ul>
+ <pre class="example"><span class="keyword">local</span> system = <span class="global">require</span>(<span class="string">'system'</span>)
+<span class="keyword">if</span> system.<span class="function-name">isatty</span>(<span class="global">io</span>.stdin) <span class="keyword">then</span>
+ <span class="comment">-- enable ANSI coloring etc on Windows, does nothing in Posix.
+</span> <span class="keyword">local</span> flags = system.<span class="function-name">getconsoleflags</span>(<span class="global">io</span>.stdout)
+ system.<span class="function-name">setconsoleflags</span>(<span class="global">io</span>.stdout, flags + sys.COF_VIRTUAL_TERMINAL_PROCESSING)
+<span class="keyword">end</span></pre>
+ </ul>
+
+</dd>
+ <dt>
+ <a name = "listconsoleflags"></a>
+ <strong>listconsoleflags (fh)</strong>
+ </dt>
+ <dd>
+ Debug function for console flags (Windows).
+ Pretty prints the current flags set for the handle.
+
+
+ <h3>Parameters:</h3>
+ <ul>
+ <li><span class="parameter">fh</span>
+ file handle (<a href="https://www.lua.org/manual/5.4/manual.html#pdf-io.stdin">io.stdin</a>, <a href="https://www.lua.org/manual/5.4/manual.html#pdf-io.stdout">io.stdout</a>, <a href="https://www.lua.org/manual/5.4/manual.html#pdf-io.stderr">io.stderr</a>)
+ </li>
+ </ul>
+
+
+
+
+ <h3>Usage:</h3>
+ <ul>
+ <pre class="example"><span class="comment">-- Print the flags for stdin/out/err
+</span>system.<span class="function-name">listconsoleflags</span>(<span class="global">io</span>.stdin)
+system.<span class="function-name">listconsoleflags</span>(<span class="global">io</span>.stdout)
+system.<span class="function-name">listconsoleflags</span>(<span class="global">io</span>.stderr)</pre>
+ </ul>
+
+</dd>
+ <dt>
+ <a name = "listtermflags"></a>
+ <strong>listtermflags (fh)</strong>
+ </dt>
+ <dd>
+ Debug function for terminal flags (Posix).
+ Pretty prints the current flags set for the handle.
+
+
+ <h3>Parameters:</h3>
+ <ul>
+ <li><span class="parameter">fh</span>
+ file handle (<a href="https://www.lua.org/manual/5.4/manual.html#pdf-io.stdin">io.stdin</a>, <a href="https://www.lua.org/manual/5.4/manual.html#pdf-io.stdout">io.stdout</a>, <a href="https://www.lua.org/manual/5.4/manual.html#pdf-io.stderr">io.stderr</a>)
+ </li>
+ </ul>
+
+
+
+
+ <h3>Usage:</h3>
+ <ul>
+ <pre class="example"><span class="comment">-- Print the flags for stdin/out/err
+</span>system.<span class="function-name">listconsoleflags</span>(<span class="global">io</span>.stdin)
+system.<span class="function-name">listconsoleflags</span>(<span class="global">io</span>.stdout)
+system.<span class="function-name">listconsoleflags</span>(<span class="global">io</span>.stderr)</pre>
+ </ul>
+
+</dd>
+ <dt>
+ <a name = "readansi"></a>
+ <strong>readansi (timeout)</strong>
+ </dt>
+ <dd>
+ Reads a single key, if it is the start of ansi escape sequence then it reads
+ the full sequence. The key can be a multi-byte string in case of multibyte UTF-8 character.
+ This function uses <a href="../modules/system.html#readkey">system.readkey</a>, and hence <a href="../modules/system.html#sleep">system.sleep</a> to wait until either a key is
+ available or the timeout is reached.
+ It returns immediately if a key is available or if <code>timeout</code> is less than or equal to <code>0</code>.
+ In case of an ANSI sequence, it will return the full sequence as a string.
+
+
+ <h3>Parameters:</h3>
+ <ul>
+ <li><span class="parameter">timeout</span>
+ <span class="types"><span class="type">number</span></span>
+ the timeout in seconds.
+ </li>
+ </ul>
+
+ <h3>Returns:</h3>
+ <ol>
+ <li>
+ <span class="types"><a class="type" href="https://www.lua.org/manual/5.4/manual.html#6.4">string</a></span>
+ the character that was received (can be multi-byte), or a complete ANSI sequence</li>
+ <li>
+ <span class="types"><a class="type" href="https://www.lua.org/manual/5.4/manual.html#6.4">string</a></span>
+ the type of input: <code>&quot;char&quot;</code> for a single key, <code>&quot;ansi&quot;</code> for an ANSI sequence</li>
+ </ol>
+ <h3>Or</h3>
+ <ol>
+ <li>
+ <span class="types"><span class="type">nil</span></span>
+ in case of an error</li>
+ <li>
+ <span class="types"><a class="type" href="https://www.lua.org/manual/5.4/manual.html#6.4">string</a></span>
+ error message; <code>&quot;timeout&quot;</code> if the timeout was reached.</li>
+ <li>
+ <span class="types"><a class="type" href="https://www.lua.org/manual/5.4/manual.html#6.4">string</a></span>
+ partial result in case of an error while reading a sequence, the sequence so far.</li>
+ </ol>
+
+
+
+
+</dd>
+ <dt>
+ <a name = "readkey"></a>
+ <strong>readkey (timeout)</strong>
+ </dt>
+ <dd>
+ Reads a single byte from the console, with a timeout.
+ This function uses <a href="../modules/system.html#sleep">system.sleep</a> to wait until either a byte is available or the timeout is reached.
+ The sleep period is exponentially backing off, starting at 0.0125 seconds, with a maximum of 0.2 seconds.
+ It returns immediately if a byte is available or if <code>timeout</code> is less than or equal to <code>0</code>.</p>
+
+<p> Using <a href="../modules/system.html#readansi">system.readansi</a> is preferred over this function. Since this function can leave stray/invalid
+ byte-sequences in the input buffer, while <a href="../modules/system.html#readansi">system.readansi</a> reads full ANSI and UTF8 sequences.
+
+
+ <h3>Parameters:</h3>
+ <ul>
+ <li><span class="parameter">timeout</span>
+ <span class="types"><span class="type">number</span></span>
+ the timeout in seconds.
+ </li>
+ </ul>
+
+ <h3>Returns:</h3>
+ <ol>
+
+ <span class="types"><span class="type">byte</span></span>
+ the byte value that was read.
+ </ol>
+ <h3>Or</h3>
+ <ol>
+ <li>
+ <span class="types"><span class="type">nil</span></span>
+ if no key was read</li>
+ <li>
+ <span class="types"><a class="type" href="https://www.lua.org/manual/5.4/manual.html#6.4">string</a></span>
+ error message; <code>&quot;timeout&quot;</code> if the timeout was reached.</li>
+ </ol>
+
+
+
+
+</dd>
+ <dt>
+ <a name = "setconsolecp"></a>
+ <strong>setconsolecp (cp)</strong>
+ </dt>
+ <dd>
+ Sets the current console code page (Windows).
+
+
+ <h3>Parameters:</h3>
+ <ul>
+ <li><span class="parameter">cp</span>
+ <span class="types"><span class="type">int</span></span>
+ the code page to set, use <a href="../modules/system.html#CODEPAGE_UTF8">system.CODEPAGE_UTF8</a> (65001) for UTF-8
+ </li>
+ </ul>
+
+ <h3>Returns:</h3>
+ <ol>
+
+ <span class="types"><span class="type">bool</span></span>
+ <code>true</code> on success (always <code>true</code> on Posix systems)
+ </ol>
+
+
+
+
+</dd>
+ <dt>
+ <a name = "setconsoleflags"></a>
+ <strong>setconsoleflags (file, bitflags)</strong>
+ </dt>
+ <dd>
+ Sets the console flags (Windows).
+The <code>CIF_</code> and <code>COF_</code> constants are available on the module table. Where <code>CIF</code> are the
+input flags (for use with <a href="https://www.lua.org/manual/5.4/manual.html#pdf-io.stdin">io.stdin</a>) and <code>COF</code> are the output flags (for use with
+<a href="https://www.lua.org/manual/5.4/manual.html#pdf-io.stdout">io.stdout</a>/<a href="https://www.lua.org/manual/5.4/manual.html#pdf-io.stderr">io.stderr</a>).</p>
+
+<p>To see flag status and constant names check <a href="../modules/system.html#listconsoleflags">listconsoleflags</a>.</p>
+
+<p>Note: not all combinations of flags are allowed, as some are mutually exclusive or mutually required.
+See <a href="https://learn.microsoft.com/en-us/windows/console/setconsolemode">setconsolemode documentation</a>
+
+
+ <h3>Parameters:</h3>
+ <ul>
+ <li><span class="parameter">file</span>
+ <span class="types"><span class="type">file</span></span>
+ file handle to operate on, one of <a href="https://www.lua.org/manual/5.4/manual.html#pdf-io.stdin">io.stdin</a>, <a href="https://www.lua.org/manual/5.4/manual.html#pdf-io.stdout">io.stdout</a>, <a href="https://www.lua.org/manual/5.4/manual.html#pdf-io.stderr">io.stderr</a>
+ </li>
+ <li><span class="parameter">bitflags</span>
+ <span class="types"><a class="type" href="../classes/bitflags.html#">bitflags</a></span>
+ the flags to set/unset
+ </li>
+ </ul>
+
+ <h3>Returns:</h3>
+ <ol>
+
+ <span class="types"><span class="type">boolean</span></span>
+ <code>true</code> on success
+ </ol>
+ <h3>Or</h3>
+ <ol>
+ <li>
+ <span class="types"><span class="type">nil</span></span>
+
+
+</li>
+ <li>
+ <span class="types"><a class="type" href="https://www.lua.org/manual/5.4/manual.html#6.4">string</a></span>
+ error message</li>
+ </ol>
+
+
+
+ <h3>Usage:</h3>
+ <ul>
+ <pre class="example"><span class="keyword">local</span> system = <span class="global">require</span>(<span class="string">'system'</span>)
+system.<span class="function-name">listconsoleflags</span>(<span class="global">io</span>.stdout) <span class="comment">-- List all the available flags and their current status
+</span>
+<span class="keyword">local</span> flags = system.<span class="function-name">getconsoleflags</span>(<span class="global">io</span>.stdout)
+<span class="global">assert</span>(system.<span class="function-name">setconsoleflags</span>(<span class="global">io</span>.stdout,
+ flags + system.COF_VIRTUAL_TERMINAL_PROCESSING)
+
+system.<span class="function-name">listconsoleflags</span>(<span class="global">io</span>.stdout) <span class="comment">-- List again to check the differences</span></pre>
+ </ul>
+
+</dd>
+ <dt>
+ <a name = "setconsoleoutputcp"></a>
+ <strong>setconsoleoutputcp (cp)</strong>
+ </dt>
+ <dd>
+ Sets the current console output code page (Windows).
+
+
+ <h3>Parameters:</h3>
+ <ul>
+ <li><span class="parameter">cp</span>
+ <span class="types"><span class="type">int</span></span>
+ the code page to set, use <a href="../modules/system.html#CODEPAGE_UTF8">system.CODEPAGE_UTF8</a> (65001) for UTF-8
+ </li>
+ </ul>
+
+ <h3>Returns:</h3>
+ <ol>
+
+ <span class="types"><span class="type">bool</span></span>
+ <code>true</code> on success (always <code>true</code> on Posix systems)
+ </ol>
+
+
+
+
+</dd>
+ <dt>
+ <a name = "setnonblock"></a>
+ <strong>setnonblock (fd, make_non_block)</strong>
+ </dt>
+ <dd>
+ Enables or disables non-blocking mode for a file (Posix).
+
+
+ <h3>Parameters:</h3>
+ <ul>
+ <li><span class="parameter">fd</span>
+ <span class="types"><span class="type">file</span></span>
+ file handle to operate on, one of <a href="https://www.lua.org/manual/5.4/manual.html#pdf-io.stdin">io.stdin</a>, <a href="https://www.lua.org/manual/5.4/manual.html#pdf-io.stdout">io.stdout</a>, <a href="https://www.lua.org/manual/5.4/manual.html#pdf-io.stderr">io.stderr</a>
+ </li>
+ <li><span class="parameter">make_non_block</span>
+ <span class="types"><span class="type">boolean</span></span>
+ a truthy value will enable non-blocking mode, a falsy value will disable it.
+ </li>
+ </ul>
+
+ <h3>Returns:</h3>
+ <ol>
+
+ <span class="types"><span class="type">bool</span></span>
+ <code>true</code>, if successful
+ </ol>
+ <h3>Or</h3>
+ <ol>
+ <li>
+ <span class="types"><span class="type">nil</span></span>
+
+
+</li>
+ <li>
+ <span class="types"><a class="type" href="https://www.lua.org/manual/5.4/manual.html#6.4">string</a></span>
+ error message</li>
+ <li>
+ <span class="types"><span class="type">int</span></span>
+ errnum</li>
+ </ol>
+
+
+ <h3>See also:</h3>
+ <ul>
+ <a href="../modules/system.html#getnonblock">getnonblock</a>
+ </ul>
+
+ <h3>Usage:</h3>
+ <ul>
+ <pre class="example"><span class="keyword">local</span> sys = <span class="global">require</span>(<span class="string">'system'</span>)
+
+<span class="comment">-- set io.stdin to non-blocking mode
+</span><span class="keyword">local</span> old_setting = sys.<span class="function-name">getnonblock</span>(<span class="global">io</span>.stdin)
+sys.<span class="function-name">setnonblock</span>(<span class="global">io</span>.stdin, <span class="keyword">true</span>)
+
+<span class="comment">-- do stuff
+</span>
+<span class="comment">-- restore old setting
+</span>sys.<span class="function-name">setnonblock</span>(<span class="global">io</span>.stdin, old_setting)</pre>
+ </ul>
+
+</dd>
+ <dt>
+ <a name = "tcgetattr"></a>
+ <strong>tcgetattr (fd)</strong>
+ </dt>
+ <dd>
+
+<p>Get termios state (Posix).
+The terminal attributes is a table with the following fields:</p>
+
+<ul>
+ <li><code>iflag</code> input flags</li>
+ <li><code>oflag</code> output flags</li>
+ <li><code>lflag</code> local flags</li>
+ <li><code>cflag</code> control flags</li>
+ <li><code>ispeed</code> input speed</li>
+ <li><code>ospeed</code> output speed</li>
+ <li><code>cc</code> control characters</li>
+</ul>
+
+
+
+
+ <h3>Parameters:</h3>
+ <ul>
+ <li><span class="parameter">fd</span>
+ <span class="types"><span class="type">file</span></span>
+ file handle to operate on, one of <a href="https://www.lua.org/manual/5.4/manual.html#pdf-io.stdin">io.stdin</a>, <a href="https://www.lua.org/manual/5.4/manual.html#pdf-io.stdout">io.stdout</a>, <a href="https://www.lua.org/manual/5.4/manual.html#pdf-io.stderr">io.stderr</a>
+ </li>
+ </ul>
+
+ <h3>Returns:</h3>
+ <ol>
+
+ error message if failed
+ </ol>
+ <h3>Or</h3>
+ <ol>
+
+ <span class="types"><span class="type">termios</span></span>
+ terminal attributes, if successful. On Windows the bitflags are all 0, and the <code>cc</code> table is empty.
+ </ol>
+ <h3>Or</h3>
+ <ol>
+ <li>
+ <span class="types"><span class="type">nil</span></span>
+
+
+</li>
+ <li>
+ <span class="types"><a class="type" href="https://www.lua.org/manual/5.4/manual.html#6.4">string</a></span>
+ error message</li>
+ <li>
+ <span class="types"><span class="type">int</span></span>
+ errnum</li>
+ </ol>
+
+
+
+ <h3>Usage:</h3>
+ <ul>
+ <pre class="example"><span class="keyword">local</span> system = <span class="global">require</span>(<span class="string">'system'</span>)
+
+<span class="keyword">local</span> status = <span class="global">assert</span>(<span class="function-name">tcgetattr</span>(<span class="global">io</span>.stdin))
+<span class="keyword">if</span> status.iflag:<span class="function-name">has_all_of</span>(system.I_IGNBRK) <span class="keyword">then</span>
+ <span class="global">print</span>(<span class="string">"Ignoring break condition"</span>)
+<span class="keyword">end</span></pre>
+ </ul>
+
+</dd>
+ <dt>
+ <a name = "tcsetattr"></a>
+ <strong>tcsetattr (fd, actions, termios)</strong>
+ </dt>
+ <dd>
+ Set termios state (Posix).
+This function will set the flags as given.</p>
+
+<p>The <code>I_</code>, <code>O_</code>, and <code>L_</code> constants are available on the module table. They are the respective
+flags for the <code>iflags</code>, <code>oflags</code>, and <code>lflags</code> bitmasks.</p>
+
+<p>To see flag status and constant names check <a href="../modules/system.html#listtermflags">listtermflags</a>. For their meaning check
+<a href="https://www.man7.org/linux/man-pages/man3/termios.3.html">the manpage</a>.</p>
+
+<p><em>Note</em>: only <code>iflag</code>, <code>oflag</code>, and <code>lflag</code> are supported at the moment. The other fields are ignored.
+
+
+ <h3>Parameters:</h3>
+ <ul>
+ <li><span class="parameter">fd</span>
+ <span class="types"><span class="type">file</span></span>
+ file handle to operate on, one of <a href="https://www.lua.org/manual/5.4/manual.html#pdf-io.stdin">io.stdin</a>, <a href="https://www.lua.org/manual/5.4/manual.html#pdf-io.stdout">io.stdout</a>, <a href="https://www.lua.org/manual/5.4/manual.html#pdf-io.stderr">io.stderr</a>
+ </li>
+ <li><span class="parameter">actions</span>
+ <span class="types"><span class="type">integer</span></span>
+ one of <code>TCSANOW</code>, <code>TCSADRAIN</code>, <code>TCSAFLUSH</code>
+ </li>
+ <li><span class="parameter">termios</span> a table with bitflag fields:
+ <ul>
+ <li><span class="parameter">iflag</span>
+ <span class="types"><a class="type" href="../classes/bitflags.html#">bitflags</a></span>
+ if given will set the input flags
+ (<em>optional</em>)
+ </li>
+ <li><span class="parameter">oflag</span>
+ <span class="types"><a class="type" href="../classes/bitflags.html#">bitflags</a></span>
+ if given will set the output flags
+ (<em>optional</em>)
+ </li>
+ <li><span class="parameter">lflag</span>
+ <span class="types"><a class="type" href="../classes/bitflags.html#">bitflags</a></span>
+ if given will set the local flags
+ (<em>optional</em>)
+ </li>
+ </li></ul>
+ </ul>
+
+ <h3>Returns:</h3>
+ <ol>
+
+ <span class="types"><span class="type">bool</span></span>
+ <code>true</code>, if successful. Always returns <code>true</code> on Windows.
+ </ol>
+ <h3>Or</h3>
+ <ol>
+ <li>
+ nil</li>
+ <li>
+ <span class="types"><a class="type" href="https://www.lua.org/manual/5.4/manual.html#6.4">string</a></span>
+ error message</li>
+ <li>
+ <span class="types"><span class="type">int</span></span>
+ errnum</li>
+ </ol>
+
+
+
+ <h3>Usage:</h3>
+ <ul>
+ <pre class="example"><span class="keyword">local</span> system = <span class="global">require</span>(<span class="string">'system'</span>)
+
+<span class="keyword">local</span> status = <span class="global">assert</span>(<span class="function-name">tcgetattr</span>(<span class="global">io</span>.stdin))
+<span class="keyword">if</span> <span class="keyword">not</span> status.lflag:<span class="function-name">has_all_of</span>(system.L_ECHO) <span class="keyword">then</span>
+ <span class="comment">-- if echo is off, turn echoing newlines on
+</span> <span class="function-name">tcsetattr</span>(<span class="global">io</span>.stdin, system.TCSANOW, { lflag = status.lflag + system.L_ECHONL }))
+<span class="keyword">end</span></pre>
+ </ul>
+
+</dd>
+ <dt>
+ <a name = "termbackup"></a>
+ <strong>termbackup ()</strong>
+ </dt>
+ <dd>
+ Returns a backup of terminal settings for stdin/out/err.
+ Handles terminal/console flags, Windows codepage, and non-block flags on the streams.
+ Backs up terminal/console flags only if a stream is a tty.
+
+
+
+ <h3>Returns:</h3>
+ <ol>
+
+ table with backup of terminal settings
+ </ol>
+
+
+
+
+</dd>
+ <dt>
+ <a name = "termrestore"></a>
+ <strong>termrestore (backup)</strong>
+ </dt>
+ <dd>
+ Restores terminal settings from a backup
+
+
+ <h3>Parameters:</h3>
+ <ul>
+ <li><span class="parameter">backup</span>
+ <span class="types"><a class="type" href="https://www.lua.org/manual/5.4/manual.html#6.6">table</a></span>
+ the backup of terminal settings, see <a href="../modules/system.html#termbackup">termbackup</a>.
+ </li>
+ </ul>
+
+ <h3>Returns:</h3>
+ <ol>
+
+ <span class="types"><span class="type">boolean</span></span>
+ true
+ </ol>
+
+
+
+
+</dd>
+ <dt>
+ <a name = "termsize"></a>
+ <strong>termsize ()</strong>
+ </dt>
+ <dd>
+ Get the size of the terminal in rows and columns.
+
+
+
+ <h3>Returns:</h3>
+ <ol>
+ <li>
+ <span class="types"><span class="type">int</span></span>
+ the number of rows</li>
+ <li>
+ <span class="types"><span class="type">int</span></span>
+ the number of columns</li>
+ </ol>
+ <h3>Or</h3>
+ <ol>
+ <li>
+ <span class="types"><span class="type">nil</span></span>
+
+
+</li>
+ <li>
+ <span class="types"><a class="type" href="https://www.lua.org/manual/5.4/manual.html#6.4">string</a></span>
+ error message</li>
+ </ol>
+
+
+
+
+</dd>
+ <dt>
+ <a name = "termwrap"></a>
+ <strong>termwrap (f)</strong>
+ </dt>
+ <dd>
+ Wraps a function to automatically restore terminal settings upon returning.
+ Calls <a href="../modules/system.html#termbackup">termbackup</a> before calling the function and <a href="../modules/system.html#termrestore">termrestore</a> after.
+
+
+ <h3>Parameters:</h3>
+ <ul>
+ <li><span class="parameter">f</span>
+ <span class="types"><span class="type">function</span></span>
+ function to wrap
+ </li>
+ </ul>
+
+ <h3>Returns:</h3>
+ <ol>
+
+ <span class="types"><span class="type">function</span></span>
+ wrapped function
+ </ol>
+
+
+
+
+</dd>
+ <dt>
+ <a name = "utf8cwidth"></a>
+ <strong>utf8cwidth (utf8_char)</strong>
+ </dt>
+ <dd>
+ Get the width of a utf8 character for terminal display.
+
+
+ <h3>Parameters:</h3>
+ <ul>
+ <li><span class="parameter">utf8_char</span>
+ <span class="types"><a class="type" href="https://www.lua.org/manual/5.4/manual.html#6.4">string</a></span>
+ the utf8 character to check, only the width of the first character will be returned
+ </li>
+ </ul>
+
+ <h3>Returns:</h3>
+ <ol>
+
+ <span class="types"><span class="type">int</span></span>
+ the display width in columns of the first character in the string (0 for an empty string)
+ </ol>
+ <h3>Or</h3>
+ <ol>
+ <li>
+ <span class="types"><span class="type">nil</span></span>
+
+
+</li>
+ <li>
+ <span class="types"><a class="type" href="https://www.lua.org/manual/5.4/manual.html#6.4">string</a></span>
+ error message</li>
+ </ol>
+
+
+
+
+</dd>
+ <dt>
+ <a name = "utf8swidth"></a>
+ <strong>utf8swidth (utf8_string)</strong>
+ </dt>
+ <dd>
+ Get the width of a utf8 string for terminal display.
+
+
+ <h3>Parameters:</h3>
+ <ul>
+ <li><span class="parameter">utf8_string</span>
+ <span class="types"><a class="type" href="https://www.lua.org/manual/5.4/manual.html#6.4">string</a></span>
+ the utf8 string to check
+ </li>
+ </ul>
+
+ <h3>Returns:</h3>
+ <ol>
+
+ <span class="types"><span class="type">int</span></span>
+ the display width of the string in columns (0 for an empty string)
+ </ol>
+ <h3>Or</h3>
+ <ol>
+ <li>
+ <span class="types"><span class="type">nil</span></span>
+
+
+</li>
+ <li>
+ <span class="types"><a class="type" href="https://www.lua.org/manual/5.4/manual.html#6.4">string</a></span>
+ error message</li>
+ </ol>
+
+
+
+
+</dd>
+</dl>
+ <h2 class="section-header "><a name="Time"></a>Time </h2>
+
+ <dl class="function">
+ <dt>
+ <a name = "gettime"></a>
+ <strong>gettime ()</strong>
+ </dt>
+ <dd>
+ Get system time.
+The time is returned as the seconds since the epoch (1 January 1970 00:00:00).
+
+
+
+ <h3>Returns:</h3>
+ <ol>
+
+ <span class="types"><span class="type">number</span></span>
+ seconds (fractional)
+ </ol>
+
+
+
+
+</dd>
+ <dt>
+ <a name = "monotime"></a>
+ <strong>monotime ()</strong>
+ </dt>
+ <dd>
+ Get monotonic time.
+The time is returned as the seconds since system start.
+
+
+
+ <h3>Returns:</h3>
+ <ol>
+
+ <span class="types"><span class="type">number</span></span>
+ seconds (fractional)
+ </ol>
+
+
+
+
+</dd>
+ <dt>
+ <a name = "sleep"></a>
+ <strong>sleep (seconds[, precision=16])</strong>
+ </dt>
+ <dd>
+ Sleep without a busy loop.
+This function will sleep, without doing a busy-loop and wasting CPU cycles.
+
+
+ <h3>Parameters:</h3>
+ <ul>
+ <li><span class="parameter">seconds</span>
+ <span class="types"><span class="type">number</span></span>
+ seconds to sleep (fractional).
+ </li>
+ <li><span class="parameter">precision</span>
+ <span class="types"><span class="type">integer</span></span>
+ minimum stepsize in milliseconds (Windows only, ignored elsewhere)
+ (<em>default</em> 16)
+ </li>
+ </ul>
+
+ <h3>Returns:</h3>
+ <ol>
+
+ <code>true</code> on success, or <code>nil+err</code> on failure
+ </ol>
+
+
+
+
+</dd>
+</dl>
+
+
+</div> <!-- id="content" -->
+</div> <!-- id="main" -->
+<div id="about">
+<i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i>
+<i style="float:right;">Last updated 2024-06-20 23:11:37 </i>
+</div> <!-- id="about" -->
+</div> <!-- id="container" -->
+</body>
+</html>
diff --git a/docs/topics/01-introduction.md.html b/docs/topics/01-introduction.md.html
index 319b9d5..019f7e4 100644
--- a/docs/topics/01-introduction.md.html
+++ b/docs/topics/01-introduction.md.html
@@ -27,17 +27,38 @@
<h1>Lua-System</h1>
+<ul>
+ <li><a href="../index.html">Index</a></li>
+</ul>
+
<h2>Topics</h2>
<ul class="">
<li><strong>1. Introduction</strong></li>
+ <li><a href="../topics/02-development.md.html">2. Development</a></li>
+ <li><a href="../topics/03-terminal.md.html">3. Terminal functionality</a></li>
<li><a href="../topics/CHANGELOG.md.html">CHANGELOG</a></li>
<li><a href="../topics/LICENSE.md.html">MIT License</a></li>
</ul>
<h2>Modules</h2>
<ul class="nowrap">
- <li><a href="../index.html">system</a></li>
+ <li><a href="../modules/system.html">system</a></li>
+</ul>
+<h2>Classes</h2>
+<ul class="nowrap">
+ <li><a href="../classes/bitflags.html">bitflags</a></li>
+</ul>
+<h2>Examples</h2>
+<ul class="nowrap">
+ <li><a href="../examples/compat.lua.html">compat.lua</a></li>
+ <li><a href="../examples/flag_debugging.lua.html">flag_debugging.lua</a></li>
+ <li><a href="../examples/password_input.lua.html">password_input.lua</a></li>
+ <li><a href="../examples/read.lua.html">read.lua</a></li>
+ <li><a href="../examples/readline.lua.html">readline.lua</a></li>
+ <li><a href="../examples/spinner.lua.html">spinner.lua</a></li>
+ <li><a href="../examples/spiral_snake.lua.html">spiral_snake.lua</a></li>
+ <li><a href="../examples/terminalsize.lua.html">terminalsize.lua</a></li>
</ul>
</div>
@@ -62,8 +83,8 @@ independence.</p>
</div> <!-- id="content" -->
</div> <!-- id="main" -->
<div id="about">
-<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
-<i style="float:right;">Last updated 2023-12-15 13:15:09 </i>
+<i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i>
+<i style="float:right;">Last updated 2024-06-20 23:11:37 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>
diff --git a/docs/topics/02-development.md.html b/docs/topics/02-development.md.html
new file mode 100644
index 0000000..e911eed
--- /dev/null
+++ b/docs/topics/02-development.md.html
@@ -0,0 +1,91 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+<head>
+ <title>Lua-System docs</title>
+ <link rel="stylesheet" href="../ldoc.css" type="text/css" />
+</head>
+<body>
+
+<div id="container">
+
+<div id="product">
+ <div id="product_logo"></div>
+ <div id="product_name"><big><b></b></big></div>
+ <div id="product_description"></div>
+</div> <!-- id="product" -->
+
+
+<div id="main">
+
+
+<!-- Menu -->
+
+<div id="navigation">
+<br/>
+<h1>Lua-System</h1>
+
+
+<ul>
+ <li><a href="../index.html">Index</a></li>
+</ul>
+
+
+
+<h2>Topics</h2>
+<ul class="">
+ <li><a href="../topics/01-introduction.md.html">1. Introduction</a></li>
+ <li><strong>2. Development</strong></li>
+ <li><a href="../topics/03-terminal.md.html">3. Terminal functionality</a></li>
+ <li><a href="../topics/CHANGELOG.md.html">CHANGELOG</a></li>
+ <li><a href="../topics/LICENSE.md.html">MIT License</a></li>
+</ul>
+<h2>Modules</h2>
+<ul class="nowrap">
+ <li><a href="../modules/system.html">system</a></li>
+</ul>
+<h2>Classes</h2>
+<ul class="nowrap">
+ <li><a href="../classes/bitflags.html">bitflags</a></li>
+</ul>
+<h2>Examples</h2>
+<ul class="nowrap">
+ <li><a href="../examples/compat.lua.html">compat.lua</a></li>
+ <li><a href="../examples/flag_debugging.lua.html">flag_debugging.lua</a></li>
+ <li><a href="../examples/password_input.lua.html">password_input.lua</a></li>
+ <li><a href="../examples/read.lua.html">read.lua</a></li>
+ <li><a href="../examples/readline.lua.html">readline.lua</a></li>
+ <li><a href="../examples/spinner.lua.html">spinner.lua</a></li>
+ <li><a href="../examples/spiral_snake.lua.html">spiral_snake.lua</a></li>
+ <li><a href="../examples/terminalsize.lua.html">terminalsize.lua</a></li>
+</ul>
+
+</div>
+
+<div id="content">
+
+
+<h1>2. Development</h1>
+
+<p>Some tests cannot be run in CI becasue they test system specifics that
+simply do not exist in a CI environment. An example is the <code>isatty</code> function
+Which cannot be set to return a truthy value in CI.</p>
+
+<p>The tests concerned are all labelled with <code>#manual</code>. And in CI they will
+be skipped because <code>--exclude-tags=manual</code> is being passed to the
+<code>busted</code> command line.</p>
+
+<p>Hence if tests like this are being added, then please ensure the tests
+pass locally, and do not rely on CI only.</p>
+
+
+</div> <!-- id="content" -->
+</div> <!-- id="main" -->
+<div id="about">
+<i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i>
+<i style="float:right;">Last updated 2024-06-20 23:11:37 </i>
+</div> <!-- id="about" -->
+</div> <!-- id="container" -->
+</body>
+</html>
diff --git a/docs/topics/03-terminal.md.html b/docs/topics/03-terminal.md.html
new file mode 100644
index 0000000..3e7e548
--- /dev/null
+++ b/docs/topics/03-terminal.md.html
@@ -0,0 +1,225 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+<head>
+ <title>Lua-System docs</title>
+ <link rel="stylesheet" href="../ldoc.css" type="text/css" />
+</head>
+<body>
+
+<div id="container">
+
+<div id="product">
+ <div id="product_logo"></div>
+ <div id="product_name"><big><b></b></big></div>
+ <div id="product_description"></div>
+</div> <!-- id="product" -->
+
+
+<div id="main">
+
+
+<!-- Menu -->
+
+<div id="navigation">
+<br/>
+<h1>Lua-System</h1>
+
+
+<ul>
+ <li><a href="../index.html">Index</a></li>
+</ul>
+
+<h2>Contents</h2>
+<ul>
+<li><a href="#3_1_Backup_and_Restore_terminal_settings">3.1 Backup and Restore terminal settings </a></li>
+<li><a href="#3_1_Terminal_ANSI_sequences">3.1 Terminal ANSI sequences </a></li>
+<li><a href="#3_2_UTF_8_in_output_and_display_width">3.2 UTF-8 in/output and display width </a></li>
+<li><a href="#3_3_reading_keyboard_input">3.3 reading keyboard input </a></li>
+</ul>
+
+
+<h2>Topics</h2>
+<ul class="">
+ <li><a href="../topics/01-introduction.md.html">1. Introduction</a></li>
+ <li><a href="../topics/02-development.md.html">2. Development</a></li>
+ <li><strong>3. Terminal functionality</strong></li>
+ <li><a href="../topics/CHANGELOG.md.html">CHANGELOG</a></li>
+ <li><a href="../topics/LICENSE.md.html">MIT License</a></li>
+</ul>
+<h2>Modules</h2>
+<ul class="nowrap">
+ <li><a href="../modules/system.html">system</a></li>
+</ul>
+<h2>Classes</h2>
+<ul class="nowrap">
+ <li><a href="../classes/bitflags.html">bitflags</a></li>
+</ul>
+<h2>Examples</h2>
+<ul class="nowrap">
+ <li><a href="../examples/compat.lua.html">compat.lua</a></li>
+ <li><a href="../examples/flag_debugging.lua.html">flag_debugging.lua</a></li>
+ <li><a href="../examples/password_input.lua.html">password_input.lua</a></li>
+ <li><a href="../examples/read.lua.html">read.lua</a></li>
+ <li><a href="../examples/readline.lua.html">readline.lua</a></li>
+ <li><a href="../examples/spinner.lua.html">spinner.lua</a></li>
+ <li><a href="../examples/spiral_snake.lua.html">spiral_snake.lua</a></li>
+ <li><a href="../examples/terminalsize.lua.html">terminalsize.lua</a></li>
+</ul>
+
+</div>
+
+<div id="content">
+
+
+<h1>3. Terminal functionality</h1>
+
+<p>Terminals are fundamentally different on Windows and Posix. So even though
+<code>luasystem</code> provides primitives to manipulate both the Windows and Posix terminals,
+the user will still have to write platform specific code.</p>
+
+<p>To mitigate this a little, all functions are available on all platforms. They just
+will be a no-op if invoked on another platform. This means that no platform specific
+branching is required (but still possible) in user code. The user must simply set
+up both platforms to make it work.</p>
+
+<p><a name="3_1_Backup_and_Restore_terminal_settings"></a></p>
+<h2>3.1 Backup and Restore terminal settings</h2>
+
+<p>Since there are a myriad of settings available;</p>
+
+<ul>
+ <li><a href="../modules/system.html#setconsoleflags">system.setconsoleflags</a> (Windows)</li>
+ <li><a href="../modules/system.html#setconsolecp">system.setconsolecp</a> (Windows)</li>
+ <li><a href="../modules/system.html#setconsoleoutputcp">system.setconsoleoutputcp</a> (Windows)</li>
+ <li><a href="../modules/system.html#setnonblock">system.setnonblock</a> (Posix)</li>
+ <li><a href="../modules/system.html#tcsetattr">system.tcsetattr</a> (Posix)</li>
+</ul>
+
+<p>Some helper functions are available to backup and restore them all at once.
+See <code>termbackup</code>, <code>termrestore</code>, <code>autotermrestore</code> and <code>termwrap</code>.</p>
+
+
+<p><a name="3_1_Terminal_ANSI_sequences"></a></p>
+<h2>3.1 Terminal ANSI sequences</h2>
+
+<p>Windows is catching up with this. In Windows 10 (since 2019), the Windows Terminal application (not to be
+mistaken for the <code>cmd</code> console application) supports ANSI sequences. However this
+might not be enabled by default.</p>
+
+<p>ANSI processing can be set up both on the input (key sequences, reading cursor position)
+as well as on the output (setting colors and cursor shapes).</p>
+
+<p>To enable it use <a href="../modules/system.html#setconsoleflags">system.setconsoleflags</a> like this:</p>
+
+
+<pre>
+<span class="comment">-- setup Windows console to handle ANSI processing on output
+</span>sys.<span class="function-name">setconsoleflags</span>(<span class="global">io</span>.stdout, sys.<span class="function-name">getconsoleflags</span>(<span class="global">io</span>.stdout) + sys.COF_VIRTUAL_TERMINAL_PROCESSING)
+sys.<span class="function-name">setconsoleflags</span>(<span class="global">io</span>.stderr, sys.<span class="function-name">getconsoleflags</span>(<span class="global">io</span>.stderr) + sys.COF_VIRTUAL_TERMINAL_PROCESSING)
+
+<span class="comment">-- setup Windows console to handle ANSI processing on input
+</span>sys.<span class="function-name">setconsoleflags</span>(<span class="global">io</span>.stdin, sys.<span class="function-name">getconsoleflags</span>(<span class="global">io</span>.stdin) + sys.CIF_VIRTUAL_TERMINAL_INPUT)
+</pre>
+
+<p><a name="3_2_UTF_8_in_output_and_display_width"></a></p>
+<h2>3.2 UTF-8 in/output and display width</h2>
+
+<h3>3.2.1 UTF-8 in/output</h3>
+
+<p>Where (most) Posix systems use UTF-8 by default, Windows internally uses UTF-16. More
+recent versions of Lua also have UTF-8 support. So <code>luasystem</code> also focusses on UTF-8.</p>
+
+<p>On Windows UTF-8 output can be enabled by setting the output codepage like this:</p>
+
+
+<pre>
+<span class="comment">-- setup Windows output codepage to UTF-8
+</span>sys.<span class="function-name">setconsoleoutputcp</span>(sys.CODEPAGE_UTF8)
+</pre>
+
+<p>Terminal input is handled by the <a href="https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/getchar-getwchar"><code>_getwchar()</code></a> function on Windows which returns
+UTF-16 surrogate pairs. <code>luasystem</code> will automatically convert those to UTF-8.
+So when using <code>readkey</code> or <code>readansi</code> to read keyboard input no additional changes
+are required.</p>
+
+<h3>3.2.2 UTF-8 display width</h3>
+
+<p>Typical western characters and symbols are single width characters and will use only
+a single column when displayed on a terminal. However many characters from other
+languages/cultures or emojis require 2 columns for display.</p>
+
+<p>Typically the <code>wcwidth</code> function is used on Posix to check the number of columns
+required for display. However since Windows doesn't provide this functionality a
+custom implementation is included based on <a href="http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c">the work by Markus Kuhn</a>.</p>
+
+<p>2 functions are provided, <a href="../modules/system.html#utf8cwidth">system.utf8cwidth</a> for a single character, and <a href="../modules/system.html#utf8swidth">system.utf8swidth</a> for
+a string. When writing terminal applications the display width is relevant to
+positioning the cursor properly. For an example see the <a href="../examples/readline.lua.html"><code>examples/readline.lua</code></a> file.</p>
+
+
+<p><a name="3_3_reading_keyboard_input"></a></p>
+<h2>3.3 reading keyboard input</h2>
+
+<h3>3.3.1 Non-blocking</h3>
+
+<p>There are 2 functions for keyboard input (actually 3, if taking <a href="../modules/system.html#_readkey">system._readkey</a> into
+account): <code>readkey</code> and <code>readansi</code>.</p>
+
+<p><code>readkey</code> is a low level function and should preferably not be used, it returns
+a byte at a time, and hence can leave stray/invalid byte sequences in the buffer if
+only the start of a UTF-8 or ANSI sequence is consumed.</p>
+
+<p>The preferred way is to use <code>readansi</code> which will parse and return entire characters in
+single or multiple bytes, or a full ANSI sequence.</p>
+
+<p>On Windows the input is read using <a href="https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/getchar-getwchar"><code>_getwchar()</code></a> which bypasses the terminal and reads
+the input directly from the keyboard buffer. This means however that the character is
+also not being echoed to the terminal (independent of the echo settings used with
+<a href="../modules/system.html#setconsoleflags">system.setconsoleflags</a>).</p>
+
+<p>On Posix the traditional file approach is used, which:</p>
+
+<ul>
+ <li>is blocking by default</li>
+ <li>echoes input to the terminal</li>
+ <li>requires enter to be pressed to pass the input (canonical mode)</li>
+</ul>
+
+<p>To use non-blocking input here's how to set it up:</p>
+
+
+<pre>
+<span class="comment">-- setup Windows console to disable echo and line input (not required since _getwchar is used, just for consistency)
+</span>sys.<span class="function-name">setconsoleflags</span>(<span class="global">io</span>.stdin, sys.<span class="function-name">getconsoleflags</span>(<span class="global">io</span>.stdin) - sys.CIF_ECHO_INPUT - sys.CIF_LINE_INPUT)
+
+<span class="comment">-- setup Posix by disabling echo, canonical mode, and making non-blocking
+</span><span class="keyword">local</span> of_attr = sys.<span class="function-name">tcgetattr</span>(<span class="global">io</span>.stdin)
+sys.<span class="function-name">tcsetattr</span>(<span class="global">io</span>.stdin, sys.TCSANOW, {
+ lflag = of_attr.lflag - sys.L_ICANON - sys.L_ECHO,
+})
+sys.<span class="function-name">setnonblock</span>(<span class="global">io</span>.stdin, <span class="keyword">true</span>)
+</pre>
+
+<p>Both functions require a timeout to be provided which allows for proper asynchronous
+code to be written. Since the underlying sleep method used is <a href="../modules/system.html#sleep">system.sleep</a>, just patching
+that function with a coroutine based yielding one should be all that is needed to make
+the result work with asynchroneous coroutine schedulers.</p>
+
+<h3>3.3.2 Blocking input</h3>
+
+<p>When using traditional input method like <code>io.stdin:read()</code> (which is blocking) the echo
+and newline properties should be set on Windows similar to Posix.
+For an example see <a href="../examples/password_input.lua.html"><code>examples/password_input.lua</code></a>.</p>
+
+
+</div> <!-- id="content" -->
+</div> <!-- id="main" -->
+<div id="about">
+<i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i>
+<i style="float:right;">Last updated 2024-06-20 23:11:37 </i>
+</div> <!-- id="about" -->
+</div> <!-- id="container" -->
+</body>
+</html>
diff --git a/docs/topics/CHANGELOG.md.html b/docs/topics/CHANGELOG.md.html
index 4e656c7..da8ddde 100644
--- a/docs/topics/CHANGELOG.md.html
+++ b/docs/topics/CHANGELOG.md.html
@@ -27,6 +27,10 @@
<h1>Lua-System</h1>
+<ul>
+ <li><a href="../index.html">Index</a></li>
+</ul>
+
<h2>Contents</h2>
<ul>
<li><a href="#Versioning">Versioning </a></li>
@@ -37,12 +41,29 @@
<h2>Topics</h2>
<ul class="">
<li><a href="../topics/01-introduction.md.html">1. Introduction</a></li>
+ <li><a href="../topics/02-development.md.html">2. Development</a></li>
+ <li><a href="../topics/03-terminal.md.html">3. Terminal functionality</a></li>
<li><strong>CHANGELOG</strong></li>
<li><a href="../topics/LICENSE.md.html">MIT License</a></li>
</ul>
<h2>Modules</h2>
<ul class="nowrap">
- <li><a href="../index.html">system</a></li>
+ <li><a href="../modules/system.html">system</a></li>
+</ul>
+<h2>Classes</h2>
+<ul class="nowrap">
+ <li><a href="../classes/bitflags.html">bitflags</a></li>
+</ul>
+<h2>Examples</h2>
+<ul class="nowrap">
+ <li><a href="../examples/compat.lua.html">compat.lua</a></li>
+ <li><a href="../examples/flag_debugging.lua.html">flag_debugging.lua</a></li>
+ <li><a href="../examples/password_input.lua.html">password_input.lua</a></li>
+ <li><a href="../examples/read.lua.html">read.lua</a></li>
+ <li><a href="../examples/readline.lua.html">readline.lua</a></li>
+ <li><a href="../examples/spinner.lua.html">spinner.lua</a></li>
+ <li><a href="../examples/spiral_snake.lua.html">spiral_snake.lua</a></li>
+ <li><a href="../examples/terminalsize.lua.html">terminalsize.lua</a></li>
</ul>
</div>
@@ -86,15 +107,31 @@
<p><a name="Version_history"></a></p>
<h2>Version history</h2>
+<h3>Version 0.4.0, released 20-Jun-2024</h3>
+
+<ul>
+ <li>Feat: <code>getconsoleflags</code> and <code>setconsoleflags</code> for getting/setting the current console configuration flags on Windows</li>
+ <li>Feat: <code>getconsolecp</code> and <code>setconsolecp</code> for getting/setting the console codepage on Windows</li>
+ <li>Feat: <code>getconsoleoutputcp</code> and <code>setconsoleoutputcp</code> for getting/setting the console output codepage on Windows</li>
+ <li>Feat: <code>tcgetattr</code> and <code>tcsetattr</code> for getting/setting the current console configuration flags on Posix</li>
+ <li>Feat: <code>getnonblock</code> and <code>setnonblock</code> for getting/setting the non-blocking flag on Posix</li>
+ <li>Feat: <a href="../classes/bitflags.html#">bitflags</a>: a support feature for the above flag type controls to facilitate bit manipulation without resorting to binary operations (to also support PuC Lua 5.1)</li>
+ <li>Feat: <code>readkey</code> reads a keyboard input from <code>stdin</code> in a non-blocking way (utf8, also on Windows)</li>
+ <li>Feat: <code>readansi</code> reads a keyboard input from <code>stdin</code> in a non-blocking way, parses ansi and utf8 sequences</li>
+ <li>Feat: <code>termsize</code> gets the current terminal size in rows and columns</li>
+ <li>Feat: <code>utf8cwidth</code> and <code>utf8swidth</code> for getting the display width (in columns) of respectively a single utf8 character, or a utf8 string</li>
+ <li>Feat: helpers; <code>termbackup</code>, <code>termrestore</code>, <code>autotermrestore</code>, and <code>termwrap</code> for managing the many terminal settings on all platforms.</li>
+</ul>
+
<h3>Version 0.3.0, released 15-Dec-2023</h3>
<ul>
- <li>Feat: on Windows <a href="../index.html#sleep">sleep</a> now has a precision parameter</li>
- <li>Feat: <a href="../index.html#setenv">setenv</a> added to set environment variables.</li>
- <li>Feat: <a href="../index.html#getenvs">getenvs</a> added to list environment variables.</li>
- <li>Feat: <a href="../index.html#getenv">getenv</a> added to get environment variable previously set (Windows).</li>
- <li>Feat: <a href="../index.html#random">random</a> added to return high-quality random bytes</li>
- <li>Feat: <a href="../index.html#isatty">isatty</a> added to check if a file-handle is a tty</li>
+ <li>Feat: on Windows <code>sleep</code> now has a precision parameter</li>
+ <li>Feat: <code>setenv</code> added to set environment variables.</li>
+ <li>Feat: <code>getenvs</code> added to list environment variables.</li>
+ <li>Feat: <code>getenv</code> added to get environment variable previously set (Windows).</li>
+ <li>Feat: <code>random</code> added to return high-quality random bytes</li>
+ <li>Feat: <code>isatty</code> added to check if a file-handle is a tty</li>
</ul>
<h3>Version 0.2.1, released 02-Oct-2016</h3>
@@ -113,8 +150,8 @@
</div> <!-- id="content" -->
</div> <!-- id="main" -->
<div id="about">
-<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
-<i style="float:right;">Last updated 2023-12-15 13:15:09 </i>
+<i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i>
+<i style="float:right;">Last updated 2024-06-20 23:11:37 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>
diff --git a/docs/topics/LICENSE.md.html b/docs/topics/LICENSE.md.html
index de3eeff..9866af5 100644
--- a/docs/topics/LICENSE.md.html
+++ b/docs/topics/LICENSE.md.html
@@ -27,17 +27,38 @@
<h1>Lua-System</h1>
+<ul>
+ <li><a href="../index.html">Index</a></li>
+</ul>
+
<h2>Topics</h2>
<ul class="">
<li><a href="../topics/01-introduction.md.html">1. Introduction</a></li>
+ <li><a href="../topics/02-development.md.html">2. Development</a></li>
+ <li><a href="../topics/03-terminal.md.html">3. Terminal functionality</a></li>
<li><a href="../topics/CHANGELOG.md.html">CHANGELOG</a></li>
<li><strong>MIT License</strong></li>
</ul>
<h2>Modules</h2>
<ul class="nowrap">
- <li><a href="../index.html">system</a></li>
+ <li><a href="../modules/system.html">system</a></li>
+</ul>
+<h2>Classes</h2>
+<ul class="nowrap">
+ <li><a href="../classes/bitflags.html">bitflags</a></li>
+</ul>
+<h2>Examples</h2>
+<ul class="nowrap">
+ <li><a href="../examples/compat.lua.html">compat.lua</a></li>
+ <li><a href="../examples/flag_debugging.lua.html">flag_debugging.lua</a></li>
+ <li><a href="../examples/password_input.lua.html">password_input.lua</a></li>
+ <li><a href="../examples/read.lua.html">read.lua</a></li>
+ <li><a href="../examples/readline.lua.html">readline.lua</a></li>
+ <li><a href="../examples/spinner.lua.html">spinner.lua</a></li>
+ <li><a href="../examples/spiral_snake.lua.html">spiral_snake.lua</a></li>
+ <li><a href="../examples/terminalsize.lua.html">terminalsize.lua</a></li>
</ul>
</div>
@@ -47,7 +68,7 @@
<h1>MIT License</h1>
-<h3>Copyright (c) 2016-2023 Oscar Lim</h3>
+<h3>Copyright (c) 2016-2024 Oscar Lim</h3>
<p>Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
@@ -71,8 +92,8 @@ SOFTWARE.</p>
</div> <!-- id="content" -->
</div> <!-- id="main" -->
<div id="about">
-<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
-<i style="float:right;">Last updated 2023-12-15 13:15:09 </i>
+<i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i>
+<i style="float:right;">Last updated 2024-06-20 23:11:37 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>
diff --git a/rockspecs/luasystem-0.4.0-1.rockspec b/rockspecs/luasystem-0.4.0-1.rockspec
new file mode 100644
index 0000000..d35565d
--- /dev/null
+++ b/rockspecs/luasystem-0.4.0-1.rockspec
@@ -0,0 +1,85 @@
+local package_name = "luasystem"
+local package_version = "0.4.0"
+local rockspec_revision = "1"
+local github_account_name = "lunarmodules"
+local github_repo_name = "luasystem"
+
+
+package = package_name
+version = package_version.."-"..rockspec_revision
+
+source = {
+ url = "git+https://github.com/"..github_account_name.."/"..github_repo_name..".git",
+ branch = (package_version == "scm") and "master" or nil,
+ tag = (package_version ~= "scm") and "v"..package_version or nil,
+}
+
+description = {
+ summary = 'Platform independent system calls for Lua.',
+ detailed = [[
+ Adds a Lua API for making platform independent system calls.
+ ]],
+ license = 'MIT <http://opensource.org/licenses/MIT>',
+ homepage = "https://github.com/"..github_account_name.."/"..github_repo_name,
+}
+
+dependencies = {
+ 'lua >= 5.1',
+}
+
+local function make_platform(plat)
+ local defines = {
+ linux = { },
+ unix = { },
+ macosx = { },
+ win32 = { "WINVER=0x0600", "_WIN32_WINNT=0x0600" },
+ mingw32 = { "WINVER=0x0600", "_WIN32_WINNT=0x0600" },
+ }
+ local libraries = {
+ linux = { "rt" },
+ unix = { },
+ macosx = { },
+ win32 = { "advapi32", "winmm" },
+ mingw32 = { },
+ }
+ local libdirs = {
+ linux = nil,
+ unix = nil,
+ macosx = nil,
+ win32 = nil,
+ mingw32 = { },
+ }
+ return {
+ modules = {
+ ['system.core'] = {
+ sources = {
+ 'src/core.c',
+ 'src/compat.c',
+ 'src/time.c',
+ 'src/environment.c',
+ 'src/random.c',
+ 'src/term.c',
+ 'src/bitflags.c',
+ 'src/wcwidth.c',
+ },
+ defines = defines[plat],
+ libraries = libraries[plat],
+ libdirs = libdirs[plat],
+ },
+ },
+ }
+end
+
+build = {
+ type = 'builtin',
+ platforms = {
+ linux = make_platform('linux'),
+ unix = make_platform('unix'),
+ macosx = make_platform('macosx'),
+ win32 = make_platform('win32'),
+ mingw32 = make_platform('mingw32'),
+ },
+ modules = {
+ ['system.init'] = 'system/init.lua',
+ },
+}
diff --git a/src/core.c b/src/core.c
index d233ecc..24764c5 100644
--- a/src/core.c
+++ b/src/core.c
@@ -4,7 +4,7 @@
#include <lua.h>
#include <lauxlib.h>
-#define LUASYSTEM_VERSION "LuaSystem 0.3.0"
+#define LUASYSTEM_VERSION "LuaSystem 0.4.0"
#ifdef _WIN32
#define LUAEXPORT __declspec(dllexport)
@@ -26,6 +26,9 @@ LUAEXPORT int luaopen_system_core(lua_State *L) {
lua_pushstring(L, "_VERSION");
lua_pushstring(L, LUASYSTEM_VERSION);
lua_rawset(L, -3);
+
+/// Flag to identify Windows.
+// @field windows `true` if on Windows, `false` otherwise.
lua_pushstring(L, "windows");
#ifdef _WIN32
lua_pushboolean(L, 1);