diff options
28 files changed, 1211 insertions, 475 deletions
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 093ef05..5b3d31a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml | |||
@@ -21,7 +21,7 @@ jobs: | |||
21 | strategy: | 21 | strategy: |
22 | fail-fast: false | 22 | fail-fast: false |
23 | matrix: | 23 | matrix: |
24 | os: ['ubuntu-20.04', 'macos-13'] | 24 | os: ['ubuntu-24.04', 'macos-13'] |
25 | luaVersion: | 25 | luaVersion: |
26 | - "5.1" | 26 | - "5.1" |
27 | - "5.2" | 27 | - "5.2" |
@@ -97,7 +97,7 @@ jobs: | |||
97 | 97 | ||
98 | - uses: hishamhm/gh-actions-luarocks@master | 98 | - uses: hishamhm/gh-actions-luarocks@master |
99 | with: | 99 | with: |
100 | luaRocksVersion: "3.11.0" | 100 | luaRocksVersion: "3.12.0" |
101 | 101 | ||
102 | - name: test dependencies | 102 | - name: test dependencies |
103 | run: | | 103 | run: | |
diff --git a/.github/workflows/luacheck.yml b/.github/workflows/lint.yml index 3ad8db7..83abc44 100644 --- a/.github/workflows/luacheck.yml +++ b/.github/workflows/lint.yml | |||
@@ -1,5 +1,5 @@ | |||
1 | --- | 1 | --- |
2 | name: Luacheck | 2 | name: Lint |
3 | 3 | ||
4 | on: [push, pull_request] | 4 | on: [push, pull_request] |
5 | 5 | ||
diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c9e15e..3b00fb6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md | |||
@@ -27,6 +27,33 @@ The scope of what is covered by the version number excludes: | |||
27 | 27 | ||
28 | ## Version history | 28 | ## Version history |
29 | 29 | ||
30 | ### version 0.6.3, released 11-Jul-2025 | ||
31 | |||
32 | - Fix: maximum key-delay, reduced from 0.2 to 0.1 seconds to reduce slugginess feel on some key presses. | ||
33 | See [#69](https://github.com/lunarmodules/luasystem/pull/69). | ||
34 | - Fix: `readansi` now only reports printable chars as characters | ||
35 | See [#70](https://github.com/lunarmodules/luasystem/pull/70). | ||
36 | - Fix: readkey now ignores Windows scancodes if received. | ||
37 | See [#74](https://github.com/lunarmodules/luasystem/pull/74). | ||
38 | - Fix: readkey now passes errors on. | ||
39 | See [#74](https://github.com/lunarmodules/luasystem/pull/74). | ||
40 | |||
41 | ### version 0.6.2, released 15-Apr-2025 | ||
42 | |||
43 | - Fix: autotermrestore didn't work because its metatable was overwritten. | ||
44 | |||
45 | ### version 0.6.1, released 13-Apr-2025 | ||
46 | |||
47 | - Docs: document readansi internal buffer for incomplete sequences. | ||
48 | - Fix: ensure to properly parse `<alt>+key` key presses | ||
49 | |||
50 | ### version 0.6.0, released 10-Apr-2025 | ||
51 | |||
52 | - Fix: when sleep returns an error, pass that on in `readkey`. | ||
53 | - Feat: added `detachfds` which will create separate file descriptions for `stdout` | ||
54 | and `stderr` to ensure that related settings (eg. non-blocking flag) will not be shared | ||
55 | amongst those streams and `stdin`. | ||
56 | |||
30 | ### version 0.5.1, released 12-Mar-2025 | 57 | ### version 0.5.1, released 12-Mar-2025 |
31 | 58 | ||
32 | - Fix: on older unixes with glibc < 2.25, fall back to `/dev/urandom` | 59 | - Fix: on older unixes with glibc < 2.25, fall back to `/dev/urandom` |
@@ -38,12 +65,12 @@ The scope of what is covered by the version number excludes: | |||
38 | - Feat: allow passing in a sleep function to `readkey` and `readansi` | 65 | - Feat: allow passing in a sleep function to `readkey` and `readansi` |
39 | - Fix: NetBSD fix compilation, undeclared directives | 66 | - Fix: NetBSD fix compilation, undeclared directives |
40 | - Refactor: random bytes; remove deprecated API usage on Windows, move to | 67 | - Refactor: random bytes; remove deprecated API usage on Windows, move to |
41 | binary api instead of /dev/urandom file on linux and bsd | 68 | binary api instead of `/dev/urandom` file on linux and bsd |
42 | 69 | ||
43 | ### version 0.4.5, released 18-Dec-2024 | 70 | ### version 0.4.5, released 18-Dec-2024 |
44 | 71 | ||
45 | - Fix: suppress a warning when building with clang | 72 | - Fix: suppress a warning when building with clang |
46 | - Fix: do not rely on luaconf.h to include limits.h, fixes builds with latest LuaJIT (#38). | 73 | - Fix: do not rely on `luaconf.h` to include `limits.h`, fixes builds with latest LuaJIT (#38). |
47 | 74 | ||
48 | ### version 0.4.4, released 03-Sep-2024 | 75 | ### version 0.4.4, released 03-Sep-2024 |
49 | 76 | ||
diff --git a/doc_topics/03-terminal.md b/doc_topics/03-terminal.md index 5bdf543..a5341d6 100644 --- a/doc_topics/03-terminal.md +++ b/doc_topics/03-terminal.md | |||
@@ -16,6 +16,7 @@ Since there are a myriad of settings available; | |||
16 | - `system.setconsoleflags` (Windows) | 16 | - `system.setconsoleflags` (Windows) |
17 | - `system.setconsolecp` (Windows) | 17 | - `system.setconsolecp` (Windows) |
18 | - `system.setconsoleoutputcp` (Windows) | 18 | - `system.setconsoleoutputcp` (Windows) |
19 | - `system.detachfds` (Posix) | ||
19 | - `system.setnonblock` (Posix) | 20 | - `system.setnonblock` (Posix) |
20 | - `system.tcsetattr` (Posix) | 21 | - `system.tcsetattr` (Posix) |
21 | 22 | ||
@@ -105,6 +106,7 @@ To use non-blocking input here's how to set it up: | |||
105 | sys.setconsoleflags(io.stdin, sys.getconsoleflags(io.stdin) - sys.CIF_ECHO_INPUT - sys.CIF_LINE_INPUT) | 106 | sys.setconsoleflags(io.stdin, sys.getconsoleflags(io.stdin) - sys.CIF_ECHO_INPUT - sys.CIF_LINE_INPUT) |
106 | 107 | ||
107 | -- setup Posix by disabling echo, canonical mode, and making non-blocking | 108 | -- setup Posix by disabling echo, canonical mode, and making non-blocking |
109 | sys.detachfds() -- ensure stdin/out/err have their own file descriptions | ||
108 | local of_attr = sys.tcgetattr(io.stdin) | 110 | local of_attr = sys.tcgetattr(io.stdin) |
109 | sys.tcsetattr(io.stdin, sys.TCSANOW, { | 111 | sys.tcsetattr(io.stdin, sys.TCSANOW, { |
110 | lflag = of_attr.lflag - sys.L_ICANON - sys.L_ECHO, | 112 | lflag = of_attr.lflag - sys.L_ICANON - sys.L_ECHO, |
diff --git a/docs/classes/bitflags.html b/docs/classes/bitflags.html index 647cc62..7637aeb 100644 --- a/docs/classes/bitflags.html +++ b/docs/classes/bitflags.html | |||
@@ -298,7 +298,7 @@ return <code>false</code> if the flags are checked. | |||
298 | </div> <!-- id="main" --> | 298 | </div> <!-- id="main" --> |
299 | <div id="about"> | 299 | <div id="about"> |
300 | <i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i> | 300 | <i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i> |
301 | <i style="float:right;">Last updated 2025-03-12 15:17:50 </i> | 301 | <i style="float:right;">Last updated 2025-07-11 22:55:05 </i> |
302 | </div> <!-- id="about" --> | 302 | </div> <!-- id="about" --> |
303 | </div> <!-- id="container" --> | 303 | </div> <!-- id="container" --> |
304 | </body> | 304 | </body> |
diff --git a/docs/examples/compat.lua.html b/docs/examples/compat.lua.html index e421044..ca4e489 100644 --- a/docs/examples/compat.lua.html +++ b/docs/examples/compat.lua.html | |||
@@ -112,7 +112,7 @@ | |||
112 | </div> <!-- id="main" --> | 112 | </div> <!-- id="main" --> |
113 | <div id="about"> | 113 | <div id="about"> |
114 | <i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i> | 114 | <i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i> |
115 | <i style="float:right;">Last updated 2025-03-12 15:17:50 </i> | 115 | <i style="float:right;">Last updated 2025-07-11 22:55:05 </i> |
116 | </div> <!-- id="about" --> | 116 | </div> <!-- id="about" --> |
117 | </div> <!-- id="container" --> | 117 | </div> <!-- id="container" --> |
118 | </body> | 118 | </body> |
diff --git a/docs/examples/flag_debugging.lua.html b/docs/examples/flag_debugging.lua.html index e8a75e3..dba4471 100644 --- a/docs/examples/flag_debugging.lua.html +++ b/docs/examples/flag_debugging.lua.html | |||
@@ -80,7 +80,7 @@ | |||
80 | </div> <!-- id="main" --> | 80 | </div> <!-- id="main" --> |
81 | <div id="about"> | 81 | <div id="about"> |
82 | <i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i> | 82 | <i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i> |
83 | <i style="float:right;">Last updated 2025-03-12 15:17:50 </i> | 83 | <i style="float:right;">Last updated 2025-07-11 22:55:05 </i> |
84 | </div> <!-- id="about" --> | 84 | </div> <!-- id="about" --> |
85 | </div> <!-- id="container" --> | 85 | </div> <!-- id="container" --> |
86 | </body> | 86 | </body> |
diff --git a/docs/examples/password_input.lua.html b/docs/examples/password_input.lua.html index a5eac4d..342b066 100644 --- a/docs/examples/password_input.lua.html +++ b/docs/examples/password_input.lua.html | |||
@@ -132,7 +132,7 @@ useful for reading secrets from the user. | |||
132 | </div> <!-- id="main" --> | 132 | </div> <!-- id="main" --> |
133 | <div id="about"> | 133 | <div id="about"> |
134 | <i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i> | 134 | <i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i> |
135 | <i style="float:right;">Last updated 2025-03-12 15:17:50 </i> | 135 | <i style="float:right;">Last updated 2025-07-11 22:55:05 </i> |
136 | </div> <!-- id="about" --> | 136 | </div> <!-- id="about" --> |
137 | </div> <!-- id="container" --> | 137 | </div> <!-- id="container" --> |
138 | </body> | 138 | </body> |
diff --git a/docs/examples/read.lua.html b/docs/examples/read.lua.html index 3b53a8b..4995bda 100644 --- a/docs/examples/read.lua.html +++ b/docs/examples/read.lua.html | |||
@@ -143,7 +143,7 @@ sys.<span class="function-name">setnonblock</span>(<span class="global">io</span | |||
143 | </div> <!-- id="main" --> | 143 | </div> <!-- id="main" --> |
144 | <div id="about"> | 144 | <div id="about"> |
145 | <i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i> | 145 | <i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i> |
146 | <i style="float:right;">Last updated 2025-03-12 15:17:50 </i> | 146 | <i style="float:right;">Last updated 2025-07-11 22:55:05 </i> |
147 | </div> <!-- id="about" --> | 147 | </div> <!-- id="about" --> |
148 | </div> <!-- id="container" --> | 148 | </div> <!-- id="container" --> |
149 | </body> | 149 | </body> |
diff --git a/docs/examples/readline.lua.html b/docs/examples/readline.lua.html index dd63721..493de2c 100644 --- a/docs/examples/readline.lua.html +++ b/docs/examples/readline.lua.html | |||
@@ -549,7 +549,7 @@ sys.<span class="function-name">setconsoleflags</span>(<span class="global">io</ | |||
549 | </div> <!-- id="main" --> | 549 | </div> <!-- id="main" --> |
550 | <div id="about"> | 550 | <div id="about"> |
551 | <i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i> | 551 | <i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i> |
552 | <i style="float:right;">Last updated 2025-03-12 15:17:50 </i> | 552 | <i style="float:right;">Last updated 2025-07-11 22:55:05 </i> |
553 | </div> <!-- id="about" --> | 553 | </div> <!-- id="about" --> |
554 | </div> <!-- id="container" --> | 554 | </div> <!-- id="container" --> |
555 | </body> | 555 | </body> |
diff --git a/docs/examples/spinner.lua.html b/docs/examples/spinner.lua.html index 99a1c91..6e2d63a 100644 --- a/docs/examples/spinner.lua.html +++ b/docs/examples/spinner.lua.html | |||
@@ -137,7 +137,7 @@ sys.<span class="function-name">setnonblock</span>(<span class="global">io</span | |||
137 | </div> <!-- id="main" --> | 137 | </div> <!-- id="main" --> |
138 | <div id="about"> | 138 | <div id="about"> |
139 | <i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i> | 139 | <i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i> |
140 | <i style="float:right;">Last updated 2025-03-12 15:17:50 </i> | 140 | <i style="float:right;">Last updated 2025-07-11 22:55:05 </i> |
141 | </div> <!-- id="about" --> | 141 | </div> <!-- id="about" --> |
142 | </div> <!-- id="container" --> | 142 | </div> <!-- id="container" --> |
143 | </body> | 143 | </body> |
diff --git a/docs/examples/spiral_snake.lua.html b/docs/examples/spiral_snake.lua.html index 7be16e8..97d5f77 100644 --- a/docs/examples/spiral_snake.lua.html +++ b/docs/examples/spiral_snake.lua.html | |||
@@ -145,7 +145,7 @@ codes for moving the cursor around. | |||
145 | </div> <!-- id="main" --> | 145 | </div> <!-- id="main" --> |
146 | <div id="about"> | 146 | <div id="about"> |
147 | <i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i> | 147 | <i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i> |
148 | <i style="float:right;">Last updated 2025-03-12 15:17:50 </i> | 148 | <i style="float:right;">Last updated 2025-07-11 22:55:05 </i> |
149 | </div> <!-- id="about" --> | 149 | </div> <!-- id="about" --> |
150 | </div> <!-- id="container" --> | 150 | </div> <!-- id="container" --> |
151 | </body> | 151 | </body> |
diff --git a/docs/examples/terminalsize.lua.html b/docs/examples/terminalsize.lua.html index 6a6a93e..d3486bb 100644 --- a/docs/examples/terminalsize.lua.html +++ b/docs/examples/terminalsize.lua.html | |||
@@ -110,7 +110,7 @@ sys.<span class="function-name">tcsetattr</span>(<span class="global">io</span>. | |||
110 | </div> <!-- id="main" --> | 110 | </div> <!-- id="main" --> |
111 | <div id="about"> | 111 | <div id="about"> |
112 | <i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i> | 112 | <i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i> |
113 | <i style="float:right;">Last updated 2025-03-12 15:17:50 </i> | 113 | <i style="float:right;">Last updated 2025-07-11 22:55:05 </i> |
114 | </div> <!-- id="about" --> | 114 | </div> <!-- id="about" --> |
115 | </div> <!-- id="container" --> | 115 | </div> <!-- id="container" --> |
116 | </body> | 116 | </body> |
diff --git a/docs/index.html b/docs/index.html index 5d7b02f..e901d08 100644 --- a/docs/index.html +++ b/docs/index.html | |||
@@ -142,7 +142,7 @@ | |||
142 | </div> <!-- id="main" --> | 142 | </div> <!-- id="main" --> |
143 | <div id="about"> | 143 | <div id="about"> |
144 | <i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i> | 144 | <i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i> |
145 | <i style="float:right;">Last updated 2025-03-12 15:17:50 </i> | 145 | <i style="float:right;">Last updated 2025-07-11 22:55:05 </i> |
146 | </div> <!-- id="about" --> | 146 | </div> <!-- id="about" --> |
147 | </div> <!-- id="container" --> | 147 | </div> <!-- id="container" --> |
148 | </body> | 148 | </body> |
diff --git a/docs/modules/system.html b/docs/modules/system.html index fa41458..0a2447e 100644 --- a/docs/modules/system.html +++ b/docs/modules/system.html | |||
@@ -37,7 +37,12 @@ | |||
37 | <li><a href="#Environment">Environment </a></li> | 37 | <li><a href="#Environment">Environment </a></li> |
38 | <li><a href="#Random">Random </a></li> | 38 | <li><a href="#Random">Random </a></li> |
39 | <li><a href="#Terminal">Terminal </a></li> | 39 | <li><a href="#Terminal">Terminal </a></li> |
40 | <li><a href="#Terminal_Windows">Terminal_Windows</a></li> | ||
41 | <li><a href="#Terminal_Posix">Terminal_Posix</a></li> | ||
42 | <li><a href="#Terminal_Input">Terminal_Input</a></li> | ||
43 | <li><a href="#Terminal_UTF_8">Terminal_UTF-8</a></li> | ||
40 | <li><a href="#Time">Time </a></li> | 44 | <li><a href="#Time">Time </a></li> |
45 | <li><a href="#Terminal_Backup">Terminal_Backup</a></li> | ||
41 | </ul> | 46 | </ul> |
42 | 47 | ||
43 | 48 | ||
@@ -112,93 +117,93 @@ | |||
112 | <h2><a href="#Terminal">Terminal </a></h2> | 117 | <h2><a href="#Terminal">Terminal </a></h2> |
113 | <table class="function_list"> | 118 | <table class="function_list"> |
114 | <tr> | 119 | <tr> |
115 | <td class="name" nowrap><a href="#CODEPAGE_UTF8">CODEPAGE_UTF8</a></td> | 120 | <td class="name" nowrap><a href="#isatty">isatty (file)</a></td> |
116 | <td class="summary">UTF8 codepage.</td> | 121 | <td class="summary">Checks if a file-handle is a TTY.</td> |
117 | </tr> | ||
118 | <tr> | ||
119 | <td class="name" nowrap><a href="#_readkey">_readkey ()</a></td> | ||
120 | <td class="summary">Reads a key from the console non-blocking.</td> | ||
121 | </tr> | ||
122 | <tr> | ||
123 | <td class="name" nowrap><a href="#autotermrestore">autotermrestore ()</a></td> | ||
124 | <td class="summary">Backs up terminal settings and restores them on application exit.</td> | ||
125 | </tr> | 122 | </tr> |
126 | <tr> | 123 | <tr> |
127 | <td class="name" nowrap><a href="#getconsolecp">getconsolecp ()</a></td> | 124 | <td class="name" nowrap><a href="#termsize">termsize ()</a></td> |
128 | <td class="summary">Gets the current console code page (Windows).</td> | 125 | <td class="summary">Get the size of the terminal in rows and columns.</td> |
129 | </tr> | 126 | </tr> |
127 | </table> | ||
128 | <h2><a href="#Terminal_Windows">Terminal_Windows</a></h2> | ||
129 | <table class="function_list"> | ||
130 | <tr> | 130 | <tr> |
131 | <td class="name" nowrap><a href="#getconsoleflags">getconsoleflags (file)</a></td> | 131 | <td class="name" nowrap><a href="#getconsoleflags">getconsoleflags (file)</a></td> |
132 | <td class="summary">Gets console flags (Windows).</td> | 132 | <td class="summary">Gets console flags (Windows).</td> |
133 | </tr> | 133 | </tr> |
134 | <tr> | 134 | <tr> |
135 | <td class="name" nowrap><a href="#getconsoleoutputcp">getconsoleoutputcp ()</a></td> | 135 | <td class="name" nowrap><a href="#listconsoleflags">listconsoleflags (fh)</a></td> |
136 | <td class="summary">Gets the current console output code page (Windows).</td> | 136 | <td class="summary">Debug function for console flags (Windows).</td> |
137 | </tr> | 137 | </tr> |
138 | <tr> | 138 | <tr> |
139 | <td class="name" nowrap><a href="#getnonblock">getnonblock (fd)</a></td> | 139 | <td class="name" nowrap><a href="#setconsoleflags">setconsoleflags (file, bitflags)</a></td> |
140 | <td class="summary">Gets non-blocking mode status for a file (Posix).</td> | 140 | <td class="summary">Sets the console flags (Windows).</td> |
141 | </tr> | 141 | </tr> |
142 | </table> | ||
143 | <h2><a href="#Terminal_Posix">Terminal_Posix</a></h2> | ||
144 | <table class="function_list"> | ||
142 | <tr> | 145 | <tr> |
143 | <td class="name" nowrap><a href="#isatty">isatty (file)</a></td> | 146 | <td class="name" nowrap><a href="#detachfds">detachfds ()</a></td> |
144 | <td class="summary">Checks if a file-handle is a TTY.</td> | 147 | <td class="summary">Creates new file descriptions for <code>stdout</code> and <code>stderr</code>.</td> |
145 | </tr> | 148 | </tr> |
146 | <tr> | 149 | <tr> |
147 | <td class="name" nowrap><a href="#listconsoleflags">listconsoleflags (fh)</a></td> | 150 | <td class="name" nowrap><a href="#getnonblock">getnonblock (fd)</a></td> |
148 | <td class="summary">Debug function for console flags (Windows).</td> | 151 | <td class="summary">Gets non-blocking mode status for a file (Posix).</td> |
149 | </tr> | 152 | </tr> |
150 | <tr> | 153 | <tr> |
151 | <td class="name" nowrap><a href="#listtermflags">listtermflags (fh)</a></td> | 154 | <td class="name" nowrap><a href="#listtermflags">listtermflags (fh)</a></td> |
152 | <td class="summary">Debug function for terminal flags (Posix).</td> | 155 | <td class="summary">Debug function for terminal flags (Posix).</td> |
153 | </tr> | 156 | </tr> |
154 | <tr> | 157 | <tr> |
155 | <td class="name" nowrap><a href="#readansi">readansi (timeout[, fsleep=system.sleep])</a></td> | 158 | <td class="name" nowrap><a href="#setnonblock">setnonblock (fd, make_non_block)</a></td> |
156 | <td class="summary">Reads a single key, if it is the start of ansi escape sequence then it reads | 159 | <td class="summary">Enables or disables non-blocking mode for a file (Posix).</td> |
157 | the full sequence.</td> | ||
158 | </tr> | ||
159 | <tr> | ||
160 | <td class="name" nowrap><a href="#readkey">readkey (timeout[, fsleep=system.sleep])</a></td> | ||
161 | <td class="summary">Reads a single byte from the console, with a timeout.</td> | ||
162 | </tr> | 160 | </tr> |
163 | <tr> | 161 | <tr> |
164 | <td class="name" nowrap><a href="#setconsolecp">setconsolecp (cp)</a></td> | 162 | <td class="name" nowrap><a href="#tcgetattr">tcgetattr (fd)</a></td> |
165 | <td class="summary">Sets the current console code page (Windows).</td> | 163 | <td class="summary">Get termios state (Posix).</td> |
166 | </tr> | 164 | </tr> |
167 | <tr> | 165 | <tr> |
168 | <td class="name" nowrap><a href="#setconsoleflags">setconsoleflags (file, bitflags)</a></td> | 166 | <td class="name" nowrap><a href="#tcsetattr">tcsetattr (fd, actions, termios)</a></td> |
169 | <td class="summary">Sets the console flags (Windows).</td> | 167 | <td class="summary">Set termios state (Posix).</td> |
170 | </tr> | 168 | </tr> |
169 | </table> | ||
170 | <h2><a href="#Terminal_Input">Terminal_Input</a></h2> | ||
171 | <table class="function_list"> | ||
171 | <tr> | 172 | <tr> |
172 | <td class="name" nowrap><a href="#setconsoleoutputcp">setconsoleoutputcp (cp)</a></td> | 173 | <td class="name" nowrap><a href="#_readkey">_readkey ()</a></td> |
173 | <td class="summary">Sets the current console output code page (Windows).</td> | 174 | <td class="summary">Reads a key from the console non-blocking.</td> |
174 | </tr> | 175 | </tr> |
175 | <tr> | 176 | <tr> |
176 | <td class="name" nowrap><a href="#setnonblock">setnonblock (fd, make_non_block)</a></td> | 177 | <td class="name" nowrap><a href="#readansi">readansi (timeout[, fsleep=system.sleep])</a></td> |
177 | <td class="summary">Enables or disables non-blocking mode for a file (Posix).</td> | 178 | <td class="summary">Reads a single key, if it is the start of ansi escape sequence then it reads |
179 | the full sequence.</td> | ||
178 | </tr> | 180 | </tr> |
179 | <tr> | 181 | <tr> |
180 | <td class="name" nowrap><a href="#tcgetattr">tcgetattr (fd)</a></td> | 182 | <td class="name" nowrap><a href="#readkey">readkey (timeout[, fsleep=system.sleep])</a></td> |
181 | <td class="summary">Get termios state (Posix).</td> | 183 | <td class="summary">Reads a single byte from the console, with a timeout.</td> |
182 | </tr> | 184 | </tr> |
185 | </table> | ||
186 | <h2><a href="#Terminal_UTF_8">Terminal_UTF-8</a></h2> | ||
187 | <table class="function_list"> | ||
183 | <tr> | 188 | <tr> |
184 | <td class="name" nowrap><a href="#tcsetattr">tcsetattr (fd, actions, termios)</a></td> | 189 | <td class="name" nowrap><a href="#CODEPAGE_UTF8">CODEPAGE_UTF8</a></td> |
185 | <td class="summary">Set termios state (Posix).</td> | 190 | <td class="summary">UTF8 codepage.</td> |
186 | </tr> | 191 | </tr> |
187 | <tr> | 192 | <tr> |
188 | <td class="name" nowrap><a href="#termbackup">termbackup ()</a></td> | 193 | <td class="name" nowrap><a href="#getconsolecp">getconsolecp ()</a></td> |
189 | <td class="summary">Returns a backup of terminal settings for stdin/out/err.</td> | 194 | <td class="summary">Gets the current console code page (Windows).</td> |
190 | </tr> | 195 | </tr> |
191 | <tr> | 196 | <tr> |
192 | <td class="name" nowrap><a href="#termrestore">termrestore (backup)</a></td> | 197 | <td class="name" nowrap><a href="#getconsoleoutputcp">getconsoleoutputcp ()</a></td> |
193 | <td class="summary">Restores terminal settings from a backup</td> | 198 | <td class="summary">Gets the current console output code page (Windows).</td> |
194 | </tr> | 199 | </tr> |
195 | <tr> | 200 | <tr> |
196 | <td class="name" nowrap><a href="#termsize">termsize ()</a></td> | 201 | <td class="name" nowrap><a href="#setconsolecp">setconsolecp (cp)</a></td> |
197 | <td class="summary">Get the size of the terminal in rows and columns.</td> | 202 | <td class="summary">Sets the current console code page (Windows).</td> |
198 | </tr> | 203 | </tr> |
199 | <tr> | 204 | <tr> |
200 | <td class="name" nowrap><a href="#termwrap">termwrap (f)</a></td> | 205 | <td class="name" nowrap><a href="#setconsoleoutputcp">setconsoleoutputcp (cp)</a></td> |
201 | <td class="summary">Wraps a function to automatically restore terminal settings upon returning.</td> | 206 | <td class="summary">Sets the current console output code page (Windows).</td> |
202 | </tr> | 207 | </tr> |
203 | <tr> | 208 | <tr> |
204 | <td class="name" nowrap><a href="#utf8cwidth">utf8cwidth (utf8_char)</a></td> | 209 | <td class="name" nowrap><a href="#utf8cwidth">utf8cwidth (utf8_char)</a></td> |
@@ -224,6 +229,25 @@ | |||
224 | <td class="summary">Sleep without a busy loop.</td> | 229 | <td class="summary">Sleep without a busy loop.</td> |
225 | </tr> | 230 | </tr> |
226 | </table> | 231 | </table> |
232 | <h2><a href="#Terminal_Backup">Terminal_Backup</a></h2> | ||
233 | <table class="function_list"> | ||
234 | <tr> | ||
235 | <td class="name" nowrap><a href="#autotermrestore">autotermrestore ()</a></td> | ||
236 | <td class="summary">Backs up terminal settings and restores them on application exit.</td> | ||
237 | </tr> | ||
238 | <tr> | ||
239 | <td class="name" nowrap><a href="#termbackup">termbackup ()</a></td> | ||
240 | <td class="summary">Returns a backup of terminal settings for stdin/out/err.</td> | ||
241 | </tr> | ||
242 | <tr> | ||
243 | <td class="name" nowrap><a href="#termrestore">termrestore (backup)</a></td> | ||
244 | <td class="summary">Restores terminal settings from a backup</td> | ||
245 | </tr> | ||
246 | <tr> | ||
247 | <td class="name" nowrap><a href="#termwrap">termwrap (f)</a></td> | ||
248 | <td class="summary">Wraps a function to automatically restore terminal settings upon returning.</td> | ||
249 | </tr> | ||
250 | </table> | ||
227 | 251 | ||
228 | <br/> | 252 | <br/> |
229 | <br/> | 253 | <br/> |
@@ -399,95 +423,66 @@ requested number of bytes, or an error, never a partial result. | |||
399 | </div> | 423 | </div> |
400 | <dl class="function"> | 424 | <dl class="function"> |
401 | <dt> | 425 | <dt> |
402 | <a name = "CODEPAGE_UTF8"></a> | 426 | <a name = "isatty"></a> |
403 | <strong>CODEPAGE_UTF8</strong> | 427 | <strong>isatty (file)</strong> |
404 | </dt> | 428 | </dt> |
405 | <dd> | 429 | <dd> |
406 | UTF8 codepage. | 430 | Checks if a file-handle is a TTY. |
407 | To be used with <a href="../modules/system.html#setconsoleoutputcp">system.setconsoleoutputcp</a> and <a href="../modules/system.html#setconsolecp">system.setconsolecp</a>. | ||
408 | 431 | ||
409 | 432 | ||
433 | <h3>Parameters:</h3> | ||
410 | <ul> | 434 | <ul> |
411 | <li><span class="parameter">CODEPAGE_UTF8</span> | 435 | <li><span class="parameter">file</span> |
412 | The Windows CodePage for UTF8. | 436 | <span class="types"><span class="type">file</span></span> |
437 | 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>. | ||
413 | </li> | 438 | </li> |
414 | </ul> | 439 | </ul> |
415 | 440 | ||
416 | |||
417 | |||
418 | |||
419 | |||
420 | </dd> | ||
421 | <dt> | ||
422 | <a name = "_readkey"></a> | ||
423 | <strong>_readkey ()</strong> | ||
424 | </dt> | ||
425 | <dd> | ||
426 | Reads a key from the console non-blocking. This function should not be called | ||
427 | 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 | ||
428 | will return the next byte from the input stream, or <code>nil</code> if no key was pressed.</p> | ||
429 | |||
430 | <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> | ||
431 | and canonical mode must be turned off using <a href="../modules/system.html#tcsetattr">tcsetattr</a>, | ||
432 | before calling this function. Otherwise it will block. No conversions are | ||
433 | done on Posix, so the byte read is returned as-is.</p> | ||
434 | |||
435 | <p>On Windows this reads a wide character and converts it to UTF-8. Multi-byte | ||
436 | sequences will be buffered internally and returned one byte at a time. | ||
437 | |||
438 | |||
439 | |||
440 | <h3>Returns:</h3> | 441 | <h3>Returns:</h3> |
441 | <ol> | 442 | <ol> |
442 | 443 | ||
443 | <span class="types"><span class="type">integer</span></span> | 444 | <span class="types"><span class="type">boolean</span></span> |
444 | the byte read from the input stream | 445 | true if the file is a tty |
445 | </ol> | ||
446 | <h3>Or</h3> | ||
447 | <ol> | ||
448 | |||
449 | <span class="types"><span class="type">nil</span></span> | ||
450 | if no key was pressed | ||
451 | </ol> | ||
452 | <h3>Or</h3> | ||
453 | <ol> | ||
454 | <li> | ||
455 | <span class="types"><span class="type">nil</span></span> | ||
456 | on error</li> | ||
457 | <li> | ||
458 | <span class="types"><a class="type" href="https://www.lua.org/manual/5.4/manual.html#6.4">string</a></span> | ||
459 | error message</li> | ||
460 | <li> | ||
461 | <span class="types"><span class="type">int</span></span> | ||
462 | errnum (on posix)</li> | ||
463 | </ol> | 446 | </ol> |
464 | 447 | ||
465 | 448 | ||
466 | 449 | ||
450 | <h3>Usage:</h3> | ||
451 | <ul> | ||
452 | <pre class="example"><span class="keyword">local</span> system = <span class="global">require</span>(<span class="string">'system'</span>) | ||
453 | <span class="keyword">if</span> system.<span class="function-name">isatty</span>(<span class="global">io</span>.stdin) <span class="keyword">then</span> | ||
454 | <span class="comment">-- enable ANSI coloring etc on Windows, does nothing in Posix. | ||
455 | </span> <span class="keyword">local</span> flags = system.<span class="function-name">getconsoleflags</span>(<span class="global">io</span>.stdout) | ||
456 | system.<span class="function-name">setconsoleflags</span>(<span class="global">io</span>.stdout, flags + sys.COF_VIRTUAL_TERMINAL_PROCESSING) | ||
457 | <span class="keyword">end</span></pre> | ||
458 | </ul> | ||
467 | 459 | ||
468 | </dd> | 460 | </dd> |
469 | <dt> | 461 | <dt> |
470 | <a name = "autotermrestore"></a> | 462 | <a name = "termsize"></a> |
471 | <strong>autotermrestore ()</strong> | 463 | <strong>termsize ()</strong> |
472 | </dt> | 464 | </dt> |
473 | <dd> | 465 | <dd> |
474 | Backs up terminal settings and restores them on application exit. | 466 | Get the size of the terminal in rows and columns. |
475 | Calls <a href="../modules/system.html#termbackup">termbackup</a> to back up terminal settings and sets up a GC method to | ||
476 | automatically restore them on application exit (also works on Lua 5.1). | ||
477 | 467 | ||
478 | 468 | ||
479 | 469 | ||
480 | <h3>Returns:</h3> | 470 | <h3>Returns:</h3> |
481 | <ol> | 471 | <ol> |
482 | 472 | <li> | |
483 | <span class="types"><span class="type">boolean</span></span> | 473 | <span class="types"><span class="type">int</span></span> |
484 | true | 474 | the number of rows</li> |
475 | <li> | ||
476 | <span class="types"><span class="type">int</span></span> | ||
477 | the number of columns</li> | ||
485 | </ol> | 478 | </ol> |
486 | <h3>Or</h3> | 479 | <h3>Or</h3> |
487 | <ol> | 480 | <ol> |
488 | <li> | 481 | <li> |
489 | <span class="types"><span class="type">nil</span></span> | 482 | <span class="types"><span class="type">nil</span></span> |
490 | if the backup was already created</li> | 483 | |
484 | |||
485 | </li> | ||
491 | <li> | 486 | <li> |
492 | <span class="types"><a class="type" href="https://www.lua.org/manual/5.4/manual.html#6.4">string</a></span> | 487 | <span class="types"><a class="type" href="https://www.lua.org/manual/5.4/manual.html#6.4">string</a></span> |
493 | error message</li> | 488 | error message</li> |
@@ -497,26 +492,10 @@ sequences will be buffered internally and returned one byte at a time. | |||
497 | 492 | ||
498 | 493 | ||
499 | </dd> | 494 | </dd> |
500 | <dt> | 495 | </dl> |
501 | <a name = "getconsolecp"></a> | 496 | <h2 class="section-header "><a name="Terminal_Windows"></a>Terminal_Windows</h2> |
502 | <strong>getconsolecp ()</strong> | ||
503 | </dt> | ||
504 | <dd> | ||
505 | Gets the current console code page (Windows). | ||
506 | |||
507 | |||
508 | |||
509 | <h3>Returns:</h3> | ||
510 | <ol> | ||
511 | |||
512 | <span class="types"><span class="type">int</span></span> | ||
513 | the current code page (always 65001 on Posix systems) | ||
514 | </ol> | ||
515 | |||
516 | |||
517 | |||
518 | 497 | ||
519 | </dd> | 498 | <dl class="function"> |
520 | <dt> | 499 | <dt> |
521 | <a name = "getconsoleflags"></a> | 500 | <a name = "getconsoleflags"></a> |
522 | <strong>getconsoleflags (file)</strong> | 501 | <strong>getconsoleflags (file)</strong> |
@@ -575,103 +554,6 @@ for more information on the flags. | |||
575 | 554 | ||
576 | </dd> | 555 | </dd> |
577 | <dt> | 556 | <dt> |
578 | <a name = "getconsoleoutputcp"></a> | ||
579 | <strong>getconsoleoutputcp ()</strong> | ||
580 | </dt> | ||
581 | <dd> | ||
582 | Gets the current console output code page (Windows). | ||
583 | |||
584 | |||
585 | |||
586 | <h3>Returns:</h3> | ||
587 | <ol> | ||
588 | |||
589 | <span class="types"><span class="type">int</span></span> | ||
590 | the current code page (always 65001 on Posix systems) | ||
591 | </ol> | ||
592 | |||
593 | |||
594 | |||
595 | |||
596 | </dd> | ||
597 | <dt> | ||
598 | <a name = "getnonblock"></a> | ||
599 | <strong>getnonblock (fd)</strong> | ||
600 | </dt> | ||
601 | <dd> | ||
602 | Gets non-blocking mode status for a file (Posix). | ||
603 | |||
604 | |||
605 | <h3>Parameters:</h3> | ||
606 | <ul> | ||
607 | <li><span class="parameter">fd</span> | ||
608 | <span class="types"><span class="type">file</span></span> | ||
609 | 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> | ||
610 | </li> | ||
611 | </ul> | ||
612 | |||
613 | <h3>Returns:</h3> | ||
614 | <ol> | ||
615 | |||
616 | <span class="types"><span class="type">bool</span></span> | ||
617 | <code>true</code> if set to non-blocking, <code>false</code> if not. Always returns <code>false</code> on Windows. | ||
618 | </ol> | ||
619 | <h3>Or</h3> | ||
620 | <ol> | ||
621 | <li> | ||
622 | <span class="types"><span class="type">nil</span></span> | ||
623 | |||
624 | |||
625 | </li> | ||
626 | <li> | ||
627 | <span class="types"><a class="type" href="https://www.lua.org/manual/5.4/manual.html#6.4">string</a></span> | ||
628 | error message</li> | ||
629 | <li> | ||
630 | <span class="types"><span class="type">int</span></span> | ||
631 | errnum</li> | ||
632 | </ol> | ||
633 | |||
634 | |||
635 | |||
636 | |||
637 | </dd> | ||
638 | <dt> | ||
639 | <a name = "isatty"></a> | ||
640 | <strong>isatty (file)</strong> | ||
641 | </dt> | ||
642 | <dd> | ||
643 | Checks if a file-handle is a TTY. | ||
644 | |||
645 | |||
646 | <h3>Parameters:</h3> | ||
647 | <ul> | ||
648 | <li><span class="parameter">file</span> | ||
649 | <span class="types"><span class="type">file</span></span> | ||
650 | 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>. | ||
651 | </li> | ||
652 | </ul> | ||
653 | |||
654 | <h3>Returns:</h3> | ||
655 | <ol> | ||
656 | |||
657 | <span class="types"><span class="type">boolean</span></span> | ||
658 | true if the file is a tty | ||
659 | </ol> | ||
660 | |||
661 | |||
662 | |||
663 | <h3>Usage:</h3> | ||
664 | <ul> | ||
665 | <pre class="example"><span class="keyword">local</span> system = <span class="global">require</span>(<span class="string">'system'</span>) | ||
666 | <span class="keyword">if</span> system.<span class="function-name">isatty</span>(<span class="global">io</span>.stdin) <span class="keyword">then</span> | ||
667 | <span class="comment">-- enable ANSI coloring etc on Windows, does nothing in Posix. | ||
668 | </span> <span class="keyword">local</span> flags = system.<span class="function-name">getconsoleflags</span>(<span class="global">io</span>.stdout) | ||
669 | system.<span class="function-name">setconsoleflags</span>(<span class="global">io</span>.stdout, flags + sys.COF_VIRTUAL_TERMINAL_PROCESSING) | ||
670 | <span class="keyword">end</span></pre> | ||
671 | </ul> | ||
672 | |||
673 | </dd> | ||
674 | <dt> | ||
675 | <a name = "listconsoleflags"></a> | 557 | <a name = "listconsoleflags"></a> |
676 | <strong>listconsoleflags (fh)</strong> | 558 | <strong>listconsoleflags (fh)</strong> |
677 | </dt> | 559 | </dt> |
@@ -700,192 +582,125 @@ system.<span class="function-name">listconsoleflags</span>(<span class="global"> | |||
700 | 582 | ||
701 | </dd> | 583 | </dd> |
702 | <dt> | 584 | <dt> |
703 | <a name = "listtermflags"></a> | 585 | <a name = "setconsoleflags"></a> |
704 | <strong>listtermflags (fh)</strong> | 586 | <strong>setconsoleflags (file, bitflags)</strong> |
705 | </dt> | 587 | </dt> |
706 | <dd> | 588 | <dd> |
707 | Debug function for terminal flags (Posix). | 589 | Sets the console flags (Windows). |
708 | Pretty prints the current flags set for the handle. | 590 | The <code>CIF_</code> and <code>COF_</code> constants are available on the module table. Where <code>CIF</code> are the |
709 | 591 | 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 | |
710 | 592 | <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> | |
711 | <h3>Parameters:</h3> | ||
712 | <ul> | ||
713 | <li><span class="parameter">fh</span> | ||
714 | 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>) | ||
715 | </li> | ||
716 | </ul> | ||
717 | |||
718 | |||
719 | |||
720 | 593 | ||
721 | <h3>Usage:</h3> | 594 | <p>To see flag status and constant names check <a href="../modules/system.html#listconsoleflags">listconsoleflags</a>.</p> |
722 | <ul> | ||
723 | <pre class="example"><span class="comment">-- Print the flags for stdin/out/err | ||
724 | </span>system.<span class="function-name">listconsoleflags</span>(<span class="global">io</span>.stdin) | ||
725 | system.<span class="function-name">listconsoleflags</span>(<span class="global">io</span>.stdout) | ||
726 | system.<span class="function-name">listconsoleflags</span>(<span class="global">io</span>.stderr)</pre> | ||
727 | </ul> | ||
728 | 595 | ||
729 | </dd> | 596 | <p>Note: not all combinations of flags are allowed, as some are mutually exclusive or mutually required. |
730 | <dt> | 597 | See <a href="https://learn.microsoft.com/en-us/windows/console/setconsolemode">setconsolemode documentation</a> |
731 | <a name = "readansi"></a> | ||
732 | <strong>readansi (timeout[, fsleep=system.sleep])</strong> | ||
733 | </dt> | ||
734 | <dd> | ||
735 | Reads a single key, if it is the start of ansi escape sequence then it reads | ||
736 | the full sequence. The key can be a multi-byte string in case of multibyte UTF-8 character. | ||
737 | This function uses <a href="../modules/system.html#readkey">system.readkey</a>, and hence <code>fsleep</code> to wait until either a key is | ||
738 | available or the timeout is reached. | ||
739 | It returns immediately if a key is available or if <code>timeout</code> is less than or equal to <code>0</code>. | ||
740 | In case of an ANSI sequence, it will return the full sequence as a string. | ||
741 | 598 | ||
742 | 599 | ||
743 | <h3>Parameters:</h3> | 600 | <h3>Parameters:</h3> |
744 | <ul> | 601 | <ul> |
745 | <li><span class="parameter">timeout</span> | 602 | <li><span class="parameter">file</span> |
746 | <span class="types"><span class="type">number</span></span> | 603 | <span class="types"><span class="type">file</span></span> |
747 | the timeout in seconds. | 604 | 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> |
748 | </li> | 605 | </li> |
749 | <li><span class="parameter">fsleep</span> | 606 | <li><span class="parameter">bitflags</span> |
750 | <span class="types"><span class="type">function</span></span> | 607 | <span class="types"><a class="type" href="../classes/bitflags.html#">bitflags</a></span> |
751 | the function to call for sleeping. | 608 | the flags to set/unset |
752 | (<em>default</em> system.sleep) | ||
753 | </li> | 609 | </li> |
754 | </ul> | 610 | </ul> |
755 | 611 | ||
756 | <h3>Returns:</h3> | 612 | <h3>Returns:</h3> |
757 | <ol> | 613 | <ol> |
758 | <li> | 614 | |
759 | <span class="types"><a class="type" href="https://www.lua.org/manual/5.4/manual.html#6.4">string</a></span> | 615 | <span class="types"><span class="type">boolean</span></span> |
760 | the character that was received (can be multi-byte), or a complete ANSI sequence</li> | 616 | <code>true</code> on success |
761 | <li> | ||
762 | <span class="types"><a class="type" href="https://www.lua.org/manual/5.4/manual.html#6.4">string</a></span> | ||
763 | the type of input: <code>"char"</code> for a single key, <code>"ansi"</code> for an ANSI sequence</li> | ||
764 | </ol> | 617 | </ol> |
765 | <h3>Or</h3> | 618 | <h3>Or</h3> |
766 | <ol> | 619 | <ol> |
767 | <li> | 620 | <li> |
768 | <span class="types"><span class="type">nil</span></span> | 621 | <span class="types"><span class="type">nil</span></span> |
769 | in case of an error</li> | 622 | |
770 | <li> | 623 | |
771 | <span class="types"><a class="type" href="https://www.lua.org/manual/5.4/manual.html#6.4">string</a></span> | 624 | </li> |
772 | error message; <code>"timeout"</code> if the timeout was reached.</li> | ||
773 | <li> | 625 | <li> |
774 | <span class="types"><a class="type" href="https://www.lua.org/manual/5.4/manual.html#6.4">string</a></span> | 626 | <span class="types"><a class="type" href="https://www.lua.org/manual/5.4/manual.html#6.4">string</a></span> |
775 | partial result in case of an error while reading a sequence, the sequence so far.</li> | 627 | error message</li> |
776 | </ol> | 628 | </ol> |
777 | 629 | ||
778 | 630 | ||
779 | 631 | ||
632 | <h3>Usage:</h3> | ||
633 | <ul> | ||
634 | <pre class="example"><span class="keyword">local</span> system = <span class="global">require</span>(<span class="string">'system'</span>) | ||
635 | 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 | ||
636 | </span> | ||
637 | <span class="keyword">local</span> flags = system.<span class="function-name">getconsoleflags</span>(<span class="global">io</span>.stdout) | ||
638 | <span class="global">assert</span>(system.<span class="function-name">setconsoleflags</span>(<span class="global">io</span>.stdout, | ||
639 | flags + system.COF_VIRTUAL_TERMINAL_PROCESSING) | ||
640 | |||
641 | system.<span class="function-name">listconsoleflags</span>(<span class="global">io</span>.stdout) <span class="comment">-- List again to check the differences</span></pre> | ||
642 | </ul> | ||
780 | 643 | ||
781 | </dd> | 644 | </dd> |
645 | </dl> | ||
646 | <h2 class="section-header "><a name="Terminal_Posix"></a>Terminal_Posix</h2> | ||
647 | |||
648 | <dl class="function"> | ||
782 | <dt> | 649 | <dt> |
783 | <a name = "readkey"></a> | 650 | <a name = "detachfds"></a> |
784 | <strong>readkey (timeout[, fsleep=system.sleep])</strong> | 651 | <strong>detachfds ()</strong> |
785 | </dt> | 652 | </dt> |
786 | <dd> | 653 | <dd> |
787 | Reads a single byte from the console, with a timeout. | 654 | Creates new file descriptions for <code>stdout</code> and <code>stderr</code>. |
788 | This function uses <code>fsleep</code> to wait until either a byte is available or the timeout is reached. | 655 | Even if the file descriptors are unique, they still might point to the same |
789 | The sleep period is exponentially backing off, starting at 0.0125 seconds, with a maximum of 0.2 seconds. | 656 | file description, and hence share settings like <code>O_NONBLOCK</code>. This means that |
790 | It returns immediately if a byte is available or if <code>timeout</code> is less than or equal to <code>0</code>.</p> | 657 | if one of them is set to non-blocking, the other will be as well. This can |
658 | lead to unexpected behavior.</p> | ||
791 | 659 | ||
792 | <p> Using <a href="../modules/system.html#readansi">system.readansi</a> is preferred over this function. Since this function can leave stray/invalid | 660 | <p>This function is used to detach <code>stdout</code> and <code>stderr</code> from the original |
793 | byte-sequences in the input buffer, while <a href="../modules/system.html#readansi">system.readansi</a> reads full ANSI and UTF8 sequences. | 661 | file descriptions, and create new file descriptions for them. This allows |
662 | independent control of flags (e.g., <code>O_NONBLOCK</code>) on <code>stdout</code> and <code>stderr</code>, | ||
663 | avoiding shared side effects.</p> | ||
664 | |||
665 | <p>Does not modify <code>stdin</code> (fd 0), and does nothing on Windows. | ||
794 | 666 | ||
795 | 667 | ||
796 | <h3>Parameters:</h3> | ||
797 | <ul> | ||
798 | <li><span class="parameter">timeout</span> | ||
799 | <span class="types"><span class="type">number</span></span> | ||
800 | the timeout in seconds. | ||
801 | </li> | ||
802 | <li><span class="parameter">fsleep</span> | ||
803 | <span class="types"><span class="type">function</span></span> | ||
804 | the function to call for sleeping. | ||
805 | (<em>default</em> system.sleep) | ||
806 | </li> | ||
807 | </ul> | ||
808 | 668 | ||
809 | <h3>Returns:</h3> | 669 | <h3>Returns:</h3> |
810 | <ol> | 670 | <ol> |
811 | 671 | ||
812 | <span class="types"><span class="type">byte</span></span> | 672 | boolean <code>true</code> on success, or throws an error on failure. |
813 | the byte value that was read. | ||
814 | </ol> | 673 | </ol> |
815 | <h3>Or</h3> | ||
816 | <ol> | ||
817 | <li> | ||
818 | <span class="types"><span class="type">nil</span></span> | ||
819 | if no key was read</li> | ||
820 | <li> | ||
821 | <span class="types"><a class="type" href="https://www.lua.org/manual/5.4/manual.html#6.4">string</a></span> | ||
822 | error message; <code>"timeout"</code> if the timeout was reached.</li> | ||
823 | </ol> | ||
824 | |||
825 | 674 | ||
826 | 675 | ||
827 | 676 | <h3>See also:</h3> | |
828 | </dd> | ||
829 | <dt> | ||
830 | <a name = "setconsolecp"></a> | ||
831 | <strong>setconsolecp (cp)</strong> | ||
832 | </dt> | ||
833 | <dd> | ||
834 | Sets the current console code page (Windows). | ||
835 | |||
836 | |||
837 | <h3>Parameters:</h3> | ||
838 | <ul> | 677 | <ul> |
839 | <li><span class="parameter">cp</span> | 678 | <a href="../modules/system.html#setnonblock">setnonblock</a> |
840 | <span class="types"><span class="type">int</span></span> | ||
841 | the code page to set, use <a href="../modules/system.html#CODEPAGE_UTF8">system.CODEPAGE_UTF8</a> (65001) for UTF-8 | ||
842 | </li> | ||
843 | </ul> | 679 | </ul> |
844 | 680 | ||
845 | <h3>Returns:</h3> | ||
846 | <ol> | ||
847 | |||
848 | <span class="types"><span class="type">bool</span></span> | ||
849 | <code>true</code> on success (always <code>true</code> on Posix systems) | ||
850 | </ol> | ||
851 | |||
852 | |||
853 | |||
854 | 681 | ||
855 | </dd> | 682 | </dd> |
856 | <dt> | 683 | <dt> |
857 | <a name = "setconsoleflags"></a> | 684 | <a name = "getnonblock"></a> |
858 | <strong>setconsoleflags (file, bitflags)</strong> | 685 | <strong>getnonblock (fd)</strong> |
859 | </dt> | 686 | </dt> |
860 | <dd> | 687 | <dd> |
861 | Sets the console flags (Windows). | 688 | Gets non-blocking mode status for a file (Posix). |
862 | The <code>CIF_</code> and <code>COF_</code> constants are available on the module table. Where <code>CIF</code> are the | ||
863 | 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 | ||
864 | <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> | ||
865 | |||
866 | <p>To see flag status and constant names check <a href="../modules/system.html#listconsoleflags">listconsoleflags</a>.</p> | ||
867 | |||
868 | <p>Note: not all combinations of flags are allowed, as some are mutually exclusive or mutually required. | ||
869 | See <a href="https://learn.microsoft.com/en-us/windows/console/setconsolemode">setconsolemode documentation</a> | ||
870 | 689 | ||
871 | 690 | ||
872 | <h3>Parameters:</h3> | 691 | <h3>Parameters:</h3> |
873 | <ul> | 692 | <ul> |
874 | <li><span class="parameter">file</span> | 693 | <li><span class="parameter">fd</span> |
875 | <span class="types"><span class="type">file</span></span> | 694 | <span class="types"><span class="type">file</span></span> |
876 | 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> | 695 | 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> |
877 | </li> | 696 | </li> |
878 | <li><span class="parameter">bitflags</span> | ||
879 | <span class="types"><a class="type" href="../classes/bitflags.html#">bitflags</a></span> | ||
880 | the flags to set/unset | ||
881 | </li> | ||
882 | </ul> | 697 | </ul> |
883 | 698 | ||
884 | <h3>Returns:</h3> | 699 | <h3>Returns:</h3> |
885 | <ol> | 700 | <ol> |
886 | 701 | ||
887 | <span class="types"><span class="type">boolean</span></span> | 702 | <span class="types"><span class="type">bool</span></span> |
888 | <code>true</code> on success | 703 | <code>true</code> if set to non-blocking, <code>false</code> if not. Always returns <code>false</code> on Windows. |
889 | </ol> | 704 | </ol> |
890 | <h3>Or</h3> | 705 | <h3>Or</h3> |
891 | <ol> | 706 | <ol> |
@@ -897,48 +712,45 @@ See <a href="https://learn.microsoft.com/en-us/windows/console/setconsolemode">s | |||
897 | <li> | 712 | <li> |
898 | <span class="types"><a class="type" href="https://www.lua.org/manual/5.4/manual.html#6.4">string</a></span> | 713 | <span class="types"><a class="type" href="https://www.lua.org/manual/5.4/manual.html#6.4">string</a></span> |
899 | error message</li> | 714 | error message</li> |
715 | <li> | ||
716 | <span class="types"><span class="type">int</span></span> | ||
717 | errnum</li> | ||
900 | </ol> | 718 | </ol> |
901 | 719 | ||
902 | 720 | ||
903 | 721 | <h3>See also:</h3> | |
904 | <h3>Usage:</h3> | ||
905 | <ul> | 722 | <ul> |
906 | <pre class="example"><span class="keyword">local</span> system = <span class="global">require</span>(<span class="string">'system'</span>) | 723 | <a href="../modules/system.html#setnonblock">setnonblock</a> |
907 | 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 | ||
908 | </span> | ||
909 | <span class="keyword">local</span> flags = system.<span class="function-name">getconsoleflags</span>(<span class="global">io</span>.stdout) | ||
910 | <span class="global">assert</span>(system.<span class="function-name">setconsoleflags</span>(<span class="global">io</span>.stdout, | ||
911 | flags + system.COF_VIRTUAL_TERMINAL_PROCESSING) | ||
912 | |||
913 | system.<span class="function-name">listconsoleflags</span>(<span class="global">io</span>.stdout) <span class="comment">-- List again to check the differences</span></pre> | ||
914 | </ul> | 724 | </ul> |
915 | 725 | ||
726 | |||
916 | </dd> | 727 | </dd> |
917 | <dt> | 728 | <dt> |
918 | <a name = "setconsoleoutputcp"></a> | 729 | <a name = "listtermflags"></a> |
919 | <strong>setconsoleoutputcp (cp)</strong> | 730 | <strong>listtermflags (fh)</strong> |
920 | </dt> | 731 | </dt> |
921 | <dd> | 732 | <dd> |
922 | Sets the current console output code page (Windows). | 733 | Debug function for terminal flags (Posix). |
734 | Pretty prints the current flags set for the handle. | ||
923 | 735 | ||
924 | 736 | ||
925 | <h3>Parameters:</h3> | 737 | <h3>Parameters:</h3> |
926 | <ul> | 738 | <ul> |
927 | <li><span class="parameter">cp</span> | 739 | <li><span class="parameter">fh</span> |
928 | <span class="types"><span class="type">int</span></span> | 740 | 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>) |
929 | the code page to set, use <a href="../modules/system.html#CODEPAGE_UTF8">system.CODEPAGE_UTF8</a> (65001) for UTF-8 | ||
930 | </li> | 741 | </li> |
931 | </ul> | 742 | </ul> |
932 | 743 | ||
933 | <h3>Returns:</h3> | ||
934 | <ol> | ||
935 | |||
936 | <span class="types"><span class="type">bool</span></span> | ||
937 | <code>true</code> on success (always <code>true</code> on Posix systems) | ||
938 | </ol> | ||
939 | 744 | ||
940 | 745 | ||
941 | 746 | ||
747 | <h3>Usage:</h3> | ||
748 | <ul> | ||
749 | <pre class="example"><span class="comment">-- Print the flags for stdin/out/err | ||
750 | </span>system.<span class="function-name">listconsoleflags</span>(<span class="global">io</span>.stdin) | ||
751 | system.<span class="function-name">listconsoleflags</span>(<span class="global">io</span>.stdout) | ||
752 | system.<span class="function-name">listconsoleflags</span>(<span class="global">io</span>.stderr)</pre> | ||
753 | </ul> | ||
942 | 754 | ||
943 | </dd> | 755 | </dd> |
944 | <dt> | 756 | <dt> |
@@ -947,6 +759,7 @@ system.<span class="function-name">listconsoleflags</span>(<span class="global"> | |||
947 | </dt> | 759 | </dt> |
948 | <dd> | 760 | <dd> |
949 | Enables or disables non-blocking mode for a file (Posix). | 761 | Enables or disables non-blocking mode for a file (Posix). |
762 | Check <a href="../modules/system.html#detachfds">detachfds</a> in case there are shared file descriptions. | ||
950 | 763 | ||
951 | 764 | ||
952 | <h3>Parameters:</h3> | 765 | <h3>Parameters:</h3> |
@@ -985,13 +798,15 @@ system.<span class="function-name">listconsoleflags</span>(<span class="global"> | |||
985 | 798 | ||
986 | <h3>See also:</h3> | 799 | <h3>See also:</h3> |
987 | <ul> | 800 | <ul> |
988 | <a href="../modules/system.html#getnonblock">getnonblock</a> | 801 | <li><a href="../modules/system.html#getnonblock">getnonblock</a></li> |
802 | <li><a href="../modules/system.html#detachfds">detachfds</a></li> | ||
989 | </ul> | 803 | </ul> |
990 | 804 | ||
991 | <h3>Usage:</h3> | 805 | <h3>Usage:</h3> |
992 | <ul> | 806 | <ul> |
993 | <pre class="example"><span class="keyword">local</span> sys = <span class="global">require</span>(<span class="string">'system'</span>) | 807 | <pre class="example"><span class="keyword">local</span> sys = <span class="global">require</span>(<span class="string">'system'</span>) |
994 | 808 | sys.<span class="function-name">detachfds</span>() <span class="comment">-- detach stdout and stderr, so only stdin becomes non-blocking | |
809 | </span> | ||
995 | <span class="comment">-- set io.stdin to non-blocking mode | 810 | <span class="comment">-- set io.stdin to non-blocking mode |
996 | </span><span class="keyword">local</span> old_setting = sys.<span class="function-name">getnonblock</span>(<span class="global">io</span>.stdin) | 811 | </span><span class="keyword">local</span> old_setting = sys.<span class="function-name">getnonblock</span>(<span class="global">io</span>.stdin) |
997 | sys.<span class="function-name">setnonblock</span>(<span class="global">io</span>.stdin, <span class="keyword">true</span>) | 812 | sys.<span class="function-name">setnonblock</span>(<span class="global">io</span>.stdin, <span class="keyword">true</span>) |
@@ -1151,21 +966,52 @@ flags for the <code>iflags</code>, <code>oflags</code>, and <code>lflags</code> | |||
1151 | </ul> | 966 | </ul> |
1152 | 967 | ||
1153 | </dd> | 968 | </dd> |
969 | </dl> | ||
970 | <h2 class="section-header "><a name="Terminal_Input"></a>Terminal_Input</h2> | ||
971 | |||
972 | <dl class="function"> | ||
1154 | <dt> | 973 | <dt> |
1155 | <a name = "termbackup"></a> | 974 | <a name = "_readkey"></a> |
1156 | <strong>termbackup ()</strong> | 975 | <strong>_readkey ()</strong> |
1157 | </dt> | 976 | </dt> |
1158 | <dd> | 977 | <dd> |
1159 | Returns a backup of terminal settings for stdin/out/err. | 978 | Reads a key from the console non-blocking. This function should not be called |
1160 | Handles terminal/console flags, Windows codepage, and non-block flags on the streams. | 979 | 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 |
1161 | Backs up terminal/console flags only if a stream is a tty. | 980 | will return the next byte from the input stream, or <code>nil</code> if no key was pressed.</p> |
981 | |||
982 | <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> | ||
983 | and canonical mode must be turned off using <a href="../modules/system.html#tcsetattr">tcsetattr</a>, | ||
984 | before calling this function. Otherwise it will block. No conversions are | ||
985 | done on Posix, so the byte read is returned as-is.</p> | ||
986 | |||
987 | <p>On Windows this reads a wide character and converts it to UTF-8. Multi-byte | ||
988 | sequences will be buffered internally and returned one byte at a time. | ||
1162 | 989 | ||
1163 | 990 | ||
1164 | 991 | ||
1165 | <h3>Returns:</h3> | 992 | <h3>Returns:</h3> |
1166 | <ol> | 993 | <ol> |
1167 | 994 | ||
1168 | table with backup of terminal settings | 995 | <span class="types"><span class="type">integer</span></span> |
996 | the byte read from the input stream | ||
997 | </ol> | ||
998 | <h3>Or</h3> | ||
999 | <ol> | ||
1000 | |||
1001 | <span class="types"><span class="type">nil</span></span> | ||
1002 | if no key was pressed | ||
1003 | </ol> | ||
1004 | <h3>Or</h3> | ||
1005 | <ol> | ||
1006 | <li> | ||
1007 | <span class="types"><span class="type">nil</span></span> | ||
1008 | on error</li> | ||
1009 | <li> | ||
1010 | <span class="types"><a class="type" href="https://www.lua.org/manual/5.4/manual.html#6.4">string</a></span> | ||
1011 | error message</li> | ||
1012 | <li> | ||
1013 | <span class="types"><span class="type">int</span></span> | ||
1014 | errnum (on posix)</li> | ||
1169 | </ol> | 1015 | </ol> |
1170 | 1016 | ||
1171 | 1017 | ||
@@ -1173,60 +1019,153 @@ flags for the <code>iflags</code>, <code>oflags</code>, and <code>lflags</code> | |||
1173 | 1019 | ||
1174 | </dd> | 1020 | </dd> |
1175 | <dt> | 1021 | <dt> |
1176 | <a name = "termrestore"></a> | 1022 | <a name = "readansi"></a> |
1177 | <strong>termrestore (backup)</strong> | 1023 | <strong>readansi (timeout[, fsleep=system.sleep])</strong> |
1178 | </dt> | 1024 | </dt> |
1179 | <dd> | 1025 | <dd> |
1180 | Restores terminal settings from a backup | 1026 | Reads a single key, if it is the start of ansi escape sequence then it reads |
1027 | the full sequence. The key can be a multi-byte string in case of multibyte UTF-8 character. | ||
1028 | This function uses <a href="../modules/system.html#readkey">system.readkey</a>, and hence <code>fsleep</code> to wait until either a key is | ||
1029 | available or the timeout is reached. | ||
1030 | It returns immediately if a key is available or if <code>timeout</code> is less than or equal to <code>0</code>. | ||
1031 | In case of an ANSI sequence, it will return the full sequence as a string. | ||
1181 | 1032 | ||
1182 | 1033 | ||
1183 | <h3>Parameters:</h3> | 1034 | <h3>Parameters:</h3> |
1184 | <ul> | 1035 | <ul> |
1185 | <li><span class="parameter">backup</span> | 1036 | <li><span class="parameter">timeout</span> |
1186 | <span class="types"><a class="type" href="https://www.lua.org/manual/5.4/manual.html#6.6">table</a></span> | 1037 | <span class="types"><span class="type">number</span></span> |
1187 | the backup of terminal settings, see <a href="../modules/system.html#termbackup">termbackup</a>. | 1038 | the timeout in seconds. |
1039 | </li> | ||
1040 | <li><span class="parameter">fsleep</span> | ||
1041 | <span class="types"><span class="type">function</span></span> | ||
1042 | the function to call for sleeping. | ||
1043 | (<em>default</em> system.sleep) | ||
1188 | </li> | 1044 | </li> |
1189 | </ul> | 1045 | </ul> |
1190 | 1046 | ||
1191 | <h3>Returns:</h3> | 1047 | <h3>Returns:</h3> |
1192 | <ol> | 1048 | <ol> |
1193 | 1049 | <li> | |
1194 | <span class="types"><span class="type">boolean</span></span> | 1050 | <span class="types"><a class="type" href="https://www.lua.org/manual/5.4/manual.html#6.4">string</a></span> |
1195 | true | 1051 | the character that was received (can be multi-byte), or a complete ANSI sequence</li> |
1052 | <li> | ||
1053 | <span class="types"><a class="type" href="https://www.lua.org/manual/5.4/manual.html#6.4">string</a></span> | ||
1054 | the type of input: <code>"ctrl"</code> for 0-31 and 127 bytes, <code>"char"</code> for other UTF-8 characters, <code>"ansi"</code> for an ANSI sequence</li> | ||
1055 | </ol> | ||
1056 | <h3>Or</h3> | ||
1057 | <ol> | ||
1058 | <li> | ||
1059 | <span class="types"><span class="type">nil</span></span> | ||
1060 | in case of an error</li> | ||
1061 | <li> | ||
1062 | <span class="types"><a class="type" href="https://www.lua.org/manual/5.4/manual.html#6.4">string</a></span> | ||
1063 | error message; <code>"timeout"</code> if the timeout was reached.</li> | ||
1064 | <li> | ||
1065 | <span class="types"><a class="type" href="https://www.lua.org/manual/5.4/manual.html#6.4">string</a></span> | ||
1066 | partial result in case of an error while reading a sequence, the sequence so far. | ||
1067 | The function retains its own internal buffer, so on the next call the incomplete buffer is used to | ||
1068 | complete the sequence.</li> | ||
1196 | </ol> | 1069 | </ol> |
1197 | 1070 | ||
1198 | 1071 | ||
1199 | 1072 | ||
1073 | <h3>Usage:</h3> | ||
1074 | <ul> | ||
1075 | <pre class="example"><span class="keyword">local</span> key, keytype = system.<span class="function-name">readansi</span>(<span class="number">5</span>) | ||
1076 | <span class="keyword">if</span> keytype == <span class="string">"char"</span> <span class="keyword">then</span> ... <span class="keyword">end</span> <span class="comment">-- printable character | ||
1077 | </span><span class="keyword">if</span> keytype ~= <span class="string">"char"</span> <span class="keyword">then</span> ... <span class="keyword">end</span> <span class="comment">-- non-printable character or sequence | ||
1078 | </span><span class="keyword">if</span> keytype == <span class="string">"ansi"</span> <span class="keyword">then</span> ... <span class="keyword">end</span> <span class="comment">-- a multi-byte sequence, but not a UTF8 character | ||
1079 | </span><span class="keyword">if</span> keytype ~= <span class="string">"ansi"</span> <span class="keyword">then</span> ... <span class="keyword">end</span> <span class="comment">-- a valid UTF8 character (which includes control characters) | ||
1080 | </span><span class="keyword">if</span> keytype == <span class="string">"ctrl"</span> <span class="keyword">then</span> ... <span class="keyword">end</span> <span class="comment">-- a single-byte ctrl character (0-31, 127)</span></pre> | ||
1081 | </ul> | ||
1200 | 1082 | ||
1201 | </dd> | 1083 | </dd> |
1202 | <dt> | 1084 | <dt> |
1203 | <a name = "termsize"></a> | 1085 | <a name = "readkey"></a> |
1204 | <strong>termsize ()</strong> | 1086 | <strong>readkey (timeout[, fsleep=system.sleep])</strong> |
1205 | </dt> | 1087 | </dt> |
1206 | <dd> | 1088 | <dd> |
1207 | Get the size of the terminal in rows and columns. | 1089 | Reads a single byte from the console, with a timeout. |
1090 | This function uses <code>fsleep</code> to wait until either a byte is available or the timeout is reached. | ||
1091 | The sleep period is exponentially backing off, starting at 0.0125 seconds, with a maximum of 0.1 seconds. | ||
1092 | It returns immediately if a byte is available or if <code>timeout</code> is less than or equal to <code>0</code>.</p> | ||
1208 | 1093 | ||
1094 | <p> Using <a href="../modules/system.html#readansi">system.readansi</a> is preferred over this function. Since this function can leave stray/invalid | ||
1095 | byte-sequences in the input buffer, while <a href="../modules/system.html#readansi">system.readansi</a> reads full ANSI and UTF8 sequences. | ||
1209 | 1096 | ||
1210 | 1097 | ||
1098 | <h3>Parameters:</h3> | ||
1099 | <ul> | ||
1100 | <li><span class="parameter">timeout</span> | ||
1101 | <span class="types"><span class="type">number</span></span> | ||
1102 | the timeout in seconds. | ||
1103 | </li> | ||
1104 | <li><span class="parameter">fsleep</span> | ||
1105 | <span class="types"><span class="type">function</span></span> | ||
1106 | the function to call for sleeping; <code>ok, err = fsleep(secs)</code> | ||
1107 | (<em>default</em> system.sleep) | ||
1108 | </li> | ||
1109 | </ul> | ||
1110 | |||
1211 | <h3>Returns:</h3> | 1111 | <h3>Returns:</h3> |
1212 | <ol> | 1112 | <ol> |
1213 | <li> | 1113 | |
1214 | <span class="types"><span class="type">int</span></span> | 1114 | <span class="types"><span class="type">byte</span></span> |
1215 | the number of rows</li> | 1115 | the byte value that was read. |
1216 | <li> | ||
1217 | <span class="types"><span class="type">int</span></span> | ||
1218 | the number of columns</li> | ||
1219 | </ol> | 1116 | </ol> |
1220 | <h3>Or</h3> | 1117 | <h3>Or</h3> |
1221 | <ol> | 1118 | <ol> |
1222 | <li> | 1119 | <li> |
1223 | <span class="types"><span class="type">nil</span></span> | 1120 | <span class="types"><span class="type">nil</span></span> |
1224 | 1121 | if no key was read</li> | |
1225 | |||
1226 | </li> | ||
1227 | <li> | 1122 | <li> |
1228 | <span class="types"><a class="type" href="https://www.lua.org/manual/5.4/manual.html#6.4">string</a></span> | 1123 | <span class="types"><a class="type" href="https://www.lua.org/manual/5.4/manual.html#6.4">string</a></span> |
1229 | error message</li> | 1124 | error message when the timeout was reached (<code>"timeout"</code>), or if <a href="../modules/system.html#sleep">sleep</a> failed.</li> |
1125 | </ol> | ||
1126 | |||
1127 | |||
1128 | |||
1129 | |||
1130 | </dd> | ||
1131 | </dl> | ||
1132 | <h2 class="section-header "><a name="Terminal_UTF_8"></a>Terminal_UTF-8</h2> | ||
1133 | |||
1134 | <dl class="function"> | ||
1135 | <dt> | ||
1136 | <a name = "CODEPAGE_UTF8"></a> | ||
1137 | <strong>CODEPAGE_UTF8</strong> | ||
1138 | </dt> | ||
1139 | <dd> | ||
1140 | UTF8 codepage. | ||
1141 | To be used with <a href="../modules/system.html#setconsoleoutputcp">system.setconsoleoutputcp</a> and <a href="../modules/system.html#setconsolecp">system.setconsolecp</a>. | ||
1142 | |||
1143 | |||
1144 | <ul> | ||
1145 | <li><span class="parameter">CODEPAGE_UTF8</span> | ||
1146 | The Windows CodePage for UTF8. | ||
1147 | </li> | ||
1148 | </ul> | ||
1149 | |||
1150 | |||
1151 | |||
1152 | |||
1153 | |||
1154 | </dd> | ||
1155 | <dt> | ||
1156 | <a name = "getconsolecp"></a> | ||
1157 | <strong>getconsolecp ()</strong> | ||
1158 | </dt> | ||
1159 | <dd> | ||
1160 | Gets the current console code page (Windows). | ||
1161 | |||
1162 | |||
1163 | |||
1164 | <h3>Returns:</h3> | ||
1165 | <ol> | ||
1166 | |||
1167 | <span class="types"><span class="type">int</span></span> | ||
1168 | the current code page (always 65001 on Posix systems) | ||
1230 | </ol> | 1169 | </ol> |
1231 | 1170 | ||
1232 | 1171 | ||
@@ -1234,27 +1173,73 @@ flags for the <code>iflags</code>, <code>oflags</code>, and <code>lflags</code> | |||
1234 | 1173 | ||
1235 | </dd> | 1174 | </dd> |
1236 | <dt> | 1175 | <dt> |
1237 | <a name = "termwrap"></a> | 1176 | <a name = "getconsoleoutputcp"></a> |
1238 | <strong>termwrap (f)</strong> | 1177 | <strong>getconsoleoutputcp ()</strong> |
1239 | </dt> | 1178 | </dt> |
1240 | <dd> | 1179 | <dd> |
1241 | Wraps a function to automatically restore terminal settings upon returning. | 1180 | Gets the current console output code page (Windows). |
1242 | Calls <a href="../modules/system.html#termbackup">termbackup</a> before calling the function and <a href="../modules/system.html#termrestore">termrestore</a> after. | 1181 | |
1182 | |||
1183 | |||
1184 | <h3>Returns:</h3> | ||
1185 | <ol> | ||
1186 | |||
1187 | <span class="types"><span class="type">int</span></span> | ||
1188 | the current code page (always 65001 on Posix systems) | ||
1189 | </ol> | ||
1190 | |||
1191 | |||
1192 | |||
1193 | |||
1194 | </dd> | ||
1195 | <dt> | ||
1196 | <a name = "setconsolecp"></a> | ||
1197 | <strong>setconsolecp (cp)</strong> | ||
1198 | </dt> | ||
1199 | <dd> | ||
1200 | Sets the current console code page (Windows). | ||
1243 | 1201 | ||
1244 | 1202 | ||
1245 | <h3>Parameters:</h3> | 1203 | <h3>Parameters:</h3> |
1246 | <ul> | 1204 | <ul> |
1247 | <li><span class="parameter">f</span> | 1205 | <li><span class="parameter">cp</span> |
1248 | <span class="types"><span class="type">function</span></span> | 1206 | <span class="types"><span class="type">int</span></span> |
1249 | function to wrap | 1207 | the code page to set, use <a href="../modules/system.html#CODEPAGE_UTF8">system.CODEPAGE_UTF8</a> (65001) for UTF-8 |
1250 | </li> | 1208 | </li> |
1251 | </ul> | 1209 | </ul> |
1252 | 1210 | ||
1253 | <h3>Returns:</h3> | 1211 | <h3>Returns:</h3> |
1254 | <ol> | 1212 | <ol> |
1255 | 1213 | ||
1256 | <span class="types"><span class="type">function</span></span> | 1214 | <span class="types"><span class="type">bool</span></span> |
1257 | wrapped function | 1215 | <code>true</code> on success (always <code>true</code> on Posix systems) |
1216 | </ol> | ||
1217 | |||
1218 | |||
1219 | |||
1220 | |||
1221 | </dd> | ||
1222 | <dt> | ||
1223 | <a name = "setconsoleoutputcp"></a> | ||
1224 | <strong>setconsoleoutputcp (cp)</strong> | ||
1225 | </dt> | ||
1226 | <dd> | ||
1227 | Sets the current console output code page (Windows). | ||
1228 | |||
1229 | |||
1230 | <h3>Parameters:</h3> | ||
1231 | <ul> | ||
1232 | <li><span class="parameter">cp</span> | ||
1233 | <span class="types"><span class="type">int</span></span> | ||
1234 | the code page to set, use <a href="../modules/system.html#CODEPAGE_UTF8">system.CODEPAGE_UTF8</a> (65001) for UTF-8 | ||
1235 | </li> | ||
1236 | </ul> | ||
1237 | |||
1238 | <h3>Returns:</h3> | ||
1239 | <ol> | ||
1240 | |||
1241 | <span class="types"><span class="type">bool</span></span> | ||
1242 | <code>true</code> on success (always <code>true</code> on Posix systems) | ||
1258 | </ol> | 1243 | </ol> |
1259 | 1244 | ||
1260 | 1245 | ||
@@ -1416,13 +1401,124 @@ This function will sleep, without doing a busy-loop and wasting CPU cycles. | |||
1416 | 1401 | ||
1417 | </dd> | 1402 | </dd> |
1418 | </dl> | 1403 | </dl> |
1404 | <h2 class="section-header "><a name="Terminal_Backup"></a>Terminal_Backup</h2> | ||
1405 | |||
1406 | <dl class="function"> | ||
1407 | <dt> | ||
1408 | <a name = "autotermrestore"></a> | ||
1409 | <strong>autotermrestore ()</strong> | ||
1410 | </dt> | ||
1411 | <dd> | ||
1412 | Backs up terminal settings and restores them on application exit. | ||
1413 | Calls <a href="../modules/system.html#termbackup">termbackup</a> to back up terminal settings and sets up a GC method to | ||
1414 | automatically restore them on application exit (also works on Lua 5.1). | ||
1415 | |||
1416 | |||
1417 | |||
1418 | <h3>Returns:</h3> | ||
1419 | <ol> | ||
1420 | |||
1421 | <span class="types"><span class="type">boolean</span></span> | ||
1422 | true | ||
1423 | </ol> | ||
1424 | <h3>Or</h3> | ||
1425 | <ol> | ||
1426 | <li> | ||
1427 | <span class="types"><span class="type">nil</span></span> | ||
1428 | if the backup was already created</li> | ||
1429 | <li> | ||
1430 | <span class="types"><a class="type" href="https://www.lua.org/manual/5.4/manual.html#6.4">string</a></span> | ||
1431 | error message</li> | ||
1432 | </ol> | ||
1433 | |||
1434 | |||
1435 | |||
1436 | |||
1437 | </dd> | ||
1438 | <dt> | ||
1439 | <a name = "termbackup"></a> | ||
1440 | <strong>termbackup ()</strong> | ||
1441 | </dt> | ||
1442 | <dd> | ||
1443 | Returns a backup of terminal settings for stdin/out/err. | ||
1444 | Handles terminal/console flags, Windows codepage, and non-block flags on the streams. | ||
1445 | Backs up terminal/console flags only if a stream is a tty. | ||
1446 | |||
1447 | |||
1448 | |||
1449 | <h3>Returns:</h3> | ||
1450 | <ol> | ||
1451 | |||
1452 | table with backup of terminal settings | ||
1453 | </ol> | ||
1454 | |||
1455 | |||
1456 | |||
1457 | |||
1458 | </dd> | ||
1459 | <dt> | ||
1460 | <a name = "termrestore"></a> | ||
1461 | <strong>termrestore (backup)</strong> | ||
1462 | </dt> | ||
1463 | <dd> | ||
1464 | Restores terminal settings from a backup | ||
1465 | |||
1466 | |||
1467 | <h3>Parameters:</h3> | ||
1468 | <ul> | ||
1469 | <li><span class="parameter">backup</span> | ||
1470 | <span class="types"><a class="type" href="https://www.lua.org/manual/5.4/manual.html#6.6">table</a></span> | ||
1471 | the backup of terminal settings, see <a href="../modules/system.html#termbackup">termbackup</a>. | ||
1472 | </li> | ||
1473 | </ul> | ||
1474 | |||
1475 | <h3>Returns:</h3> | ||
1476 | <ol> | ||
1477 | |||
1478 | <span class="types"><span class="type">boolean</span></span> | ||
1479 | true | ||
1480 | </ol> | ||
1481 | |||
1482 | |||
1483 | |||
1484 | |||
1485 | </dd> | ||
1486 | <dt> | ||
1487 | <a name = "termwrap"></a> | ||
1488 | <strong>termwrap (f)</strong> | ||
1489 | </dt> | ||
1490 | <dd> | ||
1491 | Wraps a function to automatically restore terminal settings upon returning. | ||
1492 | Calls <a href="../modules/system.html#termbackup">termbackup</a> before calling the function and <a href="../modules/system.html#termrestore">termrestore</a> after. | ||
1493 | |||
1494 | |||
1495 | <h3>Parameters:</h3> | ||
1496 | <ul> | ||
1497 | <li><span class="parameter">f</span> | ||
1498 | <span class="types"><span class="type">function</span></span> | ||
1499 | function to wrap | ||
1500 | </li> | ||
1501 | </ul> | ||
1502 | |||
1503 | <h3>Returns:</h3> | ||
1504 | <ol> | ||
1505 | |||
1506 | <span class="types"><span class="type">function</span></span> | ||
1507 | wrapped function | ||
1508 | </ol> | ||
1509 | |||
1510 | |||
1511 | |||
1512 | |||
1513 | </dd> | ||
1514 | </dl> | ||
1419 | 1515 | ||
1420 | 1516 | ||
1421 | </div> <!-- id="content" --> | 1517 | </div> <!-- id="content" --> |
1422 | </div> <!-- id="main" --> | 1518 | </div> <!-- id="main" --> |
1423 | <div id="about"> | 1519 | <div id="about"> |
1424 | <i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i> | 1520 | <i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i> |
1425 | <i style="float:right;">Last updated 2025-03-12 15:17:50 </i> | 1521 | <i style="float:right;">Last updated 2025-07-11 22:55:05 </i> |
1426 | </div> <!-- id="about" --> | 1522 | </div> <!-- id="about" --> |
1427 | </div> <!-- id="container" --> | 1523 | </div> <!-- id="container" --> |
1428 | </body> | 1524 | </body> |
diff --git a/docs/topics/01-introduction.md.html b/docs/topics/01-introduction.md.html index f0f627d..264aa71 100644 --- a/docs/topics/01-introduction.md.html +++ b/docs/topics/01-introduction.md.html | |||
@@ -84,7 +84,7 @@ independence.</p> | |||
84 | </div> <!-- id="main" --> | 84 | </div> <!-- id="main" --> |
85 | <div id="about"> | 85 | <div id="about"> |
86 | <i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i> | 86 | <i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i> |
87 | <i style="float:right;">Last updated 2025-03-12 15:17:50 </i> | 87 | <i style="float:right;">Last updated 2025-07-11 22:55:05 </i> |
88 | </div> <!-- id="about" --> | 88 | </div> <!-- id="about" --> |
89 | </div> <!-- id="container" --> | 89 | </div> <!-- id="container" --> |
90 | </body> | 90 | </body> |
diff --git a/docs/topics/02-development.md.html b/docs/topics/02-development.md.html index 315fa37..15efe55 100644 --- a/docs/topics/02-development.md.html +++ b/docs/topics/02-development.md.html | |||
@@ -84,7 +84,7 @@ pass locally, and do not rely on CI only.</p> | |||
84 | </div> <!-- id="main" --> | 84 | </div> <!-- id="main" --> |
85 | <div id="about"> | 85 | <div id="about"> |
86 | <i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i> | 86 | <i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i> |
87 | <i style="float:right;">Last updated 2025-03-12 15:17:50 </i> | 87 | <i style="float:right;">Last updated 2025-07-11 22:55:05 </i> |
88 | </div> <!-- id="about" --> | 88 | </div> <!-- id="about" --> |
89 | </div> <!-- id="container" --> | 89 | </div> <!-- id="container" --> |
90 | </body> | 90 | </body> |
diff --git a/docs/topics/03-terminal.md.html b/docs/topics/03-terminal.md.html index 7ce28af..27772ac 100644 --- a/docs/topics/03-terminal.md.html +++ b/docs/topics/03-terminal.md.html | |||
@@ -93,6 +93,7 @@ up both platforms to make it work.</p> | |||
93 | <li><a href="../modules/system.html#setconsoleflags">system.setconsoleflags</a> (Windows)</li> | 93 | <li><a href="../modules/system.html#setconsoleflags">system.setconsoleflags</a> (Windows)</li> |
94 | <li><a href="../modules/system.html#setconsolecp">system.setconsolecp</a> (Windows)</li> | 94 | <li><a href="../modules/system.html#setconsolecp">system.setconsolecp</a> (Windows)</li> |
95 | <li><a href="../modules/system.html#setconsoleoutputcp">system.setconsoleoutputcp</a> (Windows)</li> | 95 | <li><a href="../modules/system.html#setconsoleoutputcp">system.setconsoleoutputcp</a> (Windows)</li> |
96 | <li><a href="../modules/system.html#detachfds">system.detachfds</a> (Posix)</li> | ||
96 | <li><a href="../modules/system.html#setnonblock">system.setnonblock</a> (Posix)</li> | 97 | <li><a href="../modules/system.html#setnonblock">system.setnonblock</a> (Posix)</li> |
97 | <li><a href="../modules/system.html#tcsetattr">system.tcsetattr</a> (Posix)</li> | 98 | <li><a href="../modules/system.html#tcsetattr">system.tcsetattr</a> (Posix)</li> |
98 | </ul> | 99 | </ul> |
@@ -195,6 +196,7 @@ also not being echoed to the terminal (independent of the echo settings used wit | |||
195 | </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) | 196 | </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) |
196 | 197 | ||
197 | <span class="comment">-- setup Posix by disabling echo, canonical mode, and making non-blocking | 198 | <span class="comment">-- setup Posix by disabling echo, canonical mode, and making non-blocking |
199 | </span>sys.<span class="function-name">detachfds</span>() <span class="comment">-- ensure stdin/out/err have their own file descriptions | ||
198 | </span><span class="keyword">local</span> of_attr = sys.<span class="function-name">tcgetattr</span>(<span class="global">io</span>.stdin) | 200 | </span><span class="keyword">local</span> of_attr = sys.<span class="function-name">tcgetattr</span>(<span class="global">io</span>.stdin) |
199 | sys.<span class="function-name">tcsetattr</span>(<span class="global">io</span>.stdin, sys.TCSANOW, { | 201 | sys.<span class="function-name">tcsetattr</span>(<span class="global">io</span>.stdin, sys.TCSANOW, { |
200 | lflag = of_attr.lflag - sys.L_ICANON - sys.L_ECHO, | 202 | lflag = of_attr.lflag - sys.L_ICANON - sys.L_ECHO, |
@@ -218,7 +220,7 @@ For an example see <a href="../examples/password_input.lua.html"><code>examples/ | |||
218 | </div> <!-- id="main" --> | 220 | </div> <!-- id="main" --> |
219 | <div id="about"> | 221 | <div id="about"> |
220 | <i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i> | 222 | <i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i> |
221 | <i style="float:right;">Last updated 2025-03-12 15:17:50 </i> | 223 | <i style="float:right;">Last updated 2025-07-11 22:55:05 </i> |
222 | </div> <!-- id="about" --> | 224 | </div> <!-- id="about" --> |
223 | </div> <!-- id="container" --> | 225 | </div> <!-- id="container" --> |
224 | </body> | 226 | </body> |
diff --git a/docs/topics/CHANGELOG.md.html b/docs/topics/CHANGELOG.md.html index fa2d706..9603abd 100644 --- a/docs/topics/CHANGELOG.md.html +++ b/docs/topics/CHANGELOG.md.html | |||
@@ -106,6 +106,41 @@ | |||
106 | <p><a name="Version_history"></a></p> | 106 | <p><a name="Version_history"></a></p> |
107 | <h2>Version history</h2> | 107 | <h2>Version history</h2> |
108 | 108 | ||
109 | <h3>version 0.6.3, released 11-Jul-2025</h3> | ||
110 | |||
111 | <ul> | ||
112 | <li>Fix: maximum key-delay, reduced from 0.2 to 0.1 seconds to reduce slugginess feel on some key presses. | ||
113 | See <a href="https://github.com/lunarmodules/luasystem/pull/69">#69</a>.</li> | ||
114 | <li>Fix: <code>readansi</code> now only reports printable chars as characters | ||
115 | See <a href="https://github.com/lunarmodules/luasystem/pull/70">#70</a>.</li> | ||
116 | <li>Fix: readkey now ignores Windows scancodes if received. | ||
117 | See <a href="https://github.com/lunarmodules/luasystem/pull/74">#74</a>.</li> | ||
118 | <li>Fix: readkey now passes errors on. | ||
119 | See <a href="https://github.com/lunarmodules/luasystem/pull/74">#74</a>.</li> | ||
120 | </ul> | ||
121 | |||
122 | <h3>version 0.6.2, released 15-Apr-2025</h3> | ||
123 | |||
124 | <ul> | ||
125 | <li>Fix: autotermrestore didn't work because its metatable was overwritten.</li> | ||
126 | </ul> | ||
127 | |||
128 | <h3>version 0.6.1, released 13-Apr-2025</h3> | ||
129 | |||
130 | <ul> | ||
131 | <li>Docs: document readansi internal buffer for incomplete sequences.</li> | ||
132 | <li>Fix: ensure to properly parse <code><alt>+key</code> key presses</li> | ||
133 | </ul> | ||
134 | |||
135 | <h3>version 0.6.0, released 10-Apr-2025</h3> | ||
136 | |||
137 | <ul> | ||
138 | <li>Fix: when sleep returns an error, pass that on in <code>readkey</code>.</li> | ||
139 | <li>Feat: added <code>detachfds</code> which will create separate file descriptions for <code>stdout</code> | ||
140 | and <code>stderr</code> to ensure that related settings (eg. non-blocking flag) will not be shared | ||
141 | amongst those streams and <code>stdin</code>.</li> | ||
142 | </ul> | ||
143 | |||
109 | <h3>version 0.5.1, released 12-Mar-2025</h3> | 144 | <h3>version 0.5.1, released 12-Mar-2025</h3> |
110 | 145 | ||
111 | <ul> | 146 | <ul> |
@@ -120,14 +155,14 @@ | |||
120 | <li>Feat: allow passing in a sleep function to <code>readkey</code> and <code>readansi</code></li> | 155 | <li>Feat: allow passing in a sleep function to <code>readkey</code> and <code>readansi</code></li> |
121 | <li>Fix: NetBSD fix compilation, undeclared directives</li> | 156 | <li>Fix: NetBSD fix compilation, undeclared directives</li> |
122 | <li>Refactor: random bytes; remove deprecated API usage on Windows, move to | 157 | <li>Refactor: random bytes; remove deprecated API usage on Windows, move to |
123 | binary api instead of /dev/urandom file on linux and bsd</li> | 158 | binary api instead of <code>/dev/urandom</code> file on linux and bsd</li> |
124 | </ul> | 159 | </ul> |
125 | 160 | ||
126 | <h3>version 0.4.5, released 18-Dec-2024</h3> | 161 | <h3>version 0.4.5, released 18-Dec-2024</h3> |
127 | 162 | ||
128 | <ul> | 163 | <ul> |
129 | <li>Fix: suppress a warning when building with clang</li> | 164 | <li>Fix: suppress a warning when building with clang</li> |
130 | <li>Fix: do not rely on luaconf.h to include limits.h, fixes builds with latest LuaJIT (#38).</li> | 165 | <li>Fix: do not rely on <code>luaconf.h</code> to include <code>limits.h</code>, fixes builds with latest LuaJIT (#38).</li> |
131 | </ul> | 166 | </ul> |
132 | 167 | ||
133 | <h3>version 0.4.4, released 03-Sep-2024</h3> | 168 | <h3>version 0.4.4, released 03-Sep-2024</h3> |
@@ -199,7 +234,7 @@ | |||
199 | </div> <!-- id="main" --> | 234 | </div> <!-- id="main" --> |
200 | <div id="about"> | 235 | <div id="about"> |
201 | <i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i> | 236 | <i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i> |
202 | <i style="float:right;">Last updated 2025-03-12 15:17:50 </i> | 237 | <i style="float:right;">Last updated 2025-07-11 22:55:05 </i> |
203 | </div> <!-- id="about" --> | 238 | </div> <!-- id="about" --> |
204 | </div> <!-- id="container" --> | 239 | </div> <!-- id="container" --> |
205 | </body> | 240 | </body> |
diff --git a/docs/topics/LICENSE.md.html b/docs/topics/LICENSE.md.html index 612cdb9..c0b9b93 100644 --- a/docs/topics/LICENSE.md.html +++ b/docs/topics/LICENSE.md.html | |||
@@ -94,7 +94,7 @@ SOFTWARE.</p> | |||
94 | </div> <!-- id="main" --> | 94 | </div> <!-- id="main" --> |
95 | <div id="about"> | 95 | <div id="about"> |
96 | <i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i> | 96 | <i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i> |
97 | <i style="float:right;">Last updated 2025-03-12 15:17:50 </i> | 97 | <i style="float:right;">Last updated 2025-07-11 22:55:05 </i> |
98 | </div> <!-- id="about" --> | 98 | </div> <!-- id="about" --> |
99 | </div> <!-- id="container" --> | 99 | </div> <!-- id="container" --> |
100 | </body> | 100 | </body> |
diff --git a/rockspecs/luasystem-0.6.0-1.rockspec b/rockspecs/luasystem-0.6.0-1.rockspec new file mode 100644 index 0000000..21c2dc0 --- /dev/null +++ b/rockspecs/luasystem-0.6.0-1.rockspec | |||
@@ -0,0 +1,85 @@ | |||
1 | local package_name = "luasystem" | ||
2 | local package_version = "0.6.0" | ||
3 | local rockspec_revision = "1" | ||
4 | local github_account_name = "lunarmodules" | ||
5 | local github_repo_name = "luasystem" | ||
6 | |||
7 | |||
8 | package = package_name | ||
9 | version = package_version.."-"..rockspec_revision | ||
10 | |||
11 | source = { | ||
12 | url = "git+https://github.com/"..github_account_name.."/"..github_repo_name..".git", | ||
13 | branch = (package_version == "scm") and "master" or nil, | ||
14 | tag = (package_version ~= "scm") and "v"..package_version or nil, | ||
15 | } | ||
16 | |||
17 | description = { | ||
18 | summary = 'Platform independent system calls for Lua.', | ||
19 | detailed = [[ | ||
20 | Adds a Lua API for making platform independent system calls. | ||
21 | ]], | ||
22 | license = 'MIT <http://opensource.org/licenses/MIT>', | ||
23 | homepage = "https://github.com/"..github_account_name.."/"..github_repo_name, | ||
24 | } | ||
25 | |||
26 | dependencies = { | ||
27 | 'lua >= 5.1', | ||
28 | } | ||
29 | |||
30 | local function make_platform(plat) | ||
31 | local defines = { | ||
32 | linux = { }, | ||
33 | unix = { }, | ||
34 | macosx = { }, | ||
35 | win32 = { "WINVER=0x0600", "_WIN32_WINNT=0x0600" }, | ||
36 | mingw32 = { "WINVER=0x0600", "_WIN32_WINNT=0x0600" }, | ||
37 | } | ||
38 | local libraries = { | ||
39 | linux = { "rt" }, | ||
40 | unix = { }, | ||
41 | macosx = { }, | ||
42 | win32 = { "advapi32", "winmm", "bcrypt" }, | ||
43 | mingw32 = { }, | ||
44 | } | ||
45 | local libdirs = { | ||
46 | linux = nil, | ||
47 | unix = nil, | ||
48 | macosx = nil, | ||
49 | win32 = nil, | ||
50 | mingw32 = { }, | ||
51 | } | ||
52 | return { | ||
53 | modules = { | ||
54 | ['system.core'] = { | ||
55 | sources = { | ||
56 | 'src/core.c', | ||
57 | 'src/compat.c', | ||
58 | 'src/time.c', | ||
59 | 'src/environment.c', | ||
60 | 'src/random.c', | ||
61 | 'src/term.c', | ||
62 | 'src/bitflags.c', | ||
63 | 'src/wcwidth.c', | ||
64 | }, | ||
65 | defines = defines[plat], | ||
66 | libraries = libraries[plat], | ||
67 | libdirs = libdirs[plat], | ||
68 | }, | ||
69 | }, | ||
70 | } | ||
71 | end | ||
72 | |||
73 | build = { | ||
74 | type = 'builtin', | ||
75 | platforms = { | ||
76 | linux = make_platform('linux'), | ||
77 | unix = make_platform('unix'), | ||
78 | macosx = make_platform('macosx'), | ||
79 | win32 = make_platform('win32'), | ||
80 | mingw32 = make_platform('mingw32'), | ||
81 | }, | ||
82 | modules = { | ||
83 | ['system.init'] = 'system/init.lua', | ||
84 | }, | ||
85 | } | ||
diff --git a/rockspecs/luasystem-0.6.1-1.rockspec b/rockspecs/luasystem-0.6.1-1.rockspec new file mode 100644 index 0000000..51bbddd --- /dev/null +++ b/rockspecs/luasystem-0.6.1-1.rockspec | |||
@@ -0,0 +1,85 @@ | |||
1 | local package_name = "luasystem" | ||
2 | local package_version = "0.6.1" | ||
3 | local rockspec_revision = "1" | ||
4 | local github_account_name = "lunarmodules" | ||
5 | local github_repo_name = "luasystem" | ||
6 | |||
7 | |||
8 | package = package_name | ||
9 | version = package_version.."-"..rockspec_revision | ||
10 | |||
11 | source = { | ||
12 | url = "git+https://github.com/"..github_account_name.."/"..github_repo_name..".git", | ||
13 | branch = (package_version == "scm") and "master" or nil, | ||
14 | tag = (package_version ~= "scm") and "v"..package_version or nil, | ||
15 | } | ||
16 | |||
17 | description = { | ||
18 | summary = 'Platform independent system calls for Lua.', | ||
19 | detailed = [[ | ||
20 | Adds a Lua API for making platform independent system calls. | ||
21 | ]], | ||
22 | license = 'MIT <http://opensource.org/licenses/MIT>', | ||
23 | homepage = "https://github.com/"..github_account_name.."/"..github_repo_name, | ||
24 | } | ||
25 | |||
26 | dependencies = { | ||
27 | 'lua >= 5.1', | ||
28 | } | ||
29 | |||
30 | local function make_platform(plat) | ||
31 | local defines = { | ||
32 | linux = { }, | ||
33 | unix = { }, | ||
34 | macosx = { }, | ||
35 | win32 = { "WINVER=0x0600", "_WIN32_WINNT=0x0600" }, | ||
36 | mingw32 = { "WINVER=0x0600", "_WIN32_WINNT=0x0600" }, | ||
37 | } | ||
38 | local libraries = { | ||
39 | linux = { "rt" }, | ||
40 | unix = { }, | ||
41 | macosx = { }, | ||
42 | win32 = { "advapi32", "winmm", "bcrypt" }, | ||
43 | mingw32 = { }, | ||
44 | } | ||
45 | local libdirs = { | ||
46 | linux = nil, | ||
47 | unix = nil, | ||
48 | macosx = nil, | ||
49 | win32 = nil, | ||
50 | mingw32 = { }, | ||
51 | } | ||
52 | return { | ||
53 | modules = { | ||
54 | ['system.core'] = { | ||
55 | sources = { | ||
56 | 'src/core.c', | ||
57 | 'src/compat.c', | ||
58 | 'src/time.c', | ||
59 | 'src/environment.c', | ||
60 | 'src/random.c', | ||
61 | 'src/term.c', | ||
62 | 'src/bitflags.c', | ||
63 | 'src/wcwidth.c', | ||
64 | }, | ||
65 | defines = defines[plat], | ||
66 | libraries = libraries[plat], | ||
67 | libdirs = libdirs[plat], | ||
68 | }, | ||
69 | }, | ||
70 | } | ||
71 | end | ||
72 | |||
73 | build = { | ||
74 | type = 'builtin', | ||
75 | platforms = { | ||
76 | linux = make_platform('linux'), | ||
77 | unix = make_platform('unix'), | ||
78 | macosx = make_platform('macosx'), | ||
79 | win32 = make_platform('win32'), | ||
80 | mingw32 = make_platform('mingw32'), | ||
81 | }, | ||
82 | modules = { | ||
83 | ['system.init'] = 'system/init.lua', | ||
84 | }, | ||
85 | } | ||
diff --git a/rockspecs/luasystem-0.6.2-1.rockspec b/rockspecs/luasystem-0.6.2-1.rockspec new file mode 100644 index 0000000..7a8549f --- /dev/null +++ b/rockspecs/luasystem-0.6.2-1.rockspec | |||
@@ -0,0 +1,85 @@ | |||
1 | local package_name = "luasystem" | ||
2 | local package_version = "0.6.2" | ||
3 | local rockspec_revision = "1" | ||
4 | local github_account_name = "lunarmodules" | ||
5 | local github_repo_name = "luasystem" | ||
6 | |||
7 | |||
8 | package = package_name | ||
9 | version = package_version.."-"..rockspec_revision | ||
10 | |||
11 | source = { | ||
12 | url = "git+https://github.com/"..github_account_name.."/"..github_repo_name..".git", | ||
13 | branch = (package_version == "scm") and "master" or nil, | ||
14 | tag = (package_version ~= "scm") and "v"..package_version or nil, | ||
15 | } | ||
16 | |||
17 | description = { | ||
18 | summary = 'Platform independent system calls for Lua.', | ||
19 | detailed = [[ | ||
20 | Adds a Lua API for making platform independent system calls. | ||
21 | ]], | ||
22 | license = 'MIT <http://opensource.org/licenses/MIT>', | ||
23 | homepage = "https://github.com/"..github_account_name.."/"..github_repo_name, | ||
24 | } | ||
25 | |||
26 | dependencies = { | ||
27 | 'lua >= 5.1', | ||
28 | } | ||
29 | |||
30 | local function make_platform(plat) | ||
31 | local defines = { | ||
32 | linux = { }, | ||
33 | unix = { }, | ||
34 | macosx = { }, | ||
35 | win32 = { "WINVER=0x0600", "_WIN32_WINNT=0x0600" }, | ||
36 | mingw32 = { "WINVER=0x0600", "_WIN32_WINNT=0x0600" }, | ||
37 | } | ||
38 | local libraries = { | ||
39 | linux = { "rt" }, | ||
40 | unix = { }, | ||
41 | macosx = { }, | ||
42 | win32 = { "advapi32", "winmm", "bcrypt" }, | ||
43 | mingw32 = { }, | ||
44 | } | ||
45 | local libdirs = { | ||
46 | linux = nil, | ||
47 | unix = nil, | ||
48 | macosx = nil, | ||
49 | win32 = nil, | ||
50 | mingw32 = { }, | ||
51 | } | ||
52 | return { | ||
53 | modules = { | ||
54 | ['system.core'] = { | ||
55 | sources = { | ||
56 | 'src/core.c', | ||
57 | 'src/compat.c', | ||
58 | 'src/time.c', | ||
59 | 'src/environment.c', | ||
60 | 'src/random.c', | ||
61 | 'src/term.c', | ||
62 | 'src/bitflags.c', | ||
63 | 'src/wcwidth.c', | ||
64 | }, | ||
65 | defines = defines[plat], | ||
66 | libraries = libraries[plat], | ||
67 | libdirs = libdirs[plat], | ||
68 | }, | ||
69 | }, | ||
70 | } | ||
71 | end | ||
72 | |||
73 | build = { | ||
74 | type = 'builtin', | ||
75 | platforms = { | ||
76 | linux = make_platform('linux'), | ||
77 | unix = make_platform('unix'), | ||
78 | macosx = make_platform('macosx'), | ||
79 | win32 = make_platform('win32'), | ||
80 | mingw32 = make_platform('mingw32'), | ||
81 | }, | ||
82 | modules = { | ||
83 | ['system.init'] = 'system/init.lua', | ||
84 | }, | ||
85 | } | ||
diff --git a/rockspecs/luasystem-0.6.3-1.rockspec b/rockspecs/luasystem-0.6.3-1.rockspec new file mode 100644 index 0000000..e70373f --- /dev/null +++ b/rockspecs/luasystem-0.6.3-1.rockspec | |||
@@ -0,0 +1,85 @@ | |||
1 | local package_name = "luasystem" | ||
2 | local package_version = "0.6.3" | ||
3 | local rockspec_revision = "1" | ||
4 | local github_account_name = "lunarmodules" | ||
5 | local github_repo_name = "luasystem" | ||
6 | |||
7 | |||
8 | package = package_name | ||
9 | version = package_version.."-"..rockspec_revision | ||
10 | |||
11 | source = { | ||
12 | url = "git+https://github.com/"..github_account_name.."/"..github_repo_name..".git", | ||
13 | branch = (package_version == "scm") and "master" or nil, | ||
14 | tag = (package_version ~= "scm") and "v"..package_version or nil, | ||
15 | } | ||
16 | |||
17 | description = { | ||
18 | summary = 'Platform independent system calls for Lua.', | ||
19 | detailed = [[ | ||
20 | Adds a Lua API for making platform independent system calls. | ||
21 | ]], | ||
22 | license = 'MIT <http://opensource.org/licenses/MIT>', | ||
23 | homepage = "https://github.com/"..github_account_name.."/"..github_repo_name, | ||
24 | } | ||
25 | |||
26 | dependencies = { | ||
27 | 'lua >= 5.1', | ||
28 | } | ||
29 | |||
30 | local function make_platform(plat) | ||
31 | local defines = { | ||
32 | linux = { }, | ||
33 | unix = { }, | ||
34 | macosx = { }, | ||
35 | win32 = { "WINVER=0x0600", "_WIN32_WINNT=0x0600" }, | ||
36 | mingw32 = { "WINVER=0x0600", "_WIN32_WINNT=0x0600" }, | ||
37 | } | ||
38 | local libraries = { | ||
39 | linux = { "rt" }, | ||
40 | unix = { }, | ||
41 | macosx = { }, | ||
42 | win32 = { "advapi32", "winmm", "bcrypt" }, | ||
43 | mingw32 = { }, | ||
44 | } | ||
45 | local libdirs = { | ||
46 | linux = nil, | ||
47 | unix = nil, | ||
48 | macosx = nil, | ||
49 | win32 = nil, | ||
50 | mingw32 = { }, | ||
51 | } | ||
52 | return { | ||
53 | modules = { | ||
54 | ['system.core'] = { | ||
55 | sources = { | ||
56 | 'src/core.c', | ||
57 | 'src/compat.c', | ||
58 | 'src/time.c', | ||
59 | 'src/environment.c', | ||
60 | 'src/random.c', | ||
61 | 'src/term.c', | ||
62 | 'src/bitflags.c', | ||
63 | 'src/wcwidth.c', | ||
64 | }, | ||
65 | defines = defines[plat], | ||
66 | libraries = libraries[plat], | ||
67 | libdirs = libdirs[plat], | ||
68 | }, | ||
69 | }, | ||
70 | } | ||
71 | end | ||
72 | |||
73 | build = { | ||
74 | type = 'builtin', | ||
75 | platforms = { | ||
76 | linux = make_platform('linux'), | ||
77 | unix = make_platform('unix'), | ||
78 | macosx = make_platform('macosx'), | ||
79 | win32 = make_platform('win32'), | ||
80 | mingw32 = make_platform('mingw32'), | ||
81 | }, | ||
82 | modules = { | ||
83 | ['system.init'] = 'system/init.lua', | ||
84 | }, | ||
85 | } | ||
diff --git a/spec/04-term_spec.lua b/spec/04-term_spec.lua index 907f903..5dea046 100644 --- a/spec/04-term_spec.lua +++ b/spec/04-term_spec.lua | |||
@@ -855,6 +855,32 @@ describe("Terminal:", function() | |||
855 | assert.is.near(1, timing, 0.5) -- this also works for MacOS in CI | 855 | assert.is.near(1, timing, 0.5) -- this also works for MacOS in CI |
856 | end) | 856 | end) |
857 | 857 | ||
858 | |||
859 | it("calls flseep to execute the sleep", function() | ||
860 | setbuffer("") | ||
861 | |||
862 | local sleep_called = false | ||
863 | local mysleep = function() | ||
864 | sleep_called = true | ||
865 | end | ||
866 | |||
867 | system.readkey(0.01, mysleep) | ||
868 | assert.is_true(sleep_called) | ||
869 | end) | ||
870 | |||
871 | |||
872 | it("returns errors by fsleep", function() | ||
873 | setbuffer("") | ||
874 | |||
875 | local mysleep = function() | ||
876 | return nil, "boom!" | ||
877 | end | ||
878 | |||
879 | local ok, err = system.readkey(1, mysleep) | ||
880 | assert.is.falsy(ok) | ||
881 | assert.equals("boom!", err) | ||
882 | end) | ||
883 | |||
858 | end) | 884 | end) |
859 | 885 | ||
860 | 886 | ||
@@ -876,6 +902,14 @@ describe("Terminal:", function() | |||
876 | end) | 902 | end) |
877 | 903 | ||
878 | 904 | ||
905 | it("reads a control byte for single-byte control characters", function() | ||
906 | setbuffer("\000\031\127") | ||
907 | assert.are.same({"\000", "ctrl"}, {system.readansi(0)}) | ||
908 | assert.are.same({"\031", "ctrl"}, {system.readansi(0)}) | ||
909 | assert.are.same({"\127", "ctrl"}, {system.readansi(0)}) | ||
910 | end) | ||
911 | |||
912 | |||
879 | it("reads a multi-byte characters one at a time", function() | 913 | it("reads a multi-byte characters one at a time", function() |
880 | setbuffer(string.char(226, 130, 172) .. -- "€" single | 914 | setbuffer(string.char(226, 130, 172) .. -- "€" single |
881 | string.char(240, 159, 154, 128)) -- "🚀" double | 915 | string.char(240, 159, 154, 128)) -- "🚀" double |
@@ -902,10 +936,31 @@ describe("Terminal:", function() | |||
902 | end) | 936 | end) |
903 | 937 | ||
904 | 938 | ||
939 | it("reads ANSI escape sequences, just an '<esc>O' (<alt><O> key press)", function() | ||
940 | setbuffer("\27O") | ||
941 | assert.are.same({"\27O", "ansi"}, {system.readansi(0)}) | ||
942 | end) | ||
943 | |||
944 | |||
945 | it("reads <alt>+key key presses; <esc>+<key>", function() | ||
946 | setbuffer("\27a\27b\27c\27d") | ||
947 | assert.are.same({"\27a", "ansi"}, {system.readansi(0)}) | ||
948 | assert.are.same({"\27b", "ansi"}, {system.readansi(0)}) | ||
949 | assert.are.same({"\27c", "ansi"}, {system.readansi(0)}) | ||
950 | assert.are.same({"\27d", "ansi"}, {system.readansi(0)}) | ||
951 | end) | ||
952 | |||
953 | |||
954 | it("reads <ctrl><alt>[ key press; <esc>+<esc>", function() | ||
955 | setbuffer("\27\27\27\27") | ||
956 | assert.are.same({"\27\27", "ansi"}, {system.readansi(0)}) | ||
957 | assert.are.same({"\27\27", "ansi"}, {system.readansi(0)}) | ||
958 | end) | ||
959 | |||
960 | |||
905 | it("returns a single <esc> character if no sequence is found", function() | 961 | it("returns a single <esc> character if no sequence is found", function() |
906 | setbuffer("\27\27[A") | 962 | setbuffer("\27") |
907 | assert.are.same({"\27", "char"}, {system.readansi(0)}) | 963 | assert.are.same({"\27", "ctrl"}, {system.readansi(0)}) |
908 | assert.are.same({"\27[A", "ansi"}, {system.readansi(0)}) | ||
909 | end) | 964 | end) |
910 | 965 | ||
911 | 966 | ||
@@ -919,6 +974,22 @@ describe("Terminal:", function() | |||
919 | assert.is.near(1, timing, 0.5) -- this also works for MacOS in CI | 974 | assert.is.near(1, timing, 0.5) -- this also works for MacOS in CI |
920 | end) | 975 | end) |
921 | 976 | ||
977 | |||
978 | it("incomplete ANSI sequences will be completed on next call", function() | ||
979 | setbuffer("\27[") | ||
980 | assert.are.same({nil, "timeout", "\27["}, {system.readansi(0)}) | ||
981 | setbuffer("A") | ||
982 | assert.are.same({"\27[A", "ansi"}, {system.readansi(0)}) | ||
983 | end) | ||
984 | |||
985 | |||
986 | it("incomplete UTF8 sequences will be completed on next call", function() | ||
987 | setbuffer(string.char(240, 159)) | ||
988 | assert.are.same({nil, "timeout", string.char(240, 159)}, {system.readansi(0)}) | ||
989 | setbuffer(string.char(154, 128)) | ||
990 | assert.are.same({"🚀", "char"}, {system.readansi(0)}) | ||
991 | end) | ||
992 | |||
922 | end) | 993 | end) |
923 | 994 | ||
924 | end) | 995 | end) |
@@ -4,7 +4,7 @@ | |||
4 | #include <lua.h> | 4 | #include <lua.h> |
5 | #include <lauxlib.h> | 5 | #include <lauxlib.h> |
6 | 6 | ||
7 | #define LUASYSTEM_VERSION "LuaSystem 0.5.1" | 7 | #define LUASYSTEM_VERSION "LuaSystem 0.6.3" |
8 | 8 | ||
9 | #ifdef _WIN32 | 9 | #ifdef _WIN32 |
10 | #define LUAEXPORT __declspec(dllexport) | 10 | #define LUAEXPORT __declspec(dllexport) |
@@ -384,6 +384,7 @@ See [setconsolemode documentation](https://learn.microsoft.com/en-us/windows/con | |||
384 | @treturn[1] boolean `true` on success | 384 | @treturn[1] boolean `true` on success |
385 | @treturn[2] nil | 385 | @treturn[2] nil |
386 | @treturn[2] string error message | 386 | @treturn[2] string error message |
387 | @within Terminal_Windows | ||
387 | @usage | 388 | @usage |
388 | local system = require('system') | 389 | local system = require('system') |
389 | system.listconsoleflags(io.stdout) -- List all the available flags and their current status | 390 | system.listconsoleflags(io.stdout) -- List all the available flags and their current status |
@@ -427,13 +428,12 @@ input flags (for use with `io.stdin`) and `COF` are the output flags (for use wi | |||
427 | _Note_: See [setconsolemode documentation](https://learn.microsoft.com/en-us/windows/console/setconsolemode) | 428 | _Note_: See [setconsolemode documentation](https://learn.microsoft.com/en-us/windows/console/setconsolemode) |
428 | for more information on the flags. | 429 | for more information on the flags. |
429 | 430 | ||
430 | |||
431 | |||
432 | @function getconsoleflags | 431 | @function getconsoleflags |
433 | @tparam file file file handle to operate on, one of `io.stdin`, `io.stdout`, `io.stderr` | 432 | @tparam file file file handle to operate on, one of `io.stdin`, `io.stdout`, `io.stderr` |
434 | @treturn[1] bitflags the current console flags. | 433 | @treturn[1] bitflags the current console flags. |
435 | @treturn[2] nil | 434 | @treturn[2] nil |
436 | @treturn[2] string error message | 435 | @treturn[2] string error message |
436 | @within Terminal_Windows | ||
437 | @usage | 437 | @usage |
438 | local system = require('system') | 438 | local system = require('system') |
439 | 439 | ||
@@ -497,6 +497,7 @@ The terminal attributes is a table with the following fields: | |||
497 | @treturn[2] string error message | 497 | @treturn[2] string error message |
498 | @treturn[2] int errnum | 498 | @treturn[2] int errnum |
499 | @return error message if failed | 499 | @return error message if failed |
500 | @within Terminal_Posix | ||
500 | @usage | 501 | @usage |
501 | local system = require('system') | 502 | local system = require('system') |
502 | 503 | ||
@@ -591,6 +592,7 @@ _Note_: only `iflag`, `oflag`, and `lflag` are supported at the moment. The othe | |||
591 | @return[2] nil | 592 | @return[2] nil |
592 | @treturn[2] string error message | 593 | @treturn[2] string error message |
593 | @treturn[2] int errnum | 594 | @treturn[2] int errnum |
595 | @within Terminal_Posix | ||
594 | @usage | 596 | @usage |
595 | local system = require('system') | 597 | local system = require('system') |
596 | 598 | ||
@@ -649,8 +651,105 @@ static int lst_tcsetattr(lua_State *L) | |||
649 | 651 | ||
650 | 652 | ||
651 | 653 | ||
654 | #ifndef _WIN32 | ||
655 | /* | ||
656 | reopen FDs for independent file descriptions. | ||
657 | */ | ||
658 | static void reopen_fd(lua_State *L, int fd, int flags) { | ||
659 | char path[64]; | ||
660 | int newfd = -1; | ||
661 | |||
662 | if (fd != STDOUT_FILENO && fd != STDERR_FILENO) { | ||
663 | luaL_error(L, "Invalid file descriptor: %d. Only stdout (1) and stderr (2) are supported.", fd); | ||
664 | } | ||
665 | |||
666 | const char *fallback_path = (fd == STDOUT_FILENO) ? "/dev/stdout" : | ||
667 | (fd == STDERR_FILENO) ? "/dev/stderr" : NULL; | ||
668 | |||
669 | // If fd is a terminal, reopen its actual device (e.g. /dev/ttys003) | ||
670 | // Works on all POSIX platforms that have terminals (macOS, Linux, BSD, etc.) | ||
671 | if (isatty(fd)) { | ||
672 | const char *tty = ttyname(fd); | ||
673 | if (tty) { | ||
674 | newfd = open(tty, flags); | ||
675 | } | ||
676 | } | ||
677 | |||
678 | if (newfd < 0) { | ||
679 | // For non-tty: try /dev/fd/N — POSIX-compliant and standard on macOS, Linux, BSD. | ||
680 | // This gives a new file description even if the target is a file or pipe. | ||
681 | snprintf(path, sizeof(path), "/dev/fd/%d", fd); | ||
682 | newfd = open(path, flags); | ||
683 | } | ||
684 | |||
685 | if (newfd < 0) { | ||
686 | // Fallback: for platforms/environments where /dev/fd/N doesn't exist. | ||
687 | // /dev/stdout and /dev/stderr are standard on Linux, but may not create new descriptions. | ||
688 | if (fallback_path) { | ||
689 | newfd = open(fallback_path, flags); | ||
690 | } | ||
691 | } | ||
692 | |||
693 | if (newfd < 0) { | ||
694 | // All attempts failed — raise error with detailed info (call will not return) | ||
695 | luaL_error(L, "Failed to reopen fd %d: tried ttyname(), /dev/fd/%d, and fallback %s: %s", | ||
696 | fd, fd, fallback_path ? fallback_path : "(none)", strerror(errno)); | ||
697 | } | ||
698 | |||
699 | // Replace the original fd with the new one | ||
700 | if (dup2(newfd, fd) < 0) { | ||
701 | close(newfd); | ||
702 | luaL_error(L, "dup2 failed for fd %d: %s", fd, strerror(errno)); | ||
703 | } | ||
704 | |||
705 | close(newfd); // Close the new fd, as dup2 has replaced the original fd with it | ||
706 | } | ||
707 | #endif | ||
708 | |||
709 | |||
710 | |||
711 | /*** | ||
712 | Creates new file descriptions for `stdout` and `stderr`. | ||
713 | Even if the file descriptors are unique, they still might point to the same | ||
714 | file description, and hence share settings like `O_NONBLOCK`. This means that | ||
715 | if one of them is set to non-blocking, the other will be as well. This can | ||
716 | lead to unexpected behavior. | ||
717 | |||
718 | This function is used to detach `stdout` and `stderr` from the original | ||
719 | file descriptions, and create new file descriptions for them. This allows | ||
720 | independent control of flags (e.g., `O_NONBLOCK`) on `stdout` and `stderr`, | ||
721 | avoiding shared side effects. | ||
722 | |||
723 | Does not modify `stdin` (fd 0), and does nothing on Windows. | ||
724 | @function detachfds | ||
725 | @return boolean `true` on success, or throws an error on failure. | ||
726 | @within Terminal_Posix | ||
727 | @see setnonblock | ||
728 | */ | ||
729 | static int lst_detachfds(lua_State *L) { | ||
730 | static int already_detached = 0; // detaching is once per process(not per thread or Lua state) | ||
731 | if (already_detached) { | ||
732 | lua_pushnil(L); | ||
733 | lua_pushliteral(L, "stdout and stderr already detached"); | ||
734 | return 1; | ||
735 | } | ||
736 | already_detached = 1; | ||
737 | |||
738 | #ifndef _WIN32 | ||
739 | // Reopen stdout and stderr with new file descriptions | ||
740 | reopen_fd(L, STDOUT_FILENO, O_WRONLY); | ||
741 | reopen_fd(L, STDERR_FILENO, O_WRONLY); | ||
742 | #endif | ||
743 | |||
744 | lua_pushboolean(L, 1); | ||
745 | return 1; | ||
746 | } | ||
747 | |||
748 | |||
749 | |||
652 | /*** | 750 | /*** |
653 | Enables or disables non-blocking mode for a file (Posix). | 751 | Enables or disables non-blocking mode for a file (Posix). |
752 | Check `detachfds` in case there are shared file descriptions. | ||
654 | @function setnonblock | 753 | @function setnonblock |
655 | @tparam file fd file handle to operate on, one of `io.stdin`, `io.stdout`, `io.stderr` | 754 | @tparam file fd file handle to operate on, one of `io.stdin`, `io.stdout`, `io.stderr` |
656 | @tparam boolean make_non_block a truthy value will enable non-blocking mode, a falsy value will disable it. | 755 | @tparam boolean make_non_block a truthy value will enable non-blocking mode, a falsy value will disable it. |
@@ -658,9 +757,12 @@ Enables or disables non-blocking mode for a file (Posix). | |||
658 | @treturn[2] nil | 757 | @treturn[2] nil |
659 | @treturn[2] string error message | 758 | @treturn[2] string error message |
660 | @treturn[2] int errnum | 759 | @treturn[2] int errnum |
760 | @within Terminal_Posix | ||
661 | @see getnonblock | 761 | @see getnonblock |
762 | @see detachfds | ||
662 | @usage | 763 | @usage |
663 | local sys = require('system') | 764 | local sys = require('system') |
765 | sys.detachfds() -- detach stdout and stderr, so only stdin becomes non-blocking | ||
664 | 766 | ||
665 | -- set io.stdin to non-blocking mode | 767 | -- set io.stdin to non-blocking mode |
666 | local old_setting = sys.getnonblock(io.stdin) | 768 | local old_setting = sys.getnonblock(io.stdin) |
@@ -717,6 +819,8 @@ Gets non-blocking mode status for a file (Posix). | |||
717 | @treturn[2] nil | 819 | @treturn[2] nil |
718 | @treturn[2] string error message | 820 | @treturn[2] string error message |
719 | @treturn[2] int errnum | 821 | @treturn[2] int errnum |
822 | @within Terminal_Posix | ||
823 | @see setnonblock | ||
720 | */ | 824 | */ |
721 | static int lst_getnonblock(lua_State *L) | 825 | static int lst_getnonblock(lua_State *L) |
722 | { | 826 | { |
@@ -783,6 +887,7 @@ sequences will be buffered internally and returned one byte at a time. | |||
783 | @treturn[3] nil on error | 887 | @treturn[3] nil on error |
784 | @treturn[3] string error message | 888 | @treturn[3] string error message |
785 | @treturn[3] int errnum (on posix) | 889 | @treturn[3] int errnum (on posix) |
890 | @within Terminal_Input | ||
786 | */ | 891 | */ |
787 | static int lst_readkey(lua_State *L) { | 892 | static int lst_readkey(lua_State *L) { |
788 | #ifdef _WIN32 | 893 | #ifdef _WIN32 |
@@ -803,7 +908,18 @@ static int lst_readkey(lua_State *L) { | |||
803 | } | 908 | } |
804 | 909 | ||
805 | wchar_t wc = _getwch(); | 910 | wchar_t wc = _getwch(); |
806 | // printf("----\nread wchar_t: %x\n", wc); | 911 | // printf("----\nread wchar_t: %x\n", (unsigned int)wc); |
912 | |||
913 | if (wc == 0x00 || wc == 0xE0) { | ||
914 | // printf("Ignoring scan code: %x\n", (unsigned int)wc); | ||
915 | // On Windows, especially with key-repeat, we can get native scancodes even if we've set the console | ||
916 | // to ANSI mode. Something, something, terminal not keeping up... These are not valid wide characters, | ||
917 | // so we ignore them. Scan codes start with either 0x00 or 0xE0, and have a follow up byte, which we all ignore. | ||
918 | // These codes are unique, so we do not risk dropping valid data. | ||
919 | _getwch(); // Discard 2nd half of the scan code | ||
920 | return 0; | ||
921 | } | ||
922 | |||
807 | if (wc == WEOF) { | 923 | if (wc == WEOF) { |
808 | lua_pushnil(L); | 924 | lua_pushnil(L); |
809 | lua_pushliteral(L, "read error"); | 925 | lua_pushliteral(L, "read error"); |
@@ -824,7 +940,7 @@ static int lst_readkey(lua_State *L) { | |||
824 | } | 940 | } |
825 | 941 | ||
826 | wchar_t wc2 = _getwch(); | 942 | wchar_t wc2 = _getwch(); |
827 | // printf("read wchar_t 2: %x\n", wc2); | 943 | // printf("read wchar_t 2: %x\n", (unsigned int)wc2); |
828 | if (wc2 == WEOF) { | 944 | if (wc2 == WEOF) { |
829 | lua_pushnil(L); | 945 | lua_pushnil(L); |
830 | lua_pushliteral(L, "read error"); | 946 | lua_pushliteral(L, "read error"); |
@@ -972,6 +1088,7 @@ Get the width of a utf8 character for terminal display. | |||
972 | @treturn[1] int the display width in columns of the first character in the string (0 for an empty string) | 1088 | @treturn[1] int the display width in columns of the first character in the string (0 for an empty string) |
973 | @treturn[2] nil | 1089 | @treturn[2] nil |
974 | @treturn[2] string error message | 1090 | @treturn[2] string error message |
1091 | @within Terminal_UTF-8 | ||
975 | */ | 1092 | */ |
976 | int lst_utf8cwidth(lua_State *L) { | 1093 | int lst_utf8cwidth(lua_State *L) { |
977 | int width = 0; | 1094 | int width = 0; |
@@ -1033,6 +1150,7 @@ Get the width of a utf8 string for terminal display. | |||
1033 | @treturn[1] int the display width of the string in columns (0 for an empty string) | 1150 | @treturn[1] int the display width of the string in columns (0 for an empty string) |
1034 | @treturn[2] nil | 1151 | @treturn[2] nil |
1035 | @treturn[2] string error message | 1152 | @treturn[2] string error message |
1153 | @within Terminal_UTF-8 | ||
1036 | */ | 1154 | */ |
1037 | int lst_utf8swidth(lua_State *L) { | 1155 | int lst_utf8swidth(lua_State *L) { |
1038 | const char *utf8_str; | 1156 | const char *utf8_str; |
@@ -1083,6 +1201,7 @@ int lst_utf8swidth(lua_State *L) { | |||
1083 | Gets the current console code page (Windows). | 1201 | Gets the current console code page (Windows). |
1084 | @function getconsolecp | 1202 | @function getconsolecp |
1085 | @treturn[1] int the current code page (always 65001 on Posix systems) | 1203 | @treturn[1] int the current code page (always 65001 on Posix systems) |
1204 | @within Terminal_UTF-8 | ||
1086 | */ | 1205 | */ |
1087 | static int lst_getconsolecp(lua_State *L) { | 1206 | static int lst_getconsolecp(lua_State *L) { |
1088 | unsigned int cp = 65001; | 1207 | unsigned int cp = 65001; |
@@ -1100,6 +1219,7 @@ Sets the current console code page (Windows). | |||
1100 | @function setconsolecp | 1219 | @function setconsolecp |
1101 | @tparam int cp the code page to set, use `system.CODEPAGE_UTF8` (65001) for UTF-8 | 1220 | @tparam int cp the code page to set, use `system.CODEPAGE_UTF8` (65001) for UTF-8 |
1102 | @treturn[1] bool `true` on success (always `true` on Posix systems) | 1221 | @treturn[1] bool `true` on success (always `true` on Posix systems) |
1222 | @within Terminal_UTF-8 | ||
1103 | */ | 1223 | */ |
1104 | static int lst_setconsolecp(lua_State *L) { | 1224 | static int lst_setconsolecp(lua_State *L) { |
1105 | unsigned int cp = (unsigned int)luaL_checkinteger(L, 1); | 1225 | unsigned int cp = (unsigned int)luaL_checkinteger(L, 1); |
@@ -1117,6 +1237,7 @@ static int lst_setconsolecp(lua_State *L) { | |||
1117 | Gets the current console output code page (Windows). | 1237 | Gets the current console output code page (Windows). |
1118 | @function getconsoleoutputcp | 1238 | @function getconsoleoutputcp |
1119 | @treturn[1] int the current code page (always 65001 on Posix systems) | 1239 | @treturn[1] int the current code page (always 65001 on Posix systems) |
1240 | @within Terminal_UTF-8 | ||
1120 | */ | 1241 | */ |
1121 | static int lst_getconsoleoutputcp(lua_State *L) { | 1242 | static int lst_getconsoleoutputcp(lua_State *L) { |
1122 | unsigned int cp = 65001; | 1243 | unsigned int cp = 65001; |
@@ -1134,6 +1255,7 @@ Sets the current console output code page (Windows). | |||
1134 | @function setconsoleoutputcp | 1255 | @function setconsoleoutputcp |
1135 | @tparam int cp the code page to set, use `system.CODEPAGE_UTF8` (65001) for UTF-8 | 1256 | @tparam int cp the code page to set, use `system.CODEPAGE_UTF8` (65001) for UTF-8 |
1136 | @treturn[1] bool `true` on success (always `true` on Posix systems) | 1257 | @treturn[1] bool `true` on success (always `true` on Posix systems) |
1258 | @within Terminal_UTF-8 | ||
1137 | */ | 1259 | */ |
1138 | static int lst_setconsoleoutputcp(lua_State *L) { | 1260 | static int lst_setconsoleoutputcp(lua_State *L) { |
1139 | unsigned int cp = (unsigned int)luaL_checkinteger(L, 1); | 1261 | unsigned int cp = (unsigned int)luaL_checkinteger(L, 1); |
@@ -1157,6 +1279,7 @@ static luaL_Reg func[] = { | |||
1157 | { "setconsoleflags", lst_setconsoleflags }, | 1279 | { "setconsoleflags", lst_setconsoleflags }, |
1158 | { "tcgetattr", lst_tcgetattr }, | 1280 | { "tcgetattr", lst_tcgetattr }, |
1159 | { "tcsetattr", lst_tcsetattr }, | 1281 | { "tcsetattr", lst_tcsetattr }, |
1282 | { "detachfds", lst_detachfds }, | ||
1160 | { "getnonblock", lst_getnonblock }, | 1283 | { "getnonblock", lst_getnonblock }, |
1161 | { "setnonblock", lst_setnonblock }, | 1284 | { "setnonblock", lst_setnonblock }, |
1162 | { "_readkey", lst_readkey }, | 1285 | { "_readkey", lst_readkey }, |
diff --git a/system/init.lua b/system/init.lua index a81978e..9b71d4d 100644 --- a/system/init.lua +++ b/system/init.lua | |||
@@ -10,17 +10,21 @@ local system = require 'system.core' | |||
10 | --- UTF8 codepage. | 10 | --- UTF8 codepage. |
11 | -- To be used with `system.setconsoleoutputcp` and `system.setconsolecp`. | 11 | -- To be used with `system.setconsoleoutputcp` and `system.setconsolecp`. |
12 | -- @field CODEPAGE_UTF8 The Windows CodePage for UTF8. | 12 | -- @field CODEPAGE_UTF8 The Windows CodePage for UTF8. |
13 | -- @within Terminal_UTF-8 | ||
13 | system.CODEPAGE_UTF8 = 65001 | 14 | system.CODEPAGE_UTF8 = 65001 |
14 | 15 | ||
15 | do | 16 | do |
16 | local backup_mt = {} | 17 | local backup_indicator = {} |
17 | 18 | ||
18 | --- Returns a backup of terminal settings for stdin/out/err. | 19 | --- Returns a backup of terminal settings for stdin/out/err. |
19 | -- Handles terminal/console flags, Windows codepage, and non-block flags on the streams. | 20 | -- Handles terminal/console flags, Windows codepage, and non-block flags on the streams. |
20 | -- Backs up terminal/console flags only if a stream is a tty. | 21 | -- Backs up terminal/console flags only if a stream is a tty. |
21 | -- @return table with backup of terminal settings | 22 | -- @return table with backup of terminal settings |
23 | -- @within Terminal_Backup | ||
22 | function system.termbackup() | 24 | function system.termbackup() |
23 | local backup = setmetatable({}, backup_mt) | 25 | local backup = { |
26 | __type = backup_indicator, -- cannot set a metatable, since autotermrestore uses it for GC | ||
27 | } | ||
24 | 28 | ||
25 | if system.isatty(io.stdin) then | 29 | if system.isatty(io.stdin) then |
26 | backup.console_in = system.getconsoleflags(io.stdin) | 30 | backup.console_in = system.getconsoleflags(io.stdin) |
@@ -50,8 +54,9 @@ do | |||
50 | --- Restores terminal settings from a backup | 54 | --- Restores terminal settings from a backup |
51 | -- @tparam table backup the backup of terminal settings, see `termbackup`. | 55 | -- @tparam table backup the backup of terminal settings, see `termbackup`. |
52 | -- @treturn boolean true | 56 | -- @treturn boolean true |
57 | -- @within Terminal_Backup | ||
53 | function system.termrestore(backup) | 58 | function system.termrestore(backup) |
54 | if getmetatable(backup) ~= backup_mt then | 59 | if type(backup) ~= "table" or backup.__type ~= backup_indicator then |
55 | error("arg #1 to termrestore, expected backup table, got " .. type(backup), 2) | 60 | error("arg #1 to termrestore, expected backup table, got " .. type(backup), 2) |
56 | end | 61 | end |
57 | 62 | ||
@@ -106,6 +111,7 @@ do -- autotermrestore | |||
106 | -- @treturn[1] boolean true | 111 | -- @treturn[1] boolean true |
107 | -- @treturn[2] nil if the backup was already created | 112 | -- @treturn[2] nil if the backup was already created |
108 | -- @treturn[2] string error message | 113 | -- @treturn[2] string error message |
114 | -- @within Terminal_Backup | ||
109 | function system.autotermrestore() | 115 | function system.autotermrestore() |
110 | if global_backup then | 116 | if global_backup then |
111 | return nil, "global terminal backup was already set up" | 117 | return nil, "global terminal backup was already set up" |
@@ -134,6 +140,7 @@ do | |||
134 | -- Calls `termbackup` before calling the function and `termrestore` after. | 140 | -- Calls `termbackup` before calling the function and `termrestore` after. |
135 | -- @tparam function f function to wrap | 141 | -- @tparam function f function to wrap |
136 | -- @treturn function wrapped function | 142 | -- @treturn function wrapped function |
143 | -- @within Terminal_Backup | ||
137 | function system.termwrap(f) | 144 | function system.termwrap(f) |
138 | if type(f) ~= "function" then | 145 | if type(f) ~= "function" then |
139 | error("arg #1 to wrap, expected function, got " .. type(f), 2) | 146 | error("arg #1 to wrap, expected function, got " .. type(f), 2) |
@@ -153,6 +160,7 @@ end | |||
153 | --- Debug function for console flags (Windows). | 160 | --- Debug function for console flags (Windows). |
154 | -- Pretty prints the current flags set for the handle. | 161 | -- Pretty prints the current flags set for the handle. |
155 | -- @param fh file handle (`io.stdin`, `io.stdout`, `io.stderr`) | 162 | -- @param fh file handle (`io.stdin`, `io.stdout`, `io.stderr`) |
163 | -- @within Terminal_Windows | ||
156 | -- @usage -- Print the flags for stdin/out/err | 164 | -- @usage -- Print the flags for stdin/out/err |
157 | -- system.listconsoleflags(io.stdin) | 165 | -- system.listconsoleflags(io.stdin) |
158 | -- system.listconsoleflags(io.stdout) | 166 | -- system.listconsoleflags(io.stdout) |
@@ -192,6 +200,7 @@ end | |||
192 | --- Debug function for terminal flags (Posix). | 200 | --- Debug function for terminal flags (Posix). |
193 | -- Pretty prints the current flags set for the handle. | 201 | -- Pretty prints the current flags set for the handle. |
194 | -- @param fh file handle (`io.stdin`, `io.stdout`, `io.stderr`) | 202 | -- @param fh file handle (`io.stdin`, `io.stdout`, `io.stderr`) |
203 | -- @within Terminal_Posix | ||
195 | -- @usage -- Print the flags for stdin/out/err | 204 | -- @usage -- Print the flags for stdin/out/err |
196 | -- system.listconsoleflags(io.stdin) | 205 | -- system.listconsoleflags(io.stdin) |
197 | -- system.listconsoleflags(io.stdout) | 206 | -- system.listconsoleflags(io.stdout) |
@@ -230,32 +239,40 @@ end | |||
230 | do | 239 | do |
231 | --- Reads a single byte from the console, with a timeout. | 240 | --- Reads a single byte from the console, with a timeout. |
232 | -- This function uses `fsleep` to wait until either a byte is available or the timeout is reached. | 241 | -- This function uses `fsleep` to wait until either a byte is available or the timeout is reached. |
233 | -- The sleep period is exponentially backing off, starting at 0.0125 seconds, with a maximum of 0.2 seconds. | 242 | -- The sleep period is exponentially backing off, starting at 0.0125 seconds, with a maximum of 0.1 seconds. |
234 | -- It returns immediately if a byte is available or if `timeout` is less than or equal to `0`. | 243 | -- It returns immediately if a byte is available or if `timeout` is less than or equal to `0`. |
235 | -- | 244 | -- |
236 | -- Using `system.readansi` is preferred over this function. Since this function can leave stray/invalid | 245 | -- Using `system.readansi` is preferred over this function. Since this function can leave stray/invalid |
237 | -- byte-sequences in the input buffer, while `system.readansi` reads full ANSI and UTF8 sequences. | 246 | -- byte-sequences in the input buffer, while `system.readansi` reads full ANSI and UTF8 sequences. |
238 | -- @tparam number timeout the timeout in seconds. | 247 | -- @tparam number timeout the timeout in seconds. |
239 | -- @tparam[opt=system.sleep] function fsleep the function to call for sleeping. | 248 | -- @tparam[opt=system.sleep] function fsleep the function to call for sleeping; `ok, err = fsleep(secs)` |
240 | -- @treturn[1] byte the byte value that was read. | 249 | -- @treturn[1] byte the byte value that was read. |
241 | -- @treturn[2] nil if no key was read | 250 | -- @treturn[2] nil if no key was read |
242 | -- @treturn[2] string error message; `"timeout"` if the timeout was reached. | 251 | -- @treturn[2] string error message when the timeout was reached (`"timeout"`), or if `sleep` failed. |
252 | -- @within Terminal_Input | ||
243 | function system.readkey(timeout, fsleep) | 253 | function system.readkey(timeout, fsleep) |
244 | if type(timeout) ~= "number" then | 254 | if type(timeout) ~= "number" then |
245 | error("arg #1 to readkey, expected timeout in seconds, got " .. type(timeout), 2) | 255 | error("arg #1 to readkey, expected timeout in seconds, got " .. type(timeout), 2) |
246 | end | 256 | end |
247 | 257 | ||
248 | local interval = 0.0125 | 258 | local interval = 0.0125 |
249 | local key = system._readkey() | 259 | local ok |
260 | local key, err = system._readkey() | ||
250 | while key == nil and timeout > 0 do | 261 | while key == nil and timeout > 0 do |
251 | (fsleep or system.sleep)(math.min(interval, timeout)) | 262 | if err then |
263 | return nil, err | ||
264 | end | ||
265 | ok, err = (fsleep or system.sleep)(math.min(interval, timeout)) | ||
266 | if not ok then | ||
267 | return nil, err | ||
268 | end | ||
252 | timeout = timeout - interval | 269 | timeout = timeout - interval |
253 | interval = math.min(0.2, interval * 2) | 270 | interval = math.min(0.1, interval * 2) |
254 | key = system._readkey() | 271 | key, err = system._readkey() |
255 | end | 272 | end |
256 | 273 | ||
257 | if key then | 274 | if key or err then |
258 | return key | 275 | return key, err |
259 | end | 276 | end |
260 | return nil, "timeout" | 277 | return nil, "timeout" |
261 | end | 278 | end |
@@ -264,7 +281,6 @@ end | |||
264 | 281 | ||
265 | 282 | ||
266 | do | 283 | do |
267 | local left_over_key | ||
268 | local sequence -- table to store the sequence in progress | 284 | local sequence -- table to store the sequence in progress |
269 | local utf8_length -- length of utf8 sequence currently being processed | 285 | local utf8_length -- length of utf8 sequence currently being processed |
270 | local unpack = unpack or table.unpack | 286 | local unpack = unpack or table.unpack |
@@ -278,10 +294,20 @@ do | |||
278 | -- @tparam number timeout the timeout in seconds. | 294 | -- @tparam number timeout the timeout in seconds. |
279 | -- @tparam[opt=system.sleep] function fsleep the function to call for sleeping. | 295 | -- @tparam[opt=system.sleep] function fsleep the function to call for sleeping. |
280 | -- @treturn[1] string the character that was received (can be multi-byte), or a complete ANSI sequence | 296 | -- @treturn[1] string the character that was received (can be multi-byte), or a complete ANSI sequence |
281 | -- @treturn[1] string the type of input: `"char"` for a single key, `"ansi"` for an ANSI sequence | 297 | -- @treturn[1] string the type of input: `"ctrl"` for 0-31 and 127 bytes, `"char"` for other UTF-8 characters, `"ansi"` for an ANSI sequence |
282 | -- @treturn[2] nil in case of an error | 298 | -- @treturn[2] nil in case of an error |
283 | -- @treturn[2] string error message; `"timeout"` if the timeout was reached. | 299 | -- @treturn[2] string error message; `"timeout"` if the timeout was reached. |
284 | -- @treturn[2] string partial result in case of an error while reading a sequence, the sequence so far. | 300 | -- @treturn[2] string partial result in case of an error while reading a sequence, the sequence so far. |
301 | -- The function retains its own internal buffer, so on the next call the incomplete buffer is used to | ||
302 | -- complete the sequence. | ||
303 | -- @within Terminal_Input | ||
304 | -- @usage | ||
305 | -- local key, keytype = system.readansi(5) | ||
306 | -- if keytype == "char" then ... end -- printable character | ||
307 | -- if keytype ~= "char" then ... end -- non-printable character or sequence | ||
308 | -- if keytype == "ansi" then ... end -- a multi-byte sequence, but not a UTF8 character | ||
309 | -- if keytype ~= "ansi" then ... end -- a valid UTF8 character (which includes control characters) | ||
310 | -- if keytype == "ctrl" then ... end -- a single-byte ctrl character (0-31, 127) | ||
285 | function system.readansi(timeout, fsleep) | 311 | function system.readansi(timeout, fsleep) |
286 | if type(timeout) ~= "number" then | 312 | if type(timeout) ~= "number" then |
287 | error("arg #1 to readansi, expected timeout in seconds, got " .. type(timeout), 2) | 313 | error("arg #1 to readansi, expected timeout in seconds, got " .. type(timeout), 2) |
@@ -292,40 +318,54 @@ do | |||
292 | 318 | ||
293 | if not sequence then | 319 | if not sequence then |
294 | -- no sequence in progress, read a key | 320 | -- no sequence in progress, read a key |
295 | 321 | local err | |
296 | if left_over_key then | 322 | key, err = system.readkey(timeout, fsleep) |
297 | -- we still have a cached key from the last call | 323 | if key == nil then -- timeout or error |
298 | key = left_over_key | 324 | return nil, err |
299 | left_over_key = nil | ||
300 | else | ||
301 | -- read a new key | ||
302 | local err | ||
303 | key, err = system.readkey(timeout, fsleep) | ||
304 | if key == nil then -- timeout or error | ||
305 | return nil, err | ||
306 | end | ||
307 | end | 325 | end |
308 | 326 | ||
309 | if key == 27 then | 327 | if key == 27 then |
310 | -- looks like an ansi escape sequence, immediately read next char | 328 | -- looks like an ansi escape sequence, immediately read next char |
311 | -- as an heuristic against manually typing escape sequences | 329 | -- as an heuristic against manually typing escape sequences |
312 | local key2 = system.readkey(0, fsleep) | 330 | local key2 = system.readkey(0, fsleep) |
313 | if key2 ~= 91 and key2 ~= 79 then -- we expect either "[" or "O" for an ANSI sequence | 331 | if key2 == nil then |
314 | -- not the expected [ or O character, so we return the key as is | 332 | -- no key available, return the escape key, on its own |
315 | -- and store the extra key read for the next call | 333 | sequence = nil |
316 | left_over_key = key2 | 334 | return string.char(key), "ctrl" |
317 | return string.char(key), "char" | 335 | |
336 | elseif key2 == 91 then | ||
337 | -- "[" means it is for sure an ANSI sequence | ||
338 | sequence = { key, key2 } | ||
339 | |||
340 | elseif key2 == 79 then | ||
341 | -- "O" means it is either an ANSI sequence or just an <alt>+O key stroke | ||
342 | -- check if there is yet another byte available | ||
343 | local key3 = system.readkey(0, fsleep) | ||
344 | if key3 == nil then | ||
345 | -- no key available, return the <alt>O key stroke, report as ANSI | ||
346 | sequence = nil | ||
347 | return string.char(key, key2), "ansi" | ||
348 | end | ||
349 | -- it's an ANSI sequence, marked with <ESC>O | ||
350 | if (key3 >= 65 and key3 <= 90) or (key3 >= 97 and key3 <= 126) then | ||
351 | -- end of sequence, return the full sequence | ||
352 | return string.char(key, key2, key3), "ansi" | ||
353 | end | ||
354 | sequence = { key, key2, key3 } | ||
355 | |||
356 | else | ||
357 | -- not an ANSI sequence, but an <alt>+<key2> key stroke, so report as ANSI | ||
358 | sequence = nil | ||
359 | return string.char(key, key2), "ansi" | ||
318 | end | 360 | end |
319 | 361 | ||
320 | -- escape sequence detected | ||
321 | sequence = { key, key2 } | ||
322 | else | 362 | else |
323 | -- check UTF8 length | 363 | -- check UTF8 length |
324 | utf8_length = key < 128 and 1 or key < 224 and 2 or key < 240 and 3 or key < 248 and 4 | 364 | utf8_length = key < 128 and 1 or key < 224 and 2 or key < 240 and 3 or key < 248 and 4 |
325 | if utf8_length == 1 then | 365 | if utf8_length == 1 then |
326 | -- single byte character | 366 | -- single byte character |
327 | utf8_length = nil | 367 | utf8_length = nil |
328 | return string.char(key), "char" | 368 | return string.char(key), ((key <= 31 or key == 127) and "ctrl" or "char") |
329 | else | 369 | else |
330 | -- UTF8 sequence detected | 370 | -- UTF8 sequence detected |
331 | sequence = { key } | 371 | sequence = { key } |