aboutsummaryrefslogtreecommitdiff
path: root/doc_topics
diff options
context:
space:
mode:
authorThijs Schreijer <thijs@thijsschreijer.nl>2024-05-23 20:46:18 +0200
committerThijs Schreijer <thijs@thijsschreijer.nl>2024-05-23 20:57:20 +0200
commit56db1511baeb0376a12915c69c1552b04010c26f (patch)
treed03aa6b4c33a6de39371e9be336c471bfd2cafc5 /doc_topics
parent8f8d34f03428dbaa6cac229bbe36efc6d80d186d (diff)
downloadluasystem-56db1511baeb0376a12915c69c1552b04010c26f.tar.gz
luasystem-56db1511baeb0376a12915c69c1552b04010c26f.tar.bz2
luasystem-56db1511baeb0376a12915c69c1552b04010c26f.zip
cleanup and documentation
Diffstat (limited to 'doc_topics')
-rw-r--r--doc_topics/03-terminal.md124
1 files changed, 124 insertions, 0 deletions
diff --git a/doc_topics/03-terminal.md b/doc_topics/03-terminal.md
new file mode 100644
index 0000000..06a6b96
--- /dev/null
+++ b/doc_topics/03-terminal.md
@@ -0,0 +1,124 @@
1# 3. Terminal functionality
2
3Terminals are fundamentally different on Windows and Posix. So even though
4`luasystem` provides primitives to manipulate both the Windows and Posix terminals,
5the user will still have to write platform specific code.
6
7To mitigate this a little, all functions are available on all platforms. They just
8will be a no-op if invoked on another platform. This means that no platform specific
9branching is required (but still possible) in user code. The user must simply set
10up both platforms to make it work.
11
12## 3.1 Backup and Restore terminal settings
13
14Since there are a myriad of settings available;
15
16- `system.setconsoleflags` (Windows)
17- `system.setconsolecp` (Windows)
18- `system.setconsoleoutputcp` (Windows)
19- `system.setnonblock` (Posix)
20- `system.tcsetattr` (Posix)
21
22Some helper functions are available to backup and restore them all at once.
23See `termbackup`, `termrestore`, `autotermrestore` and `termwrap`.
24
25
26## 3.1 Terminal ANSI sequences
27
28Windows is catching up with this. In Windows 10 (since 2019), the Windows Terminal application (not to be
29mistaken for the `cmd` console application) supports ANSI sequences. However this
30might not be enabled by default.
31
32ANSI processing can be set up both on the input (key sequences, reading cursor position)
33as well as on the output (setting colors and cursor shapes).
34
35To enable it use `system.setconsoleflags` like this:
36
37 -- setup Windows console to handle ANSI processing on output
38 sys.setconsoleflags(io.stdout, sys.getconsoleflags(io.stdout) + sys.COF_VIRTUAL_TERMINAL_PROCESSING)
39 sys.setconsoleflags(io.stderr, sys.getconsoleflags(io.stderr) + sys.COF_VIRTUAL_TERMINAL_PROCESSING)
40
41 -- setup Windows console to handle ANSI processing on input
42 sys.setconsoleflags(io.stdin, sys.getconsoleflags(io.stdin) + sys.CIF_VIRTUAL_TERMINAL_INPUT)
43
44
45## 3.2 UTF-8 in/output and display width
46
47### 3.2.1 UTF-8 in/output
48
49Where (most) Posix systems use UTF-8 by default, Windows internally uses UTF-16. More
50recent versions of Lua also have UTF-8 support. So `luasystem` also focusses on UTF-8.
51
52On Windows UTF-8 output can be enabled by setting the output codepage like this:
53
54 -- setup Windows output codepage to UTF-8; 65001
55 sys.setconsoleoutputcp(65001)
56
57Terminal input is handled by the [`_getwchar()`](https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/getchar-getwchar) function on Windows which returns
58UTF-16 surrogate pairs. `luasystem` will automatically convert those to UTF-8.
59So when using `readkey` or `readansi` to read keyboard input no additional changes
60are required.
61
62### 3.2.2 UTF-8 display width
63
64Typical western characters and symbols are single width characters and will use only
65a single column when displayed on a terminal. However many characters from other
66languages/cultures or emojis require 2 columns for display.
67
68Typically the `wcwidth` function is used on Posix to check the number of columns
69required for display. However since Windows doesn't provide this functionality a
70custom implementation is included based on [the work by Markus Kuhn](http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c).
71
722 functions are provided, `system.utf8cwidth` for a single character, and `system.utf8swidth` for
73a string. When writing terminal applications the display width is relevant to
74positioning the cursor properly. For an example see the [`examples/readline.lua`](../examples/readline.lua.html) file.
75
76
77## 3.3 reading keyboard input
78
79### 3.3.1 Non-blocking
80
81There are 2 functions for keyboard input (actually 3, if taking `system._readkey` into
82account): `readkey` and `readansi`.
83
84`readkey` is a low level function and should preferably not be used, it returns
85a byte at a time, and hence can leave stray/invalid byte sequences in the buffer if
86only the start of a UTF-8 or ANSI sequence is consumed.
87
88The preferred way is to use `readansi` which will parse and return entire characters in
89single or multiple bytes, or a full ANSI sequence.
90
91On Windows the input is read using [`_getwchar()`](https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/getchar-getwchar) which bypasses the terminal and reads
92the input directly from the keyboard buffer. This means however that the character is
93also not being echoed to the terminal (independent of the echo settings used with
94`system.setconsoleflags`).
95
96On Posix the traditional file approach is used, which:
97
98- is blocking by default
99- echoes input to the terminal
100- requires enter to be pressed to pass the input (canonical mode)
101
102To use non-blocking input here's how to set it up:
103
104 -- setup Windows console to disable echo and line input (not required since _getwchar is used, just for consistency)
105 sys.setconsoleflags(io.stdin, sys.getconsoleflags(io.stdin) - sys.CIF_ECHO_INPUT - sys.CIF_LINE_INPUT)
106
107 -- setup Posix by disabling echo, canonical mode, and making non-blocking
108 local of_attr = sys.tcgetattr(io.stdin)
109 sys.tcsetattr(io.stdin, sys.TCSANOW, {
110 lflag = of_attr.lflag - sys.L_ICANON - sys.L_ECHO,
111 })
112 sys.setnonblock(io.stdin, true)
113
114
115Both functions require a timeout to be provided which allows for proper asynchronous
116code to be written. Since the underlying sleep method used is `system.sleep`, just patching
117that function with a coroutine based yielding one should be all that is needed to make
118the result work with asynchroneous coroutine schedulers.
119
120### 3.3.2 Blocking input
121
122When using traditional input method like `io.stdin:read()` (which is blocking) the echo
123and newline properties should be set on Windows similar to Posix.
124For an example see [`examples/password_input.lua`](../examples/password_input.lua.html).