diff options
author | Thijs Schreijer <thijs@thijsschreijer.nl> | 2024-06-20 23:16:29 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-06-20 23:16:29 +0200 |
commit | bb4fd73c317cc88beb5e58c1abf52138abed107f (patch) | |
tree | 35b774efc97d820a908424a5bc2452e0d6bf12a8 /docs/topics/03-terminal.md.html | |
parent | c1a64c1b75f97cef97965b3bd9a941564a6270bd (diff) | |
download | luasystem-0.4.0.tar.gz luasystem-0.4.0.tar.bz2 luasystem-0.4.0.zip |
Release v0.4.0 (#24)v0.4.0
Diffstat (limited to 'docs/topics/03-terminal.md.html')
-rw-r--r-- | docs/topics/03-terminal.md.html | 225 |
1 files changed, 225 insertions, 0 deletions
diff --git a/docs/topics/03-terminal.md.html b/docs/topics/03-terminal.md.html new file mode 100644 index 0000000..3e7e548 --- /dev/null +++ b/docs/topics/03-terminal.md.html | |||
@@ -0,0 +1,225 @@ | |||
1 | <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" | ||
2 | "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> | ||
3 | <html> | ||
4 | <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> | ||
5 | <head> | ||
6 | <title>Lua-System docs</title> | ||
7 | <link rel="stylesheet" href="../ldoc.css" type="text/css" /> | ||
8 | </head> | ||
9 | <body> | ||
10 | |||
11 | <div id="container"> | ||
12 | |||
13 | <div id="product"> | ||
14 | <div id="product_logo"></div> | ||
15 | <div id="product_name"><big><b></b></big></div> | ||
16 | <div id="product_description"></div> | ||
17 | </div> <!-- id="product" --> | ||
18 | |||
19 | |||
20 | <div id="main"> | ||
21 | |||
22 | |||
23 | <!-- Menu --> | ||
24 | |||
25 | <div id="navigation"> | ||
26 | <br/> | ||
27 | <h1>Lua-System</h1> | ||
28 | |||
29 | |||
30 | <ul> | ||
31 | <li><a href="../index.html">Index</a></li> | ||
32 | </ul> | ||
33 | |||
34 | <h2>Contents</h2> | ||
35 | <ul> | ||
36 | <li><a href="#3_1_Backup_and_Restore_terminal_settings">3.1 Backup and Restore terminal settings </a></li> | ||
37 | <li><a href="#3_1_Terminal_ANSI_sequences">3.1 Terminal ANSI sequences </a></li> | ||
38 | <li><a href="#3_2_UTF_8_in_output_and_display_width">3.2 UTF-8 in/output and display width </a></li> | ||
39 | <li><a href="#3_3_reading_keyboard_input">3.3 reading keyboard input </a></li> | ||
40 | </ul> | ||
41 | |||
42 | |||
43 | <h2>Topics</h2> | ||
44 | <ul class=""> | ||
45 | <li><a href="../topics/01-introduction.md.html">1. Introduction</a></li> | ||
46 | <li><a href="../topics/02-development.md.html">2. Development</a></li> | ||
47 | <li><strong>3. Terminal functionality</strong></li> | ||
48 | <li><a href="../topics/CHANGELOG.md.html">CHANGELOG</a></li> | ||
49 | <li><a href="../topics/LICENSE.md.html">MIT License</a></li> | ||
50 | </ul> | ||
51 | <h2>Modules</h2> | ||
52 | <ul class="nowrap"> | ||
53 | <li><a href="../modules/system.html">system</a></li> | ||
54 | </ul> | ||
55 | <h2>Classes</h2> | ||
56 | <ul class="nowrap"> | ||
57 | <li><a href="../classes/bitflags.html">bitflags</a></li> | ||
58 | </ul> | ||
59 | <h2>Examples</h2> | ||
60 | <ul class="nowrap"> | ||
61 | <li><a href="../examples/compat.lua.html">compat.lua</a></li> | ||
62 | <li><a href="../examples/flag_debugging.lua.html">flag_debugging.lua</a></li> | ||
63 | <li><a href="../examples/password_input.lua.html">password_input.lua</a></li> | ||
64 | <li><a href="../examples/read.lua.html">read.lua</a></li> | ||
65 | <li><a href="../examples/readline.lua.html">readline.lua</a></li> | ||
66 | <li><a href="../examples/spinner.lua.html">spinner.lua</a></li> | ||
67 | <li><a href="../examples/spiral_snake.lua.html">spiral_snake.lua</a></li> | ||
68 | <li><a href="../examples/terminalsize.lua.html">terminalsize.lua</a></li> | ||
69 | </ul> | ||
70 | |||
71 | </div> | ||
72 | |||
73 | <div id="content"> | ||
74 | |||
75 | |||
76 | <h1>3. Terminal functionality</h1> | ||
77 | |||
78 | <p>Terminals are fundamentally different on Windows and Posix. So even though | ||
79 | <code>luasystem</code> provides primitives to manipulate both the Windows and Posix terminals, | ||
80 | the user will still have to write platform specific code.</p> | ||
81 | |||
82 | <p>To mitigate this a little, all functions are available on all platforms. They just | ||
83 | will be a no-op if invoked on another platform. This means that no platform specific | ||
84 | branching is required (but still possible) in user code. The user must simply set | ||
85 | up both platforms to make it work.</p> | ||
86 | |||
87 | <p><a name="3_1_Backup_and_Restore_terminal_settings"></a></p> | ||
88 | <h2>3.1 Backup and Restore terminal settings</h2> | ||
89 | |||
90 | <p>Since there are a myriad of settings available;</p> | ||
91 | |||
92 | <ul> | ||
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> | ||
95 | <li><a href="../modules/system.html#setconsoleoutputcp">system.setconsoleoutputcp</a> (Windows)</li> | ||
96 | <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 | </ul> | ||
99 | |||
100 | <p>Some helper functions are available to backup and restore them all at once. | ||
101 | See <code>termbackup</code>, <code>termrestore</code>, <code>autotermrestore</code> and <code>termwrap</code>.</p> | ||
102 | |||
103 | |||
104 | <p><a name="3_1_Terminal_ANSI_sequences"></a></p> | ||
105 | <h2>3.1 Terminal ANSI sequences</h2> | ||
106 | |||
107 | <p>Windows is catching up with this. In Windows 10 (since 2019), the Windows Terminal application (not to be | ||
108 | mistaken for the <code>cmd</code> console application) supports ANSI sequences. However this | ||
109 | might not be enabled by default.</p> | ||
110 | |||
111 | <p>ANSI processing can be set up both on the input (key sequences, reading cursor position) | ||
112 | as well as on the output (setting colors and cursor shapes).</p> | ||
113 | |||
114 | <p>To enable it use <a href="../modules/system.html#setconsoleflags">system.setconsoleflags</a> like this:</p> | ||
115 | |||
116 | |||
117 | <pre> | ||
118 | <span class="comment">-- setup Windows console to handle ANSI processing on output | ||
119 | </span>sys.<span class="function-name">setconsoleflags</span>(<span class="global">io</span>.stdout, sys.<span class="function-name">getconsoleflags</span>(<span class="global">io</span>.stdout) + sys.COF_VIRTUAL_TERMINAL_PROCESSING) | ||
120 | sys.<span class="function-name">setconsoleflags</span>(<span class="global">io</span>.stderr, sys.<span class="function-name">getconsoleflags</span>(<span class="global">io</span>.stderr) + sys.COF_VIRTUAL_TERMINAL_PROCESSING) | ||
121 | |||
122 | <span class="comment">-- setup Windows console to handle ANSI processing on input | ||
123 | </span>sys.<span class="function-name">setconsoleflags</span>(<span class="global">io</span>.stdin, sys.<span class="function-name">getconsoleflags</span>(<span class="global">io</span>.stdin) + sys.CIF_VIRTUAL_TERMINAL_INPUT) | ||
124 | </pre> | ||
125 | |||
126 | <p><a name="3_2_UTF_8_in_output_and_display_width"></a></p> | ||
127 | <h2>3.2 UTF-8 in/output and display width</h2> | ||
128 | |||
129 | <h3>3.2.1 UTF-8 in/output</h3> | ||
130 | |||
131 | <p>Where (most) Posix systems use UTF-8 by default, Windows internally uses UTF-16. More | ||
132 | recent versions of Lua also have UTF-8 support. So <code>luasystem</code> also focusses on UTF-8.</p> | ||
133 | |||
134 | <p>On Windows UTF-8 output can be enabled by setting the output codepage like this:</p> | ||
135 | |||
136 | |||
137 | <pre> | ||
138 | <span class="comment">-- setup Windows output codepage to UTF-8 | ||
139 | </span>sys.<span class="function-name">setconsoleoutputcp</span>(sys.CODEPAGE_UTF8) | ||
140 | </pre> | ||
141 | |||
142 | <p>Terminal input is handled by the <a href="https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/getchar-getwchar"><code>_getwchar()</code></a> function on Windows which returns | ||
143 | UTF-16 surrogate pairs. <code>luasystem</code> will automatically convert those to UTF-8. | ||
144 | So when using <code>readkey</code> or <code>readansi</code> to read keyboard input no additional changes | ||
145 | are required.</p> | ||
146 | |||
147 | <h3>3.2.2 UTF-8 display width</h3> | ||
148 | |||
149 | <p>Typical western characters and symbols are single width characters and will use only | ||
150 | a single column when displayed on a terminal. However many characters from other | ||
151 | languages/cultures or emojis require 2 columns for display.</p> | ||
152 | |||
153 | <p>Typically the <code>wcwidth</code> function is used on Posix to check the number of columns | ||
154 | required for display. However since Windows doesn't provide this functionality a | ||
155 | custom implementation is included based on <a href="http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c">the work by Markus Kuhn</a>.</p> | ||
156 | |||
157 | <p>2 functions are provided, <a href="../modules/system.html#utf8cwidth">system.utf8cwidth</a> for a single character, and <a href="../modules/system.html#utf8swidth">system.utf8swidth</a> for | ||
158 | a string. When writing terminal applications the display width is relevant to | ||
159 | positioning the cursor properly. For an example see the <a href="../examples/readline.lua.html"><code>examples/readline.lua</code></a> file.</p> | ||
160 | |||
161 | |||
162 | <p><a name="3_3_reading_keyboard_input"></a></p> | ||
163 | <h2>3.3 reading keyboard input</h2> | ||
164 | |||
165 | <h3>3.3.1 Non-blocking</h3> | ||
166 | |||
167 | <p>There are 2 functions for keyboard input (actually 3, if taking <a href="../modules/system.html#_readkey">system._readkey</a> into | ||
168 | account): <code>readkey</code> and <code>readansi</code>.</p> | ||
169 | |||
170 | <p><code>readkey</code> is a low level function and should preferably not be used, it returns | ||
171 | a byte at a time, and hence can leave stray/invalid byte sequences in the buffer if | ||
172 | only the start of a UTF-8 or ANSI sequence is consumed.</p> | ||
173 | |||
174 | <p>The preferred way is to use <code>readansi</code> which will parse and return entire characters in | ||
175 | single or multiple bytes, or a full ANSI sequence.</p> | ||
176 | |||
177 | <p>On Windows the input is read using <a href="https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/getchar-getwchar"><code>_getwchar()</code></a> which bypasses the terminal and reads | ||
178 | the input directly from the keyboard buffer. This means however that the character is | ||
179 | also not being echoed to the terminal (independent of the echo settings used with | ||
180 | <a href="../modules/system.html#setconsoleflags">system.setconsoleflags</a>).</p> | ||
181 | |||
182 | <p>On Posix the traditional file approach is used, which:</p> | ||
183 | |||
184 | <ul> | ||
185 | <li>is blocking by default</li> | ||
186 | <li>echoes input to the terminal</li> | ||
187 | <li>requires enter to be pressed to pass the input (canonical mode)</li> | ||
188 | </ul> | ||
189 | |||
190 | <p>To use non-blocking input here's how to set it up:</p> | ||
191 | |||
192 | |||
193 | <pre> | ||
194 | <span class="comment">-- setup Windows console to disable echo and line input (not required since _getwchar is used, just for consistency) | ||
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 | |||
197 | <span class="comment">-- setup Posix by disabling echo, canonical mode, and making non-blocking | ||
198 | </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, { | ||
200 | lflag = of_attr.lflag - sys.L_ICANON - sys.L_ECHO, | ||
201 | }) | ||
202 | sys.<span class="function-name">setnonblock</span>(<span class="global">io</span>.stdin, <span class="keyword">true</span>) | ||
203 | </pre> | ||
204 | |||
205 | <p>Both functions require a timeout to be provided which allows for proper asynchronous | ||
206 | code to be written. Since the underlying sleep method used is <a href="../modules/system.html#sleep">system.sleep</a>, just patching | ||
207 | that function with a coroutine based yielding one should be all that is needed to make | ||
208 | the result work with asynchroneous coroutine schedulers.</p> | ||
209 | |||
210 | <h3>3.3.2 Blocking input</h3> | ||
211 | |||
212 | <p>When using traditional input method like <code>io.stdin:read()</code> (which is blocking) the echo | ||
213 | and newline properties should be set on Windows similar to Posix. | ||
214 | For an example see <a href="../examples/password_input.lua.html"><code>examples/password_input.lua</code></a>.</p> | ||
215 | |||
216 | |||
217 | </div> <!-- id="content" --> | ||
218 | </div> <!-- id="main" --> | ||
219 | <div id="about"> | ||
220 | <i>generated by <a href="http://github.com/lunarmodules/LDoc">LDoc 1.5.0</a></i> | ||
221 | <i style="float:right;">Last updated 2024-06-20 23:11:37 </i> | ||
222 | </div> <!-- id="about" --> | ||
223 | </div> <!-- id="container" --> | ||
224 | </body> | ||
225 | </html> | ||