Reorganized Namespaces

- Consolidated `main.zig` into `vaxis.zig` as the new library entry point.
- Exposed more Types throughout the library for more transparent doc navigation.
- Reorganized certain Modules and Types to be more coherent and readable.
- Re-generated docs to reflect these changes.
This commit is contained in:
00JCIV00 2024-02-26 17:39:29 -05:00 committed by Tim Culverhouse
parent f8544be262
commit a07d4f19a7
40 changed files with 7655 additions and 1004 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1 +1 @@
var modules =[{"name":"main","file":0,"main":66,"table":{"builtin":1,"zigimg":3,"ziglyph":2,"main":0}},{"name":"builtin","file":0,"main":462,"table":{}},{"name":"ziglyph","file":0,"main":32522,"table":{}},{"name":"zigimg","file":0,"main":34283,"table":{"builtin":4}},{"name":"builtin","file":0,"main":34497,"table":{}}];
var modules =[{"name":"vaxis","file":0,"main":66,"table":{"ziglyph":4,"vaxis":0,"zigimg":2,"builtin":1}},{"name":"builtin","file":0,"main":462,"table":{}},{"name":"zigimg","file":0,"main":32363,"table":{"builtin":3}},{"name":"builtin","file":0,"main":32577,"table":{}},{"name":"ziglyph","file":0,"main":33845,"table":{}}];

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,175 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Cell.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-kw">const</span> Image = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;Image.zig&quot;</span>);</span>
<span class="line" id="L2"></span>
<span class="line" id="L3">char: Character = .{},</span>
<span class="line" id="L4">style: Style = .{},</span>
<span class="line" id="L5">link: Hyperlink = .{},</span>
<span class="line" id="L6">image: ?Image.Placement = <span class="tok-null">null</span>,</span>
<span class="line" id="L7"></span>
<span class="line" id="L8"><span class="tok-comment">/// Segment is a contiguous run of text that has a constant style</span></span>
<span class="line" id="L9"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Segment = <span class="tok-kw">struct</span> {</span>
<span class="line" id="L10"> text: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>,</span>
<span class="line" id="L11"> style: Style = .{},</span>
<span class="line" id="L12"> link: Hyperlink = .{},</span>
<span class="line" id="L13">};</span>
<span class="line" id="L14"></span>
<span class="line" id="L15"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Character = <span class="tok-kw">struct</span> {</span>
<span class="line" id="L16"> grapheme: []<span class="tok-kw">const</span> <span class="tok-type">u8</span> = <span class="tok-str">&quot; &quot;</span>,</span>
<span class="line" id="L17"> <span class="tok-comment">/// width should only be provided when the application is sure the terminal</span></span>
<span class="line" id="L18"> <span class="tok-comment">/// will measure the same width. This can be ensure by using the gwidth method</span></span>
<span class="line" id="L19"> <span class="tok-comment">/// included in libvaxis. If width is 0, libvaxis will measure the glyph at</span></span>
<span class="line" id="L20"> <span class="tok-comment">/// render time</span></span>
<span class="line" id="L21"> width: <span class="tok-type">usize</span> = <span class="tok-number">1</span>,</span>
<span class="line" id="L22">};</span>
<span class="line" id="L23"></span>
<span class="line" id="L24"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Hyperlink = <span class="tok-kw">struct</span> {</span>
<span class="line" id="L25"> uri: []<span class="tok-kw">const</span> <span class="tok-type">u8</span> = <span class="tok-str">&quot;&quot;</span>,</span>
<span class="line" id="L26"> <span class="tok-comment">/// ie &quot;id=app-1234&quot;</span></span>
<span class="line" id="L27"> params: []<span class="tok-kw">const</span> <span class="tok-type">u8</span> = <span class="tok-str">&quot;&quot;</span>,</span>
<span class="line" id="L28">};</span>
<span class="line" id="L29"></span>
<span class="line" id="L30"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Style = <span class="tok-kw">struct</span> {</span>
<span class="line" id="L31"> <span class="tok-kw">pub</span> <span class="tok-kw">const</span> Underline = <span class="tok-kw">enum</span> {</span>
<span class="line" id="L32"> off,</span>
<span class="line" id="L33"> single,</span>
<span class="line" id="L34"> double,</span>
<span class="line" id="L35"> curly,</span>
<span class="line" id="L36"> dotted,</span>
<span class="line" id="L37"> dashed,</span>
<span class="line" id="L38"> };</span>
<span class="line" id="L39"></span>
<span class="line" id="L40"> fg: Color = .default,</span>
<span class="line" id="L41"> bg: Color = .default,</span>
<span class="line" id="L42"> ul: Color = .default,</span>
<span class="line" id="L43"> ul_style: Underline = .off,</span>
<span class="line" id="L44"></span>
<span class="line" id="L45"> bold: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L46"> dim: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L47"> italic: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L48"> blink: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L49"> reverse: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L50"> invisible: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L51"> strikethrough: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L52">};</span>
<span class="line" id="L53"></span>
<span class="line" id="L54"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Color = <span class="tok-kw">union</span>(<span class="tok-kw">enum</span>) {</span>
<span class="line" id="L55"> default,</span>
<span class="line" id="L56"> index: <span class="tok-type">u8</span>,</span>
<span class="line" id="L57"> rgb: [<span class="tok-number">3</span>]<span class="tok-type">u8</span>,</span>
<span class="line" id="L58">};</span>
<span class="line" id="L59"></span>
</code></pre></body>
</html>

View file

@ -0,0 +1,142 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>GraphemeCache.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-kw">const</span> std = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;std&quot;</span>);</span>
<span class="line" id="L2"><span class="tok-kw">const</span> testing = std.testing;</span>
<span class="line" id="L3"></span>
<span class="line" id="L4"><span class="tok-kw">const</span> GraphemeCache = <span class="tok-builtin">@This</span>();</span>
<span class="line" id="L5"></span>
<span class="line" id="L6"><span class="tok-comment">/// the underlying storage for graphemes. Right now 8kb</span></span>
<span class="line" id="L7">buf: [<span class="tok-number">1024</span> * <span class="tok-number">8</span>]<span class="tok-type">u8</span> = <span class="tok-null">undefined</span>,</span>
<span class="line" id="L8"></span>
<span class="line" id="L9"><span class="tok-comment">// the start index of the next grapheme</span>
</span>
<span class="line" id="L10">idx: <span class="tok-type">usize</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L11"></span>
<span class="line" id="L12"><span class="tok-comment">/// put a slice of bytes in the cache as a grapheme</span></span>
<span class="line" id="L13"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">put</span>(self: *GraphemeCache, bytes: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>) []<span class="tok-type">u8</span> {</span>
<span class="line" id="L14"> <span class="tok-comment">// reset the idx to 0 if we would overflow</span>
</span>
<span class="line" id="L15"> <span class="tok-kw">if</span> (self.idx + bytes.len &gt; self.buf.len) self.idx = <span class="tok-number">0</span>;</span>
<span class="line" id="L16"> <span class="tok-kw">defer</span> self.idx += bytes.len;</span>
<span class="line" id="L17"> <span class="tok-comment">// copy the grapheme to our storage</span>
</span>
<span class="line" id="L18"> <span class="tok-builtin">@memcpy</span>(self.buf[self.idx .. self.idx + bytes.len], bytes);</span>
<span class="line" id="L19"> <span class="tok-comment">// return the slice</span>
</span>
<span class="line" id="L20"> <span class="tok-kw">return</span> self.buf[self.idx .. self.idx + bytes.len];</span>
<span class="line" id="L21">}</span>
<span class="line" id="L22"></span>
</code></pre></body>
</html>

View file

@ -0,0 +1,191 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Image.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-kw">const</span> std = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;std&quot;</span>);</span>
<span class="line" id="L2"><span class="tok-kw">const</span> fmt = std.fmt;</span>
<span class="line" id="L3"><span class="tok-kw">const</span> math = std.math;</span>
<span class="line" id="L4"><span class="tok-kw">const</span> testing = std.testing;</span>
<span class="line" id="L5"><span class="tok-kw">const</span> base64 = std.base64.standard.Encoder;</span>
<span class="line" id="L6"><span class="tok-kw">const</span> zigimg = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;zigimg&quot;</span>);</span>
<span class="line" id="L7"></span>
<span class="line" id="L8"><span class="tok-kw">const</span> Window = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;Window.zig&quot;</span>);</span>
<span class="line" id="L9"></span>
<span class="line" id="L10"><span class="tok-kw">const</span> log = std.log.scoped(.image);</span>
<span class="line" id="L11"></span>
<span class="line" id="L12"><span class="tok-kw">const</span> Image = <span class="tok-builtin">@This</span>();</span>
<span class="line" id="L13"></span>
<span class="line" id="L14"><span class="tok-kw">const</span> transmit_opener = <span class="tok-str">&quot;\x1b_Gf=32,i={d},s={d},v={d},m={d};&quot;</span>;</span>
<span class="line" id="L15"></span>
<span class="line" id="L16"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Source = <span class="tok-kw">union</span>(<span class="tok-kw">enum</span>) {</span>
<span class="line" id="L17"> path: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>,</span>
<span class="line" id="L18"> mem: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>,</span>
<span class="line" id="L19">};</span>
<span class="line" id="L20"></span>
<span class="line" id="L21"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Placement = <span class="tok-kw">struct</span> {</span>
<span class="line" id="L22"> img_id: <span class="tok-type">u32</span>,</span>
<span class="line" id="L23"> z_index: <span class="tok-type">i32</span>,</span>
<span class="line" id="L24"> size: ?CellSize = <span class="tok-null">null</span>,</span>
<span class="line" id="L25">};</span>
<span class="line" id="L26"></span>
<span class="line" id="L27"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> CellSize = <span class="tok-kw">struct</span> {</span>
<span class="line" id="L28"> rows: <span class="tok-type">usize</span>,</span>
<span class="line" id="L29"> cols: <span class="tok-type">usize</span>,</span>
<span class="line" id="L30">};</span>
<span class="line" id="L31"></span>
<span class="line" id="L32"><span class="tok-comment">/// unique identifier for this image. This will be managed by the screen.</span></span>
<span class="line" id="L33">id: <span class="tok-type">u32</span>,</span>
<span class="line" id="L34"></span>
<span class="line" id="L35"><span class="tok-comment">// width in pixels</span>
</span>
<span class="line" id="L36">width: <span class="tok-type">usize</span>,</span>
<span class="line" id="L37"><span class="tok-comment">// height in pixels</span>
</span>
<span class="line" id="L38">height: <span class="tok-type">usize</span>,</span>
<span class="line" id="L39"></span>
<span class="line" id="L40"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">draw</span>(self: Image, win: Window, scale: <span class="tok-type">bool</span>, z_index: <span class="tok-type">i32</span>) <span class="tok-type">void</span> {</span>
<span class="line" id="L41"> <span class="tok-kw">const</span> p = Placement{</span>
<span class="line" id="L42"> .img_id = self.id,</span>
<span class="line" id="L43"> .z_index = z_index,</span>
<span class="line" id="L44"> .size = sz: {</span>
<span class="line" id="L45"> <span class="tok-kw">if</span> (!scale) <span class="tok-kw">break</span> :sz <span class="tok-null">null</span>;</span>
<span class="line" id="L46"> <span class="tok-kw">break</span> :sz CellSize{</span>
<span class="line" id="L47"> .rows = win.height,</span>
<span class="line" id="L48"> .cols = win.width,</span>
<span class="line" id="L49"> };</span>
<span class="line" id="L50"> },</span>
<span class="line" id="L51"> };</span>
<span class="line" id="L52"> win.writeCell(<span class="tok-number">0</span>, <span class="tok-number">0</span>, .{ .image = p });</span>
<span class="line" id="L53">}</span>
<span class="line" id="L54"></span>
<span class="line" id="L55"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">cellSize</span>(self: Image, win: Window) !CellSize {</span>
<span class="line" id="L56"> <span class="tok-comment">// cell geometry</span>
</span>
<span class="line" id="L57"> <span class="tok-kw">const</span> x_pix = win.screen.width_pix;</span>
<span class="line" id="L58"> <span class="tok-kw">const</span> y_pix = win.screen.height_pix;</span>
<span class="line" id="L59"> <span class="tok-kw">const</span> w = win.screen.width;</span>
<span class="line" id="L60"> <span class="tok-kw">const</span> h = win.screen.height;</span>
<span class="line" id="L61"></span>
<span class="line" id="L62"> <span class="tok-kw">const</span> pix_per_col = <span class="tok-kw">try</span> std.math.divCeil(<span class="tok-type">usize</span>, x_pix, w);</span>
<span class="line" id="L63"> <span class="tok-kw">const</span> pix_per_row = <span class="tok-kw">try</span> std.math.divCeil(<span class="tok-type">usize</span>, y_pix, h);</span>
<span class="line" id="L64"></span>
<span class="line" id="L65"> <span class="tok-kw">const</span> cell_width = std.math.divCeil(<span class="tok-type">usize</span>, self.width, pix_per_col) <span class="tok-kw">catch</span> <span class="tok-number">0</span>;</span>
<span class="line" id="L66"> <span class="tok-kw">const</span> cell_height = std.math.divCeil(<span class="tok-type">usize</span>, self.height, pix_per_row) <span class="tok-kw">catch</span> <span class="tok-number">0</span>;</span>
<span class="line" id="L67"> <span class="tok-kw">return</span> .{</span>
<span class="line" id="L68"> .rows = cell_height,</span>
<span class="line" id="L69"> .cols = cell_width,</span>
<span class="line" id="L70"> };</span>
<span class="line" id="L71">}</span>
<span class="line" id="L72"></span>
</code></pre></body>
</html>

View file

@ -0,0 +1,215 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>InternalScreen.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-kw">const</span> std = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;std&quot;</span>);</span>
<span class="line" id="L2"><span class="tok-kw">const</span> assert = std.debug.assert;</span>
<span class="line" id="L3"><span class="tok-kw">const</span> Style = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;Cell.zig&quot;</span>).Style;</span>
<span class="line" id="L4"><span class="tok-kw">const</span> Cell = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;Cell.zig&quot;</span>);</span>
<span class="line" id="L5"><span class="tok-kw">const</span> Shape = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;Mouse.zig&quot;</span>).Shape;</span>
<span class="line" id="L6"></span>
<span class="line" id="L7"><span class="tok-kw">const</span> log = std.log.scoped(.internal_screen);</span>
<span class="line" id="L8"></span>
<span class="line" id="L9"><span class="tok-kw">const</span> InternalScreen = <span class="tok-builtin">@This</span>();</span>
<span class="line" id="L10"></span>
<span class="line" id="L11"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> InternalCell = <span class="tok-kw">struct</span> {</span>
<span class="line" id="L12"> char: std.ArrayList(<span class="tok-type">u8</span>) = <span class="tok-null">undefined</span>,</span>
<span class="line" id="L13"> style: Style = .{},</span>
<span class="line" id="L14"> uri: std.ArrayList(<span class="tok-type">u8</span>) = <span class="tok-null">undefined</span>,</span>
<span class="line" id="L15"> uri_id: std.ArrayList(<span class="tok-type">u8</span>) = <span class="tok-null">undefined</span>,</span>
<span class="line" id="L16"> <span class="tok-comment">// if we got skipped because of a wide character</span>
</span>
<span class="line" id="L17"> skipped: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L18"></span>
<span class="line" id="L19"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">eql</span>(self: InternalCell, cell: Cell) <span class="tok-type">bool</span> {</span>
<span class="line" id="L20"> <span class="tok-kw">return</span> std.mem.eql(<span class="tok-type">u8</span>, self.char.items, cell.char.grapheme) <span class="tok-kw">and</span></span>
<span class="line" id="L21"> std.meta.eql(self.style, cell.style) <span class="tok-kw">and</span></span>
<span class="line" id="L22"> std.mem.eql(<span class="tok-type">u8</span>, self.uri.items, cell.link.uri) <span class="tok-kw">and</span></span>
<span class="line" id="L23"> std.mem.eql(<span class="tok-type">u8</span>, self.uri_id.items, cell.link.params);</span>
<span class="line" id="L24"> }</span>
<span class="line" id="L25">};</span>
<span class="line" id="L26"></span>
<span class="line" id="L27">width: <span class="tok-type">usize</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L28">height: <span class="tok-type">usize</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L29"></span>
<span class="line" id="L30">buf: []InternalCell = <span class="tok-null">undefined</span>,</span>
<span class="line" id="L31"></span>
<span class="line" id="L32">cursor_row: <span class="tok-type">usize</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L33">cursor_col: <span class="tok-type">usize</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L34">cursor_vis: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L35"></span>
<span class="line" id="L36">mouse_shape: Shape = .default,</span>
<span class="line" id="L37"></span>
<span class="line" id="L38"><span class="tok-comment">/// sets each cell to the default cell</span></span>
<span class="line" id="L39"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">init</span>(alloc: std.mem.Allocator, w: <span class="tok-type">usize</span>, h: <span class="tok-type">usize</span>) !InternalScreen {</span>
<span class="line" id="L40"> <span class="tok-kw">var</span> screen = InternalScreen{</span>
<span class="line" id="L41"> .buf = <span class="tok-kw">try</span> alloc.alloc(InternalCell, w * h),</span>
<span class="line" id="L42"> };</span>
<span class="line" id="L43"> <span class="tok-kw">for</span> (screen.buf, <span class="tok-number">0</span>..) |_, i| {</span>
<span class="line" id="L44"> screen.buf[i] = .{</span>
<span class="line" id="L45"> .char = <span class="tok-kw">try</span> std.ArrayList(<span class="tok-type">u8</span>).initCapacity(alloc, <span class="tok-number">1</span>),</span>
<span class="line" id="L46"> .uri = std.ArrayList(<span class="tok-type">u8</span>).init(alloc),</span>
<span class="line" id="L47"> .uri_id = std.ArrayList(<span class="tok-type">u8</span>).init(alloc),</span>
<span class="line" id="L48"> };</span>
<span class="line" id="L49"> }</span>
<span class="line" id="L50"> screen.width = w;</span>
<span class="line" id="L51"> screen.height = h;</span>
<span class="line" id="L52"> <span class="tok-kw">return</span> screen;</span>
<span class="line" id="L53">}</span>
<span class="line" id="L54"></span>
<span class="line" id="L55"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">deinit</span>(self: *InternalScreen, alloc: std.mem.Allocator) <span class="tok-type">void</span> {</span>
<span class="line" id="L56"> <span class="tok-kw">for</span> (self.buf, <span class="tok-number">0</span>..) |_, i| {</span>
<span class="line" id="L57"> self.buf[i].char.deinit();</span>
<span class="line" id="L58"> self.buf[i].uri.deinit();</span>
<span class="line" id="L59"> self.buf[i].uri_id.deinit();</span>
<span class="line" id="L60"> }</span>
<span class="line" id="L61"></span>
<span class="line" id="L62"> alloc.free(self.buf);</span>
<span class="line" id="L63">}</span>
<span class="line" id="L64"></span>
<span class="line" id="L65"><span class="tok-comment">/// writes a cell to a location. 0 indexed</span></span>
<span class="line" id="L66"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">writeCell</span>(</span>
<span class="line" id="L67"> self: *InternalScreen,</span>
<span class="line" id="L68"> col: <span class="tok-type">usize</span>,</span>
<span class="line" id="L69"> row: <span class="tok-type">usize</span>,</span>
<span class="line" id="L70"> cell: Cell,</span>
<span class="line" id="L71">) <span class="tok-type">void</span> {</span>
<span class="line" id="L72"> <span class="tok-kw">if</span> (self.width &lt; col) {</span>
<span class="line" id="L73"> <span class="tok-comment">// column out of bounds</span>
</span>
<span class="line" id="L74"> <span class="tok-kw">return</span>;</span>
<span class="line" id="L75"> }</span>
<span class="line" id="L76"> <span class="tok-kw">if</span> (self.height &lt; row) {</span>
<span class="line" id="L77"> <span class="tok-comment">// height out of bounds</span>
</span>
<span class="line" id="L78"> <span class="tok-kw">return</span>;</span>
<span class="line" id="L79"> }</span>
<span class="line" id="L80"> <span class="tok-kw">const</span> i = (row * self.width) + col;</span>
<span class="line" id="L81"> assert(i &lt; self.buf.len);</span>
<span class="line" id="L82"> self.buf[i].char.clearRetainingCapacity();</span>
<span class="line" id="L83"> self.buf[i].char.appendSlice(cell.char.grapheme) <span class="tok-kw">catch</span> {</span>
<span class="line" id="L84"> log.warn(<span class="tok-str">&quot;couldn't write grapheme&quot;</span>, .{});</span>
<span class="line" id="L85"> };</span>
<span class="line" id="L86"> self.buf[i].uri.clearRetainingCapacity();</span>
<span class="line" id="L87"> self.buf[i].uri.appendSlice(cell.link.uri) <span class="tok-kw">catch</span> {</span>
<span class="line" id="L88"> log.warn(<span class="tok-str">&quot;couldn't write uri&quot;</span>, .{});</span>
<span class="line" id="L89"> };</span>
<span class="line" id="L90"> self.buf[i].uri.clearRetainingCapacity();</span>
<span class="line" id="L91"> self.buf[i].uri_id.appendSlice(cell.link.params) <span class="tok-kw">catch</span> {</span>
<span class="line" id="L92"> log.warn(<span class="tok-str">&quot;couldn't write uri_id&quot;</span>, .{});</span>
<span class="line" id="L93"> };</span>
<span class="line" id="L94"> self.buf[i].style = cell.style;</span>
<span class="line" id="L95">}</span>
<span class="line" id="L96"></span>
</code></pre></body>
</html>

419
docs/src/vaxis/Key.zig.html Normal file
View file

@ -0,0 +1,419 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Key.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-kw">const</span> std = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;std&quot;</span>);</span>
<span class="line" id="L2"><span class="tok-kw">const</span> testing = std.testing;</span>
<span class="line" id="L3"></span>
<span class="line" id="L4"><span class="tok-kw">const</span> ziglyph = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;ziglyph&quot;</span>);</span>
<span class="line" id="L5"></span>
<span class="line" id="L6"><span class="tok-kw">const</span> Key = <span class="tok-builtin">@This</span>();</span>
<span class="line" id="L7"></span>
<span class="line" id="L8"><span class="tok-comment">/// Modifier Keys for a Key Match Event.</span></span>
<span class="line" id="L9"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Modifiers = <span class="tok-kw">packed</span> <span class="tok-kw">struct</span>(<span class="tok-type">u8</span>) {</span>
<span class="line" id="L10"> shift: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L11"> alt: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L12"> ctrl: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L13"> super: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L14"> hyper: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L15"> meta: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L16"> caps_lock: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L17"> num_lock: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L18">};</span>
<span class="line" id="L19"></span>
<span class="line" id="L20"><span class="tok-comment">/// Flags for the Kitty Protocol.</span></span>
<span class="line" id="L21"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> KittyFlags = <span class="tok-kw">packed</span> <span class="tok-kw">struct</span>(<span class="tok-type">u5</span>) {</span>
<span class="line" id="L22"> disambiguate: <span class="tok-type">bool</span> = <span class="tok-null">true</span>,</span>
<span class="line" id="L23"> report_events: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L24"> report_alternate_keys: <span class="tok-type">bool</span> = <span class="tok-null">true</span>,</span>
<span class="line" id="L25"> report_all_as_ctl_seqs: <span class="tok-type">bool</span> = <span class="tok-null">true</span>,</span>
<span class="line" id="L26"> report_text: <span class="tok-type">bool</span> = <span class="tok-null">true</span>,</span>
<span class="line" id="L27">};</span>
<span class="line" id="L28"></span>
<span class="line" id="L29"><span class="tok-comment">/// the unicode codepoint of the key event.</span></span>
<span class="line" id="L30">codepoint: <span class="tok-type">u21</span>,</span>
<span class="line" id="L31"></span>
<span class="line" id="L32"><span class="tok-comment">/// the text generated from the key event. The underlying slice has a limited</span></span>
<span class="line" id="L33"><span class="tok-comment">/// lifetime. Vaxis maintains an internal ring buffer to temporarily store text.</span></span>
<span class="line" id="L34"><span class="tok-comment">/// If the application needs these values longer than the lifetime of the event</span></span>
<span class="line" id="L35"><span class="tok-comment">/// it must copy the data.</span></span>
<span class="line" id="L36">text: ?[]<span class="tok-kw">const</span> <span class="tok-type">u8</span> = <span class="tok-null">null</span>,</span>
<span class="line" id="L37"></span>
<span class="line" id="L38"><span class="tok-comment">/// the shifted codepoint of this key event. This will only be present if the</span></span>
<span class="line" id="L39"><span class="tok-comment">/// Shift modifier was used to generate the event</span></span>
<span class="line" id="L40">shifted_codepoint: ?<span class="tok-type">u21</span> = <span class="tok-null">null</span>,</span>
<span class="line" id="L41"></span>
<span class="line" id="L42"><span class="tok-comment">/// the key that would have been pressed on a standard keyboard layout. This is</span></span>
<span class="line" id="L43"><span class="tok-comment">/// useful for shortcut matching</span></span>
<span class="line" id="L44">base_layout_codepoint: ?<span class="tok-type">u21</span> = <span class="tok-null">null</span>,</span>
<span class="line" id="L45"></span>
<span class="line" id="L46">mods: Modifiers = .{},</span>
<span class="line" id="L47"></span>
<span class="line" id="L48"><span class="tok-comment">/// matches follows a loose matching algorithm for key matches.</span></span>
<span class="line" id="L49"><span class="tok-comment">/// 1. If the codepoint and modifiers are exact matches</span></span>
<span class="line" id="L50"><span class="tok-comment">/// 2. If the utf8 encoding of the codepoint matches the text</span></span>
<span class="line" id="L51"><span class="tok-comment">/// 3. If there is a shifted codepoint and it matches after removing the shift</span></span>
<span class="line" id="L52"><span class="tok-comment">/// modifier from self</span></span>
<span class="line" id="L53"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">matches</span>(self: Key, cp: <span class="tok-type">u21</span>, mods: Modifiers) <span class="tok-type">bool</span> {</span>
<span class="line" id="L54"> <span class="tok-comment">// rule 1</span>
</span>
<span class="line" id="L55"> <span class="tok-kw">if</span> (self.matchExact(cp, mods)) <span class="tok-kw">return</span> <span class="tok-null">true</span>;</span>
<span class="line" id="L56"></span>
<span class="line" id="L57"> <span class="tok-comment">// rule 2</span>
</span>
<span class="line" id="L58"> <span class="tok-kw">if</span> (self.matchText(cp, mods)) <span class="tok-kw">return</span> <span class="tok-null">true</span>;</span>
<span class="line" id="L59"></span>
<span class="line" id="L60"> <span class="tok-comment">// rule 3</span>
</span>
<span class="line" id="L61"> <span class="tok-kw">if</span> (self.matchShiftedCodepoint(cp, mods)) <span class="tok-kw">return</span> <span class="tok-null">true</span>;</span>
<span class="line" id="L62"></span>
<span class="line" id="L63"> <span class="tok-kw">return</span> <span class="tok-null">false</span>;</span>
<span class="line" id="L64">}</span>
<span class="line" id="L65"></span>
<span class="line" id="L66"><span class="tok-comment">/// matches against any of the provided codepoints.</span></span>
<span class="line" id="L67"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">matchesAny</span>(self: Key, cps: []<span class="tok-kw">const</span> <span class="tok-type">u21</span>, mods: Modifiers) <span class="tok-type">bool</span> {</span>
<span class="line" id="L68"> <span class="tok-kw">for</span> (cps) |cp| {</span>
<span class="line" id="L69"> <span class="tok-kw">if</span> (self.matches(cp, mods)) <span class="tok-kw">return</span> <span class="tok-null">true</span>;</span>
<span class="line" id="L70"> }</span>
<span class="line" id="L71"> <span class="tok-kw">return</span> <span class="tok-null">false</span>;</span>
<span class="line" id="L72">}</span>
<span class="line" id="L73"></span>
<span class="line" id="L74"><span class="tok-comment">/// matches base layout codes, useful for shortcut matching when an alternate key</span></span>
<span class="line" id="L75"><span class="tok-comment">/// layout is used</span></span>
<span class="line" id="L76"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">matchShortcut</span>(self: Key, cp: <span class="tok-type">u21</span>, mods: Modifiers) <span class="tok-type">bool</span> {</span>
<span class="line" id="L77"> <span class="tok-kw">if</span> (self.base_layout_codepoint == <span class="tok-null">null</span>) <span class="tok-kw">return</span> <span class="tok-null">false</span>;</span>
<span class="line" id="L78"> <span class="tok-kw">return</span> cp == self.base_layout_codepoint.? <span class="tok-kw">and</span> std.meta.eql(self.mods, mods);</span>
<span class="line" id="L79">}</span>
<span class="line" id="L80"></span>
<span class="line" id="L81"><span class="tok-comment">/// matches keys that aren't upper case versions when shifted. For example, shift</span></span>
<span class="line" id="L82"><span class="tok-comment">/// + semicolon produces a colon. The key can be matched against shift +</span></span>
<span class="line" id="L83"><span class="tok-comment">/// semicolon or just colon...or shift + ctrl + ; or just ctrl + :</span></span>
<span class="line" id="L84"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">matchShiftedCodepoint</span>(self: Key, cp: <span class="tok-type">u21</span>, mods: Modifiers) <span class="tok-type">bool</span> {</span>
<span class="line" id="L85"> <span class="tok-kw">if</span> (self.shifted_codepoint == <span class="tok-null">null</span>) <span class="tok-kw">return</span> <span class="tok-null">false</span>;</span>
<span class="line" id="L86"> <span class="tok-kw">if</span> (!self.mods.shift) <span class="tok-kw">return</span> <span class="tok-null">false</span>;</span>
<span class="line" id="L87"> <span class="tok-kw">var</span> self_mods = self.mods;</span>
<span class="line" id="L88"> self_mods.shift = <span class="tok-null">false</span>;</span>
<span class="line" id="L89"> <span class="tok-kw">return</span> cp == self.shifted_codepoint.? <span class="tok-kw">and</span> std.meta.eql(self_mods, mods);</span>
<span class="line" id="L90">}</span>
<span class="line" id="L91"></span>
<span class="line" id="L92"><span class="tok-comment">/// matches when the utf8 encoding of the codepoint and relevant mods matches the</span></span>
<span class="line" id="L93"><span class="tok-comment">/// text of the key. This function will consume Shift and Caps Lock when matching</span></span>
<span class="line" id="L94"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">matchText</span>(self: Key, cp: <span class="tok-type">u21</span>, mods: Modifiers) <span class="tok-type">bool</span> {</span>
<span class="line" id="L95"> <span class="tok-comment">// return early if we have no text</span>
</span>
<span class="line" id="L96"> <span class="tok-kw">if</span> (self.text == <span class="tok-null">null</span>) <span class="tok-kw">return</span> <span class="tok-null">false</span>;</span>
<span class="line" id="L97"></span>
<span class="line" id="L98"> <span class="tok-kw">var</span> self_mods = self.mods;</span>
<span class="line" id="L99"> <span class="tok-kw">var</span> arg_mods = mods;</span>
<span class="line" id="L100"> <span class="tok-kw">var</span> code = cp;</span>
<span class="line" id="L101"> <span class="tok-comment">// if the passed codepoint is upper, we consume all shift and caps mods for</span>
</span>
<span class="line" id="L102"> <span class="tok-comment">// checking</span>
</span>
<span class="line" id="L103"> <span class="tok-kw">if</span> (ziglyph.isUpper(cp)) {</span>
<span class="line" id="L104"> <span class="tok-comment">// consume mods</span>
</span>
<span class="line" id="L105"> self_mods.shift = <span class="tok-null">false</span>;</span>
<span class="line" id="L106"> self_mods.caps_lock = <span class="tok-null">false</span>;</span>
<span class="line" id="L107"> arg_mods.shift = <span class="tok-null">false</span>;</span>
<span class="line" id="L108"> arg_mods.caps_lock = <span class="tok-null">false</span>;</span>
<span class="line" id="L109"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (mods.shift <span class="tok-kw">or</span> mods.caps_lock) {</span>
<span class="line" id="L110"> <span class="tok-comment">// uppercase the cp and consume all mods</span>
</span>
<span class="line" id="L111"> code = ziglyph.toUpper(cp);</span>
<span class="line" id="L112"> self_mods.shift = <span class="tok-null">false</span>;</span>
<span class="line" id="L113"> self_mods.caps_lock = <span class="tok-null">false</span>;</span>
<span class="line" id="L114"> arg_mods.shift = <span class="tok-null">false</span>;</span>
<span class="line" id="L115"> arg_mods.caps_lock = <span class="tok-null">false</span>;</span>
<span class="line" id="L116"> }</span>
<span class="line" id="L117"></span>
<span class="line" id="L118"> <span class="tok-kw">var</span> buf: [<span class="tok-number">4</span>]<span class="tok-type">u8</span> = <span class="tok-null">undefined</span>;</span>
<span class="line" id="L119"> <span class="tok-kw">const</span> n = std.unicode.utf8Encode(cp, buf[<span class="tok-number">0</span>..]) <span class="tok-kw">catch</span> <span class="tok-kw">return</span> <span class="tok-null">false</span>;</span>
<span class="line" id="L120"> <span class="tok-kw">return</span> std.mem.eql(<span class="tok-type">u8</span>, self.text.?, buf[<span class="tok-number">0</span>..n]) <span class="tok-kw">and</span> std.meta.eql(self_mods, arg_mods);</span>
<span class="line" id="L121">}</span>
<span class="line" id="L122"></span>
<span class="line" id="L123"><span class="tok-comment">/// The key must exactly match the codepoint and modifiers</span></span>
<span class="line" id="L124"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">matchExact</span>(self: Key, cp: <span class="tok-type">u21</span>, mods: Modifiers) <span class="tok-type">bool</span> {</span>
<span class="line" id="L125"> <span class="tok-kw">return</span> self.codepoint == cp <span class="tok-kw">and</span> std.meta.eql(self.mods, mods);</span>
<span class="line" id="L126">}</span>
<span class="line" id="L127"></span>
<span class="line" id="L128"><span class="tok-comment">// a few special keys that we encode as their actual ascii value</span>
</span>
<span class="line" id="L129"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> tab: <span class="tok-type">u21</span> = <span class="tok-number">0x09</span>;</span>
<span class="line" id="L130"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> escape: <span class="tok-type">u21</span> = <span class="tok-number">0x1B</span>;</span>
<span class="line" id="L131"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> space: <span class="tok-type">u21</span> = <span class="tok-number">0x20</span>;</span>
<span class="line" id="L132"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> enter: <span class="tok-type">u21</span> = <span class="tok-number">0x6D</span>;</span>
<span class="line" id="L133"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> backspace: <span class="tok-type">u21</span> = <span class="tok-number">0x7F</span>;</span>
<span class="line" id="L134"></span>
<span class="line" id="L135"><span class="tok-comment">/// multicodepoint is a key which generated text but cannot be expressed as a</span></span>
<span class="line" id="L136"><span class="tok-comment">/// single codepoint. The value is the maximum unicode codepoint + 1</span></span>
<span class="line" id="L137"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> multicodepoint: <span class="tok-type">u21</span> = <span class="tok-number">1_114_112</span> + <span class="tok-number">1</span>;</span>
<span class="line" id="L138"></span>
<span class="line" id="L139"><span class="tok-comment">// kitty encodes these keys directly in the private use area. We reuse those</span>
</span>
<span class="line" id="L140"><span class="tok-comment">// mappings</span>
</span>
<span class="line" id="L141"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> insert: <span class="tok-type">u21</span> = <span class="tok-number">57348</span>;</span>
<span class="line" id="L142"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> delete: <span class="tok-type">u21</span> = <span class="tok-number">57349</span>;</span>
<span class="line" id="L143"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> left: <span class="tok-type">u21</span> = <span class="tok-number">57350</span>;</span>
<span class="line" id="L144"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> right: <span class="tok-type">u21</span> = <span class="tok-number">57351</span>;</span>
<span class="line" id="L145"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> up: <span class="tok-type">u21</span> = <span class="tok-number">57352</span>;</span>
<span class="line" id="L146"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> down: <span class="tok-type">u21</span> = <span class="tok-number">57353</span>;</span>
<span class="line" id="L147"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> page_up: <span class="tok-type">u21</span> = <span class="tok-number">57354</span>;</span>
<span class="line" id="L148"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> page_down: <span class="tok-type">u21</span> = <span class="tok-number">57355</span>;</span>
<span class="line" id="L149"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> home: <span class="tok-type">u21</span> = <span class="tok-number">57356</span>;</span>
<span class="line" id="L150"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> end: <span class="tok-type">u21</span> = <span class="tok-number">57357</span>;</span>
<span class="line" id="L151"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> caps_lock: <span class="tok-type">u21</span> = <span class="tok-number">57358</span>;</span>
<span class="line" id="L152"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> scroll_lock: <span class="tok-type">u21</span> = <span class="tok-number">57359</span>;</span>
<span class="line" id="L153"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> num_lock: <span class="tok-type">u21</span> = <span class="tok-number">57360</span>;</span>
<span class="line" id="L154"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> print_screen: <span class="tok-type">u21</span> = <span class="tok-number">57361</span>;</span>
<span class="line" id="L155"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> pause: <span class="tok-type">u21</span> = <span class="tok-number">57362</span>;</span>
<span class="line" id="L156"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> menu: <span class="tok-type">u21</span> = <span class="tok-number">57363</span>;</span>
<span class="line" id="L157"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> f1: <span class="tok-type">u21</span> = <span class="tok-number">57364</span>;</span>
<span class="line" id="L158"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> f2: <span class="tok-type">u21</span> = <span class="tok-number">57365</span>;</span>
<span class="line" id="L159"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> f3: <span class="tok-type">u21</span> = <span class="tok-number">57366</span>;</span>
<span class="line" id="L160"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> f4: <span class="tok-type">u21</span> = <span class="tok-number">57367</span>;</span>
<span class="line" id="L161"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> f5: <span class="tok-type">u21</span> = <span class="tok-number">57368</span>;</span>
<span class="line" id="L162"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> f6: <span class="tok-type">u21</span> = <span class="tok-number">57369</span>;</span>
<span class="line" id="L163"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> f7: <span class="tok-type">u21</span> = <span class="tok-number">57370</span>;</span>
<span class="line" id="L164"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> f8: <span class="tok-type">u21</span> = <span class="tok-number">57371</span>;</span>
<span class="line" id="L165"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> f9: <span class="tok-type">u21</span> = <span class="tok-number">57372</span>;</span>
<span class="line" id="L166"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> f10: <span class="tok-type">u21</span> = <span class="tok-number">57373</span>;</span>
<span class="line" id="L167"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> f11: <span class="tok-type">u21</span> = <span class="tok-number">57374</span>;</span>
<span class="line" id="L168"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> f12: <span class="tok-type">u21</span> = <span class="tok-number">57375</span>;</span>
<span class="line" id="L169"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> f13: <span class="tok-type">u21</span> = <span class="tok-number">57376</span>;</span>
<span class="line" id="L170"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> f14: <span class="tok-type">u21</span> = <span class="tok-number">57377</span>;</span>
<span class="line" id="L171"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> f15: <span class="tok-type">u21</span> = <span class="tok-number">57378</span>;</span>
<span class="line" id="L172"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> @&quot;f16&quot;: <span class="tok-type">u21</span> = <span class="tok-number">57379</span>;</span>
<span class="line" id="L173"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> f17: <span class="tok-type">u21</span> = <span class="tok-number">57380</span>;</span>
<span class="line" id="L174"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> f18: <span class="tok-type">u21</span> = <span class="tok-number">57381</span>;</span>
<span class="line" id="L175"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> f19: <span class="tok-type">u21</span> = <span class="tok-number">57382</span>;</span>
<span class="line" id="L176"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> f20: <span class="tok-type">u21</span> = <span class="tok-number">57383</span>;</span>
<span class="line" id="L177"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> f21: <span class="tok-type">u21</span> = <span class="tok-number">57384</span>;</span>
<span class="line" id="L178"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> f22: <span class="tok-type">u21</span> = <span class="tok-number">57385</span>;</span>
<span class="line" id="L179"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> f23: <span class="tok-type">u21</span> = <span class="tok-number">57386</span>;</span>
<span class="line" id="L180"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> f24: <span class="tok-type">u21</span> = <span class="tok-number">57387</span>;</span>
<span class="line" id="L181"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> f25: <span class="tok-type">u21</span> = <span class="tok-number">57388</span>;</span>
<span class="line" id="L182"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> f26: <span class="tok-type">u21</span> = <span class="tok-number">57389</span>;</span>
<span class="line" id="L183"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> f27: <span class="tok-type">u21</span> = <span class="tok-number">57390</span>;</span>
<span class="line" id="L184"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> f28: <span class="tok-type">u21</span> = <span class="tok-number">57391</span>;</span>
<span class="line" id="L185"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> f29: <span class="tok-type">u21</span> = <span class="tok-number">57392</span>;</span>
<span class="line" id="L186"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> f30: <span class="tok-type">u21</span> = <span class="tok-number">57393</span>;</span>
<span class="line" id="L187"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> f31: <span class="tok-type">u21</span> = <span class="tok-number">57394</span>;</span>
<span class="line" id="L188"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> @&quot;f32&quot;: <span class="tok-type">u21</span> = <span class="tok-number">57395</span>;</span>
<span class="line" id="L189"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> f33: <span class="tok-type">u21</span> = <span class="tok-number">57396</span>;</span>
<span class="line" id="L190"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> f34: <span class="tok-type">u21</span> = <span class="tok-number">57397</span>;</span>
<span class="line" id="L191"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> f35: <span class="tok-type">u21</span> = <span class="tok-number">57398</span>;</span>
<span class="line" id="L192"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> kp_0: <span class="tok-type">u21</span> = <span class="tok-number">57399</span>;</span>
<span class="line" id="L193"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> kp_1: <span class="tok-type">u21</span> = <span class="tok-number">57400</span>;</span>
<span class="line" id="L194"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> kp_2: <span class="tok-type">u21</span> = <span class="tok-number">57401</span>;</span>
<span class="line" id="L195"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> kp_3: <span class="tok-type">u21</span> = <span class="tok-number">57402</span>;</span>
<span class="line" id="L196"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> kp_4: <span class="tok-type">u21</span> = <span class="tok-number">57403</span>;</span>
<span class="line" id="L197"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> kp_5: <span class="tok-type">u21</span> = <span class="tok-number">57404</span>;</span>
<span class="line" id="L198"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> kp_6: <span class="tok-type">u21</span> = <span class="tok-number">57405</span>;</span>
<span class="line" id="L199"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> kp_7: <span class="tok-type">u21</span> = <span class="tok-number">57406</span>;</span>
<span class="line" id="L200"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> kp_8: <span class="tok-type">u21</span> = <span class="tok-number">57407</span>;</span>
<span class="line" id="L201"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> kp_9: <span class="tok-type">u21</span> = <span class="tok-number">57408</span>;</span>
<span class="line" id="L202"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> kp_decimal: <span class="tok-type">u21</span> = <span class="tok-number">57409</span>;</span>
<span class="line" id="L203"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> kp_divide: <span class="tok-type">u21</span> = <span class="tok-number">57410</span>;</span>
<span class="line" id="L204"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> kp_multiply: <span class="tok-type">u21</span> = <span class="tok-number">57411</span>;</span>
<span class="line" id="L205"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> kp_subtract: <span class="tok-type">u21</span> = <span class="tok-number">57412</span>;</span>
<span class="line" id="L206"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> kp_add: <span class="tok-type">u21</span> = <span class="tok-number">57413</span>;</span>
<span class="line" id="L207"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> kp_enter: <span class="tok-type">u21</span> = <span class="tok-number">57414</span>;</span>
<span class="line" id="L208"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> kp_equal: <span class="tok-type">u21</span> = <span class="tok-number">57415</span>;</span>
<span class="line" id="L209"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> kp_separator: <span class="tok-type">u21</span> = <span class="tok-number">57416</span>;</span>
<span class="line" id="L210"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> kp_left: <span class="tok-type">u21</span> = <span class="tok-number">57417</span>;</span>
<span class="line" id="L211"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> kp_right: <span class="tok-type">u21</span> = <span class="tok-number">57418</span>;</span>
<span class="line" id="L212"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> kp_up: <span class="tok-type">u21</span> = <span class="tok-number">57419</span>;</span>
<span class="line" id="L213"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> kp_down: <span class="tok-type">u21</span> = <span class="tok-number">57420</span>;</span>
<span class="line" id="L214"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> kp_page_up: <span class="tok-type">u21</span> = <span class="tok-number">57421</span>;</span>
<span class="line" id="L215"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> kp_page_down: <span class="tok-type">u21</span> = <span class="tok-number">57422</span>;</span>
<span class="line" id="L216"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> kp_home: <span class="tok-type">u21</span> = <span class="tok-number">57423</span>;</span>
<span class="line" id="L217"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> kp_end: <span class="tok-type">u21</span> = <span class="tok-number">57424</span>;</span>
<span class="line" id="L218"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> kp_insert: <span class="tok-type">u21</span> = <span class="tok-number">57425</span>;</span>
<span class="line" id="L219"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> kp_delete: <span class="tok-type">u21</span> = <span class="tok-number">57426</span>;</span>
<span class="line" id="L220"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> kp_begin: <span class="tok-type">u21</span> = <span class="tok-number">57427</span>;</span>
<span class="line" id="L221"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> media_play: <span class="tok-type">u21</span> = <span class="tok-number">57428</span>;</span>
<span class="line" id="L222"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> media_pause: <span class="tok-type">u21</span> = <span class="tok-number">57429</span>;</span>
<span class="line" id="L223"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> media_play_pause: <span class="tok-type">u21</span> = <span class="tok-number">57430</span>;</span>
<span class="line" id="L224"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> media_reverse: <span class="tok-type">u21</span> = <span class="tok-number">57431</span>;</span>
<span class="line" id="L225"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> media_stop: <span class="tok-type">u21</span> = <span class="tok-number">57432</span>;</span>
<span class="line" id="L226"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> media_fast_forward: <span class="tok-type">u21</span> = <span class="tok-number">57433</span>;</span>
<span class="line" id="L227"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> media_rewind: <span class="tok-type">u21</span> = <span class="tok-number">57434</span>;</span>
<span class="line" id="L228"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> media_track_next: <span class="tok-type">u21</span> = <span class="tok-number">57435</span>;</span>
<span class="line" id="L229"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> media_track_previous: <span class="tok-type">u21</span> = <span class="tok-number">57436</span>;</span>
<span class="line" id="L230"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> media_record: <span class="tok-type">u21</span> = <span class="tok-number">57437</span>;</span>
<span class="line" id="L231"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> lower_volume: <span class="tok-type">u21</span> = <span class="tok-number">57438</span>;</span>
<span class="line" id="L232"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> raise_volume: <span class="tok-type">u21</span> = <span class="tok-number">57439</span>;</span>
<span class="line" id="L233"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> mute_volume: <span class="tok-type">u21</span> = <span class="tok-number">57440</span>;</span>
<span class="line" id="L234"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> left_shift: <span class="tok-type">u21</span> = <span class="tok-number">57441</span>;</span>
<span class="line" id="L235"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> left_control: <span class="tok-type">u21</span> = <span class="tok-number">57442</span>;</span>
<span class="line" id="L236"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> left_alt: <span class="tok-type">u21</span> = <span class="tok-number">57443</span>;</span>
<span class="line" id="L237"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> left_super: <span class="tok-type">u21</span> = <span class="tok-number">57444</span>;</span>
<span class="line" id="L238"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> left_hyper: <span class="tok-type">u21</span> = <span class="tok-number">57445</span>;</span>
<span class="line" id="L239"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> left_meta: <span class="tok-type">u21</span> = <span class="tok-number">57446</span>;</span>
<span class="line" id="L240"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> right_shift: <span class="tok-type">u21</span> = <span class="tok-number">57447</span>;</span>
<span class="line" id="L241"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> right_control: <span class="tok-type">u21</span> = <span class="tok-number">57448</span>;</span>
<span class="line" id="L242"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> right_alt: <span class="tok-type">u21</span> = <span class="tok-number">57449</span>;</span>
<span class="line" id="L243"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> right_super: <span class="tok-type">u21</span> = <span class="tok-number">57450</span>;</span>
<span class="line" id="L244"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> right_hyper: <span class="tok-type">u21</span> = <span class="tok-number">57451</span>;</span>
<span class="line" id="L245"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> right_meta: <span class="tok-type">u21</span> = <span class="tok-number">57452</span>;</span>
<span class="line" id="L246"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> iso_level_3_shift: <span class="tok-type">u21</span> = <span class="tok-number">57453</span>;</span>
<span class="line" id="L247"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> iso_level_5_shift: <span class="tok-type">u21</span> = <span class="tok-number">57454</span>;</span>
<span class="line" id="L248"></span>
<span class="line" id="L249"><span class="tok-kw">test</span> <span class="tok-str">&quot;matches 'a'&quot;</span> {</span>
<span class="line" id="L250"> <span class="tok-kw">const</span> key: Key = .{</span>
<span class="line" id="L251"> .codepoint = <span class="tok-str">'a'</span>,</span>
<span class="line" id="L252"> };</span>
<span class="line" id="L253"> <span class="tok-kw">try</span> testing.expect(key.matches(<span class="tok-str">'a'</span>, .{}));</span>
<span class="line" id="L254">}</span>
<span class="line" id="L255"></span>
<span class="line" id="L256"><span class="tok-kw">test</span> <span class="tok-str">&quot;matches 'shift+a'&quot;</span> {</span>
<span class="line" id="L257"> <span class="tok-kw">const</span> key: Key = .{</span>
<span class="line" id="L258"> .codepoint = <span class="tok-str">'a'</span>,</span>
<span class="line" id="L259"> .mods = .{ .shift = <span class="tok-null">true</span> },</span>
<span class="line" id="L260"> .text = <span class="tok-str">&quot;A&quot;</span>,</span>
<span class="line" id="L261"> };</span>
<span class="line" id="L262"> <span class="tok-kw">try</span> testing.expect(key.matches(<span class="tok-str">'a'</span>, .{ .shift = <span class="tok-null">true</span> }));</span>
<span class="line" id="L263"> <span class="tok-kw">try</span> testing.expect(key.matches(<span class="tok-str">'A'</span>, .{}));</span>
<span class="line" id="L264"> <span class="tok-kw">try</span> testing.expect(!key.matches(<span class="tok-str">'A'</span>, .{ .ctrl = <span class="tok-null">true</span> }));</span>
<span class="line" id="L265">}</span>
<span class="line" id="L266"></span>
<span class="line" id="L267"><span class="tok-kw">test</span> <span class="tok-str">&quot;matches 'shift+tab'&quot;</span> {</span>
<span class="line" id="L268"> <span class="tok-kw">const</span> key: Key = .{</span>
<span class="line" id="L269"> .codepoint = Key.tab,</span>
<span class="line" id="L270"> .mods = .{ .shift = <span class="tok-null">true</span> },</span>
<span class="line" id="L271"> };</span>
<span class="line" id="L272"> <span class="tok-kw">try</span> testing.expect(key.matches(Key.tab, .{ .shift = <span class="tok-null">true</span> }));</span>
<span class="line" id="L273"> <span class="tok-kw">try</span> testing.expect(!key.matches(Key.tab, .{}));</span>
<span class="line" id="L274">}</span>
<span class="line" id="L275"></span>
<span class="line" id="L276"><span class="tok-kw">test</span> <span class="tok-str">&quot;matches 'shift+;'&quot;</span> {</span>
<span class="line" id="L277"> <span class="tok-kw">const</span> key: Key = .{</span>
<span class="line" id="L278"> .codepoint = <span class="tok-str">';'</span>,</span>
<span class="line" id="L279"> .shifted_codepoint = <span class="tok-str">':'</span>,</span>
<span class="line" id="L280"> .mods = .{ .shift = <span class="tok-null">true</span> },</span>
<span class="line" id="L281"> .text = <span class="tok-str">&quot;:&quot;</span>,</span>
<span class="line" id="L282"> };</span>
<span class="line" id="L283"> <span class="tok-kw">try</span> testing.expect(key.matches(<span class="tok-str">';'</span>, .{ .shift = <span class="tok-null">true</span> }));</span>
<span class="line" id="L284"> <span class="tok-kw">try</span> testing.expect(key.matches(<span class="tok-str">':'</span>, .{}));</span>
<span class="line" id="L285"></span>
<span class="line" id="L286"> <span class="tok-kw">const</span> colon: Key = .{</span>
<span class="line" id="L287"> .codepoint = <span class="tok-str">':'</span>,</span>
<span class="line" id="L288"> .mods = .{},</span>
<span class="line" id="L289"> };</span>
<span class="line" id="L290"> <span class="tok-kw">try</span> testing.expect(colon.matches(<span class="tok-str">':'</span>, .{}));</span>
<span class="line" id="L291">}</span>
<span class="line" id="L292"></span>
</code></pre></body>
</html>

View file

@ -0,0 +1,163 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Mouse.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-comment">/// A mouse event</span></span>
<span class="line" id="L2"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Mouse = <span class="tok-builtin">@This</span>();</span>
<span class="line" id="L3"></span>
<span class="line" id="L4"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Shape = <span class="tok-kw">enum</span> {</span>
<span class="line" id="L5"> default,</span>
<span class="line" id="L6"> text,</span>
<span class="line" id="L7"> pointer,</span>
<span class="line" id="L8"> help,</span>
<span class="line" id="L9"> progress,</span>
<span class="line" id="L10"> wait,</span>
<span class="line" id="L11"> @&quot;ew-resize&quot;,</span>
<span class="line" id="L12"> @&quot;ns-resize&quot;,</span>
<span class="line" id="L13"> cell,</span>
<span class="line" id="L14">};</span>
<span class="line" id="L15"></span>
<span class="line" id="L16"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Button = <span class="tok-kw">enum</span>(<span class="tok-type">u8</span>) {</span>
<span class="line" id="L17"> left,</span>
<span class="line" id="L18"> middle,</span>
<span class="line" id="L19"> right,</span>
<span class="line" id="L20"> none,</span>
<span class="line" id="L21"> wheel_up = <span class="tok-number">64</span>,</span>
<span class="line" id="L22"> wheel_down = <span class="tok-number">65</span>,</span>
<span class="line" id="L23"> button_8 = <span class="tok-number">128</span>,</span>
<span class="line" id="L24"> button_9 = <span class="tok-number">129</span>,</span>
<span class="line" id="L25"> button_10 = <span class="tok-number">130</span>,</span>
<span class="line" id="L26"> button_11 = <span class="tok-number">131</span>,</span>
<span class="line" id="L27">};</span>
<span class="line" id="L28"></span>
<span class="line" id="L29"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Modifiers = <span class="tok-kw">packed</span> <span class="tok-kw">struct</span>(<span class="tok-type">u3</span>) {</span>
<span class="line" id="L30"> shift: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L31"> alt: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L32"> ctrl: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L33">};</span>
<span class="line" id="L34"></span>
<span class="line" id="L35"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Type = <span class="tok-kw">enum</span> {</span>
<span class="line" id="L36"> press,</span>
<span class="line" id="L37"> release,</span>
<span class="line" id="L38"> motion,</span>
<span class="line" id="L39"> drag,</span>
<span class="line" id="L40">};</span>
<span class="line" id="L41"></span>
<span class="line" id="L42">col: <span class="tok-type">usize</span>,</span>
<span class="line" id="L43">row: <span class="tok-type">usize</span>,</span>
<span class="line" id="L44">button: Button,</span>
<span class="line" id="L45">mods: Modifiers,</span>
<span class="line" id="L46"><span class="tok-type">type</span>: Type,</span>
<span class="line" id="L47"></span>
</code></pre></body>
</html>

View file

@ -0,0 +1,119 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Options.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-comment">/// Runtime options</span></span>
<span class="line" id="L2"><span class="tok-kw">const</span> Options = <span class="tok-builtin">@This</span>();</span>
<span class="line" id="L3"></span>
</code></pre></body>
</html>

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,181 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Screen.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-kw">const</span> std = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;std&quot;</span>);</span>
<span class="line" id="L2"><span class="tok-kw">const</span> assert = std.debug.assert;</span>
<span class="line" id="L3"></span>
<span class="line" id="L4"><span class="tok-kw">const</span> Cell = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;Cell.zig&quot;</span>);</span>
<span class="line" id="L5"><span class="tok-kw">const</span> Shape = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;Mouse.zig&quot;</span>).Shape;</span>
<span class="line" id="L6"><span class="tok-kw">const</span> Image = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;Image.zig&quot;</span>);</span>
<span class="line" id="L7"><span class="tok-kw">const</span> Winsize = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;Tty.zig&quot;</span>).Winsize;</span>
<span class="line" id="L8"></span>
<span class="line" id="L9"><span class="tok-kw">const</span> log = std.log.scoped(.screen);</span>
<span class="line" id="L10"></span>
<span class="line" id="L11"><span class="tok-kw">const</span> Screen = <span class="tok-builtin">@This</span>();</span>
<span class="line" id="L12"></span>
<span class="line" id="L13">width: <span class="tok-type">usize</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L14">height: <span class="tok-type">usize</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L15"></span>
<span class="line" id="L16">width_pix: <span class="tok-type">usize</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L17">height_pix: <span class="tok-type">usize</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L18"></span>
<span class="line" id="L19">buf: []Cell = <span class="tok-null">undefined</span>,</span>
<span class="line" id="L20"></span>
<span class="line" id="L21">cursor_row: <span class="tok-type">usize</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L22">cursor_col: <span class="tok-type">usize</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L23">cursor_vis: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L24"></span>
<span class="line" id="L25"><span class="tok-comment">/// true when we measure cells with unicode</span></span>
<span class="line" id="L26">unicode: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L27"></span>
<span class="line" id="L28">mouse_shape: Shape = .default,</span>
<span class="line" id="L29"></span>
<span class="line" id="L30"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">init</span>(alloc: std.mem.Allocator, winsize: Winsize) !Screen {</span>
<span class="line" id="L31"> <span class="tok-kw">const</span> w = winsize.cols;</span>
<span class="line" id="L32"> <span class="tok-kw">const</span> h = winsize.rows;</span>
<span class="line" id="L33"> <span class="tok-kw">var</span> self = Screen{</span>
<span class="line" id="L34"> .buf = <span class="tok-kw">try</span> alloc.alloc(Cell, w * h),</span>
<span class="line" id="L35"> .width = w,</span>
<span class="line" id="L36"> .height = h,</span>
<span class="line" id="L37"> .width_pix = winsize.x_pixel,</span>
<span class="line" id="L38"> .height_pix = winsize.y_pixel,</span>
<span class="line" id="L39"> };</span>
<span class="line" id="L40"> <span class="tok-kw">for</span> (self.buf, <span class="tok-number">0</span>..) |_, i| {</span>
<span class="line" id="L41"> self.buf[i] = .{};</span>
<span class="line" id="L42"> }</span>
<span class="line" id="L43"> <span class="tok-kw">return</span> self;</span>
<span class="line" id="L44">}</span>
<span class="line" id="L45"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">deinit</span>(self: *Screen, alloc: std.mem.Allocator) <span class="tok-type">void</span> {</span>
<span class="line" id="L46"> alloc.free(self.buf);</span>
<span class="line" id="L47">}</span>
<span class="line" id="L48"></span>
<span class="line" id="L49"><span class="tok-comment">/// writes a cell to a location. 0 indexed</span></span>
<span class="line" id="L50"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">writeCell</span>(self: *Screen, col: <span class="tok-type">usize</span>, row: <span class="tok-type">usize</span>, cell: Cell) <span class="tok-type">void</span> {</span>
<span class="line" id="L51"> <span class="tok-kw">if</span> (self.width &lt; col) {</span>
<span class="line" id="L52"> <span class="tok-comment">// column out of bounds</span>
</span>
<span class="line" id="L53"> <span class="tok-kw">return</span>;</span>
<span class="line" id="L54"> }</span>
<span class="line" id="L55"> <span class="tok-kw">if</span> (self.height &lt; row) {</span>
<span class="line" id="L56"> <span class="tok-comment">// height out of bounds</span>
</span>
<span class="line" id="L57"> <span class="tok-kw">return</span>;</span>
<span class="line" id="L58"> }</span>
<span class="line" id="L59"> <span class="tok-kw">const</span> i = (row * self.width) + col;</span>
<span class="line" id="L60"> assert(i &lt; self.buf.len);</span>
<span class="line" id="L61"> self.buf[i] = cell;</span>
<span class="line" id="L62">}</span>
<span class="line" id="L63"></span>
</code></pre></body>
</html>

411
docs/src/vaxis/Tty.zig.html Normal file
View file

@ -0,0 +1,411 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Tty.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-kw">const</span> std = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;std&quot;</span>);</span>
<span class="line" id="L2"><span class="tok-kw">const</span> builtin = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;builtin&quot;</span>);</span>
<span class="line" id="L3"><span class="tok-kw">const</span> os = std.os;</span>
<span class="line" id="L4"></span>
<span class="line" id="L5"><span class="tok-kw">const</span> BufferedWriter = std.io.BufferedWriter(<span class="tok-number">4096</span>, Writer);</span>
<span class="line" id="L6"><span class="tok-kw">const</span> Writer = std.io.Writer(os.fd_t, os.WriteError, os.write);</span>
<span class="line" id="L7"></span>
<span class="line" id="L8"><span class="tok-kw">const</span> Vaxis = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;vaxis.zig&quot;</span>).Vaxis;</span>
<span class="line" id="L9"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Parser = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;Parser.zig&quot;</span>);</span>
<span class="line" id="L10"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> GraphemeCache = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;GraphemeCache.zig&quot;</span>);</span>
<span class="line" id="L11"></span>
<span class="line" id="L12"><span class="tok-kw">const</span> log = std.log.scoped(.tty);</span>
<span class="line" id="L13"></span>
<span class="line" id="L14"><span class="tok-kw">const</span> Tty = <span class="tok-builtin">@This</span>();</span>
<span class="line" id="L15"></span>
<span class="line" id="L16"></span>
<span class="line" id="L17"><span class="tok-comment">/// the original state of the terminal, prior to calling makeRaw</span></span>
<span class="line" id="L18">termios: os.termios,</span>
<span class="line" id="L19"></span>
<span class="line" id="L20"><span class="tok-comment">/// The file descriptor we are using for I/O</span></span>
<span class="line" id="L21">fd: os.fd_t,</span>
<span class="line" id="L22"></span>
<span class="line" id="L23"><span class="tok-comment">/// the write end of a pipe to signal the tty should exit it's run loop</span></span>
<span class="line" id="L24">quit_fd: ?os.fd_t = <span class="tok-null">null</span>,</span>
<span class="line" id="L25"></span>
<span class="line" id="L26">buffered_writer: BufferedWriter,</span>
<span class="line" id="L27"></span>
<span class="line" id="L28"><span class="tok-comment">/// initializes a Tty instance by opening /dev/tty and &quot;making it raw&quot;</span></span>
<span class="line" id="L29"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">init</span>() !Tty {</span>
<span class="line" id="L30"> <span class="tok-comment">// Open our tty</span>
</span>
<span class="line" id="L31"> <span class="tok-kw">const</span> fd = <span class="tok-kw">try</span> os.open(<span class="tok-str">&quot;/dev/tty&quot;</span>, .{ .ACCMODE = .RDWR }, <span class="tok-number">0</span>);</span>
<span class="line" id="L32"></span>
<span class="line" id="L33"> <span class="tok-comment">// Set the termios of the tty</span>
</span>
<span class="line" id="L34"> <span class="tok-kw">const</span> termios = <span class="tok-kw">try</span> makeRaw(fd);</span>
<span class="line" id="L35"></span>
<span class="line" id="L36"> <span class="tok-kw">return</span> Tty{</span>
<span class="line" id="L37"> .fd = fd,</span>
<span class="line" id="L38"> .termios = termios,</span>
<span class="line" id="L39"> .buffered_writer = std.io.bufferedWriter(Writer{ .context = fd }),</span>
<span class="line" id="L40"> };</span>
<span class="line" id="L41">}</span>
<span class="line" id="L42"></span>
<span class="line" id="L43"><span class="tok-comment">/// release resources associated with the Tty return it to it's original state</span></span>
<span class="line" id="L44"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">deinit</span>(self: *Tty) <span class="tok-type">void</span> {</span>
<span class="line" id="L45"> os.tcsetattr(self.fd, .FLUSH, self.termios) <span class="tok-kw">catch</span> |err| {</span>
<span class="line" id="L46"> log.err(<span class="tok-str">&quot;couldn't restore terminal: {}&quot;</span>, .{err});</span>
<span class="line" id="L47"> };</span>
<span class="line" id="L48"> os.close(self.fd);</span>
<span class="line" id="L49">}</span>
<span class="line" id="L50"></span>
<span class="line" id="L51"><span class="tok-comment">/// stops the run loop</span></span>
<span class="line" id="L52"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">stop</span>(self: *Tty) <span class="tok-type">void</span> {</span>
<span class="line" id="L53"> <span class="tok-kw">if</span> (self.quit_fd) |fd| {</span>
<span class="line" id="L54"> _ = std.os.write(fd, <span class="tok-str">&quot;q&quot;</span>) <span class="tok-kw">catch</span> {};</span>
<span class="line" id="L55"> }</span>
<span class="line" id="L56">}</span>
<span class="line" id="L57"></span>
<span class="line" id="L58"><span class="tok-comment">/// read input from the tty</span></span>
<span class="line" id="L59"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">run</span>(</span>
<span class="line" id="L60"> self: *Tty,</span>
<span class="line" id="L61"> <span class="tok-kw">comptime</span> Event: <span class="tok-type">type</span>,</span>
<span class="line" id="L62"> vx: *Vaxis(Event),</span>
<span class="line" id="L63">) !<span class="tok-type">void</span> {</span>
<span class="line" id="L64"> <span class="tok-comment">// create a pipe so we can signal to exit the run loop</span>
</span>
<span class="line" id="L65"> <span class="tok-kw">const</span> pipe = <span class="tok-kw">try</span> os.pipe();</span>
<span class="line" id="L66"> <span class="tok-kw">defer</span> os.close(pipe[<span class="tok-number">0</span>]);</span>
<span class="line" id="L67"> <span class="tok-kw">defer</span> os.close(pipe[<span class="tok-number">1</span>]);</span>
<span class="line" id="L68"></span>
<span class="line" id="L69"> <span class="tok-comment">// get our initial winsize</span>
</span>
<span class="line" id="L70"> <span class="tok-kw">const</span> winsize = <span class="tok-kw">try</span> getWinsize(self.fd);</span>
<span class="line" id="L71"> <span class="tok-kw">if</span> (<span class="tok-builtin">@hasField</span>(Event, <span class="tok-str">&quot;winsize&quot;</span>)) {</span>
<span class="line" id="L72"> vx.postEvent(.{ .winsize = winsize });</span>
<span class="line" id="L73"> }</span>
<span class="line" id="L74"></span>
<span class="line" id="L75"> <span class="tok-comment">// assign the write end of the pipe to our quit_fd</span>
</span>
<span class="line" id="L76"> self.quit_fd = pipe[<span class="tok-number">1</span>];</span>
<span class="line" id="L77"></span>
<span class="line" id="L78"> <span class="tok-comment">// Build a winch handler. We need build this struct to get an anonymous</span>
</span>
<span class="line" id="L79"> <span class="tok-comment">// function which can post the winsize event</span>
</span>
<span class="line" id="L80"> <span class="tok-comment">// TODO: more signals, move this outside of this function?</span>
</span>
<span class="line" id="L81"> <span class="tok-kw">const</span> WinchHandler = <span class="tok-kw">struct</span> {</span>
<span class="line" id="L82"> <span class="tok-kw">const</span> Self = <span class="tok-builtin">@This</span>();</span>
<span class="line" id="L83"></span>
<span class="line" id="L84"> <span class="tok-kw">var</span> vx_winch: *Vaxis(Event) = <span class="tok-null">undefined</span>;</span>
<span class="line" id="L85"> <span class="tok-kw">var</span> fd: os.fd_t = <span class="tok-null">undefined</span>;</span>
<span class="line" id="L86"></span>
<span class="line" id="L87"> <span class="tok-kw">fn</span> <span class="tok-fn">init</span>(vx_arg: *Vaxis(Event), fd_arg: os.fd_t) !<span class="tok-type">void</span> {</span>
<span class="line" id="L88"> vx_winch = vx_arg;</span>
<span class="line" id="L89"> fd = fd_arg;</span>
<span class="line" id="L90"> <span class="tok-kw">var</span> act = os.Sigaction{</span>
<span class="line" id="L91"> .handler = .{ .handler = Self.handleWinch },</span>
<span class="line" id="L92"> .mask = <span class="tok-kw">switch</span> (builtin.os.tag) {</span>
<span class="line" id="L93"> .macos =&gt; <span class="tok-number">0</span>,</span>
<span class="line" id="L94"> .linux =&gt; std.os.empty_sigset,</span>
<span class="line" id="L95"> <span class="tok-kw">else</span> =&gt; <span class="tok-builtin">@compileError</span>(<span class="tok-str">&quot;os not supported&quot;</span>),</span>
<span class="line" id="L96"> },</span>
<span class="line" id="L97"> .flags = <span class="tok-number">0</span>,</span>
<span class="line" id="L98"> };</span>
<span class="line" id="L99"></span>
<span class="line" id="L100"> <span class="tok-kw">try</span> os.sigaction(os.SIG.WINCH, &amp;act, <span class="tok-null">null</span>);</span>
<span class="line" id="L101"> }</span>
<span class="line" id="L102"></span>
<span class="line" id="L103"> <span class="tok-kw">fn</span> <span class="tok-fn">handleWinch</span>(_: <span class="tok-type">c_int</span>) <span class="tok-kw">callconv</span>(.C) <span class="tok-type">void</span> {</span>
<span class="line" id="L104"> <span class="tok-kw">const</span> ws = getWinsize(fd) <span class="tok-kw">catch</span> {</span>
<span class="line" id="L105"> <span class="tok-kw">return</span>;</span>
<span class="line" id="L106"> };</span>
<span class="line" id="L107"> <span class="tok-kw">if</span> (<span class="tok-builtin">@hasField</span>(Event, <span class="tok-str">&quot;winsize&quot;</span>)) {</span>
<span class="line" id="L108"> vx_winch.postEvent(.{ .winsize = ws });</span>
<span class="line" id="L109"> }</span>
<span class="line" id="L110"> }</span>
<span class="line" id="L111"> };</span>
<span class="line" id="L112"> <span class="tok-kw">try</span> WinchHandler.init(vx, self.fd);</span>
<span class="line" id="L113"></span>
<span class="line" id="L114"> <span class="tok-comment">// initialize a grapheme cache</span>
</span>
<span class="line" id="L115"> <span class="tok-kw">var</span> cache: GraphemeCache = .{};</span>
<span class="line" id="L116"></span>
<span class="line" id="L117"> <span class="tok-comment">// Set up fds for polling</span>
</span>
<span class="line" id="L118"> <span class="tok-kw">var</span> pollfds: [<span class="tok-number">2</span>]std.os.pollfd = .{</span>
<span class="line" id="L119"> .{ .fd = self.fd, .events = std.os.POLL.IN, .revents = <span class="tok-null">undefined</span> },</span>
<span class="line" id="L120"> .{ .fd = pipe[<span class="tok-number">0</span>], .events = std.os.POLL.IN, .revents = <span class="tok-null">undefined</span> },</span>
<span class="line" id="L121"> };</span>
<span class="line" id="L122"></span>
<span class="line" id="L123"> <span class="tok-kw">var</span> parser: Parser = .{};</span>
<span class="line" id="L124"></span>
<span class="line" id="L125"> <span class="tok-comment">// initialize the read buffer</span>
</span>
<span class="line" id="L126"> <span class="tok-kw">var</span> buf: [<span class="tok-number">1024</span>]<span class="tok-type">u8</span> = <span class="tok-null">undefined</span>;</span>
<span class="line" id="L127"> <span class="tok-comment">// read loop</span>
</span>
<span class="line" id="L128"> <span class="tok-kw">while</span> (<span class="tok-null">true</span>) {</span>
<span class="line" id="L129"> _ = <span class="tok-kw">try</span> std.os.poll(&amp;pollfds, -<span class="tok-number">1</span>);</span>
<span class="line" id="L130"> <span class="tok-kw">if</span> (pollfds[<span class="tok-number">1</span>].revents &amp; std.os.POLL.IN != <span class="tok-number">0</span>) {</span>
<span class="line" id="L131"> log.info(<span class="tok-str">&quot;quitting read thread&quot;</span>, .{});</span>
<span class="line" id="L132"> <span class="tok-kw">return</span>;</span>
<span class="line" id="L133"> }</span>
<span class="line" id="L134"></span>
<span class="line" id="L135"> <span class="tok-kw">const</span> n = <span class="tok-kw">try</span> os.read(self.fd, &amp;buf);</span>
<span class="line" id="L136"> <span class="tok-kw">var</span> start: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L137"> <span class="tok-kw">while</span> (start &lt; n) {</span>
<span class="line" id="L138"> <span class="tok-kw">const</span> result = <span class="tok-kw">try</span> parser.parse(buf[start..n]);</span>
<span class="line" id="L139"> start += result.n;</span>
<span class="line" id="L140"> <span class="tok-comment">// TODO: if we get 0 byte read, copy the remaining bytes to the</span>
</span>
<span class="line" id="L141"> <span class="tok-comment">// beginning of the buffer and read mmore? this should only happen</span>
</span>
<span class="line" id="L142"> <span class="tok-comment">// if we are in the middle of a grapheme at and filled our</span>
</span>
<span class="line" id="L143"> <span class="tok-comment">// buffer. Probably can happen on large pastes so needs to be</span>
</span>
<span class="line" id="L144"> <span class="tok-comment">// implemented but low priority</span>
</span>
<span class="line" id="L145"></span>
<span class="line" id="L146"> <span class="tok-kw">const</span> event = result.event <span class="tok-kw">orelse</span> <span class="tok-kw">continue</span>;</span>
<span class="line" id="L147"> <span class="tok-kw">switch</span> (event) {</span>
<span class="line" id="L148"> .key_press =&gt; |key| {</span>
<span class="line" id="L149"> <span class="tok-kw">if</span> (<span class="tok-builtin">@hasField</span>(Event, <span class="tok-str">&quot;key_press&quot;</span>)) {</span>
<span class="line" id="L150"> <span class="tok-comment">// HACK: yuck. there has to be a better way</span>
</span>
<span class="line" id="L151"> <span class="tok-kw">var</span> mut_key = key;</span>
<span class="line" id="L152"> <span class="tok-kw">if</span> (key.text) |text| {</span>
<span class="line" id="L153"> mut_key.text = cache.put(text);</span>
<span class="line" id="L154"> }</span>
<span class="line" id="L155"> vx.postEvent(.{ .key_press = mut_key });</span>
<span class="line" id="L156"> }</span>
<span class="line" id="L157"> },</span>
<span class="line" id="L158"> .mouse =&gt; |mouse| {</span>
<span class="line" id="L159"> <span class="tok-kw">if</span> (<span class="tok-builtin">@hasField</span>(Event, <span class="tok-str">&quot;mouse&quot;</span>)) {</span>
<span class="line" id="L160"> vx.postEvent(.{ .mouse = mouse });</span>
<span class="line" id="L161"> }</span>
<span class="line" id="L162"> },</span>
<span class="line" id="L163"> .focus_in =&gt; {</span>
<span class="line" id="L164"> <span class="tok-kw">if</span> (<span class="tok-builtin">@hasField</span>(Event, <span class="tok-str">&quot;focus_in&quot;</span>)) {</span>
<span class="line" id="L165"> vx.postEvent(.focus_in);</span>
<span class="line" id="L166"> }</span>
<span class="line" id="L167"> },</span>
<span class="line" id="L168"> .focus_out =&gt; {</span>
<span class="line" id="L169"> <span class="tok-kw">if</span> (<span class="tok-builtin">@hasField</span>(Event, <span class="tok-str">&quot;focus_out&quot;</span>)) {</span>
<span class="line" id="L170"> vx.postEvent(.focus_out);</span>
<span class="line" id="L171"> }</span>
<span class="line" id="L172"> },</span>
<span class="line" id="L173"> .paste_start =&gt; {</span>
<span class="line" id="L174"> <span class="tok-kw">if</span> (<span class="tok-builtin">@hasField</span>(Event, <span class="tok-str">&quot;paste_start&quot;</span>)) {</span>
<span class="line" id="L175"> vx.postEvent(.paste_start);</span>
<span class="line" id="L176"> }</span>
<span class="line" id="L177"> },</span>
<span class="line" id="L178"> .paste_end =&gt; {</span>
<span class="line" id="L179"> <span class="tok-kw">if</span> (<span class="tok-builtin">@hasField</span>(Event, <span class="tok-str">&quot;paste_end&quot;</span>)) {</span>
<span class="line" id="L180"> vx.postEvent(.paste_end);</span>
<span class="line" id="L181"> }</span>
<span class="line" id="L182"> },</span>
<span class="line" id="L183"> .cap_kitty_keyboard =&gt; {</span>
<span class="line" id="L184"> log.info(<span class="tok-str">&quot;kitty keyboard capability detected&quot;</span>, .{});</span>
<span class="line" id="L185"> vx.caps.kitty_keyboard = <span class="tok-null">true</span>;</span>
<span class="line" id="L186"> },</span>
<span class="line" id="L187"> .cap_kitty_graphics =&gt; {</span>
<span class="line" id="L188"> <span class="tok-kw">if</span> (!vx.caps.kitty_graphics) {</span>
<span class="line" id="L189"> log.info(<span class="tok-str">&quot;kitty graphics capability detected&quot;</span>, .{});</span>
<span class="line" id="L190"> vx.caps.kitty_graphics = <span class="tok-null">true</span>;</span>
<span class="line" id="L191"> }</span>
<span class="line" id="L192"> },</span>
<span class="line" id="L193"> .cap_rgb =&gt; {</span>
<span class="line" id="L194"> log.info(<span class="tok-str">&quot;rgb capability detected&quot;</span>, .{});</span>
<span class="line" id="L195"> vx.caps.rgb = <span class="tok-null">true</span>;</span>
<span class="line" id="L196"> },</span>
<span class="line" id="L197"> .cap_unicode =&gt; {</span>
<span class="line" id="L198"> log.info(<span class="tok-str">&quot;unicode capability detected&quot;</span>, .{});</span>
<span class="line" id="L199"> vx.caps.unicode = <span class="tok-null">true</span>;</span>
<span class="line" id="L200"> vx.screen.unicode = <span class="tok-null">true</span>;</span>
<span class="line" id="L201"> },</span>
<span class="line" id="L202"> .cap_da1 =&gt; {</span>
<span class="line" id="L203"> std.Thread.Futex.wake(&amp;vx.query_futex, <span class="tok-number">10</span>);</span>
<span class="line" id="L204"> },</span>
<span class="line" id="L205"> }</span>
<span class="line" id="L206"> }</span>
<span class="line" id="L207"> }</span>
<span class="line" id="L208">}</span>
<span class="line" id="L209"></span>
<span class="line" id="L210"><span class="tok-comment">/// write to the tty. These writes are buffered and require calling flush to</span></span>
<span class="line" id="L211"><span class="tok-comment">/// flush writes to the tty</span></span>
<span class="line" id="L212"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">write</span>(self: *Tty, bytes: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>) !<span class="tok-type">usize</span> {</span>
<span class="line" id="L213"> <span class="tok-kw">return</span> self.buffered_writer.write(bytes);</span>
<span class="line" id="L214">}</span>
<span class="line" id="L215"></span>
<span class="line" id="L216"><span class="tok-comment">/// flushes the write buffer to the tty</span></span>
<span class="line" id="L217"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">flush</span>(self: *Tty) !<span class="tok-type">void</span> {</span>
<span class="line" id="L218"> <span class="tok-kw">try</span> self.buffered_writer.flush();</span>
<span class="line" id="L219">}</span>
<span class="line" id="L220"></span>
<span class="line" id="L221"><span class="tok-comment">/// makeRaw enters the raw state for the terminal.</span></span>
<span class="line" id="L222"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">makeRaw</span>(fd: os.fd_t) !os.termios {</span>
<span class="line" id="L223"> <span class="tok-kw">const</span> state = <span class="tok-kw">try</span> os.tcgetattr(fd);</span>
<span class="line" id="L224"> <span class="tok-kw">var</span> raw = state;</span>
<span class="line" id="L225"> <span class="tok-comment">// see termios(3)</span>
</span>
<span class="line" id="L226"> raw.iflag.IGNBRK = <span class="tok-null">false</span>;</span>
<span class="line" id="L227"> raw.iflag.BRKINT = <span class="tok-null">false</span>;</span>
<span class="line" id="L228"> raw.iflag.ISTRIP = <span class="tok-null">false</span>;</span>
<span class="line" id="L229"> raw.iflag.INLCR = <span class="tok-null">false</span>;</span>
<span class="line" id="L230"> raw.iflag.IGNCR = <span class="tok-null">false</span>;</span>
<span class="line" id="L231"> raw.iflag.ICRNL = <span class="tok-null">false</span>;</span>
<span class="line" id="L232"> raw.iflag.IXON = <span class="tok-null">false</span>;</span>
<span class="line" id="L233"></span>
<span class="line" id="L234"> raw.oflag.OPOST = <span class="tok-null">false</span>;</span>
<span class="line" id="L235"></span>
<span class="line" id="L236"> raw.lflag.ECHO = <span class="tok-null">false</span>;</span>
<span class="line" id="L237"> raw.lflag.ECHONL = <span class="tok-null">false</span>;</span>
<span class="line" id="L238"> raw.lflag.ICANON = <span class="tok-null">false</span>;</span>
<span class="line" id="L239"> raw.lflag.IEXTEN = <span class="tok-null">false</span>;</span>
<span class="line" id="L240"></span>
<span class="line" id="L241"> raw.cflag.CSIZE = .CS8;</span>
<span class="line" id="L242"> raw.cflag.PARENB = <span class="tok-null">false</span>;</span>
<span class="line" id="L243"></span>
<span class="line" id="L244"> raw.cc[<span class="tok-builtin">@intFromEnum</span>(std.posix.V.MIN)] = <span class="tok-number">1</span>;</span>
<span class="line" id="L245"> raw.cc[<span class="tok-builtin">@intFromEnum</span>(std.posix.V.TIME)] = <span class="tok-number">0</span>;</span>
<span class="line" id="L246"> <span class="tok-kw">try</span> os.tcsetattr(fd, .FLUSH, raw);</span>
<span class="line" id="L247"> <span class="tok-kw">return</span> state;</span>
<span class="line" id="L248">}</span>
<span class="line" id="L249"></span>
<span class="line" id="L250"><span class="tok-comment">/// The size of the terminal screen</span></span>
<span class="line" id="L251"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Winsize = <span class="tok-kw">struct</span> {</span>
<span class="line" id="L252"> rows: <span class="tok-type">usize</span>,</span>
<span class="line" id="L253"> cols: <span class="tok-type">usize</span>,</span>
<span class="line" id="L254"> x_pixel: <span class="tok-type">usize</span>,</span>
<span class="line" id="L255"> y_pixel: <span class="tok-type">usize</span>,</span>
<span class="line" id="L256">};</span>
<span class="line" id="L257"></span>
<span class="line" id="L258"><span class="tok-kw">fn</span> <span class="tok-fn">getWinsize</span>(fd: os.fd_t) !Winsize {</span>
<span class="line" id="L259"> <span class="tok-kw">var</span> winsize = os.winsize{</span>
<span class="line" id="L260"> .ws_row = <span class="tok-number">0</span>,</span>
<span class="line" id="L261"> .ws_col = <span class="tok-number">0</span>,</span>
<span class="line" id="L262"> .ws_xpixel = <span class="tok-number">0</span>,</span>
<span class="line" id="L263"> .ws_ypixel = <span class="tok-number">0</span>,</span>
<span class="line" id="L264"> };</span>
<span class="line" id="L265"></span>
<span class="line" id="L266"> <span class="tok-kw">const</span> err = os.system.ioctl(fd, os.T.IOCGWINSZ, <span class="tok-builtin">@intFromPtr</span>(&amp;winsize));</span>
<span class="line" id="L267"> <span class="tok-kw">if</span> (os.errno(err) == .SUCCESS)</span>
<span class="line" id="L268"> <span class="tok-kw">return</span> Winsize{</span>
<span class="line" id="L269"> .rows = winsize.ws_row,</span>
<span class="line" id="L270"> .cols = winsize.ws_col,</span>
<span class="line" id="L271"> .x_pixel = winsize.ws_xpixel,</span>
<span class="line" id="L272"> .y_pixel = winsize.ws_ypixel,</span>
<span class="line" id="L273"> };</span>
<span class="line" id="L274"> <span class="tok-kw">return</span> <span class="tok-kw">error</span>.IoctlError;</span>
<span class="line" id="L275">}</span>
<span class="line" id="L276"></span>
</code></pre></body>
</html>

View file

@ -0,0 +1,338 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Window.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-kw">const</span> std = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;std&quot;</span>);</span>
<span class="line" id="L2"><span class="tok-kw">const</span> ziglyph = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;ziglyph&quot;</span>);</span>
<span class="line" id="L3"><span class="tok-kw">const</span> WordIterator = ziglyph.WordIterator;</span>
<span class="line" id="L4"><span class="tok-kw">const</span> GraphemeIterator = ziglyph.GraphemeIterator;</span>
<span class="line" id="L5"></span>
<span class="line" id="L6"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Screen = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;Screen.zig&quot;</span>);</span>
<span class="line" id="L7"><span class="tok-kw">const</span> Cell = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;Cell.zig&quot;</span>);</span>
<span class="line" id="L8"><span class="tok-kw">const</span> Segment = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;Cell.zig&quot;</span>).Segment;</span>
<span class="line" id="L9"><span class="tok-kw">const</span> gw = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;gwidth.zig&quot;</span>);</span>
<span class="line" id="L10"></span>
<span class="line" id="L11"><span class="tok-kw">const</span> log = std.log.scoped(.window);</span>
<span class="line" id="L12"></span>
<span class="line" id="L13"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Window = <span class="tok-builtin">@This</span>();</span>
<span class="line" id="L14"></span>
<span class="line" id="L15"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Size = <span class="tok-kw">union</span>(<span class="tok-kw">enum</span>) {</span>
<span class="line" id="L16"> expand,</span>
<span class="line" id="L17"> limit: <span class="tok-type">usize</span>,</span>
<span class="line" id="L18">};</span>
<span class="line" id="L19"></span>
<span class="line" id="L20"><span class="tok-comment">/// horizontal offset from the screen</span></span>
<span class="line" id="L21">x_off: <span class="tok-type">usize</span>,</span>
<span class="line" id="L22"><span class="tok-comment">/// vertical offset from the screen</span></span>
<span class="line" id="L23">y_off: <span class="tok-type">usize</span>,</span>
<span class="line" id="L24"><span class="tok-comment">/// width of the window. This can't be larger than the terminal screen</span></span>
<span class="line" id="L25">width: <span class="tok-type">usize</span>,</span>
<span class="line" id="L26"><span class="tok-comment">/// height of the window. This can't be larger than the terminal screen</span></span>
<span class="line" id="L27">height: <span class="tok-type">usize</span>,</span>
<span class="line" id="L28"></span>
<span class="line" id="L29">screen: *Screen,</span>
<span class="line" id="L30"></span>
<span class="line" id="L31"><span class="tok-comment">/// Creates a new window with offset relative to parent and size clamped to the</span></span>
<span class="line" id="L32"><span class="tok-comment">/// parent's size. Windows do not retain a reference to their parent and are</span></span>
<span class="line" id="L33"><span class="tok-comment">/// unaware of resizes.</span></span>
<span class="line" id="L34"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">initChild</span>(</span>
<span class="line" id="L35"> self: Window,</span>
<span class="line" id="L36"> x_off: <span class="tok-type">usize</span>,</span>
<span class="line" id="L37"> y_off: <span class="tok-type">usize</span>,</span>
<span class="line" id="L38"> width: Size,</span>
<span class="line" id="L39"> height: Size,</span>
<span class="line" id="L40">) Window {</span>
<span class="line" id="L41"> <span class="tok-kw">const</span> resolved_width = <span class="tok-kw">switch</span> (width) {</span>
<span class="line" id="L42"> .expand =&gt; self.width - x_off,</span>
<span class="line" id="L43"> .limit =&gt; |w| blk: {</span>
<span class="line" id="L44"> <span class="tok-kw">if</span> (w + x_off &gt; self.width) {</span>
<span class="line" id="L45"> <span class="tok-kw">break</span> :blk self.width - x_off;</span>
<span class="line" id="L46"> }</span>
<span class="line" id="L47"> <span class="tok-kw">break</span> :blk w;</span>
<span class="line" id="L48"> },</span>
<span class="line" id="L49"> };</span>
<span class="line" id="L50"> <span class="tok-kw">const</span> resolved_height = <span class="tok-kw">switch</span> (height) {</span>
<span class="line" id="L51"> .expand =&gt; self.height - y_off,</span>
<span class="line" id="L52"> .limit =&gt; |h| blk: {</span>
<span class="line" id="L53"> <span class="tok-kw">if</span> (h + y_off &gt; self.height) {</span>
<span class="line" id="L54"> <span class="tok-kw">break</span> :blk self.height - y_off;</span>
<span class="line" id="L55"> }</span>
<span class="line" id="L56"> <span class="tok-kw">break</span> :blk h;</span>
<span class="line" id="L57"> },</span>
<span class="line" id="L58"> };</span>
<span class="line" id="L59"> <span class="tok-kw">return</span> Window{</span>
<span class="line" id="L60"> .x_off = x_off + self.x_off,</span>
<span class="line" id="L61"> .y_off = y_off + self.y_off,</span>
<span class="line" id="L62"> .width = resolved_width,</span>
<span class="line" id="L63"> .height = resolved_height,</span>
<span class="line" id="L64"> .screen = self.screen,</span>
<span class="line" id="L65"> };</span>
<span class="line" id="L66">}</span>
<span class="line" id="L67"></span>
<span class="line" id="L68"><span class="tok-comment">/// writes a cell to the location in the window</span></span>
<span class="line" id="L69"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">writeCell</span>(self: Window, col: <span class="tok-type">usize</span>, row: <span class="tok-type">usize</span>, cell: Cell) <span class="tok-type">void</span> {</span>
<span class="line" id="L70"> <span class="tok-kw">if</span> (self.height == <span class="tok-number">0</span> <span class="tok-kw">or</span> self.width == <span class="tok-number">0</span>) <span class="tok-kw">return</span>;</span>
<span class="line" id="L71"> <span class="tok-kw">if</span> (self.height &lt;= row <span class="tok-kw">or</span> self.width &lt;= col) <span class="tok-kw">return</span>;</span>
<span class="line" id="L72"> self.screen.writeCell(col + self.x_off, row + self.y_off, cell);</span>
<span class="line" id="L73">}</span>
<span class="line" id="L74"></span>
<span class="line" id="L75"><span class="tok-comment">/// fills the window with the default cell</span></span>
<span class="line" id="L76"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">clear</span>(self: Window) <span class="tok-type">void</span> {</span>
<span class="line" id="L77"> self.fill(.{});</span>
<span class="line" id="L78">}</span>
<span class="line" id="L79"></span>
<span class="line" id="L80"><span class="tok-comment">/// returns the width of the grapheme. This depends on the terminal capabilities</span></span>
<span class="line" id="L81"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">gwidth</span>(self: Window, str: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>) <span class="tok-type">usize</span> {</span>
<span class="line" id="L82"> <span class="tok-kw">const</span> m: gw.Method = <span class="tok-kw">if</span> (self.screen.unicode) .unicode <span class="tok-kw">else</span> .wcwidth;</span>
<span class="line" id="L83"> <span class="tok-kw">return</span> gw.gwidth(str, m) <span class="tok-kw">catch</span> <span class="tok-number">1</span>;</span>
<span class="line" id="L84">}</span>
<span class="line" id="L85"></span>
<span class="line" id="L86"><span class="tok-comment">/// fills the window with the provided cell</span></span>
<span class="line" id="L87"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">fill</span>(self: Window, cell: Cell) <span class="tok-type">void</span> {</span>
<span class="line" id="L88"> <span class="tok-kw">var</span> row: <span class="tok-type">usize</span> = self.y_off;</span>
<span class="line" id="L89"> <span class="tok-kw">while</span> (row &lt; (self.height + self.y_off)) : (row += <span class="tok-number">1</span>) {</span>
<span class="line" id="L90"> <span class="tok-kw">var</span> col: <span class="tok-type">usize</span> = self.x_off;</span>
<span class="line" id="L91"> <span class="tok-kw">while</span> (col &lt; (self.width + self.x_off)) : (col += <span class="tok-number">1</span>) {</span>
<span class="line" id="L92"> self.screen.writeCell(col, row, cell);</span>
<span class="line" id="L93"> }</span>
<span class="line" id="L94"> }</span>
<span class="line" id="L95">}</span>
<span class="line" id="L96"></span>
<span class="line" id="L97"><span class="tok-comment">/// hide the cursor</span></span>
<span class="line" id="L98"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">hideCursor</span>(self: Window) <span class="tok-type">void</span> {</span>
<span class="line" id="L99"> self.screen.cursor_vis = <span class="tok-null">false</span>;</span>
<span class="line" id="L100">}</span>
<span class="line" id="L101"></span>
<span class="line" id="L102"><span class="tok-comment">/// show the cursor at the given coordinates, 0 indexed</span></span>
<span class="line" id="L103"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">showCursor</span>(self: Window, col: <span class="tok-type">usize</span>, row: <span class="tok-type">usize</span>) <span class="tok-type">void</span> {</span>
<span class="line" id="L104"> <span class="tok-kw">if</span> (self.height == <span class="tok-number">0</span> <span class="tok-kw">or</span> self.width == <span class="tok-number">0</span>) <span class="tok-kw">return</span>;</span>
<span class="line" id="L105"> <span class="tok-kw">if</span> (self.height &lt;= row <span class="tok-kw">or</span> self.width &lt;= col) <span class="tok-kw">return</span>;</span>
<span class="line" id="L106"> self.screen.cursor_vis = <span class="tok-null">true</span>;</span>
<span class="line" id="L107"> self.screen.cursor_row = row + self.y_off;</span>
<span class="line" id="L108"> self.screen.cursor_col = col + self.x_off;</span>
<span class="line" id="L109">}</span>
<span class="line" id="L110"></span>
<span class="line" id="L111"><span class="tok-comment">/// prints text in the window with simple word wrapping.</span></span>
<span class="line" id="L112"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">wrap</span>(self: Window, segments: []Segment) !<span class="tok-type">void</span> {</span>
<span class="line" id="L113"> <span class="tok-comment">// pub fn wrap(self: Window, str: []const u8) !void {</span>
</span>
<span class="line" id="L114"> <span class="tok-kw">var</span> row: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L115"> <span class="tok-kw">var</span> col: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L116"> <span class="tok-kw">var</span> wrapped: <span class="tok-type">bool</span> = <span class="tok-null">false</span>;</span>
<span class="line" id="L117"> <span class="tok-kw">for</span> (segments) |segment| {</span>
<span class="line" id="L118"> <span class="tok-kw">var</span> word_iter = <span class="tok-kw">try</span> WordIterator.init(segment.text);</span>
<span class="line" id="L119"> <span class="tok-kw">while</span> (word_iter.next()) |word| {</span>
<span class="line" id="L120"> <span class="tok-comment">// break lines when we need</span>
</span>
<span class="line" id="L121"> <span class="tok-kw">if</span> (word.bytes[<span class="tok-number">0</span>] == <span class="tok-str">'\r'</span> <span class="tok-kw">or</span> word.bytes[<span class="tok-number">0</span>] == <span class="tok-str">'\n'</span>) {</span>
<span class="line" id="L122"> row += <span class="tok-number">1</span>;</span>
<span class="line" id="L123"> col = <span class="tok-number">0</span>;</span>
<span class="line" id="L124"> wrapped = <span class="tok-null">false</span>;</span>
<span class="line" id="L125"> <span class="tok-kw">continue</span>;</span>
<span class="line" id="L126"> }</span>
<span class="line" id="L127"> <span class="tok-comment">// break lines when we can't fit this word, and the word isn't longer</span>
</span>
<span class="line" id="L128"> <span class="tok-comment">// than our width</span>
</span>
<span class="line" id="L129"> <span class="tok-kw">const</span> word_width = self.gwidth(word.bytes);</span>
<span class="line" id="L130"> <span class="tok-kw">if</span> (word_width + col &gt;= self.width <span class="tok-kw">and</span> word_width &lt; self.width) {</span>
<span class="line" id="L131"> row += <span class="tok-number">1</span>;</span>
<span class="line" id="L132"> col = <span class="tok-number">0</span>;</span>
<span class="line" id="L133"> wrapped = <span class="tok-null">true</span>;</span>
<span class="line" id="L134"> }</span>
<span class="line" id="L135"> <span class="tok-comment">// don't print whitespace in the first column, unless we had a hard</span>
</span>
<span class="line" id="L136"> <span class="tok-comment">// break</span>
</span>
<span class="line" id="L137"> <span class="tok-kw">if</span> (col == <span class="tok-number">0</span> <span class="tok-kw">and</span> std.mem.eql(<span class="tok-type">u8</span>, word.bytes, <span class="tok-str">&quot; &quot;</span>) <span class="tok-kw">and</span> wrapped) <span class="tok-kw">continue</span>;</span>
<span class="line" id="L138"> <span class="tok-kw">var</span> iter = GraphemeIterator.init(word.bytes);</span>
<span class="line" id="L139"> <span class="tok-kw">while</span> (iter.next()) |grapheme| {</span>
<span class="line" id="L140"> <span class="tok-kw">if</span> (col &gt;= self.width) {</span>
<span class="line" id="L141"> row += <span class="tok-number">1</span>;</span>
<span class="line" id="L142"> col = <span class="tok-number">0</span>;</span>
<span class="line" id="L143"> wrapped = <span class="tok-null">true</span>;</span>
<span class="line" id="L144"> }</span>
<span class="line" id="L145"> <span class="tok-kw">const</span> s = grapheme.slice(word.bytes);</span>
<span class="line" id="L146"> <span class="tok-kw">const</span> w = self.gwidth(s);</span>
<span class="line" id="L147"> self.writeCell(col, row, .{</span>
<span class="line" id="L148"> .char = .{</span>
<span class="line" id="L149"> .grapheme = s,</span>
<span class="line" id="L150"> .width = w,</span>
<span class="line" id="L151"> },</span>
<span class="line" id="L152"> .style = segment.style,</span>
<span class="line" id="L153"> .link = segment.link,</span>
<span class="line" id="L154"> });</span>
<span class="line" id="L155"> col += w;</span>
<span class="line" id="L156"> }</span>
<span class="line" id="L157"> }</span>
<span class="line" id="L158"> }</span>
<span class="line" id="L159">}</span>
<span class="line" id="L160"></span>
<span class="line" id="L161"><span class="tok-kw">test</span> <span class="tok-str">&quot;Window size set&quot;</span> {</span>
<span class="line" id="L162"> <span class="tok-kw">var</span> parent = Window{</span>
<span class="line" id="L163"> .x_off = <span class="tok-number">0</span>,</span>
<span class="line" id="L164"> .y_off = <span class="tok-number">0</span>,</span>
<span class="line" id="L165"> .width = <span class="tok-number">20</span>,</span>
<span class="line" id="L166"> .height = <span class="tok-number">20</span>,</span>
<span class="line" id="L167"> .screen = <span class="tok-null">undefined</span>,</span>
<span class="line" id="L168"> };</span>
<span class="line" id="L169"></span>
<span class="line" id="L170"> <span class="tok-kw">const</span> child = parent.initChild(<span class="tok-number">1</span>, <span class="tok-number">1</span>, .expand, .expand);</span>
<span class="line" id="L171"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-number">19</span>, child.width);</span>
<span class="line" id="L172"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-number">19</span>, child.height);</span>
<span class="line" id="L173">}</span>
<span class="line" id="L174"></span>
<span class="line" id="L175"><span class="tok-kw">test</span> <span class="tok-str">&quot;Window size set too big&quot;</span> {</span>
<span class="line" id="L176"> <span class="tok-kw">var</span> parent = Window{</span>
<span class="line" id="L177"> .x_off = <span class="tok-number">0</span>,</span>
<span class="line" id="L178"> .y_off = <span class="tok-number">0</span>,</span>
<span class="line" id="L179"> .width = <span class="tok-number">20</span>,</span>
<span class="line" id="L180"> .height = <span class="tok-number">20</span>,</span>
<span class="line" id="L181"> .screen = <span class="tok-null">undefined</span>,</span>
<span class="line" id="L182"> };</span>
<span class="line" id="L183"></span>
<span class="line" id="L184"> <span class="tok-kw">const</span> child = parent.initChild(<span class="tok-number">0</span>, <span class="tok-number">0</span>, .{ .limit = <span class="tok-number">21</span> }, .{ .limit = <span class="tok-number">21</span> });</span>
<span class="line" id="L185"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-number">20</span>, child.width);</span>
<span class="line" id="L186"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-number">20</span>, child.height);</span>
<span class="line" id="L187">}</span>
<span class="line" id="L188"></span>
<span class="line" id="L189"><span class="tok-kw">test</span> <span class="tok-str">&quot;Window size set too big with offset&quot;</span> {</span>
<span class="line" id="L190"> <span class="tok-kw">var</span> parent = Window{</span>
<span class="line" id="L191"> .x_off = <span class="tok-number">0</span>,</span>
<span class="line" id="L192"> .y_off = <span class="tok-number">0</span>,</span>
<span class="line" id="L193"> .width = <span class="tok-number">20</span>,</span>
<span class="line" id="L194"> .height = <span class="tok-number">20</span>,</span>
<span class="line" id="L195"> .screen = <span class="tok-null">undefined</span>,</span>
<span class="line" id="L196"> };</span>
<span class="line" id="L197"></span>
<span class="line" id="L198"> <span class="tok-kw">const</span> child = parent.initChild(<span class="tok-number">10</span>, <span class="tok-number">10</span>, .{ .limit = <span class="tok-number">21</span> }, .{ .limit = <span class="tok-number">21</span> });</span>
<span class="line" id="L199"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-number">10</span>, child.width);</span>
<span class="line" id="L200"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-number">10</span>, child.height);</span>
<span class="line" id="L201">}</span>
<span class="line" id="L202"></span>
<span class="line" id="L203"><span class="tok-kw">test</span> <span class="tok-str">&quot;Window size nested offsets&quot;</span> {</span>
<span class="line" id="L204"> <span class="tok-kw">var</span> parent = Window{</span>
<span class="line" id="L205"> .x_off = <span class="tok-number">1</span>,</span>
<span class="line" id="L206"> .y_off = <span class="tok-number">1</span>,</span>
<span class="line" id="L207"> .width = <span class="tok-number">20</span>,</span>
<span class="line" id="L208"> .height = <span class="tok-number">20</span>,</span>
<span class="line" id="L209"> .screen = <span class="tok-null">undefined</span>,</span>
<span class="line" id="L210"> };</span>
<span class="line" id="L211"></span>
<span class="line" id="L212"> <span class="tok-kw">const</span> child = parent.initChild(<span class="tok-number">10</span>, <span class="tok-number">10</span>, .{ .limit = <span class="tok-number">21</span> }, .{ .limit = <span class="tok-number">21</span> });</span>
<span class="line" id="L213"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-number">11</span>, child.x_off);</span>
<span class="line" id="L214"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-number">11</span>, child.y_off);</span>
<span class="line" id="L215">}</span>
<span class="line" id="L216"></span>
</code></pre></body>
</html>

View file

@ -0,0 +1,228 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>ctlseqs.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-comment">// Queries</span>
</span>
<span class="line" id="L2"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> primary_device_attrs = <span class="tok-str">&quot;\x1b[c&quot;</span>;</span>
<span class="line" id="L3"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> tertiary_device_attrs = <span class="tok-str">&quot;\x1b[=c&quot;</span>;</span>
<span class="line" id="L4"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> xtversion = <span class="tok-str">&quot;\x1b[&gt;0q&quot;</span>;</span>
<span class="line" id="L5"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> decrqm_focus = <span class="tok-str">&quot;\x1b[?1004$p&quot;</span>;</span>
<span class="line" id="L6"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> decrqm_sync = <span class="tok-str">&quot;\x1b[?2026$p&quot;</span>;</span>
<span class="line" id="L7"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> decrqm_unicode = <span class="tok-str">&quot;\x1b[?2027$p&quot;</span>;</span>
<span class="line" id="L8"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> decrqm_color_theme = <span class="tok-str">&quot;\x1b[?2031$p&quot;</span>;</span>
<span class="line" id="L9"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> csi_u_query = <span class="tok-str">&quot;\x1b[?u&quot;</span>;</span>
<span class="line" id="L10"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> kitty_graphics_query = <span class="tok-str">&quot;\x1b_Gi=1,a=q\x1b\\&quot;</span>;</span>
<span class="line" id="L11"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> sixel_geometry_query = <span class="tok-str">&quot;\x1b[?2;1;0S&quot;</span>;</span>
<span class="line" id="L12"></span>
<span class="line" id="L13"><span class="tok-comment">// mouse</span>
</span>
<span class="line" id="L14"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> mouse_set = <span class="tok-str">&quot;\x1b[?1003;1004;1006h&quot;</span>;</span>
<span class="line" id="L15"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> mouse_reset = <span class="tok-str">&quot;\x1b[?1003;1004;1006l&quot;</span>;</span>
<span class="line" id="L16"></span>
<span class="line" id="L17"><span class="tok-comment">// sync</span>
</span>
<span class="line" id="L18"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> sync_set = <span class="tok-str">&quot;\x1b[?2026h&quot;</span>;</span>
<span class="line" id="L19"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> sync_reset = <span class="tok-str">&quot;\x1b[?2026l&quot;</span>;</span>
<span class="line" id="L20"></span>
<span class="line" id="L21"><span class="tok-comment">// unicode</span>
</span>
<span class="line" id="L22"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> unicode_set = <span class="tok-str">&quot;\x1b[?2027h&quot;</span>;</span>
<span class="line" id="L23"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> unicode_reset = <span class="tok-str">&quot;\x1b[?2027l&quot;</span>;</span>
<span class="line" id="L24"></span>
<span class="line" id="L25"><span class="tok-comment">// bracketed paste</span>
</span>
<span class="line" id="L26"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> bp_set = <span class="tok-str">&quot;\x1b[?2004h&quot;</span>;</span>
<span class="line" id="L27"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> bp_reset = <span class="tok-str">&quot;\x1b[?2004l&quot;</span>;</span>
<span class="line" id="L28"></span>
<span class="line" id="L29"><span class="tok-comment">// Key encoding</span>
</span>
<span class="line" id="L30"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> csi_u_push = <span class="tok-str">&quot;\x1b[&gt;{d}u&quot;</span>;</span>
<span class="line" id="L31"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> csi_u_pop = <span class="tok-str">&quot;\x1b[&lt;u&quot;</span>;</span>
<span class="line" id="L32"></span>
<span class="line" id="L33"><span class="tok-comment">// Cursor</span>
</span>
<span class="line" id="L34"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> home = <span class="tok-str">&quot;\x1b[H&quot;</span>;</span>
<span class="line" id="L35"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> cup = <span class="tok-str">&quot;\x1b[{d};{d}H&quot;</span>;</span>
<span class="line" id="L36"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> hide_cursor = <span class="tok-str">&quot;\x1b[?25l&quot;</span>;</span>
<span class="line" id="L37"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> show_cursor = <span class="tok-str">&quot;\x1b[?25h&quot;</span>;</span>
<span class="line" id="L38"></span>
<span class="line" id="L39"><span class="tok-comment">// alt screen</span>
</span>
<span class="line" id="L40"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> smcup = <span class="tok-str">&quot;\x1b[?1049h&quot;</span>;</span>
<span class="line" id="L41"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> rmcup = <span class="tok-str">&quot;\x1b[?1049l&quot;</span>;</span>
<span class="line" id="L42"></span>
<span class="line" id="L43"><span class="tok-comment">// sgr reset all</span>
</span>
<span class="line" id="L44"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> sgr_reset = <span class="tok-str">&quot;\x1b[m&quot;</span>;</span>
<span class="line" id="L45"></span>
<span class="line" id="L46"><span class="tok-comment">// colors</span>
</span>
<span class="line" id="L47"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> fg_base = <span class="tok-str">&quot;\x1b[3{d}m&quot;</span>;</span>
<span class="line" id="L48"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> fg_bright = <span class="tok-str">&quot;\x1b[9{d}m&quot;</span>;</span>
<span class="line" id="L49"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> bg_base = <span class="tok-str">&quot;\x1b[4{d}m&quot;</span>;</span>
<span class="line" id="L50"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> bg_bright = <span class="tok-str">&quot;\x1b[10{d}m&quot;</span>;</span>
<span class="line" id="L51"></span>
<span class="line" id="L52"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> fg_reset = <span class="tok-str">&quot;\x1b[39m&quot;</span>;</span>
<span class="line" id="L53"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> bg_reset = <span class="tok-str">&quot;\x1b[49m&quot;</span>;</span>
<span class="line" id="L54"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> ul_reset = <span class="tok-str">&quot;\x1b[59m&quot;</span>;</span>
<span class="line" id="L55"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> fg_indexed = <span class="tok-str">&quot;\x1b[38:5:{d}m&quot;</span>;</span>
<span class="line" id="L56"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> bg_indexed = <span class="tok-str">&quot;\x1b[48:5:{d}m&quot;</span>;</span>
<span class="line" id="L57"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> ul_indexed = <span class="tok-str">&quot;\x1b[58:5:{d}m&quot;</span>;</span>
<span class="line" id="L58"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> fg_rgb = <span class="tok-str">&quot;\x1b[38:2:{d}:{d}:{d}m&quot;</span>;</span>
<span class="line" id="L59"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> bg_rgb = <span class="tok-str">&quot;\x1b[48:2:{d}:{d}:{d}m&quot;</span>;</span>
<span class="line" id="L60"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> ul_rgb = <span class="tok-str">&quot;\x1b[58:2:{d}:{d}:{d}m&quot;</span>;</span>
<span class="line" id="L61"></span>
<span class="line" id="L62"><span class="tok-comment">// Underlines</span>
</span>
<span class="line" id="L63"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> ul_off = <span class="tok-str">&quot;\x1b[24m&quot;</span>; <span class="tok-comment">// NOTE: this could be \x1b[4:0m but is not as widely supported</span>
</span>
<span class="line" id="L64"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> ul_single = <span class="tok-str">&quot;\x1b[4m&quot;</span>;</span>
<span class="line" id="L65"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> ul_double = <span class="tok-str">&quot;\x1b[4:2m&quot;</span>;</span>
<span class="line" id="L66"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> ul_curly = <span class="tok-str">&quot;\x1b[4:3m&quot;</span>;</span>
<span class="line" id="L67"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> ul_dotted = <span class="tok-str">&quot;\x1b[4:4m&quot;</span>;</span>
<span class="line" id="L68"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> ul_dashed = <span class="tok-str">&quot;\x1b[4:5m&quot;</span>;</span>
<span class="line" id="L69"></span>
<span class="line" id="L70"><span class="tok-comment">// Attributes</span>
</span>
<span class="line" id="L71"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> bold_set = <span class="tok-str">&quot;\x1b[1m&quot;</span>;</span>
<span class="line" id="L72"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> dim_set = <span class="tok-str">&quot;\x1b[2m&quot;</span>;</span>
<span class="line" id="L73"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> italic_set = <span class="tok-str">&quot;\x1b[3m&quot;</span>;</span>
<span class="line" id="L74"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> blink_set = <span class="tok-str">&quot;\x1b[5m&quot;</span>;</span>
<span class="line" id="L75"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> reverse_set = <span class="tok-str">&quot;\x1b[7m&quot;</span>;</span>
<span class="line" id="L76"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> invisible_set = <span class="tok-str">&quot;\x1b[8m&quot;</span>;</span>
<span class="line" id="L77"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> strikethrough_set = <span class="tok-str">&quot;\x1b[9m&quot;</span>;</span>
<span class="line" id="L78"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> bold_dim_reset = <span class="tok-str">&quot;\x1b[22m&quot;</span>;</span>
<span class="line" id="L79"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> italic_reset = <span class="tok-str">&quot;\x1b[23m&quot;</span>;</span>
<span class="line" id="L80"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> blink_reset = <span class="tok-str">&quot;\x1b[25m&quot;</span>;</span>
<span class="line" id="L81"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> reverse_reset = <span class="tok-str">&quot;\x1b[27m&quot;</span>;</span>
<span class="line" id="L82"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> invisible_reset = <span class="tok-str">&quot;\x1b[28m&quot;</span>;</span>
<span class="line" id="L83"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> strikethrough_reset = <span class="tok-str">&quot;\x1b[29m&quot;</span>;</span>
<span class="line" id="L84"></span>
<span class="line" id="L85"><span class="tok-comment">// OSC sequences</span>
</span>
<span class="line" id="L86"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> osc2_set_title = <span class="tok-str">&quot;\x1b]2;{s}\x1b\\&quot;</span>;</span>
<span class="line" id="L87"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> osc8 = <span class="tok-str">&quot;\x1b]8;{s};{s}\x1b\\&quot;</span>;</span>
<span class="line" id="L88"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> osc8_clear = <span class="tok-str">&quot;\x1b]8;;\x1b\\&quot;</span>;</span>
<span class="line" id="L89"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> osc9_notify = <span class="tok-str">&quot;\x1b]9;{s}\x1b\\&quot;</span>;</span>
<span class="line" id="L90"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> osc777_notify = <span class="tok-str">&quot;\x1b]777;notify;{s};{s}\x1b\\&quot;</span>;</span>
<span class="line" id="L91"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> osc22_mouse_shape = <span class="tok-str">&quot;\x1b]22;{s}\x1b\\&quot;</span>;</span>
<span class="line" id="L92"></span>
<span class="line" id="L93"><span class="tok-comment">// Kitty graphics</span>
</span>
<span class="line" id="L94"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> kitty_graphics_clear = <span class="tok-str">&quot;\x1b_Ga=d\x1b\\&quot;</span>;</span>
<span class="line" id="L95"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> kitty_graphics_place = <span class="tok-str">&quot;\x1b_Ga=p,i={d},z={d},C=1\x1b\\&quot;</span>;</span>
<span class="line" id="L96"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> kitty_graphics_scale = <span class="tok-str">&quot;\x1b_Ga=p,i={d},z={d},c={d},r={d},C=1\x1b\\&quot;</span>;</span>
<span class="line" id="L97"></span>
</code></pre></body>
</html>

View file

@ -0,0 +1,137 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>event.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Key = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;Key.zig&quot;</span>);</span>
<span class="line" id="L2"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Mouse = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;Mouse.zig&quot;</span>);</span>
<span class="line" id="L3"></span>
<span class="line" id="L4"><span class="tok-comment">/// The events that Vaxis emits internally</span></span>
<span class="line" id="L5"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Event = <span class="tok-kw">union</span>(<span class="tok-kw">enum</span>) {</span>
<span class="line" id="L6"> key_press: Key,</span>
<span class="line" id="L7"> mouse: Mouse,</span>
<span class="line" id="L8"> focus_in,</span>
<span class="line" id="L9"> focus_out,</span>
<span class="line" id="L10"> paste_start,</span>
<span class="line" id="L11"> paste_end,</span>
<span class="line" id="L12"></span>
<span class="line" id="L13"> <span class="tok-comment">// these are delivered as discovered terminal capabilities</span>
</span>
<span class="line" id="L14"> cap_kitty_keyboard,</span>
<span class="line" id="L15"> cap_kitty_graphics,</span>
<span class="line" id="L16"> cap_rgb,</span>
<span class="line" id="L17"> cap_unicode,</span>
<span class="line" id="L18"> cap_da1,</span>
<span class="line" id="L19">};</span>
<span class="line" id="L20"></span>
</code></pre></body>
</html>

View file

@ -0,0 +1,185 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>gwidth.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-kw">const</span> std = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;std&quot;</span>);</span>
<span class="line" id="L2"><span class="tok-kw">const</span> unicode = std.unicode;</span>
<span class="line" id="L3"><span class="tok-kw">const</span> testing = std.testing;</span>
<span class="line" id="L4"><span class="tok-kw">const</span> ziglyph = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;ziglyph&quot;</span>);</span>
<span class="line" id="L5"></span>
<span class="line" id="L6"><span class="tok-comment">/// the method to use when calculating the width of a grapheme</span></span>
<span class="line" id="L7"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Method = <span class="tok-kw">enum</span> {</span>
<span class="line" id="L8"> unicode,</span>
<span class="line" id="L9"> wcwidth,</span>
<span class="line" id="L10"> no_zwj,</span>
<span class="line" id="L11">};</span>
<span class="line" id="L12"></span>
<span class="line" id="L13"><span class="tok-comment">/// returns the width of the provided string, as measured by the method chosen</span></span>
<span class="line" id="L14"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">gwidth</span>(str: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>, method: Method) !<span class="tok-type">usize</span> {</span>
<span class="line" id="L15"> <span class="tok-kw">switch</span> (method) {</span>
<span class="line" id="L16"> .unicode =&gt; {</span>
<span class="line" id="L17"> <span class="tok-kw">return</span> <span class="tok-kw">try</span> ziglyph.display_width.strWidth(str, .half);</span>
<span class="line" id="L18"> },</span>
<span class="line" id="L19"> .wcwidth =&gt; {</span>
<span class="line" id="L20"> <span class="tok-kw">var</span> total: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L21"> <span class="tok-kw">const</span> utf8 = <span class="tok-kw">try</span> unicode.Utf8View.init(str);</span>
<span class="line" id="L22"> <span class="tok-kw">var</span> iter = utf8.iterator();</span>
<span class="line" id="L23"></span>
<span class="line" id="L24"> <span class="tok-kw">while</span> (iter.nextCodepoint()) |cp| {</span>
<span class="line" id="L25"> <span class="tok-kw">const</span> w = ziglyph.display_width.codePointWidth(cp, .half);</span>
<span class="line" id="L26"> <span class="tok-kw">if</span> (w &lt; <span class="tok-number">0</span>) <span class="tok-kw">continue</span>;</span>
<span class="line" id="L27"> total += <span class="tok-builtin">@intCast</span>(w);</span>
<span class="line" id="L28"> }</span>
<span class="line" id="L29"> <span class="tok-kw">return</span> total;</span>
<span class="line" id="L30"> },</span>
<span class="line" id="L31"> .no_zwj =&gt; {</span>
<span class="line" id="L32"> <span class="tok-kw">var</span> out: [<span class="tok-number">256</span>]<span class="tok-type">u8</span> = <span class="tok-null">undefined</span>;</span>
<span class="line" id="L33"> <span class="tok-kw">if</span> (str.len &gt; out.len) <span class="tok-kw">return</span> <span class="tok-kw">error</span>.OutOfMemory;</span>
<span class="line" id="L34"> <span class="tok-kw">const</span> n = std.mem.replace(<span class="tok-type">u8</span>, str, <span class="tok-str">&quot;\u{200D}&quot;</span>, <span class="tok-str">&quot;&quot;</span>, &amp;out);</span>
<span class="line" id="L35"> <span class="tok-kw">return</span> gwidth(out[<span class="tok-number">0</span>..n], .unicode);</span>
<span class="line" id="L36"> },</span>
<span class="line" id="L37"> }</span>
<span class="line" id="L38">}</span>
<span class="line" id="L39"></span>
<span class="line" id="L40"><span class="tok-kw">test</span> <span class="tok-str">&quot;gwidth: a&quot;</span> {</span>
<span class="line" id="L41"> <span class="tok-kw">try</span> testing.expectEqual(<span class="tok-number">1</span>, <span class="tok-kw">try</span> gwidth(<span class="tok-str">&quot;a&quot;</span>, .unicode));</span>
<span class="line" id="L42"> <span class="tok-kw">try</span> testing.expectEqual(<span class="tok-number">1</span>, <span class="tok-kw">try</span> gwidth(<span class="tok-str">&quot;a&quot;</span>, .wcwidth));</span>
<span class="line" id="L43"> <span class="tok-kw">try</span> testing.expectEqual(<span class="tok-number">1</span>, <span class="tok-kw">try</span> gwidth(<span class="tok-str">&quot;a&quot;</span>, .no_zwj));</span>
<span class="line" id="L44">}</span>
<span class="line" id="L45"></span>
<span class="line" id="L46"><span class="tok-kw">test</span> <span class="tok-str">&quot;gwidth: emoji with ZWJ&quot;</span> {</span>
<span class="line" id="L47"> <span class="tok-kw">try</span> testing.expectEqual(<span class="tok-number">2</span>, <span class="tok-kw">try</span> gwidth(<span class="tok-str">&quot;👩‍🚀&quot;</span>, .unicode));</span>
<span class="line" id="L48"> <span class="tok-kw">try</span> testing.expectEqual(<span class="tok-number">4</span>, <span class="tok-kw">try</span> gwidth(<span class="tok-str">&quot;👩‍🚀&quot;</span>, .wcwidth));</span>
<span class="line" id="L49"> <span class="tok-kw">try</span> testing.expectEqual(<span class="tok-number">4</span>, <span class="tok-kw">try</span> gwidth(<span class="tok-str">&quot;👩‍🚀&quot;</span>, .no_zwj));</span>
<span class="line" id="L50">}</span>
<span class="line" id="L51"></span>
<span class="line" id="L52"><span class="tok-kw">test</span> <span class="tok-str">&quot;gwidth: emoji with VS16 selector&quot;</span> {</span>
<span class="line" id="L53"> <span class="tok-kw">try</span> testing.expectEqual(<span class="tok-number">2</span>, <span class="tok-kw">try</span> gwidth(<span class="tok-str">&quot;\xE2\x9D\xA4\xEF\xB8\x8F&quot;</span>, .unicode));</span>
<span class="line" id="L54"> <span class="tok-kw">try</span> testing.expectEqual(<span class="tok-number">1</span>, <span class="tok-kw">try</span> gwidth(<span class="tok-str">&quot;\xE2\x9D\xA4\xEF\xB8\x8F&quot;</span>, .wcwidth));</span>
<span class="line" id="L55"> <span class="tok-kw">try</span> testing.expectEqual(<span class="tok-number">2</span>, <span class="tok-kw">try</span> gwidth(<span class="tok-str">&quot;\xE2\x9D\xA4\xEF\xB8\x8F&quot;</span>, .no_zwj));</span>
<span class="line" id="L56">}</span>
<span class="line" id="L57"></span>
<span class="line" id="L58"><span class="tok-kw">test</span> <span class="tok-str">&quot;gwidth: emoji with skin tone selector&quot;</span> {</span>
<span class="line" id="L59"> <span class="tok-kw">try</span> testing.expectEqual(<span class="tok-number">2</span>, <span class="tok-kw">try</span> gwidth(<span class="tok-str">&quot;👋🏿&quot;</span>, .unicode));</span>
<span class="line" id="L60"> <span class="tok-kw">try</span> testing.expectEqual(<span class="tok-number">4</span>, <span class="tok-kw">try</span> gwidth(<span class="tok-str">&quot;👋🏿&quot;</span>, .wcwidth));</span>
<span class="line" id="L61"> <span class="tok-kw">try</span> testing.expectEqual(<span class="tok-number">2</span>, <span class="tok-kw">try</span> gwidth(<span class="tok-str">&quot;👋🏿&quot;</span>, .no_zwj));</span>
<span class="line" id="L62">}</span>
<span class="line" id="L63"></span>
<span class="line" id="L64"><span class="tok-kw">test</span> <span class="tok-str">&quot;gwidth: invalid string&quot;</span> {</span>
<span class="line" id="L65"> <span class="tok-kw">try</span> testing.expectError(<span class="tok-kw">error</span>.InvalidUtf8, gwidth(<span class="tok-str">&quot;\xc3\x28&quot;</span>, .unicode));</span>
<span class="line" id="L66"> <span class="tok-kw">try</span> testing.expectError(<span class="tok-kw">error</span>.InvalidUtf8, gwidth(<span class="tok-str">&quot;\xc3\x28&quot;</span>, .wcwidth));</span>
<span class="line" id="L67"> <span class="tok-kw">try</span> testing.expectError(<span class="tok-kw">error</span>.InvalidUtf8, gwidth(<span class="tok-str">&quot;\xc3\x28&quot;</span>, .no_zwj));</span>
<span class="line" id="L68">}</span>
<span class="line" id="L69"></span>
</code></pre></body>
</html>

View file

@ -0,0 +1,243 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>queue.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-kw">const</span> std = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;std&quot;</span>);</span>
<span class="line" id="L2"><span class="tok-kw">const</span> assert = std.debug.assert;</span>
<span class="line" id="L3"><span class="tok-kw">const</span> atomic = std.atomic;</span>
<span class="line" id="L4"><span class="tok-kw">const</span> Futex = std.Thread.Futex;</span>
<span class="line" id="L5"></span>
<span class="line" id="L6"><span class="tok-kw">const</span> log = std.log.scoped(.queue);</span>
<span class="line" id="L7"></span>
<span class="line" id="L8"><span class="tok-comment">/// Thread safe. Fixed size. Blocking push and pop.</span></span>
<span class="line" id="L9"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">Queue</span>(</span>
<span class="line" id="L10"> <span class="tok-kw">comptime</span> T: <span class="tok-type">type</span>,</span>
<span class="line" id="L11"> <span class="tok-kw">comptime</span> size: <span class="tok-type">usize</span>,</span>
<span class="line" id="L12">) <span class="tok-type">type</span> {</span>
<span class="line" id="L13"> <span class="tok-kw">return</span> <span class="tok-kw">struct</span> {</span>
<span class="line" id="L14"> buf: [size]T = <span class="tok-null">undefined</span>,</span>
<span class="line" id="L15"></span>
<span class="line" id="L16"> read_index: <span class="tok-type">usize</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L17"> write_index: <span class="tok-type">usize</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L18"></span>
<span class="line" id="L19"> mutex: std.Thread.Mutex = .{},</span>
<span class="line" id="L20"> <span class="tok-comment">/// blocks when the buffer is full or empty</span></span>
<span class="line" id="L21"> futex: atomic.Value(<span class="tok-type">u32</span>) = atomic.Value(<span class="tok-type">u32</span>).init(<span class="tok-number">0</span>),</span>
<span class="line" id="L22"></span>
<span class="line" id="L23"> <span class="tok-kw">const</span> Self = <span class="tok-builtin">@This</span>();</span>
<span class="line" id="L24"></span>
<span class="line" id="L25"> <span class="tok-comment">/// pop an item from the queue. Blocks until an item is available</span></span>
<span class="line" id="L26"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">pop</span>(self: *Self) T {</span>
<span class="line" id="L27"> self.mutex.lock();</span>
<span class="line" id="L28"> <span class="tok-kw">defer</span> self.mutex.unlock();</span>
<span class="line" id="L29"> <span class="tok-kw">if</span> (self.isEmpty()) {</span>
<span class="line" id="L30"> <span class="tok-comment">// If we don't have any items, we unlock and wait</span>
</span>
<span class="line" id="L31"> self.mutex.unlock();</span>
<span class="line" id="L32"> Futex.wait(&amp;self.futex, <span class="tok-number">0</span>);</span>
<span class="line" id="L33"> <span class="tok-comment">// regain our lock</span>
</span>
<span class="line" id="L34"> self.mutex.lock();</span>
<span class="line" id="L35"> }</span>
<span class="line" id="L36"> <span class="tok-kw">if</span> (self.isFull()) {</span>
<span class="line" id="L37"> <span class="tok-comment">// If we are full, wake up the push</span>
</span>
<span class="line" id="L38"> Futex.wake(&amp;self.futex, <span class="tok-number">1</span>);</span>
<span class="line" id="L39"> }</span>
<span class="line" id="L40"> <span class="tok-kw">const</span> i = self.read_index;</span>
<span class="line" id="L41"> self.read_index += <span class="tok-number">1</span>;</span>
<span class="line" id="L42"> self.read_index = self.read_index % self.buf.len;</span>
<span class="line" id="L43"> <span class="tok-kw">return</span> self.buf[i];</span>
<span class="line" id="L44"> }</span>
<span class="line" id="L45"></span>
<span class="line" id="L46"> <span class="tok-comment">/// push an item into the queue. Blocks until the item has been put in</span></span>
<span class="line" id="L47"> <span class="tok-comment">/// the queue</span></span>
<span class="line" id="L48"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">push</span>(self: *Self, item: T) <span class="tok-type">void</span> {</span>
<span class="line" id="L49"> self.mutex.lock();</span>
<span class="line" id="L50"> <span class="tok-kw">defer</span> self.mutex.unlock();</span>
<span class="line" id="L51"> <span class="tok-kw">if</span> (self.isFull()) {</span>
<span class="line" id="L52"> self.mutex.unlock();</span>
<span class="line" id="L53"> Futex.wait(&amp;self.futex, <span class="tok-number">0</span>);</span>
<span class="line" id="L54"> self.mutex.lock();</span>
<span class="line" id="L55"> }</span>
<span class="line" id="L56"> <span class="tok-kw">if</span> (self.isEmpty()) {</span>
<span class="line" id="L57"> Futex.wake(&amp;self.futex, <span class="tok-number">1</span>);</span>
<span class="line" id="L58"> }</span>
<span class="line" id="L59"> <span class="tok-kw">const</span> i = self.write_index;</span>
<span class="line" id="L60"> self.write_index += <span class="tok-number">1</span>;</span>
<span class="line" id="L61"> self.write_index = self.write_index % self.buf.len;</span>
<span class="line" id="L62"> self.buf[i] = item;</span>
<span class="line" id="L63"> }</span>
<span class="line" id="L64"></span>
<span class="line" id="L65"> <span class="tok-comment">/// push an item into the queue. Returns true when the item was</span></span>
<span class="line" id="L66"> <span class="tok-comment">/// successfully placed in the queue</span></span>
<span class="line" id="L67"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">tryPush</span>(self: *Self, item: T) <span class="tok-type">bool</span> {</span>
<span class="line" id="L68"> self.mutex.lock();</span>
<span class="line" id="L69"> <span class="tok-kw">if</span> (self.isFull()) {</span>
<span class="line" id="L70"> self.mutex.unlock();</span>
<span class="line" id="L71"> <span class="tok-kw">return</span> <span class="tok-null">false</span>;</span>
<span class="line" id="L72"> }</span>
<span class="line" id="L73"> self.mutex.unlock();</span>
<span class="line" id="L74"> self.push(item);</span>
<span class="line" id="L75"> <span class="tok-kw">return</span> <span class="tok-null">true</span>;</span>
<span class="line" id="L76"> }</span>
<span class="line" id="L77"></span>
<span class="line" id="L78"> <span class="tok-comment">/// pop an item from the queue. Returns null when no item is available</span></span>
<span class="line" id="L79"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">tryPop</span>(self: *Self) ?T {</span>
<span class="line" id="L80"> self.mutex.lock();</span>
<span class="line" id="L81"> <span class="tok-kw">if</span> (self.isEmpty()) {</span>
<span class="line" id="L82"> self.mutex.unlock();</span>
<span class="line" id="L83"> <span class="tok-kw">return</span> <span class="tok-null">null</span>;</span>
<span class="line" id="L84"> }</span>
<span class="line" id="L85"> self.mutex.unlock();</span>
<span class="line" id="L86"> <span class="tok-kw">return</span> self.pop();</span>
<span class="line" id="L87"> }</span>
<span class="line" id="L88"></span>
<span class="line" id="L89"> <span class="tok-comment">/// Returns `true` if the ring buffer is empty and `false` otherwise.</span></span>
<span class="line" id="L90"> <span class="tok-kw">fn</span> <span class="tok-fn">isEmpty</span>(self: Self) <span class="tok-type">bool</span> {</span>
<span class="line" id="L91"> <span class="tok-kw">return</span> self.write_index == self.read_index;</span>
<span class="line" id="L92"> }</span>
<span class="line" id="L93"></span>
<span class="line" id="L94"> <span class="tok-comment">/// Returns `true` if the ring buffer is full and `false` otherwise.</span></span>
<span class="line" id="L95"> <span class="tok-kw">fn</span> <span class="tok-fn">isFull</span>(self: Self) <span class="tok-type">bool</span> {</span>
<span class="line" id="L96"> <span class="tok-kw">return</span> self.mask2(self.write_index + self.buf.len) == self.read_index;</span>
<span class="line" id="L97"> }</span>
<span class="line" id="L98"></span>
<span class="line" id="L99"> <span class="tok-comment">/// Returns the length</span></span>
<span class="line" id="L100"> <span class="tok-kw">fn</span> <span class="tok-fn">len</span>(self: Self) <span class="tok-type">usize</span> {</span>
<span class="line" id="L101"> <span class="tok-kw">const</span> wrap_offset = <span class="tok-number">2</span> * self.buf.len * <span class="tok-builtin">@intFromBool</span>(self.write_index &lt; self.read_index);</span>
<span class="line" id="L102"> <span class="tok-kw">const</span> adjusted_write_index = self.write_index + wrap_offset;</span>
<span class="line" id="L103"> <span class="tok-kw">return</span> adjusted_write_index - self.read_index;</span>
<span class="line" id="L104"> }</span>
<span class="line" id="L105"></span>
<span class="line" id="L106"> <span class="tok-comment">/// Returns `index` modulo the length of the backing slice.</span></span>
<span class="line" id="L107"> <span class="tok-kw">fn</span> <span class="tok-fn">mask</span>(self: Self, index: <span class="tok-type">usize</span>) <span class="tok-type">usize</span> {</span>
<span class="line" id="L108"> <span class="tok-kw">return</span> index % self.buf.len;</span>
<span class="line" id="L109"> }</span>
<span class="line" id="L110"></span>
<span class="line" id="L111"> <span class="tok-comment">/// Returns `index` modulo twice the length of the backing slice.</span></span>
<span class="line" id="L112"> <span class="tok-kw">fn</span> <span class="tok-fn">mask2</span>(self: Self, index: <span class="tok-type">usize</span>) <span class="tok-type">usize</span> {</span>
<span class="line" id="L113"> <span class="tok-kw">return</span> index % (<span class="tok-number">2</span> * self.buf.len);</span>
<span class="line" id="L114"> }</span>
<span class="line" id="L115"> };</span>
<span class="line" id="L116">}</span>
<span class="line" id="L117"></span>
<span class="line" id="L118"><span class="tok-kw">test</span> <span class="tok-str">&quot;Queue: simple push / pop&quot;</span> {</span>
<span class="line" id="L119"> <span class="tok-kw">var</span> queue: Queue(<span class="tok-type">u8</span>, <span class="tok-number">16</span>) = .{};</span>
<span class="line" id="L120"> queue.push(<span class="tok-number">1</span>);</span>
<span class="line" id="L121"> <span class="tok-kw">const</span> pop = queue.pop();</span>
<span class="line" id="L122"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-number">1</span>, pop);</span>
<span class="line" id="L123">}</span>
<span class="line" id="L124"></span>
</code></pre></body>
</html>

View file

@ -0,0 +1,861 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>vaxis.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-kw">const</span> std = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;std&quot;</span>);</span>
<span class="line" id="L2"><span class="tok-kw">const</span> atomic = std.atomic;</span>
<span class="line" id="L3"><span class="tok-kw">const</span> base64 = std.base64.standard.Encoder;</span>
<span class="line" id="L4"></span>
<span class="line" id="L5"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Cell = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;Cell.zig&quot;</span>);</span>
<span class="line" id="L6"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Image = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;Image.zig&quot;</span>);</span>
<span class="line" id="L7"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> InternalScreen = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;InternalScreen.zig&quot;</span>);</span>
<span class="line" id="L8"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Key = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;Key.zig&quot;</span>);</span>
<span class="line" id="L9"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Mouse = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;Mouse.zig&quot;</span>);</span>
<span class="line" id="L10"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Options = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;Options.zig&quot;</span>);</span>
<span class="line" id="L11"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Queue = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;queue.zig&quot;</span>).Queue;</span>
<span class="line" id="L12"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Screen = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;Screen.zig&quot;</span>);</span>
<span class="line" id="L13"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Tty = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;Tty.zig&quot;</span>);</span>
<span class="line" id="L14"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Window = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;Window.zig&quot;</span>);</span>
<span class="line" id="L15"></span>
<span class="line" id="L16"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> ctlseqs = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;ctlseqs.zig&quot;</span>);</span>
<span class="line" id="L17"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> gwidth = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;gwidth.zig&quot;</span>);</span>
<span class="line" id="L18"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> widgets = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;widgets.zig&quot;</span>);</span>
<span class="line" id="L19"></span>
<span class="line" id="L20"><span class="tok-kw">const</span> zigimg = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;zigimg&quot;</span>);</span>
<span class="line" id="L21"></span>
<span class="line" id="L22"></span>
<span class="line" id="L23"><span class="tok-comment">/// Initialize a Vaxis application.</span></span>
<span class="line" id="L24"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">init</span>(<span class="tok-kw">comptime</span> Event: <span class="tok-type">type</span>, opts: Options) !Vaxis(Event) {</span>
<span class="line" id="L25"> <span class="tok-kw">return</span> Vaxis(Event).init(opts);</span>
<span class="line" id="L26">}</span>
<span class="line" id="L27"><span class="tok-kw">test</span> {</span>
<span class="line" id="L28"> std.testing.refAllDecls(<span class="tok-builtin">@This</span>());</span>
<span class="line" id="L29">}</span>
<span class="line" id="L30"></span>
<span class="line" id="L31"><span class="tok-comment">/// Vaxis is the entrypoint for a Vaxis application. The provided type T should</span></span>
<span class="line" id="L32"><span class="tok-comment">/// be a tagged union which contains all of the events the application will</span></span>
<span class="line" id="L33"><span class="tok-comment">/// handle. Vaxis will look for the following fields on the union and, if</span></span>
<span class="line" id="L34"><span class="tok-comment">/// found, emit them via the &quot;nextEvent&quot; method</span></span>
<span class="line" id="L35"><span class="tok-comment">///</span></span>
<span class="line" id="L36"><span class="tok-comment">/// The following events are available:</span></span>
<span class="line" id="L37"><span class="tok-comment">/// - `key_press: Key`, for key press events</span></span>
<span class="line" id="L38"><span class="tok-comment">/// - `winsize: Winsize`, for resize events. Must call app.resize when receiving</span></span>
<span class="line" id="L39"><span class="tok-comment">/// this event</span></span>
<span class="line" id="L40"><span class="tok-comment">/// - `focus_in` and `focus_out` for focus events</span></span>
<span class="line" id="L41"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">Vaxis</span>(<span class="tok-kw">comptime</span> T: <span class="tok-type">type</span>) <span class="tok-type">type</span> {</span>
<span class="line" id="L42"> <span class="tok-kw">return</span> <span class="tok-kw">struct</span> {</span>
<span class="line" id="L43"> <span class="tok-kw">const</span> Self = <span class="tok-builtin">@This</span>();</span>
<span class="line" id="L44"></span>
<span class="line" id="L45"> <span class="tok-kw">const</span> log = std.log.scoped(.vaxis);</span>
<span class="line" id="L46"></span>
<span class="line" id="L47"> <span class="tok-kw">pub</span> <span class="tok-kw">const</span> Event = T;</span>
<span class="line" id="L48"></span>
<span class="line" id="L49"> <span class="tok-kw">pub</span> <span class="tok-kw">const</span> Capabilities = <span class="tok-kw">struct</span> {</span>
<span class="line" id="L50"> kitty_keyboard: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L51"> kitty_graphics: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L52"> rgb: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L53"> unicode: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L54"> };</span>
<span class="line" id="L55"></span>
<span class="line" id="L56"> <span class="tok-comment">/// the event queue for Vaxis</span></span>
<span class="line" id="L57"> <span class="tok-comment">//</span>
</span>
<span class="line" id="L58"> <span class="tok-comment">// TODO: is 512 ok?</span>
</span>
<span class="line" id="L59"> queue: Queue(T, <span class="tok-number">512</span>),</span>
<span class="line" id="L60"></span>
<span class="line" id="L61"> tty: ?Tty,</span>
<span class="line" id="L62"></span>
<span class="line" id="L63"> <span class="tok-comment">/// the screen we write to</span></span>
<span class="line" id="L64"> screen: Screen,</span>
<span class="line" id="L65"> <span class="tok-comment">/// The last screen we drew. We keep this so we can efficiently update on</span></span>
<span class="line" id="L66"> <span class="tok-comment">/// the next render</span></span>
<span class="line" id="L67"> screen_last: InternalScreen = <span class="tok-null">undefined</span>,</span>
<span class="line" id="L68"></span>
<span class="line" id="L69"> state: <span class="tok-kw">struct</span> {</span>
<span class="line" id="L70"> <span class="tok-comment">/// if we are in the alt screen</span></span>
<span class="line" id="L71"> alt_screen: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L72"> <span class="tok-comment">/// if we have entered kitty keyboard</span></span>
<span class="line" id="L73"> kitty_keyboard: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L74"> bracketed_paste: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L75"> mouse: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L76"> } = .{},</span>
<span class="line" id="L77"></span>
<span class="line" id="L78"> caps: Capabilities = .{},</span>
<span class="line" id="L79"></span>
<span class="line" id="L80"> <span class="tok-comment">/// if we should redraw the entire screen on the next render</span></span>
<span class="line" id="L81"> refresh: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L82"></span>
<span class="line" id="L83"> <span class="tok-comment">/// blocks the main thread until a DA1 query has been received, or the</span></span>
<span class="line" id="L84"> <span class="tok-comment">/// futex times out</span></span>
<span class="line" id="L85"> query_futex: atomic.Value(<span class="tok-type">u32</span>) = atomic.Value(<span class="tok-type">u32</span>).init(<span class="tok-number">0</span>),</span>
<span class="line" id="L86"></span>
<span class="line" id="L87"> <span class="tok-comment">// images</span>
</span>
<span class="line" id="L88"> next_img_id: <span class="tok-type">u32</span> = <span class="tok-number">1</span>,</span>
<span class="line" id="L89"></span>
<span class="line" id="L90"> <span class="tok-comment">// statistics</span>
</span>
<span class="line" id="L91"> renders: <span class="tok-type">usize</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L92"> render_dur: <span class="tok-type">i128</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L93"></span>
<span class="line" id="L94"> <span class="tok-comment">/// Initialize Vaxis with runtime options</span></span>
<span class="line" id="L95"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">init</span>(_: Options) !Self {</span>
<span class="line" id="L96"> <span class="tok-kw">return</span> .{</span>
<span class="line" id="L97"> .queue = .{},</span>
<span class="line" id="L98"> .tty = <span class="tok-null">null</span>,</span>
<span class="line" id="L99"> .screen = .{},</span>
<span class="line" id="L100"> .screen_last = .{},</span>
<span class="line" id="L101"> };</span>
<span class="line" id="L102"> }</span>
<span class="line" id="L103"></span>
<span class="line" id="L104"> <span class="tok-comment">/// Resets the terminal to it's original state. If an allocator is</span></span>
<span class="line" id="L105"> <span class="tok-comment">/// passed, this will free resources associated with Vaxis. This is left as an</span></span>
<span class="line" id="L106"> <span class="tok-comment">/// optional so applications can choose to not free resources when the</span></span>
<span class="line" id="L107"> <span class="tok-comment">/// application will be exiting anyways</span></span>
<span class="line" id="L108"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">deinit</span>(self: *Self, alloc: ?std.mem.Allocator) <span class="tok-type">void</span> {</span>
<span class="line" id="L109"> <span class="tok-kw">if</span> (self.tty) |_| {</span>
<span class="line" id="L110"> <span class="tok-kw">var</span> tty = &amp;self.tty.?;</span>
<span class="line" id="L111"> <span class="tok-kw">if</span> (self.state.kitty_keyboard) {</span>
<span class="line" id="L112"> _ = tty.write(ctlseqs.csi_u_pop) <span class="tok-kw">catch</span> {};</span>
<span class="line" id="L113"> }</span>
<span class="line" id="L114"> <span class="tok-kw">if</span> (self.state.mouse) {</span>
<span class="line" id="L115"> _ = tty.write(ctlseqs.mouse_reset) <span class="tok-kw">catch</span> {};</span>
<span class="line" id="L116"> }</span>
<span class="line" id="L117"> <span class="tok-kw">if</span> (self.state.bracketed_paste) {</span>
<span class="line" id="L118"> _ = tty.write(ctlseqs.bp_reset) <span class="tok-kw">catch</span> {};</span>
<span class="line" id="L119"> }</span>
<span class="line" id="L120"> <span class="tok-kw">if</span> (self.state.alt_screen) {</span>
<span class="line" id="L121"> _ = tty.write(ctlseqs.rmcup) <span class="tok-kw">catch</span> {};</span>
<span class="line" id="L122"> }</span>
<span class="line" id="L123"> tty.flush() <span class="tok-kw">catch</span> {};</span>
<span class="line" id="L124"> tty.deinit();</span>
<span class="line" id="L125"> }</span>
<span class="line" id="L126"> <span class="tok-kw">if</span> (alloc) |a| {</span>
<span class="line" id="L127"> self.screen.deinit(a);</span>
<span class="line" id="L128"> self.screen_last.deinit(a);</span>
<span class="line" id="L129"> }</span>
<span class="line" id="L130"> <span class="tok-kw">if</span> (self.renders &gt; <span class="tok-number">0</span>) {</span>
<span class="line" id="L131"> <span class="tok-kw">const</span> tpr = <span class="tok-builtin">@divTrunc</span>(self.render_dur, self.renders);</span>
<span class="line" id="L132"> log.debug(<span class="tok-str">&quot;total renders = {d}&quot;</span>, .{self.renders});</span>
<span class="line" id="L133"> log.debug(<span class="tok-str">&quot;microseconds per render = {d}&quot;</span>, .{tpr});</span>
<span class="line" id="L134"> }</span>
<span class="line" id="L135"> }</span>
<span class="line" id="L136"></span>
<span class="line" id="L137"> <span class="tok-comment">/// spawns the input thread to start listening to the tty for input</span></span>
<span class="line" id="L138"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">startReadThread</span>(self: *Self) !<span class="tok-type">void</span> {</span>
<span class="line" id="L139"> self.tty = <span class="tok-kw">try</span> Tty.init();</span>
<span class="line" id="L140"> <span class="tok-comment">// run our tty read loop in it's own thread</span>
</span>
<span class="line" id="L141"> <span class="tok-kw">const</span> read_thread = <span class="tok-kw">try</span> std.Thread.spawn(.{}, Tty.run, .{ &amp;self.tty.?, T, self });</span>
<span class="line" id="L142"> <span class="tok-kw">try</span> read_thread.setName(<span class="tok-str">&quot;tty&quot;</span>);</span>
<span class="line" id="L143"> }</span>
<span class="line" id="L144"></span>
<span class="line" id="L145"> <span class="tok-comment">/// stops reading from the tty</span></span>
<span class="line" id="L146"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">stopReadThread</span>(self: *Self) <span class="tok-type">void</span> {</span>
<span class="line" id="L147"> <span class="tok-kw">if</span> (self.tty) |_| {</span>
<span class="line" id="L148"> <span class="tok-kw">var</span> tty = &amp;self.tty.?;</span>
<span class="line" id="L149"> tty.stop();</span>
<span class="line" id="L150"> }</span>
<span class="line" id="L151"> }</span>
<span class="line" id="L152"></span>
<span class="line" id="L153"> <span class="tok-comment">/// returns the next available event, blocking until one is available</span></span>
<span class="line" id="L154"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">nextEvent</span>(self: *Self) T {</span>
<span class="line" id="L155"> <span class="tok-kw">return</span> self.queue.pop();</span>
<span class="line" id="L156"> }</span>
<span class="line" id="L157"></span>
<span class="line" id="L158"> <span class="tok-comment">/// posts an event into the event queue. Will block if there is not</span></span>
<span class="line" id="L159"> <span class="tok-comment">/// capacity for the event</span></span>
<span class="line" id="L160"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">postEvent</span>(self: *Self, event: T) <span class="tok-type">void</span> {</span>
<span class="line" id="L161"> self.queue.push(event);</span>
<span class="line" id="L162"> }</span>
<span class="line" id="L163"></span>
<span class="line" id="L164"> <span class="tok-comment">/// resize allocates a slice of cells equal to the number of cells</span></span>
<span class="line" id="L165"> <span class="tok-comment">/// required to display the screen (ie width x height). Any previous screen is</span></span>
<span class="line" id="L166"> <span class="tok-comment">/// freed when resizing</span></span>
<span class="line" id="L167"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">resize</span>(self: *Self, alloc: std.mem.Allocator, winsize: Tty.Winsize) !<span class="tok-type">void</span> {</span>
<span class="line" id="L168"> log.debug(<span class="tok-str">&quot;resizing screen: width={d} height={d}&quot;</span>, .{ winsize.cols, winsize.rows });</span>
<span class="line" id="L169"> self.screen.deinit(alloc);</span>
<span class="line" id="L170"> self.screen = <span class="tok-kw">try</span> Screen.init(alloc, winsize);</span>
<span class="line" id="L171"> self.screen.unicode = self.caps.unicode;</span>
<span class="line" id="L172"> <span class="tok-comment">// try self.screen.int(alloc, winsize.cols, winsize.rows);</span>
</span>
<span class="line" id="L173"> <span class="tok-comment">// we only init our current screen. This has the effect of redrawing</span>
</span>
<span class="line" id="L174"> <span class="tok-comment">// every cell</span>
</span>
<span class="line" id="L175"> self.screen_last.deinit(alloc);</span>
<span class="line" id="L176"> self.screen_last = <span class="tok-kw">try</span> InternalScreen.init(alloc, winsize.cols, winsize.rows);</span>
<span class="line" id="L177"> <span class="tok-comment">// try self.screen_last.resize(alloc, winsize.cols, winsize.rows);</span>
</span>
<span class="line" id="L178"> }</span>
<span class="line" id="L179"></span>
<span class="line" id="L180"> <span class="tok-comment">/// returns a Window comprising of the entire terminal screen</span></span>
<span class="line" id="L181"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">window</span>(self: *Self) Window {</span>
<span class="line" id="L182"> <span class="tok-kw">return</span> .{</span>
<span class="line" id="L183"> .x_off = <span class="tok-number">0</span>,</span>
<span class="line" id="L184"> .y_off = <span class="tok-number">0</span>,</span>
<span class="line" id="L185"> .width = self.screen.width,</span>
<span class="line" id="L186"> .height = self.screen.height,</span>
<span class="line" id="L187"> .screen = &amp;self.screen,</span>
<span class="line" id="L188"> };</span>
<span class="line" id="L189"> }</span>
<span class="line" id="L190"></span>
<span class="line" id="L191"> <span class="tok-comment">/// enter the alternate screen. The alternate screen will automatically</span></span>
<span class="line" id="L192"> <span class="tok-comment">/// be exited if calling deinit while in the alt screen</span></span>
<span class="line" id="L193"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">enterAltScreen</span>(self: *Self) !<span class="tok-type">void</span> {</span>
<span class="line" id="L194"> <span class="tok-kw">if</span> (self.state.alt_screen) <span class="tok-kw">return</span>;</span>
<span class="line" id="L195"> <span class="tok-kw">var</span> tty = self.tty <span class="tok-kw">orelse</span> <span class="tok-kw">return</span>;</span>
<span class="line" id="L196"> _ = <span class="tok-kw">try</span> tty.write(ctlseqs.smcup);</span>
<span class="line" id="L197"> <span class="tok-kw">try</span> tty.flush();</span>
<span class="line" id="L198"> self.state.alt_screen = <span class="tok-null">true</span>;</span>
<span class="line" id="L199"> }</span>
<span class="line" id="L200"></span>
<span class="line" id="L201"> <span class="tok-comment">/// exit the alternate screen</span></span>
<span class="line" id="L202"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">exitAltScreen</span>(self: *Self) !<span class="tok-type">void</span> {</span>
<span class="line" id="L203"> <span class="tok-kw">if</span> (!self.state.alt_screen) <span class="tok-kw">return</span>;</span>
<span class="line" id="L204"> <span class="tok-kw">var</span> tty = self.tty <span class="tok-kw">orelse</span> <span class="tok-kw">return</span>;</span>
<span class="line" id="L205"> _ = <span class="tok-kw">try</span> tty.write(ctlseqs.rmcup);</span>
<span class="line" id="L206"> <span class="tok-kw">try</span> tty.flush();</span>
<span class="line" id="L207"> self.state.alt_screen = <span class="tok-null">false</span>;</span>
<span class="line" id="L208"> }</span>
<span class="line" id="L209"></span>
<span class="line" id="L210"> <span class="tok-comment">/// write queries to the terminal to determine capabilities. Individual</span></span>
<span class="line" id="L211"> <span class="tok-comment">/// capabilities will be delivered to the client and possibly intercepted by</span></span>
<span class="line" id="L212"> <span class="tok-comment">/// Vaxis to enable features</span></span>
<span class="line" id="L213"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">queryTerminal</span>(self: *Self) !<span class="tok-type">void</span> {</span>
<span class="line" id="L214"> <span class="tok-kw">var</span> tty = self.tty <span class="tok-kw">orelse</span> <span class="tok-kw">return</span>;</span>
<span class="line" id="L215"></span>
<span class="line" id="L216"> <span class="tok-kw">const</span> colorterm = std.os.getenv(<span class="tok-str">&quot;COLORTERM&quot;</span>) <span class="tok-kw">orelse</span> <span class="tok-str">&quot;&quot;</span>;</span>
<span class="line" id="L217"> <span class="tok-kw">if</span> (std.mem.eql(<span class="tok-type">u8</span>, colorterm, <span class="tok-str">&quot;truecolor&quot;</span>) <span class="tok-kw">or</span></span>
<span class="line" id="L218"> std.mem.eql(<span class="tok-type">u8</span>, colorterm, <span class="tok-str">&quot;24bit&quot;</span>))</span>
<span class="line" id="L219"> {</span>
<span class="line" id="L220"> <span class="tok-kw">if</span> (<span class="tok-builtin">@hasField</span>(Event, <span class="tok-str">&quot;cap_rgb&quot;</span>)) {</span>
<span class="line" id="L221"> self.postEvent(.cap_rgb);</span>
<span class="line" id="L222"> }</span>
<span class="line" id="L223"> }</span>
<span class="line" id="L224"></span>
<span class="line" id="L225"> <span class="tok-comment">// TODO: decide if we actually want to query for focus and sync. It</span>
</span>
<span class="line" id="L226"> <span class="tok-comment">// doesn't hurt to blindly use them</span>
</span>
<span class="line" id="L227"> <span class="tok-comment">// _ = try tty.write(ctlseqs.decrqm_focus);</span>
</span>
<span class="line" id="L228"> <span class="tok-comment">// _ = try tty.write(ctlseqs.decrqm_sync);</span>
</span>
<span class="line" id="L229"> _ = <span class="tok-kw">try</span> tty.write(ctlseqs.decrqm_unicode);</span>
<span class="line" id="L230"> _ = <span class="tok-kw">try</span> tty.write(ctlseqs.decrqm_color_theme);</span>
<span class="line" id="L231"> <span class="tok-comment">// TODO: XTVERSION has a DCS response. uncomment when we can parse</span>
</span>
<span class="line" id="L232"> <span class="tok-comment">// that</span>
</span>
<span class="line" id="L233"> <span class="tok-comment">// _ = try tty.write(ctlseqs.xtversion);</span>
</span>
<span class="line" id="L234"> _ = <span class="tok-kw">try</span> tty.write(ctlseqs.csi_u_query);</span>
<span class="line" id="L235"> _ = <span class="tok-kw">try</span> tty.write(ctlseqs.kitty_graphics_query);</span>
<span class="line" id="L236"> <span class="tok-comment">// TODO: sixel geometry query interferes with F4 keys.</span>
</span>
<span class="line" id="L237"> <span class="tok-comment">// _ = try tty.write(ctlseqs.sixel_geometry_query);</span>
</span>
<span class="line" id="L238"></span>
<span class="line" id="L239"> <span class="tok-comment">// TODO: XTGETTCAP queries (&quot;RGB&quot;, &quot;Smulx&quot;)</span>
</span>
<span class="line" id="L240"></span>
<span class="line" id="L241"> _ = <span class="tok-kw">try</span> tty.write(ctlseqs.primary_device_attrs);</span>
<span class="line" id="L242"> <span class="tok-kw">try</span> tty.flush();</span>
<span class="line" id="L243"></span>
<span class="line" id="L244"> <span class="tok-comment">// 1 second timeout</span>
</span>
<span class="line" id="L245"> std.Thread.Futex.timedWait(&amp;self.query_futex, <span class="tok-number">0</span>, <span class="tok-number">1</span> * std.time.ns_per_s) <span class="tok-kw">catch</span> {};</span>
<span class="line" id="L246"></span>
<span class="line" id="L247"> <span class="tok-comment">// enable detected features</span>
</span>
<span class="line" id="L248"> <span class="tok-kw">if</span> (self.caps.kitty_keyboard) {</span>
<span class="line" id="L249"> <span class="tok-kw">try</span> self.enableKittyKeyboard(.{});</span>
<span class="line" id="L250"> }</span>
<span class="line" id="L251"> <span class="tok-kw">if</span> (self.caps.unicode) {</span>
<span class="line" id="L252"> _ = <span class="tok-kw">try</span> tty.write(ctlseqs.unicode_set);</span>
<span class="line" id="L253"> }</span>
<span class="line" id="L254"> }</span>
<span class="line" id="L255"></span>
<span class="line" id="L256"> <span class="tok-comment">// the next render call will refresh the entire screen</span>
</span>
<span class="line" id="L257"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">queueRefresh</span>(self: *Self) <span class="tok-type">void</span> {</span>
<span class="line" id="L258"> self.refresh = <span class="tok-null">true</span>;</span>
<span class="line" id="L259"> }</span>
<span class="line" id="L260"></span>
<span class="line" id="L261"> <span class="tok-comment">/// draws the screen to the terminal</span></span>
<span class="line" id="L262"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">render</span>(self: *Self) !<span class="tok-type">void</span> {</span>
<span class="line" id="L263"> <span class="tok-kw">var</span> tty = self.tty <span class="tok-kw">orelse</span> <span class="tok-kw">return</span>;</span>
<span class="line" id="L264"> self.renders += <span class="tok-number">1</span>;</span>
<span class="line" id="L265"> <span class="tok-kw">const</span> timer_start = std.time.microTimestamp();</span>
<span class="line" id="L266"> <span class="tok-kw">defer</span> {</span>
<span class="line" id="L267"> self.render_dur += std.time.microTimestamp() - timer_start;</span>
<span class="line" id="L268"> }</span>
<span class="line" id="L269"></span>
<span class="line" id="L270"> <span class="tok-kw">defer</span> self.refresh = <span class="tok-null">false</span>;</span>
<span class="line" id="L271"> <span class="tok-kw">defer</span> tty.flush() <span class="tok-kw">catch</span> {};</span>
<span class="line" id="L272"></span>
<span class="line" id="L273"> <span class="tok-comment">// Set up sync before we write anything</span>
</span>
<span class="line" id="L274"> <span class="tok-comment">// TODO: optimize sync so we only sync _when we have changes_. This</span>
</span>
<span class="line" id="L275"> <span class="tok-comment">// requires a smarter buffered writer, we'll probably have to write</span>
</span>
<span class="line" id="L276"> <span class="tok-comment">// our own</span>
</span>
<span class="line" id="L277"> _ = <span class="tok-kw">try</span> tty.write(ctlseqs.sync_set);</span>
<span class="line" id="L278"> <span class="tok-kw">defer</span> _ = tty.write(ctlseqs.sync_reset) <span class="tok-kw">catch</span> {};</span>
<span class="line" id="L279"></span>
<span class="line" id="L280"> <span class="tok-comment">// Send the cursor to 0,0</span>
</span>
<span class="line" id="L281"> <span class="tok-comment">// TODO: this needs to move after we optimize writes. We only do</span>
</span>
<span class="line" id="L282"> <span class="tok-comment">// this if we have an update to make. We also need to hide cursor</span>
</span>
<span class="line" id="L283"> <span class="tok-comment">// and then reshow it if needed</span>
</span>
<span class="line" id="L284"> _ = <span class="tok-kw">try</span> tty.write(ctlseqs.hide_cursor);</span>
<span class="line" id="L285"> _ = <span class="tok-kw">try</span> tty.write(ctlseqs.home);</span>
<span class="line" id="L286"> _ = <span class="tok-kw">try</span> tty.write(ctlseqs.sgr_reset);</span>
<span class="line" id="L287"></span>
<span class="line" id="L288"> <span class="tok-comment">// initialize some variables</span>
</span>
<span class="line" id="L289"> <span class="tok-kw">var</span> reposition: <span class="tok-type">bool</span> = <span class="tok-null">false</span>;</span>
<span class="line" id="L290"> <span class="tok-kw">var</span> row: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L291"> <span class="tok-kw">var</span> col: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L292"> <span class="tok-kw">var</span> cursor: Cell.Style = .{};</span>
<span class="line" id="L293"> <span class="tok-kw">var</span> link: Cell.Hyperlink = .{};</span>
<span class="line" id="L294"></span>
<span class="line" id="L295"> <span class="tok-comment">// Clear all images</span>
</span>
<span class="line" id="L296"> _ = <span class="tok-kw">try</span> tty.write(ctlseqs.kitty_graphics_clear);</span>
<span class="line" id="L297"></span>
<span class="line" id="L298"> <span class="tok-kw">var</span> i: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L299"> <span class="tok-kw">while</span> (i &lt; self.screen.buf.len) {</span>
<span class="line" id="L300"> <span class="tok-kw">const</span> cell = self.screen.buf[i];</span>
<span class="line" id="L301"> <span class="tok-kw">defer</span> {</span>
<span class="line" id="L302"> <span class="tok-comment">// advance by the width of this char mod 1</span>
</span>
<span class="line" id="L303"> <span class="tok-kw">const</span> w = blk: {</span>
<span class="line" id="L304"> <span class="tok-kw">if</span> (cell.char.width != <span class="tok-number">0</span>) <span class="tok-kw">break</span> :blk cell.char.width;</span>
<span class="line" id="L305"></span>
<span class="line" id="L306"> <span class="tok-kw">const</span> method: gwidth.Method = <span class="tok-kw">if</span> (self.caps.unicode) .unicode <span class="tok-kw">else</span> .wcwidth;</span>
<span class="line" id="L307"> <span class="tok-kw">break</span> :blk gwidth.gwidth(cell.char.grapheme, method) <span class="tok-kw">catch</span> <span class="tok-number">1</span>;</span>
<span class="line" id="L308"> };</span>
<span class="line" id="L309"> <span class="tok-kw">var</span> j = i + <span class="tok-number">1</span>;</span>
<span class="line" id="L310"> <span class="tok-kw">while</span> (j &lt; i + w) : (j += <span class="tok-number">1</span>) {</span>
<span class="line" id="L311"> self.screen_last.buf[j].skipped = <span class="tok-null">true</span>;</span>
<span class="line" id="L312"> }</span>
<span class="line" id="L313"> col += w;</span>
<span class="line" id="L314"> i += w;</span>
<span class="line" id="L315"> }</span>
<span class="line" id="L316"> <span class="tok-kw">if</span> (col &gt;= self.screen.width) {</span>
<span class="line" id="L317"> row += <span class="tok-number">1</span>;</span>
<span class="line" id="L318"> col = <span class="tok-number">0</span>;</span>
<span class="line" id="L319"> }</span>
<span class="line" id="L320"> <span class="tok-comment">// If cell is the same as our last frame, we don't need to do</span>
</span>
<span class="line" id="L321"> <span class="tok-comment">// anything</span>
</span>
<span class="line" id="L322"> <span class="tok-kw">const</span> last = self.screen_last.buf[i];</span>
<span class="line" id="L323"> <span class="tok-kw">if</span> (!self.refresh <span class="tok-kw">and</span> last.eql(cell) <span class="tok-kw">and</span> !last.skipped <span class="tok-kw">and</span> cell.image == <span class="tok-null">null</span>) {</span>
<span class="line" id="L324"> reposition = <span class="tok-null">true</span>;</span>
<span class="line" id="L325"> <span class="tok-comment">// Close any osc8 sequence we might be in before</span>
</span>
<span class="line" id="L326"> <span class="tok-comment">// repositioning</span>
</span>
<span class="line" id="L327"> <span class="tok-kw">if</span> (link.uri.len &gt; <span class="tok-number">0</span>) {</span>
<span class="line" id="L328"> _ = <span class="tok-kw">try</span> tty.write(ctlseqs.osc8_clear);</span>
<span class="line" id="L329"> }</span>
<span class="line" id="L330"> <span class="tok-kw">continue</span>;</span>
<span class="line" id="L331"> }</span>
<span class="line" id="L332"> self.screen_last.buf[i].skipped = <span class="tok-null">false</span>;</span>
<span class="line" id="L333"> <span class="tok-kw">defer</span> {</span>
<span class="line" id="L334"> cursor = cell.style;</span>
<span class="line" id="L335"> link = cell.link;</span>
<span class="line" id="L336"> }</span>
<span class="line" id="L337"> <span class="tok-comment">// Set this cell in the last frame</span>
</span>
<span class="line" id="L338"> self.screen_last.writeCell(col, row, cell);</span>
<span class="line" id="L339"></span>
<span class="line" id="L340"> <span class="tok-comment">// reposition the cursor, if needed</span>
</span>
<span class="line" id="L341"> <span class="tok-kw">if</span> (reposition) {</span>
<span class="line" id="L342"> <span class="tok-kw">try</span> std.fmt.format(tty.buffered_writer.writer(), ctlseqs.cup, .{ row + <span class="tok-number">1</span>, col + <span class="tok-number">1</span> });</span>
<span class="line" id="L343"> }</span>
<span class="line" id="L344"></span>
<span class="line" id="L345"> <span class="tok-kw">if</span> (cell.image) |img| {</span>
<span class="line" id="L346"> <span class="tok-kw">if</span> (img.size) |size| {</span>
<span class="line" id="L347"> <span class="tok-kw">try</span> std.fmt.format(</span>
<span class="line" id="L348"> tty.buffered_writer.writer(),</span>
<span class="line" id="L349"> ctlseqs.kitty_graphics_scale,</span>
<span class="line" id="L350"> .{ img.img_id, img.z_index, size.cols, size.rows },</span>
<span class="line" id="L351"> );</span>
<span class="line" id="L352"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L353"> <span class="tok-kw">try</span> std.fmt.format(</span>
<span class="line" id="L354"> tty.buffered_writer.writer(),</span>
<span class="line" id="L355"> ctlseqs.kitty_graphics_place,</span>
<span class="line" id="L356"> .{ img.img_id, img.z_index },</span>
<span class="line" id="L357"> );</span>
<span class="line" id="L358"> }</span>
<span class="line" id="L359"> }</span>
<span class="line" id="L360"></span>
<span class="line" id="L361"> <span class="tok-comment">// something is different, so let's loop through everything and</span>
</span>
<span class="line" id="L362"> <span class="tok-comment">// find out what</span>
</span>
<span class="line" id="L363"></span>
<span class="line" id="L364"> <span class="tok-comment">// foreground</span>
</span>
<span class="line" id="L365"> <span class="tok-kw">if</span> (!std.meta.eql(cursor.fg, cell.style.fg)) {</span>
<span class="line" id="L366"> <span class="tok-kw">const</span> writer = tty.buffered_writer.writer();</span>
<span class="line" id="L367"> <span class="tok-kw">switch</span> (cell.style.fg) {</span>
<span class="line" id="L368"> .default =&gt; _ = <span class="tok-kw">try</span> tty.write(ctlseqs.fg_reset),</span>
<span class="line" id="L369"> .index =&gt; |idx| {</span>
<span class="line" id="L370"> <span class="tok-kw">switch</span> (idx) {</span>
<span class="line" id="L371"> <span class="tok-number">0</span>...<span class="tok-number">7</span> =&gt; <span class="tok-kw">try</span> std.fmt.format(writer, ctlseqs.fg_base, .{idx}),</span>
<span class="line" id="L372"> <span class="tok-number">8</span>...<span class="tok-number">15</span> =&gt; <span class="tok-kw">try</span> std.fmt.format(writer, ctlseqs.fg_bright, .{idx - <span class="tok-number">8</span>}),</span>
<span class="line" id="L373"> <span class="tok-kw">else</span> =&gt; <span class="tok-kw">try</span> std.fmt.format(writer, ctlseqs.fg_indexed, .{idx}),</span>
<span class="line" id="L374"> }</span>
<span class="line" id="L375"> },</span>
<span class="line" id="L376"> .rgb =&gt; |rgb| {</span>
<span class="line" id="L377"> <span class="tok-kw">try</span> std.fmt.format(writer, ctlseqs.fg_rgb, .{ rgb[<span class="tok-number">0</span>], rgb[<span class="tok-number">1</span>], rgb[<span class="tok-number">2</span>] });</span>
<span class="line" id="L378"> },</span>
<span class="line" id="L379"> }</span>
<span class="line" id="L380"> }</span>
<span class="line" id="L381"> <span class="tok-comment">// background</span>
</span>
<span class="line" id="L382"> <span class="tok-kw">if</span> (!std.meta.eql(cursor.bg, cell.style.bg)) {</span>
<span class="line" id="L383"> <span class="tok-kw">const</span> writer = tty.buffered_writer.writer();</span>
<span class="line" id="L384"> <span class="tok-kw">switch</span> (cell.style.bg) {</span>
<span class="line" id="L385"> .default =&gt; _ = <span class="tok-kw">try</span> tty.write(ctlseqs.bg_reset),</span>
<span class="line" id="L386"> .index =&gt; |idx| {</span>
<span class="line" id="L387"> <span class="tok-kw">switch</span> (idx) {</span>
<span class="line" id="L388"> <span class="tok-number">0</span>...<span class="tok-number">7</span> =&gt; <span class="tok-kw">try</span> std.fmt.format(writer, ctlseqs.bg_base, .{idx}),</span>
<span class="line" id="L389"> <span class="tok-number">8</span>...<span class="tok-number">15</span> =&gt; <span class="tok-kw">try</span> std.fmt.format(writer, ctlseqs.bg_bright, .{idx - <span class="tok-number">8</span>}),</span>
<span class="line" id="L390"> <span class="tok-kw">else</span> =&gt; <span class="tok-kw">try</span> std.fmt.format(writer, ctlseqs.bg_indexed, .{idx}),</span>
<span class="line" id="L391"> }</span>
<span class="line" id="L392"> },</span>
<span class="line" id="L393"> .rgb =&gt; |rgb| {</span>
<span class="line" id="L394"> <span class="tok-kw">try</span> std.fmt.format(writer, ctlseqs.bg_rgb, .{ rgb[<span class="tok-number">0</span>], rgb[<span class="tok-number">1</span>], rgb[<span class="tok-number">2</span>] });</span>
<span class="line" id="L395"> },</span>
<span class="line" id="L396"> }</span>
<span class="line" id="L397"> }</span>
<span class="line" id="L398"> <span class="tok-comment">// underline color</span>
</span>
<span class="line" id="L399"> <span class="tok-kw">if</span> (!std.meta.eql(cursor.ul, cell.style.ul)) {</span>
<span class="line" id="L400"> <span class="tok-kw">const</span> writer = tty.buffered_writer.writer();</span>
<span class="line" id="L401"> <span class="tok-kw">switch</span> (cell.style.bg) {</span>
<span class="line" id="L402"> .default =&gt; _ = <span class="tok-kw">try</span> tty.write(ctlseqs.ul_reset),</span>
<span class="line" id="L403"> .index =&gt; |idx| {</span>
<span class="line" id="L404"> <span class="tok-kw">try</span> std.fmt.format(writer, ctlseqs.ul_indexed, .{idx});</span>
<span class="line" id="L405"> },</span>
<span class="line" id="L406"> .rgb =&gt; |rgb| {</span>
<span class="line" id="L407"> <span class="tok-kw">try</span> std.fmt.format(writer, ctlseqs.ul_rgb, .{ rgb[<span class="tok-number">0</span>], rgb[<span class="tok-number">1</span>], rgb[<span class="tok-number">2</span>] });</span>
<span class="line" id="L408"> },</span>
<span class="line" id="L409"> }</span>
<span class="line" id="L410"> }</span>
<span class="line" id="L411"> <span class="tok-comment">// underline style</span>
</span>
<span class="line" id="L412"> <span class="tok-kw">if</span> (!std.meta.eql(cursor.ul_style, cell.style.ul_style)) {</span>
<span class="line" id="L413"> <span class="tok-kw">const</span> seq = <span class="tok-kw">switch</span> (cell.style.ul_style) {</span>
<span class="line" id="L414"> .off =&gt; ctlseqs.ul_off,</span>
<span class="line" id="L415"> .single =&gt; ctlseqs.ul_single,</span>
<span class="line" id="L416"> .double =&gt; ctlseqs.ul_double,</span>
<span class="line" id="L417"> .curly =&gt; ctlseqs.ul_curly,</span>
<span class="line" id="L418"> .dotted =&gt; ctlseqs.ul_dotted,</span>
<span class="line" id="L419"> .dashed =&gt; ctlseqs.ul_dashed,</span>
<span class="line" id="L420"> };</span>
<span class="line" id="L421"> _ = <span class="tok-kw">try</span> tty.write(seq);</span>
<span class="line" id="L422"> }</span>
<span class="line" id="L423"> <span class="tok-comment">// bold</span>
</span>
<span class="line" id="L424"> <span class="tok-kw">if</span> (cursor.bold != cell.style.bold) {</span>
<span class="line" id="L425"> <span class="tok-kw">const</span> seq = <span class="tok-kw">switch</span> (cell.style.bold) {</span>
<span class="line" id="L426"> <span class="tok-null">true</span> =&gt; ctlseqs.bold_set,</span>
<span class="line" id="L427"> <span class="tok-null">false</span> =&gt; ctlseqs.bold_dim_reset,</span>
<span class="line" id="L428"> };</span>
<span class="line" id="L429"> _ = <span class="tok-kw">try</span> tty.write(seq);</span>
<span class="line" id="L430"> <span class="tok-kw">if</span> (cell.style.dim) {</span>
<span class="line" id="L431"> _ = <span class="tok-kw">try</span> tty.write(ctlseqs.dim_set);</span>
<span class="line" id="L432"> }</span>
<span class="line" id="L433"> }</span>
<span class="line" id="L434"> <span class="tok-comment">// dim</span>
</span>
<span class="line" id="L435"> <span class="tok-kw">if</span> (cursor.dim != cell.style.dim) {</span>
<span class="line" id="L436"> <span class="tok-kw">const</span> seq = <span class="tok-kw">switch</span> (cell.style.dim) {</span>
<span class="line" id="L437"> <span class="tok-null">true</span> =&gt; ctlseqs.dim_set,</span>
<span class="line" id="L438"> <span class="tok-null">false</span> =&gt; ctlseqs.bold_dim_reset,</span>
<span class="line" id="L439"> };</span>
<span class="line" id="L440"> _ = <span class="tok-kw">try</span> tty.write(seq);</span>
<span class="line" id="L441"> <span class="tok-kw">if</span> (cell.style.bold) {</span>
<span class="line" id="L442"> _ = <span class="tok-kw">try</span> tty.write(ctlseqs.bold_set);</span>
<span class="line" id="L443"> }</span>
<span class="line" id="L444"> }</span>
<span class="line" id="L445"> <span class="tok-comment">// dim</span>
</span>
<span class="line" id="L446"> <span class="tok-kw">if</span> (cursor.italic != cell.style.italic) {</span>
<span class="line" id="L447"> <span class="tok-kw">const</span> seq = <span class="tok-kw">switch</span> (cell.style.italic) {</span>
<span class="line" id="L448"> <span class="tok-null">true</span> =&gt; ctlseqs.italic_set,</span>
<span class="line" id="L449"> <span class="tok-null">false</span> =&gt; ctlseqs.italic_reset,</span>
<span class="line" id="L450"> };</span>
<span class="line" id="L451"> _ = <span class="tok-kw">try</span> tty.write(seq);</span>
<span class="line" id="L452"> }</span>
<span class="line" id="L453"> <span class="tok-comment">// dim</span>
</span>
<span class="line" id="L454"> <span class="tok-kw">if</span> (cursor.blink != cell.style.blink) {</span>
<span class="line" id="L455"> <span class="tok-kw">const</span> seq = <span class="tok-kw">switch</span> (cell.style.blink) {</span>
<span class="line" id="L456"> <span class="tok-null">true</span> =&gt; ctlseqs.blink_set,</span>
<span class="line" id="L457"> <span class="tok-null">false</span> =&gt; ctlseqs.blink_reset,</span>
<span class="line" id="L458"> };</span>
<span class="line" id="L459"> _ = <span class="tok-kw">try</span> tty.write(seq);</span>
<span class="line" id="L460"> }</span>
<span class="line" id="L461"> <span class="tok-comment">// reverse</span>
</span>
<span class="line" id="L462"> <span class="tok-kw">if</span> (cursor.reverse != cell.style.reverse) {</span>
<span class="line" id="L463"> <span class="tok-kw">const</span> seq = <span class="tok-kw">switch</span> (cell.style.reverse) {</span>
<span class="line" id="L464"> <span class="tok-null">true</span> =&gt; ctlseqs.reverse_set,</span>
<span class="line" id="L465"> <span class="tok-null">false</span> =&gt; ctlseqs.reverse_reset,</span>
<span class="line" id="L466"> };</span>
<span class="line" id="L467"> _ = <span class="tok-kw">try</span> tty.write(seq);</span>
<span class="line" id="L468"> }</span>
<span class="line" id="L469"> <span class="tok-comment">// invisible</span>
</span>
<span class="line" id="L470"> <span class="tok-kw">if</span> (cursor.invisible != cell.style.invisible) {</span>
<span class="line" id="L471"> <span class="tok-kw">const</span> seq = <span class="tok-kw">switch</span> (cell.style.invisible) {</span>
<span class="line" id="L472"> <span class="tok-null">true</span> =&gt; ctlseqs.invisible_set,</span>
<span class="line" id="L473"> <span class="tok-null">false</span> =&gt; ctlseqs.invisible_reset,</span>
<span class="line" id="L474"> };</span>
<span class="line" id="L475"> _ = <span class="tok-kw">try</span> tty.write(seq);</span>
<span class="line" id="L476"> }</span>
<span class="line" id="L477"> <span class="tok-comment">// strikethrough</span>
</span>
<span class="line" id="L478"> <span class="tok-kw">if</span> (cursor.strikethrough != cell.style.strikethrough) {</span>
<span class="line" id="L479"> <span class="tok-kw">const</span> seq = <span class="tok-kw">switch</span> (cell.style.strikethrough) {</span>
<span class="line" id="L480"> <span class="tok-null">true</span> =&gt; ctlseqs.strikethrough_set,</span>
<span class="line" id="L481"> <span class="tok-null">false</span> =&gt; ctlseqs.strikethrough_reset,</span>
<span class="line" id="L482"> };</span>
<span class="line" id="L483"> _ = <span class="tok-kw">try</span> tty.write(seq);</span>
<span class="line" id="L484"> }</span>
<span class="line" id="L485"></span>
<span class="line" id="L486"> <span class="tok-comment">// url</span>
</span>
<span class="line" id="L487"> <span class="tok-kw">if</span> (!std.meta.eql(link.uri, cell.link.uri)) {</span>
<span class="line" id="L488"> <span class="tok-kw">var</span> ps = cell.link.params;</span>
<span class="line" id="L489"> <span class="tok-kw">if</span> (cell.link.uri.len == <span class="tok-number">0</span>) {</span>
<span class="line" id="L490"> <span class="tok-comment">// Empty out the params no matter what if we don't have</span>
</span>
<span class="line" id="L491"> <span class="tok-comment">// a url</span>
</span>
<span class="line" id="L492"> ps = <span class="tok-str">&quot;&quot;</span>;</span>
<span class="line" id="L493"> }</span>
<span class="line" id="L494"> <span class="tok-kw">const</span> writer = tty.buffered_writer.writer();</span>
<span class="line" id="L495"> <span class="tok-kw">try</span> std.fmt.format(writer, ctlseqs.osc8, .{ ps, cell.link.uri });</span>
<span class="line" id="L496"> }</span>
<span class="line" id="L497"> _ = <span class="tok-kw">try</span> tty.write(cell.char.grapheme);</span>
<span class="line" id="L498"> }</span>
<span class="line" id="L499"> <span class="tok-kw">if</span> (self.screen.cursor_vis) {</span>
<span class="line" id="L500"> <span class="tok-kw">try</span> std.fmt.format(</span>
<span class="line" id="L501"> tty.buffered_writer.writer(),</span>
<span class="line" id="L502"> ctlseqs.cup,</span>
<span class="line" id="L503"> .{</span>
<span class="line" id="L504"> self.screen.cursor_row + <span class="tok-number">1</span>,</span>
<span class="line" id="L505"> self.screen.cursor_col + <span class="tok-number">1</span>,</span>
<span class="line" id="L506"> },</span>
<span class="line" id="L507"> );</span>
<span class="line" id="L508"> _ = <span class="tok-kw">try</span> tty.write(ctlseqs.show_cursor);</span>
<span class="line" id="L509"> }</span>
<span class="line" id="L510"> <span class="tok-kw">if</span> (self.screen.mouse_shape != self.screen_last.mouse_shape) {</span>
<span class="line" id="L511"> <span class="tok-kw">try</span> std.fmt.format(</span>
<span class="line" id="L512"> tty.buffered_writer.writer(),</span>
<span class="line" id="L513"> ctlseqs.osc22_mouse_shape,</span>
<span class="line" id="L514"> .{<span class="tok-builtin">@tagName</span>(self.screen.mouse_shape)},</span>
<span class="line" id="L515"> );</span>
<span class="line" id="L516"> }</span>
<span class="line" id="L517"> }</span>
<span class="line" id="L518"></span>
<span class="line" id="L519"> <span class="tok-kw">fn</span> <span class="tok-fn">enableKittyKeyboard</span>(self: *Self, flags: Key.KittyFlags) !<span class="tok-type">void</span> {</span>
<span class="line" id="L520"> self.state.kitty_keyboard = <span class="tok-null">true</span>;</span>
<span class="line" id="L521"> <span class="tok-kw">const</span> flag_int: <span class="tok-type">u5</span> = <span class="tok-builtin">@bitCast</span>(flags);</span>
<span class="line" id="L522"> <span class="tok-kw">try</span> std.fmt.format(</span>
<span class="line" id="L523"> self.tty.?.buffered_writer.writer(),</span>
<span class="line" id="L524"> ctlseqs.csi_u_push,</span>
<span class="line" id="L525"> .{</span>
<span class="line" id="L526"> flag_int,</span>
<span class="line" id="L527"> },</span>
<span class="line" id="L528"> );</span>
<span class="line" id="L529"> <span class="tok-kw">try</span> self.tty.?.flush();</span>
<span class="line" id="L530"> }</span>
<span class="line" id="L531"></span>
<span class="line" id="L532"> <span class="tok-comment">/// send a system notification</span></span>
<span class="line" id="L533"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">notify</span>(self: *Self, title: ?[]<span class="tok-kw">const</span> <span class="tok-type">u8</span>, body: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>) !<span class="tok-type">void</span> {</span>
<span class="line" id="L534"> <span class="tok-kw">if</span> (self.tty == <span class="tok-null">null</span>) <span class="tok-kw">return</span>;</span>
<span class="line" id="L535"> <span class="tok-kw">if</span> (title) |t| {</span>
<span class="line" id="L536"> <span class="tok-kw">try</span> std.fmt.format(</span>
<span class="line" id="L537"> self.tty.?.buffered_writer.writer(),</span>
<span class="line" id="L538"> ctlseqs.osc777_notify,</span>
<span class="line" id="L539"> .{ t, body },</span>
<span class="line" id="L540"> );</span>
<span class="line" id="L541"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L542"> <span class="tok-kw">try</span> std.fmt.format(</span>
<span class="line" id="L543"> self.tty.?.buffered_writer.writer(),</span>
<span class="line" id="L544"> ctlseqs.osc9_notify,</span>
<span class="line" id="L545"> .{body},</span>
<span class="line" id="L546"> );</span>
<span class="line" id="L547"> }</span>
<span class="line" id="L548"> <span class="tok-kw">try</span> self.tty.?.flush();</span>
<span class="line" id="L549"> }</span>
<span class="line" id="L550"></span>
<span class="line" id="L551"> <span class="tok-comment">/// sets the window title</span></span>
<span class="line" id="L552"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">setTitle</span>(self: *Self, title: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>) !<span class="tok-type">void</span> {</span>
<span class="line" id="L553"> <span class="tok-kw">if</span> (self.tty == <span class="tok-null">null</span>) <span class="tok-kw">return</span>;</span>
<span class="line" id="L554"> <span class="tok-kw">try</span> std.fmt.format(</span>
<span class="line" id="L555"> self.tty.?.buffered_writer.writer(),</span>
<span class="line" id="L556"> ctlseqs.osc2_set_title,</span>
<span class="line" id="L557"> .{title},</span>
<span class="line" id="L558"> );</span>
<span class="line" id="L559"> <span class="tok-kw">try</span> self.tty.?.flush();</span>
<span class="line" id="L560"> }</span>
<span class="line" id="L561"></span>
<span class="line" id="L562"> <span class="tok-comment">// turn bracketed paste on or off. An event will be sent at the</span>
</span>
<span class="line" id="L563"> <span class="tok-comment">// beginning and end of a detected paste. All keystrokes between these</span>
</span>
<span class="line" id="L564"> <span class="tok-comment">// events were pasted</span>
</span>
<span class="line" id="L565"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">setBracketedPaste</span>(self: *Self, enable: <span class="tok-type">bool</span>) !<span class="tok-type">void</span> {</span>
<span class="line" id="L566"> <span class="tok-kw">if</span> (self.tty == <span class="tok-null">null</span>) <span class="tok-kw">return</span>;</span>
<span class="line" id="L567"> self.state.bracketed_paste = enable;</span>
<span class="line" id="L568"> <span class="tok-kw">const</span> seq = <span class="tok-kw">if</span> (enable) {</span>
<span class="line" id="L569"> self.state.bracketed_paste = <span class="tok-null">true</span>;</span>
<span class="line" id="L570"> ctlseqs.bp_set;</span>
<span class="line" id="L571"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L572"> self.state.bracketed_paste = <span class="tok-null">true</span>;</span>
<span class="line" id="L573"> ctlseqs.bp_reset;</span>
<span class="line" id="L574"> };</span>
<span class="line" id="L575"> _ = <span class="tok-kw">try</span> self.tty.?.write(seq);</span>
<span class="line" id="L576"> <span class="tok-kw">try</span> self.tty.?.flush();</span>
<span class="line" id="L577"> }</span>
<span class="line" id="L578"></span>
<span class="line" id="L579"> <span class="tok-comment">/// set the mouse shape</span></span>
<span class="line" id="L580"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">setMouseShape</span>(self: *Self, shape: Mouse.Shape) <span class="tok-type">void</span> {</span>
<span class="line" id="L581"> self.screen.mouse_shape = shape;</span>
<span class="line" id="L582"> }</span>
<span class="line" id="L583"></span>
<span class="line" id="L584"> <span class="tok-comment">/// turn mouse reporting on or off</span></span>
<span class="line" id="L585"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">setMouseMode</span>(self: *Self, enable: <span class="tok-type">bool</span>) !<span class="tok-type">void</span> {</span>
<span class="line" id="L586"> <span class="tok-kw">var</span> tty = self.tty <span class="tok-kw">orelse</span> <span class="tok-kw">return</span>;</span>
<span class="line" id="L587"> self.state.mouse = enable;</span>
<span class="line" id="L588"> <span class="tok-kw">if</span> (enable) {</span>
<span class="line" id="L589"> _ = <span class="tok-kw">try</span> tty.write(ctlseqs.mouse_set);</span>
<span class="line" id="L590"> <span class="tok-kw">try</span> tty.flush();</span>
<span class="line" id="L591"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L592"> _ = <span class="tok-kw">try</span> tty.write(ctlseqs.mouse_reset);</span>
<span class="line" id="L593"> <span class="tok-kw">try</span> tty.flush();</span>
<span class="line" id="L594"> }</span>
<span class="line" id="L595"> }</span>
<span class="line" id="L596"></span>
<span class="line" id="L597"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">loadImage</span>(</span>
<span class="line" id="L598"> self: *Self,</span>
<span class="line" id="L599"> alloc: std.mem.Allocator,</span>
<span class="line" id="L600"> src: Image.Source,</span>
<span class="line" id="L601"> ) !Image {</span>
<span class="line" id="L602"> <span class="tok-kw">if</span> (!self.caps.kitty_graphics) <span class="tok-kw">return</span> <span class="tok-kw">error</span>.NoGraphicsCapability;</span>
<span class="line" id="L603"> <span class="tok-kw">var</span> tty = self.tty <span class="tok-kw">orelse</span> <span class="tok-kw">return</span> <span class="tok-kw">error</span>.NoTTY;</span>
<span class="line" id="L604"> <span class="tok-kw">defer</span> self.next_img_id += <span class="tok-number">1</span>;</span>
<span class="line" id="L605"></span>
<span class="line" id="L606"> <span class="tok-kw">const</span> writer = tty.buffered_writer.writer();</span>
<span class="line" id="L607"></span>
<span class="line" id="L608"> <span class="tok-kw">var</span> img = <span class="tok-kw">switch</span> (src) {</span>
<span class="line" id="L609"> .path =&gt; |path| <span class="tok-kw">try</span> zigimg.Image.fromFilePath(alloc, path),</span>
<span class="line" id="L610"> .mem =&gt; |bytes| <span class="tok-kw">try</span> zigimg.Image.fromMemory(alloc, bytes),</span>
<span class="line" id="L611"> };</span>
<span class="line" id="L612"> <span class="tok-kw">defer</span> img.deinit();</span>
<span class="line" id="L613"> <span class="tok-kw">const</span> png_buf = <span class="tok-kw">try</span> alloc.alloc(<span class="tok-type">u8</span>, img.imageByteSize());</span>
<span class="line" id="L614"> <span class="tok-kw">defer</span> alloc.free(png_buf);</span>
<span class="line" id="L615"> <span class="tok-kw">const</span> png = <span class="tok-kw">try</span> img.writeToMemory(png_buf, .{ .png = .{} });</span>
<span class="line" id="L616"> <span class="tok-kw">const</span> b64_buf = <span class="tok-kw">try</span> alloc.alloc(<span class="tok-type">u8</span>, base64.calcSize(png.len));</span>
<span class="line" id="L617"> <span class="tok-kw">const</span> encoded = base64.encode(b64_buf, png);</span>
<span class="line" id="L618"> <span class="tok-kw">defer</span> alloc.free(b64_buf);</span>
<span class="line" id="L619"></span>
<span class="line" id="L620"> <span class="tok-kw">const</span> id = self.next_img_id;</span>
<span class="line" id="L621"></span>
<span class="line" id="L622"> log.debug(<span class="tok-str">&quot;transmitting kitty image: id={d}, len={d}&quot;</span>, .{ id, encoded.len });</span>
<span class="line" id="L623"></span>
<span class="line" id="L624"> <span class="tok-kw">if</span> (encoded.len &lt; <span class="tok-number">4096</span>) {</span>
<span class="line" id="L625"> <span class="tok-kw">try</span> std.fmt.format(</span>
<span class="line" id="L626"> writer,</span>
<span class="line" id="L627"> <span class="tok-str">&quot;\x1b_Gf=100,i={d};{s}\x1b\\&quot;</span>,</span>
<span class="line" id="L628"> .{</span>
<span class="line" id="L629"> id,</span>
<span class="line" id="L630"> encoded,</span>
<span class="line" id="L631"> },</span>
<span class="line" id="L632"> );</span>
<span class="line" id="L633"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L634"> <span class="tok-kw">var</span> n: <span class="tok-type">usize</span> = <span class="tok-number">4096</span>;</span>
<span class="line" id="L635"></span>
<span class="line" id="L636"> <span class="tok-kw">try</span> std.fmt.format(</span>
<span class="line" id="L637"> writer,</span>
<span class="line" id="L638"> <span class="tok-str">&quot;\x1b_Gf=100,i={d},m=1;{s}\x1b\\&quot;</span>,</span>
<span class="line" id="L639"> .{ id, encoded[<span class="tok-number">0</span>..n] },</span>
<span class="line" id="L640"> );</span>
<span class="line" id="L641"> <span class="tok-kw">while</span> (n &lt; encoded.len) : (n += <span class="tok-number">4096</span>) {</span>
<span class="line" id="L642"> <span class="tok-kw">const</span> end: <span class="tok-type">usize</span> = <span class="tok-builtin">@min</span>(n + <span class="tok-number">4096</span>, encoded.len);</span>
<span class="line" id="L643"> <span class="tok-kw">const</span> m: <span class="tok-type">u2</span> = <span class="tok-kw">if</span> (end == encoded.len) <span class="tok-number">0</span> <span class="tok-kw">else</span> <span class="tok-number">1</span>;</span>
<span class="line" id="L644"> <span class="tok-kw">try</span> std.fmt.format(</span>
<span class="line" id="L645"> writer,</span>
<span class="line" id="L646"> <span class="tok-str">&quot;\x1b_Gm={d};{s}\x1b\\&quot;</span>,</span>
<span class="line" id="L647"> .{</span>
<span class="line" id="L648"> m,</span>
<span class="line" id="L649"> encoded[n..end],</span>
<span class="line" id="L650"> },</span>
<span class="line" id="L651"> );</span>
<span class="line" id="L652"> }</span>
<span class="line" id="L653"> }</span>
<span class="line" id="L654"> <span class="tok-kw">try</span> tty.buffered_writer.flush();</span>
<span class="line" id="L655"> <span class="tok-kw">return</span> .{</span>
<span class="line" id="L656"> .id = id,</span>
<span class="line" id="L657"> .width = img.width,</span>
<span class="line" id="L658"> .height = img.height,</span>
<span class="line" id="L659"> };</span>
<span class="line" id="L660"> }</span>
<span class="line" id="L661"></span>
<span class="line" id="L662"> <span class="tok-comment">/// deletes an image from the terminal's memory</span></span>
<span class="line" id="L663"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">freeImage</span>(self: Self, id: <span class="tok-type">u32</span>) <span class="tok-type">void</span> {</span>
<span class="line" id="L664"> <span class="tok-kw">var</span> tty = self.tty <span class="tok-kw">orelse</span> <span class="tok-kw">return</span>;</span>
<span class="line" id="L665"> <span class="tok-kw">const</span> writer = tty.buffered_writer.writer();</span>
<span class="line" id="L666"> std.fmt.format(writer, <span class="tok-str">&quot;\x1b_Ga=d,d=I,i={d};\x1b\\&quot;</span>, .{id}) <span class="tok-kw">catch</span> |err| {</span>
<span class="line" id="L667"> log.err(<span class="tok-str">&quot;couldn't delete image {d}: {}&quot;</span>, .{ id, err });</span>
<span class="line" id="L668"> <span class="tok-kw">return</span>;</span>
<span class="line" id="L669"> };</span>
<span class="line" id="L670"> tty.buffered_writer.flush() <span class="tok-kw">catch</span> |err| {</span>
<span class="line" id="L671"> log.err(<span class="tok-str">&quot;couldn't flush writer: {}&quot;</span>, .{err});</span>
<span class="line" id="L672"> };</span>
<span class="line" id="L673"> }</span>
<span class="line" id="L674"> };</span>
<span class="line" id="L675">}</span>
<span class="line" id="L676"></span>
<span class="line" id="L677"><span class="tok-kw">test</span> <span class="tok-str">&quot;Vaxis: event queueing&quot;</span> {</span>
<span class="line" id="L678"> <span class="tok-kw">const</span> Event = <span class="tok-kw">union</span>(<span class="tok-kw">enum</span>) {</span>
<span class="line" id="L679"> key,</span>
<span class="line" id="L680"> };</span>
<span class="line" id="L681"> <span class="tok-kw">var</span> vx: Vaxis(Event) = <span class="tok-kw">try</span> Vaxis(Event).init(.{});</span>
<span class="line" id="L682"> <span class="tok-kw">defer</span> vx.deinit(<span class="tok-null">null</span>);</span>
<span class="line" id="L683"> vx.postEvent(.key);</span>
<span class="line" id="L684"> <span class="tok-kw">const</span> event = vx.nextEvent();</span>
<span class="line" id="L685"> <span class="tok-kw">try</span> std.testing.expect(event == .key);</span>
<span class="line" id="L686">}</span>
<span class="line" id="L687"></span>
</code></pre></body>
</html>

View file

@ -0,0 +1,121 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>widgets.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> border = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;widgets/border.zig&quot;</span>);</span>
<span class="line" id="L2"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> alignment = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;widgets/alignment.zig&quot;</span>);</span>
<span class="line" id="L3"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> TextInput = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;widgets/TextInput.zig&quot;</span>);</span>
<span class="line" id="L4"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Table = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;widgets/Table.zig&quot;</span>);</span>
<span class="line" id="L5"></span>
</code></pre></body>
</html>

View file

@ -0,0 +1,274 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>widgets/Table.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-kw">const</span> std = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;std&quot;</span>);</span>
<span class="line" id="L2"><span class="tok-kw">const</span> fmt = std.fmt;</span>
<span class="line" id="L3"><span class="tok-kw">const</span> heap = std.heap;</span>
<span class="line" id="L4"><span class="tok-kw">const</span> mem = std.mem;</span>
<span class="line" id="L5"><span class="tok-kw">const</span> meta = std.meta;</span>
<span class="line" id="L6"></span>
<span class="line" id="L7"><span class="tok-kw">const</span> vaxis = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../vaxis.zig&quot;</span>);</span>
<span class="line" id="L8"></span>
<span class="line" id="L9"><span class="tok-comment">/// Table Context for maintaining state and drawing Tables with `drawTable()`.</span></span>
<span class="line" id="L10"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> TableContext = <span class="tok-kw">struct</span>{</span>
<span class="line" id="L11"> <span class="tok-comment">/// Current selected Row of the Table.</span></span>
<span class="line" id="L12"> row: <span class="tok-type">usize</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L13"> <span class="tok-comment">/// Current selected Column of the Table.</span></span>
<span class="line" id="L14"> col: <span class="tok-type">usize</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L15"> <span class="tok-comment">/// Starting point within the Data List.</span></span>
<span class="line" id="L16"> start: <span class="tok-type">usize</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L17"></span>
<span class="line" id="L18"> <span class="tok-comment">/// Active status of the Table.</span></span>
<span class="line" id="L19"> active: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L20"></span>
<span class="line" id="L21"> <span class="tok-comment">/// The Background Color for Selected Rows and Column Headers.</span></span>
<span class="line" id="L22"> selected_bg: vaxis.Cell.Color,</span>
<span class="line" id="L23"> <span class="tok-comment">/// First Column Header Background Color</span></span>
<span class="line" id="L24"> hdr_bg_1: vaxis.Cell.Color = .{ .rgb = [_]<span class="tok-type">u8</span>{ <span class="tok-number">64</span>, <span class="tok-number">64</span>, <span class="tok-number">64</span> } },</span>
<span class="line" id="L25"> <span class="tok-comment">/// Second Column Header Background Color</span></span>
<span class="line" id="L26"> hdr_bg_2: vaxis.Cell.Color = .{ .rgb = [_]<span class="tok-type">u8</span>{ <span class="tok-number">8</span>, <span class="tok-number">8</span>, <span class="tok-number">24</span> } },</span>
<span class="line" id="L27"> <span class="tok-comment">/// First Row Background Color</span></span>
<span class="line" id="L28"> row_bg_1: vaxis.Cell.Color = .{ .rgb = [_]<span class="tok-type">u8</span>{ <span class="tok-number">32</span>, <span class="tok-number">32</span>, <span class="tok-number">32</span> } },</span>
<span class="line" id="L29"> <span class="tok-comment">/// Second Row Background Color</span></span>
<span class="line" id="L30"> row_bg_2: vaxis.Cell.Color = .{ .rgb = [_]<span class="tok-type">u8</span>{ <span class="tok-number">8</span>, <span class="tok-number">8</span>, <span class="tok-number">8</span> } },</span>
<span class="line" id="L31"></span>
<span class="line" id="L32"> <span class="tok-comment">/// Y Offset for drawing to the parent Window.</span></span>
<span class="line" id="L33"> y_off: <span class="tok-type">usize</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L34">};</span>
<span class="line" id="L35"></span>
<span class="line" id="L36"><span class="tok-comment">/// Draw a Table for the TUI.</span></span>
<span class="line" id="L37"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">drawTable</span>(</span>
<span class="line" id="L38"> <span class="tok-comment">/// This should be an ArenaAllocator that can be deinitialized after each event call.</span></span>
<span class="line" id="L39"> <span class="tok-comment">/// The Allocator is only used if a row field is a non-String.</span></span>
<span class="line" id="L40"> <span class="tok-comment">/// If the Allocator is not provided, those fields will show &quot;[unsupported (TypeName)]&quot;.</span></span>
<span class="line" id="L41"> alloc: ?mem.Allocator,</span>
<span class="line" id="L42"> <span class="tok-comment">/// The parent Window to draw to.</span></span>
<span class="line" id="L43"> win: vaxis.Window,</span>
<span class="line" id="L44"> <span class="tok-comment">/// Headers for the Table</span></span>
<span class="line" id="L45"> headers: []<span class="tok-kw">const</span> []<span class="tok-kw">const</span> <span class="tok-type">u8</span>,</span>
<span class="line" id="L46"> <span class="tok-comment">/// This must be an ArrayList.</span></span>
<span class="line" id="L47"> data_list: <span class="tok-kw">anytype</span>,</span>
<span class="line" id="L48"> <span class="tok-comment">// The Table Context for this Table.</span>
</span>
<span class="line" id="L49"> table_ctx: *TableContext,</span>
<span class="line" id="L50">) !<span class="tok-type">void</span> {</span>
<span class="line" id="L51"> <span class="tok-kw">const</span> table_win = win.initChild(</span>
<span class="line" id="L52"> <span class="tok-number">0</span>,</span>
<span class="line" id="L53"> table_ctx.y_off,</span>
<span class="line" id="L54"> .{ .limit = win.width },</span>
<span class="line" id="L55"> .{ .limit = win.height },</span>
<span class="line" id="L56"> );</span>
<span class="line" id="L57"> </span>
<span class="line" id="L58"> <span class="tok-kw">var</span> item_width = table_win.width / headers.len;</span>
<span class="line" id="L59"> <span class="tok-kw">if</span> (item_width % <span class="tok-number">2</span> != <span class="tok-number">0</span>) item_width += <span class="tok-number">1</span>;</span>
<span class="line" id="L60"></span>
<span class="line" id="L61"> <span class="tok-kw">if</span> (table_ctx.col &gt; headers.len - <span class="tok-number">1</span>) table_ctx.*.col = headers.len - <span class="tok-number">1</span>;</span>
<span class="line" id="L62"> <span class="tok-kw">for</span> (headers[<span class="tok-number">0</span>..], <span class="tok-number">0</span>..) |hdr_txt, idx| {</span>
<span class="line" id="L63"> <span class="tok-kw">const</span> hdr_bg =</span>
<span class="line" id="L64"> <span class="tok-kw">if</span> (table_ctx.active <span class="tok-kw">and</span> idx == table_ctx.col) table_ctx.selected_bg</span>
<span class="line" id="L65"> <span class="tok-kw">else</span> <span class="tok-kw">if</span> (idx % <span class="tok-number">2</span> == <span class="tok-number">0</span>) table_ctx.hdr_bg_1</span>
<span class="line" id="L66"> <span class="tok-kw">else</span> table_ctx.hdr_bg_2;</span>
<span class="line" id="L67"> <span class="tok-kw">const</span> hdr_win = table_win.initChild(</span>
<span class="line" id="L68"> idx * item_width,</span>
<span class="line" id="L69"> <span class="tok-number">0</span>,</span>
<span class="line" id="L70"> .{ .limit = item_width },</span>
<span class="line" id="L71"> .{ .limit = <span class="tok-number">1</span> },</span>
<span class="line" id="L72"> );</span>
<span class="line" id="L73"> <span class="tok-kw">var</span> hdr = vaxis.widgets.alignment.center(hdr_win, <span class="tok-builtin">@min</span>(item_width - <span class="tok-number">1</span>, hdr_txt.len), <span class="tok-number">1</span>);</span>
<span class="line" id="L74"> hdr_win.fill(.{ .style = .{ .bg = hdr_bg } });</span>
<span class="line" id="L75"> <span class="tok-kw">var</span> seg = [_]vaxis.Cell.Segment{ .{</span>
<span class="line" id="L76"> .text = hdr_txt,</span>
<span class="line" id="L77"> .style = .{</span>
<span class="line" id="L78"> .bg = hdr_bg,</span>
<span class="line" id="L79"> .bold = <span class="tok-null">true</span>,</span>
<span class="line" id="L80"> .ul_style = <span class="tok-kw">if</span> (idx == table_ctx.col) .single <span class="tok-kw">else</span> .dotted,</span>
<span class="line" id="L81"> },</span>
<span class="line" id="L82"> } };</span>
<span class="line" id="L83"> <span class="tok-kw">try</span> hdr.wrap(seg[<span class="tok-number">0</span>..]);</span>
<span class="line" id="L84"> }</span>
<span class="line" id="L85"></span>
<span class="line" id="L86"> <span class="tok-kw">const</span> max_items = <span class="tok-kw">if</span> (data_list.items.len &gt; table_win.height - <span class="tok-number">1</span>) table_win.height - <span class="tok-number">1</span> <span class="tok-kw">else</span> data_list.items.len;</span>
<span class="line" id="L87"> <span class="tok-kw">var</span> end = table_ctx.*.start + max_items;</span>
<span class="line" id="L88"> <span class="tok-kw">if</span> (end &gt; data_list.items.len) end = data_list.items.len;</span>
<span class="line" id="L89"> table_ctx.*.start = tableStart: {</span>
<span class="line" id="L90"> <span class="tok-kw">if</span> (table_ctx.row == <span class="tok-number">0</span>) </span>
<span class="line" id="L91"> <span class="tok-kw">break</span> :tableStart <span class="tok-number">0</span>;</span>
<span class="line" id="L92"> <span class="tok-kw">if</span> (table_ctx.row &lt; table_ctx.start) </span>
<span class="line" id="L93"> <span class="tok-kw">break</span> :tableStart table_ctx.start - (table_ctx.start - table_ctx.row);</span>
<span class="line" id="L94"> <span class="tok-kw">if</span> (table_ctx.row &gt;= data_list.items.len - <span class="tok-number">1</span>) </span>
<span class="line" id="L95"> table_ctx.*.row = data_list.items.len - <span class="tok-number">1</span>;</span>
<span class="line" id="L96"> <span class="tok-kw">if</span> (table_ctx.row &gt;= end) </span>
<span class="line" id="L97"> <span class="tok-kw">break</span> :tableStart table_ctx.start + (table_ctx.row - end + <span class="tok-number">1</span>);</span>
<span class="line" id="L98"> <span class="tok-kw">break</span> :tableStart table_ctx.start;</span>
<span class="line" id="L99"> };</span>
<span class="line" id="L100"> end = table_ctx.*.start + max_items;</span>
<span class="line" id="L101"> <span class="tok-kw">if</span> (end &gt; data_list.items.len) end = data_list.items.len;</span>
<span class="line" id="L102"> <span class="tok-kw">for</span> (data_list.items[table_ctx.start..end], <span class="tok-number">0</span>..) |data, idx| {</span>
<span class="line" id="L103"> <span class="tok-kw">const</span> row_bg =</span>
<span class="line" id="L104"> <span class="tok-kw">if</span> (table_ctx.active <span class="tok-kw">and</span> table_ctx.start + idx == table_ctx.row) table_ctx.selected_bg</span>
<span class="line" id="L105"> <span class="tok-kw">else</span> <span class="tok-kw">if</span> (idx % <span class="tok-number">2</span> == <span class="tok-number">0</span>) table_ctx.row_bg_1</span>
<span class="line" id="L106"> <span class="tok-kw">else</span> table_ctx.row_bg_2;</span>
<span class="line" id="L107"></span>
<span class="line" id="L108"> <span class="tok-kw">const</span> row_win = table_win.initChild(</span>
<span class="line" id="L109"> <span class="tok-number">0</span>,</span>
<span class="line" id="L110"> <span class="tok-number">1</span> + idx,</span>
<span class="line" id="L111"> .{ .limit = table_win.width },</span>
<span class="line" id="L112"> .{ .limit = <span class="tok-number">1</span> },</span>
<span class="line" id="L113"> );</span>
<span class="line" id="L114"> <span class="tok-kw">const</span> DataT = <span class="tok-builtin">@TypeOf</span>(data);</span>
<span class="line" id="L115"> <span class="tok-kw">const</span> item_fields = meta.fields(DataT);</span>
<span class="line" id="L116"> <span class="tok-kw">inline</span> <span class="tok-kw">for</span> (item_fields[<span class="tok-number">0</span>..], <span class="tok-number">0</span>..) |item_field, item_idx| {</span>
<span class="line" id="L117"> <span class="tok-kw">const</span> item = <span class="tok-builtin">@field</span>(data, item_field.name);</span>
<span class="line" id="L118"> <span class="tok-kw">const</span> ItemT = <span class="tok-builtin">@TypeOf</span>(item);</span>
<span class="line" id="L119"> <span class="tok-kw">const</span> item_win = row_win.initChild(</span>
<span class="line" id="L120"> item_idx * item_width,</span>
<span class="line" id="L121"> <span class="tok-number">0</span>,</span>
<span class="line" id="L122"> .{ .limit = item_width },</span>
<span class="line" id="L123"> .{ .limit = <span class="tok-number">1</span> },</span>
<span class="line" id="L124"> );</span>
<span class="line" id="L125"> item_win.fill(.{ .style = .{ .bg = row_bg } });</span>
<span class="line" id="L126"> <span class="tok-kw">var</span> seg = [_]vaxis.Cell.Segment{ .{</span>
<span class="line" id="L127"> .text = <span class="tok-kw">switch</span>(ItemT) {</span>
<span class="line" id="L128"> []<span class="tok-kw">const</span> <span class="tok-type">u8</span> =&gt; item,</span>
<span class="line" id="L129"> <span class="tok-kw">else</span> =&gt; nonStr: {</span>
<span class="line" id="L130"> <span class="tok-kw">switch</span> (<span class="tok-builtin">@typeInfo</span>(ItemT)) {</span>
<span class="line" id="L131"> .Optional =&gt; {</span>
<span class="line" id="L132"> <span class="tok-kw">const</span> opt_item = item <span class="tok-kw">orelse</span> <span class="tok-kw">break</span> :nonStr <span class="tok-str">&quot;-&quot;</span>;</span>
<span class="line" id="L133"> <span class="tok-kw">switch</span>(<span class="tok-builtin">@typeInfo</span>(ItemT).Optional.child) {</span>
<span class="line" id="L134"> []<span class="tok-kw">const</span> <span class="tok-type">u8</span> =&gt; <span class="tok-kw">break</span> :nonStr opt_item,</span>
<span class="line" id="L135"> <span class="tok-kw">else</span> =&gt; {</span>
<span class="line" id="L136"> <span class="tok-kw">break</span> :nonStr</span>
<span class="line" id="L137"> <span class="tok-kw">if</span> (alloc) |_alloc| <span class="tok-kw">try</span> fmt.allocPrint(_alloc, <span class="tok-str">&quot;{any}&quot;</span>, .{ opt_item })</span>
<span class="line" id="L138"> <span class="tok-kw">else</span> fmt.comptimePrint(<span class="tok-str">&quot;[unsupported ({s})]&quot;</span>, .{ <span class="tok-builtin">@typeName</span>(DataT) });</span>
<span class="line" id="L139"> }</span>
<span class="line" id="L140"> }</span>
<span class="line" id="L141"> },</span>
<span class="line" id="L142"> <span class="tok-kw">else</span> =&gt; {</span>
<span class="line" id="L143"> <span class="tok-kw">break</span> :nonStr</span>
<span class="line" id="L144"> <span class="tok-kw">if</span> (alloc) |_alloc| <span class="tok-kw">try</span> fmt.allocPrint(_alloc, <span class="tok-str">&quot;{any}&quot;</span>, .{ item })</span>
<span class="line" id="L145"> <span class="tok-kw">else</span> fmt.comptimePrint(<span class="tok-str">&quot;[unsupported ({s})]&quot;</span>, .{ <span class="tok-builtin">@typeName</span>(DataT) });</span>
<span class="line" id="L146"> }</span>
<span class="line" id="L147"> }</span>
<span class="line" id="L148"> },</span>
<span class="line" id="L149"> },</span>
<span class="line" id="L150"> .style = .{ .bg = row_bg },</span>
<span class="line" id="L151"> } };</span>
<span class="line" id="L152"> <span class="tok-kw">try</span> item_win.wrap(seg[<span class="tok-number">0</span>..]);</span>
<span class="line" id="L153"> }</span>
<span class="line" id="L154"> }</span>
<span class="line" id="L155">}</span>
<span class="line" id="L156"></span>
<span class="line" id="L157"></span>
</code></pre></body>
</html>

View file

@ -0,0 +1,260 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>widgets/TextInput.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-kw">const</span> std = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;std&quot;</span>);</span>
<span class="line" id="L2"><span class="tok-kw">const</span> Key = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../Key.zig&quot;</span>);</span>
<span class="line" id="L3"><span class="tok-kw">const</span> Cell = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../Cell.zig&quot;</span>);</span>
<span class="line" id="L4"><span class="tok-kw">const</span> Window = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../Window.zig&quot;</span>);</span>
<span class="line" id="L5"><span class="tok-kw">const</span> GraphemeIterator = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;ziglyph&quot;</span>).GraphemeIterator;</span>
<span class="line" id="L6"></span>
<span class="line" id="L7"><span class="tok-kw">const</span> log = std.log.scoped(.text_input);</span>
<span class="line" id="L8"></span>
<span class="line" id="L9"><span class="tok-kw">const</span> TextInput = <span class="tok-builtin">@This</span>();</span>
<span class="line" id="L10"></span>
<span class="line" id="L11"><span class="tok-comment">/// The events that this widget handles</span></span>
<span class="line" id="L12"><span class="tok-kw">const</span> Event = <span class="tok-kw">union</span>(<span class="tok-kw">enum</span>) {</span>
<span class="line" id="L13"> key_press: Key,</span>
<span class="line" id="L14">};</span>
<span class="line" id="L15"></span>
<span class="line" id="L16"><span class="tok-comment">// Index of our cursor</span>
</span>
<span class="line" id="L17">cursor_idx: <span class="tok-type">usize</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L18">grapheme_count: <span class="tok-type">usize</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L19"></span>
<span class="line" id="L20"><span class="tok-comment">// TODO: an ArrayList is not great for this. orderedRemove is O(n) and we can</span>
</span>
<span class="line" id="L21"><span class="tok-comment">// only remove one byte at a time. Make a bespoke ArrayList which allows removal</span>
</span>
<span class="line" id="L22"><span class="tok-comment">// of a slice at a time, or truncating even would be nice</span>
</span>
<span class="line" id="L23">buf: std.ArrayList(<span class="tok-type">u8</span>),</span>
<span class="line" id="L24"></span>
<span class="line" id="L25"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">init</span>(alloc: std.mem.Allocator) TextInput {</span>
<span class="line" id="L26"> <span class="tok-kw">return</span> TextInput{</span>
<span class="line" id="L27"> .buf = std.ArrayList(<span class="tok-type">u8</span>).init(alloc),</span>
<span class="line" id="L28"> };</span>
<span class="line" id="L29">}</span>
<span class="line" id="L30"></span>
<span class="line" id="L31"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">deinit</span>(self: *TextInput) <span class="tok-type">void</span> {</span>
<span class="line" id="L32"> self.buf.deinit();</span>
<span class="line" id="L33">}</span>
<span class="line" id="L34"></span>
<span class="line" id="L35"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">update</span>(self: *TextInput, event: Event) !<span class="tok-type">void</span> {</span>
<span class="line" id="L36"> <span class="tok-kw">switch</span> (event) {</span>
<span class="line" id="L37"> .key_press =&gt; |key| {</span>
<span class="line" id="L38"> <span class="tok-kw">if</span> (key.matches(Key.backspace, .{})) {</span>
<span class="line" id="L39"> <span class="tok-kw">if</span> (self.cursor_idx == <span class="tok-number">0</span>) <span class="tok-kw">return</span>;</span>
<span class="line" id="L40"> self.deleteBeforeCursor();</span>
<span class="line" id="L41"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (key.matches(Key.delete, .{}) <span class="tok-kw">or</span> key.matches(<span class="tok-str">'d'</span>, .{ .ctrl = <span class="tok-null">true</span> })) {</span>
<span class="line" id="L42"> <span class="tok-kw">if</span> (self.cursor_idx == self.grapheme_count) <span class="tok-kw">return</span>;</span>
<span class="line" id="L43"> self.deleteAtCursor();</span>
<span class="line" id="L44"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (key.matches(Key.left, .{}) <span class="tok-kw">or</span> key.matches(<span class="tok-str">'b'</span>, .{ .ctrl = <span class="tok-null">true</span> })) {</span>
<span class="line" id="L45"> <span class="tok-kw">if</span> (self.cursor_idx &gt; <span class="tok-number">0</span>) self.cursor_idx -= <span class="tok-number">1</span>;</span>
<span class="line" id="L46"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (key.matches(Key.right, .{}) <span class="tok-kw">or</span> key.matches(<span class="tok-str">'f'</span>, .{ .ctrl = <span class="tok-null">true</span> })) {</span>
<span class="line" id="L47"> <span class="tok-kw">if</span> (self.cursor_idx &lt; self.grapheme_count) self.cursor_idx += <span class="tok-number">1</span>;</span>
<span class="line" id="L48"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (key.matches(<span class="tok-str">'a'</span>, .{ .ctrl = <span class="tok-null">true</span> })) {</span>
<span class="line" id="L49"> self.cursor_idx = <span class="tok-number">0</span>;</span>
<span class="line" id="L50"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (key.matches(<span class="tok-str">'e'</span>, .{ .ctrl = <span class="tok-null">true</span> })) {</span>
<span class="line" id="L51"> self.cursor_idx = self.grapheme_count;</span>
<span class="line" id="L52"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (key.matches(<span class="tok-str">'k'</span>, .{ .ctrl = <span class="tok-null">true</span> })) {</span>
<span class="line" id="L53"> <span class="tok-kw">while</span> (self.cursor_idx &lt; self.grapheme_count) {</span>
<span class="line" id="L54"> self.deleteAtCursor();</span>
<span class="line" id="L55"> }</span>
<span class="line" id="L56"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (key.matches(<span class="tok-str">'u'</span>, .{ .ctrl = <span class="tok-null">true</span> })) {</span>
<span class="line" id="L57"> <span class="tok-kw">while</span> (self.cursor_idx &gt; <span class="tok-number">0</span>) {</span>
<span class="line" id="L58"> self.deleteBeforeCursor();</span>
<span class="line" id="L59"> }</span>
<span class="line" id="L60"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (key.text) |text| {</span>
<span class="line" id="L61"> <span class="tok-kw">try</span> self.buf.insertSlice(self.byteOffsetToCursor(), text);</span>
<span class="line" id="L62"> self.cursor_idx += <span class="tok-number">1</span>;</span>
<span class="line" id="L63"> self.grapheme_count += <span class="tok-number">1</span>;</span>
<span class="line" id="L64"> }</span>
<span class="line" id="L65"> },</span>
<span class="line" id="L66"> }</span>
<span class="line" id="L67">}</span>
<span class="line" id="L68"></span>
<span class="line" id="L69"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">draw</span>(self: *TextInput, win: Window) <span class="tok-type">void</span> {</span>
<span class="line" id="L70"> <span class="tok-kw">var</span> iter = GraphemeIterator.init(self.buf.items);</span>
<span class="line" id="L71"> <span class="tok-kw">var</span> col: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L72"> <span class="tok-kw">var</span> i: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L73"> <span class="tok-kw">var</span> cursor_idx: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L74"> <span class="tok-kw">while</span> (iter.next()) |grapheme| {</span>
<span class="line" id="L75"> <span class="tok-kw">const</span> g = grapheme.slice(self.buf.items);</span>
<span class="line" id="L76"> <span class="tok-kw">const</span> w = win.gwidth(g);</span>
<span class="line" id="L77"> win.writeCell(col, <span class="tok-number">0</span>, .{</span>
<span class="line" id="L78"> .char = .{</span>
<span class="line" id="L79"> .grapheme = g,</span>
<span class="line" id="L80"> .width = w,</span>
<span class="line" id="L81"> },</span>
<span class="line" id="L82"> });</span>
<span class="line" id="L83"> col += w;</span>
<span class="line" id="L84"> i += <span class="tok-number">1</span>;</span>
<span class="line" id="L85"> <span class="tok-kw">if</span> (i == self.cursor_idx) cursor_idx = col;</span>
<span class="line" id="L86"> }</span>
<span class="line" id="L87"> win.showCursor(cursor_idx, <span class="tok-number">0</span>);</span>
<span class="line" id="L88">}</span>
<span class="line" id="L89"></span>
<span class="line" id="L90"><span class="tok-comment">// returns the number of bytes before the cursor</span>
</span>
<span class="line" id="L91"><span class="tok-kw">fn</span> <span class="tok-fn">byteOffsetToCursor</span>(self: TextInput) <span class="tok-type">usize</span> {</span>
<span class="line" id="L92"> <span class="tok-kw">var</span> iter = GraphemeIterator.init(self.buf.items);</span>
<span class="line" id="L93"> <span class="tok-kw">var</span> offset: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L94"> <span class="tok-kw">var</span> i: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L95"> <span class="tok-kw">while</span> (iter.next()) |grapheme| {</span>
<span class="line" id="L96"> <span class="tok-kw">if</span> (i == self.cursor_idx) <span class="tok-kw">break</span>;</span>
<span class="line" id="L97"> offset += grapheme.len;</span>
<span class="line" id="L98"> i += <span class="tok-number">1</span>;</span>
<span class="line" id="L99"> }</span>
<span class="line" id="L100"> <span class="tok-kw">return</span> offset;</span>
<span class="line" id="L101">}</span>
<span class="line" id="L102"></span>
<span class="line" id="L103"><span class="tok-kw">fn</span> <span class="tok-fn">deleteBeforeCursor</span>(self: *TextInput) <span class="tok-type">void</span> {</span>
<span class="line" id="L104"> <span class="tok-kw">var</span> iter = GraphemeIterator.init(self.buf.items);</span>
<span class="line" id="L105"> <span class="tok-kw">var</span> offset: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L106"> <span class="tok-kw">var</span> i: <span class="tok-type">usize</span> = <span class="tok-number">1</span>;</span>
<span class="line" id="L107"> <span class="tok-kw">while</span> (iter.next()) |grapheme| {</span>
<span class="line" id="L108"> <span class="tok-kw">if</span> (i == self.cursor_idx) {</span>
<span class="line" id="L109"> <span class="tok-kw">var</span> j: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L110"> <span class="tok-kw">while</span> (j &lt; grapheme.len) : (j += <span class="tok-number">1</span>) {</span>
<span class="line" id="L111"> _ = self.buf.orderedRemove(offset);</span>
<span class="line" id="L112"> }</span>
<span class="line" id="L113"> self.cursor_idx -= <span class="tok-number">1</span>;</span>
<span class="line" id="L114"> self.grapheme_count -= <span class="tok-number">1</span>;</span>
<span class="line" id="L115"> <span class="tok-kw">return</span>;</span>
<span class="line" id="L116"> }</span>
<span class="line" id="L117"> offset += grapheme.len;</span>
<span class="line" id="L118"> i += <span class="tok-number">1</span>;</span>
<span class="line" id="L119"> }</span>
<span class="line" id="L120">}</span>
<span class="line" id="L121"></span>
<span class="line" id="L122"><span class="tok-kw">fn</span> <span class="tok-fn">deleteAtCursor</span>(self: *TextInput) <span class="tok-type">void</span> {</span>
<span class="line" id="L123"> <span class="tok-kw">var</span> iter = GraphemeIterator.init(self.buf.items);</span>
<span class="line" id="L124"> <span class="tok-kw">var</span> offset: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L125"> <span class="tok-kw">var</span> i: <span class="tok-type">usize</span> = <span class="tok-number">1</span>;</span>
<span class="line" id="L126"> <span class="tok-kw">while</span> (iter.next()) |grapheme| {</span>
<span class="line" id="L127"> <span class="tok-kw">if</span> (i == self.cursor_idx + <span class="tok-number">1</span>) {</span>
<span class="line" id="L128"> <span class="tok-kw">var</span> j: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L129"> <span class="tok-kw">while</span> (j &lt; grapheme.len) : (j += <span class="tok-number">1</span>) {</span>
<span class="line" id="L130"> _ = self.buf.orderedRemove(offset);</span>
<span class="line" id="L131"> }</span>
<span class="line" id="L132"> self.grapheme_count -= <span class="tok-number">1</span>;</span>
<span class="line" id="L133"> <span class="tok-kw">return</span>;</span>
<span class="line" id="L134"> }</span>
<span class="line" id="L135"> offset += grapheme.len;</span>
<span class="line" id="L136"> i += <span class="tok-number">1</span>;</span>
<span class="line" id="L137"> }</span>
<span class="line" id="L138">}</span>
<span class="line" id="L139"></span>
</code></pre></body>
</html>

View file

@ -0,0 +1,124 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>widgets/alignment.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-kw">const</span> Window = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../Window.zig&quot;</span>);</span>
<span class="line" id="L2"></span>
<span class="line" id="L3"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">center</span>(parent: Window, cols: <span class="tok-type">usize</span>, rows: <span class="tok-type">usize</span>) Window {</span>
<span class="line" id="L4"> <span class="tok-kw">const</span> y_off = (parent.height / <span class="tok-number">2</span>) - (rows / <span class="tok-number">2</span>);</span>
<span class="line" id="L5"> <span class="tok-kw">const</span> x_off = (parent.width / <span class="tok-number">2</span>) - (cols / <span class="tok-number">2</span>);</span>
<span class="line" id="L6"> <span class="tok-kw">return</span> parent.initChild(x_off, y_off, .{ .limit = cols }, .{ .limit = rows });</span>
<span class="line" id="L7">}</span>
<span class="line" id="L8"></span>
</code></pre></body>
</html>

View file

@ -0,0 +1,149 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>widgets/border.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-kw">const</span> Cell = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../Cell.zig&quot;</span>);</span>
<span class="line" id="L2"><span class="tok-kw">const</span> Window = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../Window.zig&quot;</span>);</span>
<span class="line" id="L3"></span>
<span class="line" id="L4"><span class="tok-kw">const</span> Style = Cell.Style;</span>
<span class="line" id="L5"><span class="tok-kw">const</span> Character = Cell.Character;</span>
<span class="line" id="L6"></span>
<span class="line" id="L7"><span class="tok-kw">const</span> horizontal = Character{ .grapheme = <span class="tok-str">&quot;&quot;</span>, .width = <span class="tok-number">1</span> };</span>
<span class="line" id="L8"><span class="tok-kw">const</span> vertical = Character{ .grapheme = <span class="tok-str">&quot;&quot;</span>, .width = <span class="tok-number">1</span> };</span>
<span class="line" id="L9"><span class="tok-kw">const</span> top_left = Character{ .grapheme = <span class="tok-str">&quot;&quot;</span>, .width = <span class="tok-number">1</span> };</span>
<span class="line" id="L10"><span class="tok-kw">const</span> top_right = Character{ .grapheme = <span class="tok-str">&quot;&quot;</span>, .width = <span class="tok-number">1</span> };</span>
<span class="line" id="L11"><span class="tok-kw">const</span> bottom_right = Character{ .grapheme = <span class="tok-str">&quot;&quot;</span>, .width = <span class="tok-number">1</span> };</span>
<span class="line" id="L12"><span class="tok-kw">const</span> bottom_left = Character{ .grapheme = <span class="tok-str">&quot;&quot;</span>, .width = <span class="tok-number">1</span> };</span>
<span class="line" id="L13"></span>
<span class="line" id="L14"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">all</span>(win: Window, style: Style) Window {</span>
<span class="line" id="L15"> <span class="tok-kw">const</span> h = win.height;</span>
<span class="line" id="L16"> <span class="tok-kw">const</span> w = win.width;</span>
<span class="line" id="L17"> win.writeCell(<span class="tok-number">0</span>, <span class="tok-number">0</span>, .{ .char = top_left, .style = style });</span>
<span class="line" id="L18"> win.writeCell(<span class="tok-number">0</span>, h - <span class="tok-number">1</span>, .{ .char = bottom_left, .style = style });</span>
<span class="line" id="L19"> win.writeCell(w - <span class="tok-number">1</span>, <span class="tok-number">0</span>, .{ .char = top_right, .style = style });</span>
<span class="line" id="L20"> win.writeCell(w - <span class="tok-number">1</span>, h - <span class="tok-number">1</span>, .{ .char = bottom_right, .style = style });</span>
<span class="line" id="L21"> <span class="tok-kw">var</span> i: <span class="tok-type">usize</span> = <span class="tok-number">1</span>;</span>
<span class="line" id="L22"> <span class="tok-kw">while</span> (i &lt; (h - <span class="tok-number">1</span>)) : (i += <span class="tok-number">1</span>) {</span>
<span class="line" id="L23"> win.writeCell(<span class="tok-number">0</span>, i, .{ .char = vertical, .style = style });</span>
<span class="line" id="L24"> win.writeCell(w - <span class="tok-number">1</span>, i, .{ .char = vertical, .style = style });</span>
<span class="line" id="L25"> }</span>
<span class="line" id="L26"> i = <span class="tok-number">1</span>;</span>
<span class="line" id="L27"> <span class="tok-kw">while</span> (i &lt; w - <span class="tok-number">1</span>) : (i += <span class="tok-number">1</span>) {</span>
<span class="line" id="L28"> win.writeCell(i, <span class="tok-number">0</span>, .{ .char = horizontal, .style = style });</span>
<span class="line" id="L29"> win.writeCell(i, h - <span class="tok-number">1</span>, .{ .char = horizontal, .style = style });</span>
<span class="line" id="L30"> }</span>
<span class="line" id="L31"> <span class="tok-kw">return</span> win.initChild(<span class="tok-number">1</span>, <span class="tok-number">1</span>, .{ .limit = w - <span class="tok-number">2</span> }, .{ .limit = w - <span class="tok-number">2</span> });</span>
<span class="line" id="L32">}</span>
<span class="line" id="L33"></span>
</code></pre></body>
</html>

View file

@ -136,7 +136,7 @@
<span class="line" id="L22"> std.io.StreamSource.SeekError ||</span>
<span class="line" id="L23"> std.io.StreamSource.GetSeekPosError ||</span>
<span class="line" id="L24"> std.fs.File.OpenError ||</span>
<span class="line" id="L25"> <span class="tok-kw">error</span>{ EndOfStream, InvalidData };</span>
<span class="line" id="L25"> <span class="tok-kw">error</span>{ EndOfStream, InvalidData, UnfinishedBits };</span>
<span class="line" id="L26"></span>
<span class="line" id="L27"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Format = <span class="tok-kw">enum</span> {</span>
<span class="line" id="L28"> bmp,</span>

View file

@ -184,189 +184,190 @@
<span class="line" id="L69"> }</span>
<span class="line" id="L70"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (amt &lt; <span class="tok-number">0</span>) {</span>
<span class="line" id="L71"> <span class="tok-kw">const</span> absolute_amt = <span class="tok-builtin">@abs</span>(amt);</span>
<span class="line" id="L72"> <span class="tok-kw">if</span> (absolute_amt &lt;= self.buffered_reader.start) {</span>
<span class="line" id="L73"> self.buffered_reader.start -%= absolute_amt;</span>
<span class="line" id="L74"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L75"> <span class="tok-kw">try</span> self.buffered_reader.unbuffered_reader.context.seekBy(amt - <span class="tok-builtin">@as</span>(<span class="tok-type">i64</span>, <span class="tok-builtin">@intCast</span>(bytes_availables)));</span>
<span class="line" id="L76"> self.resetBufferedReader();</span>
<span class="line" id="L77"> }</span>
<span class="line" id="L78"> }</span>
<span class="line" id="L79"> },</span>
<span class="line" id="L80"> }</span>
<span class="line" id="L81"> }</span>
<span class="line" id="L82"></span>
<span class="line" id="L83"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">getEndPos</span>(self: *Self) GetSeekPosError!<span class="tok-type">u64</span> {</span>
<span class="line" id="L84"> <span class="tok-kw">return</span> self.buffered_reader.unbuffered_reader.context.getEndPos();</span>
<span class="line" id="L85"> }</span>
<span class="line" id="L86"></span>
<span class="line" id="L87"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">getPos</span>(self: *Self) GetSeekPosError!<span class="tok-type">u64</span> {</span>
<span class="line" id="L88"> <span class="tok-kw">switch</span> (self.buffered_reader.unbuffered_reader.context.*) {</span>
<span class="line" id="L89"> .buffer =&gt; |*actual_reader| {</span>
<span class="line" id="L90"> <span class="tok-kw">return</span> actual_reader.getPos();</span>
<span class="line" id="L91"> },</span>
<span class="line" id="L92"> .const_buffer =&gt; |*actual_reader| {</span>
<span class="line" id="L93"> <span class="tok-kw">return</span> actual_reader.getPos();</span>
<span class="line" id="L94"> },</span>
<span class="line" id="L95"> .file =&gt; {</span>
<span class="line" id="L96"> <span class="tok-kw">if</span> (self.buffered_reader.unbuffered_reader.context.getPos()) |position| {</span>
<span class="line" id="L97"> <span class="tok-kw">return</span> position - (self.buffered_reader.end - self.buffered_reader.start);</span>
<span class="line" id="L98"> } <span class="tok-kw">else</span> |err| {</span>
<span class="line" id="L99"> <span class="tok-kw">return</span> err;</span>
<span class="line" id="L100"> }</span>
<span class="line" id="L101"> },</span>
<span class="line" id="L102"> }</span>
<span class="line" id="L103"> }</span>
<span class="line" id="L104"></span>
<span class="line" id="L105"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">reader</span>(self: *Self) Reader {</span>
<span class="line" id="L106"> <span class="tok-kw">return</span> .{ .context = self };</span>
<span class="line" id="L107"> }</span>
<span class="line" id="L108"></span>
<span class="line" id="L109"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">seekableStream</span>(self: *Self) SeekableStream {</span>
<span class="line" id="L110"> <span class="tok-kw">return</span> .{ .context = self };</span>
<span class="line" id="L111"> }</span>
<span class="line" id="L112"></span>
<span class="line" id="L113"> <span class="tok-kw">fn</span> <span class="tok-fn">resetBufferedReader</span>(self: *Self) <span class="tok-type">void</span> {</span>
<span class="line" id="L114"> self.buffered_reader.start = <span class="tok-number">0</span>;</span>
<span class="line" id="L115"> self.buffered_reader.end = <span class="tok-number">0</span>;</span>
<span class="line" id="L116"> }</span>
<span class="line" id="L117"> };</span>
<span class="line" id="L118">}</span>
<span class="line" id="L119"></span>
<span class="line" id="L120"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">bufferedStreamSourceReader</span>(stream: *std.io.StreamSource) BufferedStreamSourceReader(DefaultBufferSize) {</span>
<span class="line" id="L121"> <span class="tok-kw">return</span> .{ .buffered_reader = .{ .unbuffered_reader = stream.reader() } };</span>
<span class="line" id="L122">}</span>
<span class="line" id="L123"></span>
<span class="line" id="L124"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">bufferedStreamSourceReaderWithSize</span>(<span class="tok-kw">comptime</span> buffer_size: <span class="tok-type">usize</span>, stream: *std.io.StreamSource) BufferedStreamSourceReader(buffer_size) {</span>
<span class="line" id="L125"> <span class="tok-kw">return</span> .{ .buffered_reader = .{ .unbuffered_reader = stream.reader() } };</span>
<span class="line" id="L126">}</span>
<span class="line" id="L127"></span>
<span class="line" id="L128"><span class="tok-comment">// An buffered stream that can writer and seek StreamSource</span>
<span class="line" id="L72"> <span class="tok-kw">const</span> absolute_amt_usize = std.math.cast(<span class="tok-type">usize</span>, absolute_amt) <span class="tok-kw">orelse</span> std.math.maxInt(<span class="tok-type">usize</span>);</span>
<span class="line" id="L73"> <span class="tok-kw">if</span> (absolute_amt_usize &lt;= self.buffered_reader.start) {</span>
<span class="line" id="L74"> self.buffered_reader.start -%= absolute_amt_usize;</span>
<span class="line" id="L75"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L76"> <span class="tok-kw">try</span> self.buffered_reader.unbuffered_reader.context.seekBy(amt - <span class="tok-builtin">@as</span>(<span class="tok-type">i64</span>, <span class="tok-builtin">@intCast</span>(bytes_availables)));</span>
<span class="line" id="L77"> self.resetBufferedReader();</span>
<span class="line" id="L78"> }</span>
<span class="line" id="L79"> }</span>
<span class="line" id="L80"> },</span>
<span class="line" id="L81"> }</span>
<span class="line" id="L82"> }</span>
<span class="line" id="L83"></span>
<span class="line" id="L84"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">getEndPos</span>(self: *Self) GetSeekPosError!<span class="tok-type">u64</span> {</span>
<span class="line" id="L85"> <span class="tok-kw">return</span> self.buffered_reader.unbuffered_reader.context.getEndPos();</span>
<span class="line" id="L86"> }</span>
<span class="line" id="L87"></span>
<span class="line" id="L88"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">getPos</span>(self: *Self) GetSeekPosError!<span class="tok-type">u64</span> {</span>
<span class="line" id="L89"> <span class="tok-kw">switch</span> (self.buffered_reader.unbuffered_reader.context.*) {</span>
<span class="line" id="L90"> .buffer =&gt; |*actual_reader| {</span>
<span class="line" id="L91"> <span class="tok-kw">return</span> actual_reader.getPos();</span>
<span class="line" id="L92"> },</span>
<span class="line" id="L93"> .const_buffer =&gt; |*actual_reader| {</span>
<span class="line" id="L94"> <span class="tok-kw">return</span> actual_reader.getPos();</span>
<span class="line" id="L95"> },</span>
<span class="line" id="L96"> .file =&gt; {</span>
<span class="line" id="L97"> <span class="tok-kw">if</span> (self.buffered_reader.unbuffered_reader.context.getPos()) |position| {</span>
<span class="line" id="L98"> <span class="tok-kw">return</span> position - (self.buffered_reader.end - self.buffered_reader.start);</span>
<span class="line" id="L99"> } <span class="tok-kw">else</span> |err| {</span>
<span class="line" id="L100"> <span class="tok-kw">return</span> err;</span>
<span class="line" id="L101"> }</span>
<span class="line" id="L102"> },</span>
<span class="line" id="L103"> }</span>
<span class="line" id="L104"> }</span>
<span class="line" id="L105"></span>
<span class="line" id="L106"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">reader</span>(self: *Self) Reader {</span>
<span class="line" id="L107"> <span class="tok-kw">return</span> .{ .context = self };</span>
<span class="line" id="L108"> }</span>
<span class="line" id="L109"></span>
<span class="line" id="L110"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">seekableStream</span>(self: *Self) SeekableStream {</span>
<span class="line" id="L111"> <span class="tok-kw">return</span> .{ .context = self };</span>
<span class="line" id="L112"> }</span>
<span class="line" id="L113"></span>
<span class="line" id="L114"> <span class="tok-kw">fn</span> <span class="tok-fn">resetBufferedReader</span>(self: *Self) <span class="tok-type">void</span> {</span>
<span class="line" id="L115"> self.buffered_reader.start = <span class="tok-number">0</span>;</span>
<span class="line" id="L116"> self.buffered_reader.end = <span class="tok-number">0</span>;</span>
<span class="line" id="L117"> }</span>
<span class="line" id="L118"> };</span>
<span class="line" id="L119">}</span>
<span class="line" id="L120"></span>
<span class="line" id="L121"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">bufferedStreamSourceReader</span>(stream: *std.io.StreamSource) BufferedStreamSourceReader(DefaultBufferSize) {</span>
<span class="line" id="L122"> <span class="tok-kw">return</span> .{ .buffered_reader = .{ .unbuffered_reader = stream.reader() } };</span>
<span class="line" id="L123">}</span>
<span class="line" id="L124"></span>
<span class="line" id="L125"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">bufferedStreamSourceReaderWithSize</span>(<span class="tok-kw">comptime</span> buffer_size: <span class="tok-type">usize</span>, stream: *std.io.StreamSource) BufferedStreamSourceReader(buffer_size) {</span>
<span class="line" id="L126"> <span class="tok-kw">return</span> .{ .buffered_reader = .{ .unbuffered_reader = stream.reader() } };</span>
<span class="line" id="L127">}</span>
<span class="line" id="L128"></span>
<span class="line" id="L129"><span class="tok-comment">// An buffered stream that can writer and seek StreamSource</span>
</span>
<span class="line" id="L129"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">BufferedStreamSourceWriter</span>(<span class="tok-kw">comptime</span> BufferSize: <span class="tok-type">usize</span>) <span class="tok-type">type</span> {</span>
<span class="line" id="L130"> <span class="tok-kw">return</span> <span class="tok-kw">struct</span> {</span>
<span class="line" id="L131"> buffered_writer: std.io.BufferedWriter(BufferSize, std.io.StreamSource.Writer),</span>
<span class="line" id="L132"></span>
<span class="line" id="L133"> <span class="tok-kw">pub</span> <span class="tok-kw">const</span> WriteError = std.io.StreamSource.WriteError;</span>
<span class="line" id="L134"> <span class="tok-kw">pub</span> <span class="tok-kw">const</span> SeekError = std.io.StreamSource.SeekError;</span>
<span class="line" id="L135"> <span class="tok-kw">pub</span> <span class="tok-kw">const</span> GetSeekPosError = std.io.StreamSource.GetSeekPosError;</span>
<span class="line" id="L136"></span>
<span class="line" id="L137"> <span class="tok-kw">const</span> Self = <span class="tok-builtin">@This</span>();</span>
<span class="line" id="L138"></span>
<span class="line" id="L139"> <span class="tok-kw">pub</span> <span class="tok-kw">const</span> Writer = std.io.Writer(*Self, WriteError, write);</span>
<span class="line" id="L140"> <span class="tok-kw">pub</span> <span class="tok-kw">const</span> SeekableStream = std.io.SeekableStream(</span>
<span class="line" id="L141"> *Self,</span>
<span class="line" id="L142"> SeekError,</span>
<span class="line" id="L143"> GetSeekPosError,</span>
<span class="line" id="L144"> seekTo,</span>
<span class="line" id="L145"> seekBy,</span>
<span class="line" id="L146"> getPos,</span>
<span class="line" id="L147"> getEndPos,</span>
<span class="line" id="L148"> );</span>
<span class="line" id="L149"></span>
<span class="line" id="L150"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">write</span>(self: *Self, bytes: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>) WriteError!<span class="tok-type">usize</span> {</span>
<span class="line" id="L151"> <span class="tok-kw">return</span> <span class="tok-kw">switch</span> (self.buffered_writer.unbuffered_writer.context.*) {</span>
<span class="line" id="L152"> .buffer =&gt; |*actual_writer| actual_writer.write(bytes),</span>
<span class="line" id="L153"> .const_buffer =&gt; <span class="tok-kw">error</span>.AccessDenied,</span>
<span class="line" id="L154"> .file =&gt; self.buffered_writer.write(bytes),</span>
<span class="line" id="L155"> };</span>
<span class="line" id="L156"> }</span>
<span class="line" id="L157"></span>
<span class="line" id="L158"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">seekTo</span>(self: *Self, pos: <span class="tok-type">u64</span>) SeekError!<span class="tok-type">void</span> {</span>
<span class="line" id="L159"> <span class="tok-kw">switch</span> (self.buffered_writer.unbuffered_writer.context.*) {</span>
<span class="line" id="L160"> .buffer =&gt; |*actual_writer| {</span>
<span class="line" id="L161"> <span class="tok-kw">return</span> actual_writer.seekTo(pos);</span>
<span class="line" id="L162"> },</span>
<span class="line" id="L163"> .const_buffer =&gt; |*actual_writer| {</span>
<span class="line" id="L164"> <span class="tok-kw">return</span> actual_writer.seekTo(pos);</span>
<span class="line" id="L165"> },</span>
<span class="line" id="L166"> .file =&gt; {</span>
<span class="line" id="L167"> <span class="tok-kw">try</span> self.buffered_writer.flush();</span>
<span class="line" id="L168"> <span class="tok-kw">try</span> self.buffered_writer.buffered_writer.context.seekTo(pos);</span>
<span class="line" id="L169"> },</span>
<span class="line" id="L170"> }</span>
<span class="line" id="L171"> }</span>
<span class="line" id="L172"></span>
<span class="line" id="L173"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">seekBy</span>(self: *Self, amt: <span class="tok-type">i64</span>) SeekError!<span class="tok-type">void</span> {</span>
<span class="line" id="L174"> <span class="tok-kw">switch</span> (self.buffered_writer.unbuffered_writer.context.*) {</span>
<span class="line" id="L175"> .buffer =&gt; |*actual_writer| {</span>
<span class="line" id="L176"> <span class="tok-kw">return</span> actual_writer.seekBy(amt);</span>
<span class="line" id="L177"> },</span>
<span class="line" id="L178"> .const_buffer =&gt; |*actual_writer| {</span>
<span class="line" id="L179"> <span class="tok-kw">return</span> actual_writer.seekBy(amt);</span>
<span class="line" id="L180"> },</span>
<span class="line" id="L181"> .file =&gt; {</span>
<span class="line" id="L182"> <span class="tok-kw">if</span> (amt &lt; <span class="tok-number">0</span>) {</span>
<span class="line" id="L183"> <span class="tok-kw">const</span> abs_amt = <span class="tok-builtin">@abs</span>(amt);</span>
<span class="line" id="L184"> <span class="tok-kw">if</span> (abs_amt &lt;= self.buffered_writer.end) {</span>
<span class="line" id="L185"> self.buffered_writer.end -= abs_amt;</span>
<span class="line" id="L186"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L187"> self.buffered_writer.flush() <span class="tok-kw">catch</span> {</span>
<span class="line" id="L188"> <span class="tok-kw">return</span> <span class="tok-kw">error</span>.Unseekable;</span>
<span class="line" id="L189"> };</span>
<span class="line" id="L190"> <span class="tok-kw">try</span> self.buffered_writer.unbuffered_writer.context.seekBy(amt);</span>
<span class="line" id="L191"> }</span>
<span class="line" id="L192"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L193"> <span class="tok-kw">const</span> amt_usize: <span class="tok-type">usize</span> = <span class="tok-builtin">@intCast</span>(amt);</span>
<span class="line" id="L194"></span>
<span class="line" id="L195"> <span class="tok-kw">if</span> (self.buffered_writer.end + amt_usize &lt; self.buffered_writer.buf.len) {</span>
<span class="line" id="L196"> self.buffered_writer.end += amt_usize;</span>
<span class="line" id="L197"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L198"> self.buffered_writer.flush() <span class="tok-kw">catch</span> {</span>
<span class="line" id="L199"> <span class="tok-kw">return</span> <span class="tok-kw">error</span>.Unseekable;</span>
<span class="line" id="L200"> };</span>
<span class="line" id="L201"> <span class="tok-kw">try</span> self.buffered_writer.unbuffered_writer.context.seekBy(amt);</span>
<span class="line" id="L202"> }</span>
<span class="line" id="L203"> }</span>
<span class="line" id="L204"> },</span>
<span class="line" id="L205"> }</span>
<span class="line" id="L206"> }</span>
<span class="line" id="L207"></span>
<span class="line" id="L208"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">getEndPos</span>(self: *Self) GetSeekPosError!<span class="tok-type">u64</span> {</span>
<span class="line" id="L209"> <span class="tok-kw">return</span> self.buffered_writer.unbuffered_writer.context.getEndPos();</span>
<span class="line" id="L210"> }</span>
<span class="line" id="L211"></span>
<span class="line" id="L212"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">getPos</span>(self: *Self) GetSeekPosError!<span class="tok-type">u64</span> {</span>
<span class="line" id="L213"> <span class="tok-kw">switch</span> (self.buffered_writer.unbuffered_writer.context.*) {</span>
<span class="line" id="L214"> .buffer =&gt; |*actual_writer| {</span>
<span class="line" id="L215"> <span class="tok-kw">return</span> actual_writer.getPos();</span>
<span class="line" id="L216"> },</span>
<span class="line" id="L217"> .const_buffer =&gt; |*actual_writer| {</span>
<span class="line" id="L218"> <span class="tok-kw">return</span> actual_writer.getPos();</span>
<span class="line" id="L219"> },</span>
<span class="line" id="L220"> .file =&gt; {</span>
<span class="line" id="L221"> <span class="tok-kw">if</span> (self.buffered_writer.unbuffered_writer.context.getPos()) |position| {</span>
<span class="line" id="L222"> <span class="tok-kw">return</span> position + self.buffered_writer.end;</span>
<span class="line" id="L223"> } <span class="tok-kw">else</span> |err| {</span>
<span class="line" id="L224"> <span class="tok-kw">return</span> err;</span>
<span class="line" id="L225"> }</span>
<span class="line" id="L226"> },</span>
<span class="line" id="L227"> }</span>
<span class="line" id="L228"> }</span>
<span class="line" id="L229"></span>
<span class="line" id="L230"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">writer</span>(self: *Self) Writer {</span>
<span class="line" id="L231"> <span class="tok-kw">return</span> .{ .context = self };</span>
<span class="line" id="L232"> }</span>
<span class="line" id="L233"></span>
<span class="line" id="L234"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">seekableStream</span>(self: *Self) SeekableStream {</span>
<span class="line" id="L235"> <span class="tok-kw">return</span> .{ .context = self };</span>
<span class="line" id="L236"> }</span>
<span class="line" id="L237"></span>
<span class="line" id="L238"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">flush</span>(self: *Self) WriteError!<span class="tok-type">void</span> {</span>
<span class="line" id="L239"> <span class="tok-kw">return</span> <span class="tok-kw">switch</span> (self.buffered_writer.unbuffered_writer.context.*) {</span>
<span class="line" id="L240"> .file =&gt; self.buffered_writer.flush(),</span>
<span class="line" id="L241"> <span class="tok-kw">else</span> =&gt; {},</span>
<span class="line" id="L242"> };</span>
<span class="line" id="L243"> }</span>
<span class="line" id="L244"> };</span>
<span class="line" id="L245">}</span>
<span class="line" id="L246"></span>
<span class="line" id="L247"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">bufferedStreamSourceWriter</span>(stream: *std.io.StreamSource) BufferedStreamSourceWriter(DefaultBufferSize) {</span>
<span class="line" id="L248"> <span class="tok-kw">return</span> .{ .buffered_writer = .{ .unbuffered_writer = stream.writer() } };</span>
<span class="line" id="L249">}</span>
<span class="line" id="L250"></span>
<span class="line" id="L251"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">bufferedStreamSourceWriterWithSize</span>(<span class="tok-kw">comptime</span> buffer_size: <span class="tok-type">usize</span>, stream: *std.io.StreamSource) BufferedStreamSourceWriter(buffer_size) {</span>
<span class="line" id="L252"> <span class="tok-kw">return</span> .{ .buffered_writer = .{ .unbuffered_writer = stream.writer() } };</span>
<span class="line" id="L253">}</span>
<span class="line" id="L254"></span>
<span class="line" id="L130"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">BufferedStreamSourceWriter</span>(<span class="tok-kw">comptime</span> BufferSize: <span class="tok-type">usize</span>) <span class="tok-type">type</span> {</span>
<span class="line" id="L131"> <span class="tok-kw">return</span> <span class="tok-kw">struct</span> {</span>
<span class="line" id="L132"> buffered_writer: std.io.BufferedWriter(BufferSize, std.io.StreamSource.Writer),</span>
<span class="line" id="L133"></span>
<span class="line" id="L134"> <span class="tok-kw">pub</span> <span class="tok-kw">const</span> WriteError = std.io.StreamSource.WriteError;</span>
<span class="line" id="L135"> <span class="tok-kw">pub</span> <span class="tok-kw">const</span> SeekError = std.io.StreamSource.SeekError;</span>
<span class="line" id="L136"> <span class="tok-kw">pub</span> <span class="tok-kw">const</span> GetSeekPosError = std.io.StreamSource.GetSeekPosError;</span>
<span class="line" id="L137"></span>
<span class="line" id="L138"> <span class="tok-kw">const</span> Self = <span class="tok-builtin">@This</span>();</span>
<span class="line" id="L139"></span>
<span class="line" id="L140"> <span class="tok-kw">pub</span> <span class="tok-kw">const</span> Writer = std.io.Writer(*Self, WriteError, write);</span>
<span class="line" id="L141"> <span class="tok-kw">pub</span> <span class="tok-kw">const</span> SeekableStream = std.io.SeekableStream(</span>
<span class="line" id="L142"> *Self,</span>
<span class="line" id="L143"> SeekError,</span>
<span class="line" id="L144"> GetSeekPosError,</span>
<span class="line" id="L145"> seekTo,</span>
<span class="line" id="L146"> seekBy,</span>
<span class="line" id="L147"> getPos,</span>
<span class="line" id="L148"> getEndPos,</span>
<span class="line" id="L149"> );</span>
<span class="line" id="L150"></span>
<span class="line" id="L151"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">write</span>(self: *Self, bytes: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>) WriteError!<span class="tok-type">usize</span> {</span>
<span class="line" id="L152"> <span class="tok-kw">return</span> <span class="tok-kw">switch</span> (self.buffered_writer.unbuffered_writer.context.*) {</span>
<span class="line" id="L153"> .buffer =&gt; |*actual_writer| actual_writer.write(bytes),</span>
<span class="line" id="L154"> .const_buffer =&gt; <span class="tok-kw">error</span>.AccessDenied,</span>
<span class="line" id="L155"> .file =&gt; self.buffered_writer.write(bytes),</span>
<span class="line" id="L156"> };</span>
<span class="line" id="L157"> }</span>
<span class="line" id="L158"></span>
<span class="line" id="L159"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">seekTo</span>(self: *Self, pos: <span class="tok-type">u64</span>) SeekError!<span class="tok-type">void</span> {</span>
<span class="line" id="L160"> <span class="tok-kw">switch</span> (self.buffered_writer.unbuffered_writer.context.*) {</span>
<span class="line" id="L161"> .buffer =&gt; |*actual_writer| {</span>
<span class="line" id="L162"> <span class="tok-kw">return</span> actual_writer.seekTo(pos);</span>
<span class="line" id="L163"> },</span>
<span class="line" id="L164"> .const_buffer =&gt; |*actual_writer| {</span>
<span class="line" id="L165"> <span class="tok-kw">return</span> actual_writer.seekTo(pos);</span>
<span class="line" id="L166"> },</span>
<span class="line" id="L167"> .file =&gt; {</span>
<span class="line" id="L168"> <span class="tok-kw">try</span> self.buffered_writer.flush();</span>
<span class="line" id="L169"> <span class="tok-kw">try</span> self.buffered_writer.buffered_writer.context.seekTo(pos);</span>
<span class="line" id="L170"> },</span>
<span class="line" id="L171"> }</span>
<span class="line" id="L172"> }</span>
<span class="line" id="L173"></span>
<span class="line" id="L174"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">seekBy</span>(self: *Self, amt: <span class="tok-type">i64</span>) SeekError!<span class="tok-type">void</span> {</span>
<span class="line" id="L175"> <span class="tok-kw">switch</span> (self.buffered_writer.unbuffered_writer.context.*) {</span>
<span class="line" id="L176"> .buffer =&gt; |*actual_writer| {</span>
<span class="line" id="L177"> <span class="tok-kw">return</span> actual_writer.seekBy(amt);</span>
<span class="line" id="L178"> },</span>
<span class="line" id="L179"> .const_buffer =&gt; |*actual_writer| {</span>
<span class="line" id="L180"> <span class="tok-kw">return</span> actual_writer.seekBy(amt);</span>
<span class="line" id="L181"> },</span>
<span class="line" id="L182"> .file =&gt; {</span>
<span class="line" id="L183"> <span class="tok-kw">if</span> (amt &lt; <span class="tok-number">0</span>) {</span>
<span class="line" id="L184"> <span class="tok-kw">const</span> abs_amt = <span class="tok-builtin">@abs</span>(amt);</span>
<span class="line" id="L185"> <span class="tok-kw">if</span> (abs_amt &lt;= self.buffered_writer.end) {</span>
<span class="line" id="L186"> self.buffered_writer.end -= abs_amt;</span>
<span class="line" id="L187"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L188"> self.buffered_writer.flush() <span class="tok-kw">catch</span> {</span>
<span class="line" id="L189"> <span class="tok-kw">return</span> <span class="tok-kw">error</span>.Unseekable;</span>
<span class="line" id="L190"> };</span>
<span class="line" id="L191"> <span class="tok-kw">try</span> self.buffered_writer.unbuffered_writer.context.seekBy(amt);</span>
<span class="line" id="L192"> }</span>
<span class="line" id="L193"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L194"> <span class="tok-kw">const</span> amt_usize: <span class="tok-type">usize</span> = <span class="tok-builtin">@intCast</span>(amt);</span>
<span class="line" id="L195"></span>
<span class="line" id="L196"> <span class="tok-kw">if</span> (self.buffered_writer.end + amt_usize &lt; self.buffered_writer.buf.len) {</span>
<span class="line" id="L197"> self.buffered_writer.end += amt_usize;</span>
<span class="line" id="L198"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L199"> self.buffered_writer.flush() <span class="tok-kw">catch</span> {</span>
<span class="line" id="L200"> <span class="tok-kw">return</span> <span class="tok-kw">error</span>.Unseekable;</span>
<span class="line" id="L201"> };</span>
<span class="line" id="L202"> <span class="tok-kw">try</span> self.buffered_writer.unbuffered_writer.context.seekBy(amt);</span>
<span class="line" id="L203"> }</span>
<span class="line" id="L204"> }</span>
<span class="line" id="L205"> },</span>
<span class="line" id="L206"> }</span>
<span class="line" id="L207"> }</span>
<span class="line" id="L208"></span>
<span class="line" id="L209"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">getEndPos</span>(self: *Self) GetSeekPosError!<span class="tok-type">u64</span> {</span>
<span class="line" id="L210"> <span class="tok-kw">return</span> self.buffered_writer.unbuffered_writer.context.getEndPos();</span>
<span class="line" id="L211"> }</span>
<span class="line" id="L212"></span>
<span class="line" id="L213"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">getPos</span>(self: *Self) GetSeekPosError!<span class="tok-type">u64</span> {</span>
<span class="line" id="L214"> <span class="tok-kw">switch</span> (self.buffered_writer.unbuffered_writer.context.*) {</span>
<span class="line" id="L215"> .buffer =&gt; |*actual_writer| {</span>
<span class="line" id="L216"> <span class="tok-kw">return</span> actual_writer.getPos();</span>
<span class="line" id="L217"> },</span>
<span class="line" id="L218"> .const_buffer =&gt; |*actual_writer| {</span>
<span class="line" id="L219"> <span class="tok-kw">return</span> actual_writer.getPos();</span>
<span class="line" id="L220"> },</span>
<span class="line" id="L221"> .file =&gt; {</span>
<span class="line" id="L222"> <span class="tok-kw">if</span> (self.buffered_writer.unbuffered_writer.context.getPos()) |position| {</span>
<span class="line" id="L223"> <span class="tok-kw">return</span> position + self.buffered_writer.end;</span>
<span class="line" id="L224"> } <span class="tok-kw">else</span> |err| {</span>
<span class="line" id="L225"> <span class="tok-kw">return</span> err;</span>
<span class="line" id="L226"> }</span>
<span class="line" id="L227"> },</span>
<span class="line" id="L228"> }</span>
<span class="line" id="L229"> }</span>
<span class="line" id="L230"></span>
<span class="line" id="L231"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">writer</span>(self: *Self) Writer {</span>
<span class="line" id="L232"> <span class="tok-kw">return</span> .{ .context = self };</span>
<span class="line" id="L233"> }</span>
<span class="line" id="L234"></span>
<span class="line" id="L235"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">seekableStream</span>(self: *Self) SeekableStream {</span>
<span class="line" id="L236"> <span class="tok-kw">return</span> .{ .context = self };</span>
<span class="line" id="L237"> }</span>
<span class="line" id="L238"></span>
<span class="line" id="L239"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">flush</span>(self: *Self) WriteError!<span class="tok-type">void</span> {</span>
<span class="line" id="L240"> <span class="tok-kw">return</span> <span class="tok-kw">switch</span> (self.buffered_writer.unbuffered_writer.context.*) {</span>
<span class="line" id="L241"> .file =&gt; self.buffered_writer.flush(),</span>
<span class="line" id="L242"> <span class="tok-kw">else</span> =&gt; {},</span>
<span class="line" id="L243"> };</span>
<span class="line" id="L244"> }</span>
<span class="line" id="L245"> };</span>
<span class="line" id="L246">}</span>
<span class="line" id="L247"></span>
<span class="line" id="L248"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">bufferedStreamSourceWriter</span>(stream: *std.io.StreamSource) BufferedStreamSourceWriter(DefaultBufferSize) {</span>
<span class="line" id="L249"> <span class="tok-kw">return</span> .{ .buffered_writer = .{ .unbuffered_writer = stream.writer() } };</span>
<span class="line" id="L250">}</span>
<span class="line" id="L251"></span>
<span class="line" id="L252"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">bufferedStreamSourceWriterWithSize</span>(<span class="tok-kw">comptime</span> buffer_size: <span class="tok-type">usize</span>, stream: *std.io.StreamSource) BufferedStreamSourceWriter(buffer_size) {</span>
<span class="line" id="L253"> <span class="tok-kw">return</span> .{ .buffered_writer = .{ .unbuffered_writer = stream.writer() } };</span>
<span class="line" id="L254">}</span>
<span class="line" id="L255"></span>
</code></pre></body>
</html>

View file

@ -190,7 +190,7 @@
<span class="line" id="L72"> <span class="tok-kw">return</span> load(stream, allocator, default_options.get());</span>
<span class="line" id="L73"> }</span>
<span class="line" id="L74"></span>
<span class="line" id="L75"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">writeImage</span>(allocator: Allocator, write_stream: *Image.Stream, image: Image, encoder_options: Image.EncoderOptions) ImageWriteError!<span class="tok-type">void</span> {</span>
<span class="line" id="L75"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">writeImage</span>(_: Allocator, write_stream: *Image.Stream, image: Image, encoder_options: Image.EncoderOptions) ImageWriteError!<span class="tok-type">void</span> {</span>
<span class="line" id="L76"> <span class="tok-kw">const</span> options = encoder_options.png;</span>
<span class="line" id="L77"></span>
<span class="line" id="L78"> <span class="tok-kw">try</span> ensureWritable(image);</span>
@ -207,10 +207,10 @@
<span class="line" id="L89"></span>
<span class="line" id="L90"> std.debug.assert(header.isValid());</span>
<span class="line" id="L91"></span>
<span class="line" id="L92"> <span class="tok-kw">try</span> write(allocator, write_stream, image.pixels, header, options.filter_choice);</span>
<span class="line" id="L92"> <span class="tok-kw">try</span> write(write_stream, image.pixels, header, options.filter_choice);</span>
<span class="line" id="L93"> }</span>
<span class="line" id="L94"></span>
<span class="line" id="L95"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">write</span>(allocator: Allocator, write_stream: *Image.Stream, pixels: color.PixelStorage, header: HeaderData, filter_choice: filter.FilterChoice) ImageWriteError!<span class="tok-type">void</span> {</span>
<span class="line" id="L95"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">write</span>(write_stream: *Image.Stream, pixels: color.PixelStorage, header: HeaderData, filter_choice: filter.FilterChoice) ImageWriteError!<span class="tok-type">void</span> {</span>
<span class="line" id="L96"> <span class="tok-kw">if</span> (header.interlace_method != .none)</span>
<span class="line" id="L97"> <span class="tok-kw">return</span> ImageWriteError.Unsupported;</span>
<span class="line" id="L98"> <span class="tok-kw">if</span> (header.compression_method != .deflate)</span>
@ -227,7 +227,7 @@
<span class="line" id="L109"> <span class="tok-kw">try</span> writeTransparencyInfo(writer, pixels); <span class="tok-comment">// TODO: pixel format where there is no transparency</span>
</span>
<span class="line" id="L110"> }</span>
<span class="line" id="L111"> <span class="tok-kw">try</span> writeData(allocator, writer, pixels, header, filter_choice);</span>
<span class="line" id="L111"> <span class="tok-kw">try</span> writeData(writer, pixels, header, filter_choice);</span>
<span class="line" id="L112"> <span class="tok-kw">try</span> writeTrailer(writer);</span>
<span class="line" id="L113"> }</span>
<span class="line" id="L114"></span>
@ -273,7 +273,7 @@
<span class="line" id="L151"></span>
<span class="line" id="L152"> <span class="tok-comment">// IDAT (multiple maybe)</span>
</span>
<span class="line" id="L153"> <span class="tok-kw">fn</span> <span class="tok-fn">writeData</span>(allocator: Allocator, writer: <span class="tok-kw">anytype</span>, pixels: color.PixelStorage, header: HeaderData, filter_choice: filter.FilterChoice) ImageWriteError!<span class="tok-type">void</span> {</span>
<span class="line" id="L153"> <span class="tok-kw">fn</span> <span class="tok-fn">writeData</span>(writer: <span class="tok-kw">anytype</span>, pixels: color.PixelStorage, header: HeaderData, filter_choice: filter.FilterChoice) ImageWriteError!<span class="tok-type">void</span> {</span>
<span class="line" id="L154"> <span class="tok-comment">// Note: there may be more than 1 chunk</span>
</span>
<span class="line" id="L155"> <span class="tok-comment">// TODO: provide choice of how much it buffers (how much data per idat chunk)</span>
@ -282,7 +282,7 @@
<span class="line" id="L157"> <span class="tok-kw">const</span> chunk_wr = chunks.writer();</span>
<span class="line" id="L158"></span>
<span class="line" id="L159"> <span class="tok-kw">var</span> zlib: ZlibCompressor(<span class="tok-builtin">@TypeOf</span>(chunk_wr)) = <span class="tok-null">undefined</span>;</span>
<span class="line" id="L160"> <span class="tok-kw">try</span> zlib.init(allocator, chunk_wr);</span>
<span class="line" id="L160"> <span class="tok-kw">try</span> zlib.init(chunk_wr);</span>
<span class="line" id="L161"></span>
<span class="line" id="L162"> <span class="tok-kw">try</span> zlib.begin();</span>
<span class="line" id="L163"> <span class="tok-kw">try</span> filter.filter(zlib.writer(), pixels, filter_choice, header);</span>

View file

@ -160,7 +160,7 @@
<span class="line" id="L46"> .specified =&gt; |f| f,</span>
<span class="line" id="L47"> };</span>
<span class="line" id="L48"></span>
<span class="line" id="L49"> <span class="tok-kw">try</span> writer.writeByte(<span class="tok-builtin">@intFromEnum</span>(filter_type));</span>
<span class="line" id="L49"> writer.writeByte(<span class="tok-builtin">@intFromEnum</span>(filter_type)) <span class="tok-kw">catch</span> <span class="tok-kw">return</span> Image.WriteError.InvalidData;</span>
<span class="line" id="L50"></span>
<span class="line" id="L51"> <span class="tok-kw">for</span> (<span class="tok-number">0</span>..scanline.asBytes().len) |byte_index| {</span>
<span class="line" id="L52"> <span class="tok-kw">const</span> i = <span class="tok-kw">if</span> (builtin.target.cpu.arch.endian() == .little) pixelByteSwappedIndex(scanline, byte_index) <span class="tok-kw">else</span> byte_index;</span>
@ -178,7 +178,7 @@
<span class="line" id="L64"> .paeth =&gt; sample -% paeth(previous, above, above_previous),</span>
<span class="line" id="L65"> };</span>
<span class="line" id="L66"></span>
<span class="line" id="L67"> <span class="tok-kw">try</span> writer.writeByte(byte);</span>
<span class="line" id="L67"> writer.writeByte(byte) <span class="tok-kw">catch</span> <span class="tok-kw">return</span> Image.WriteError.InvalidData;</span>
<span class="line" id="L68"> }</span>
<span class="line" id="L69"> previous_scanline = scanline;</span>
<span class="line" id="L70"> }</span>

File diff suppressed because it is too large Load diff

View file

@ -114,7 +114,7 @@
<body>
<pre><code><span class="line" id="L1"><span class="tok-kw">const</span> std = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;std&quot;</span>);</span>
<span class="line" id="L2"><span class="tok-kw">const</span> io = std.io;</span>
<span class="line" id="L3"><span class="tok-kw">const</span> deflate = std.compress.deflate;</span>
<span class="line" id="L3"><span class="tok-kw">const</span> deflate = std.compress.flate;</span>
<span class="line" id="L4"></span>
<span class="line" id="L5"><span class="tok-comment">/// Zlib Compressor (Deflate) with a writer interface</span></span>
<span class="line" id="L6"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">ZlibCompressor</span>(<span class="tok-kw">comptime</span> WriterType: <span class="tok-type">type</span>) <span class="tok-type">type</span> {</span>
@ -129,9 +129,9 @@
</span>
<span class="line" id="L15"> <span class="tok-comment">/// Inits a zlibcompressor</span></span>
<span class="line" id="L16"> <span class="tok-comment">/// This is made this way because not doing it in place segfaults for a reason</span></span>
<span class="line" id="L17"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">init</span>(self: *Self, alloc: std.mem.Allocator, stream: WriterType) !<span class="tok-type">void</span> {</span>
<span class="line" id="L17"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">init</span>(self: *Self, stream: WriterType) !<span class="tok-type">void</span> {</span>
<span class="line" id="L18"> self.raw_writer = stream;</span>
<span class="line" id="L19"> self.compressor = <span class="tok-kw">try</span> deflate.compressor(alloc, self.raw_writer, .{});</span>
<span class="line" id="L19"> self.compressor = <span class="tok-kw">try</span> deflate.compressor(self.raw_writer, .{});</span>
<span class="line" id="L20"> self.adler = std.hash.Adler32.init();</span>
<span class="line" id="L21"> }</span>
<span class="line" id="L22"></span>
@ -158,7 +158,7 @@
<span class="line" id="L38"> <span class="tok-kw">try</span> wr.writeByte(compression_flags);</span>
<span class="line" id="L39"> }</span>
<span class="line" id="L40"></span>
<span class="line" id="L41"> <span class="tok-kw">pub</span> <span class="tok-kw">const</span> Error = WriterType.Error;</span>
<span class="line" id="L41"> <span class="tok-kw">pub</span> <span class="tok-kw">const</span> Error = deflate.Compressor(WriterType).Error;</span>
<span class="line" id="L42"> <span class="tok-kw">pub</span> <span class="tok-kw">const</span> Writer = std.io.Writer(*Self, Error, write);</span>
<span class="line" id="L43"></span>
<span class="line" id="L44"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">writer</span>(self: *Self) Writer {</span>
@ -173,14 +173,13 @@
<span class="line" id="L53"></span>
<span class="line" id="L54"> <span class="tok-comment">/// Ends a zlib block with the checksum</span></span>
<span class="line" id="L55"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">end</span>(self: *Self) !<span class="tok-type">void</span> {</span>
<span class="line" id="L56"> <span class="tok-kw">try</span> self.compressor.close();</span>
<span class="line" id="L57"> self.compressor.deinit();</span>
<span class="line" id="L58"> <span class="tok-comment">// Write the checksum</span>
<span class="line" id="L56"> <span class="tok-comment">// Write the checksum</span>
</span>
<span class="line" id="L59"> <span class="tok-kw">try</span> self.raw_writer.writeInt(<span class="tok-type">u32</span>, self.adler.final(), .big);</span>
<span class="line" id="L60"> }</span>
<span class="line" id="L61"> };</span>
<span class="line" id="L62">}</span>
<span class="line" id="L63"></span>
<span class="line" id="L57"> <span class="tok-kw">try</span> self.compressor.finish();</span>
<span class="line" id="L58"> <span class="tok-kw">try</span> self.raw_writer.writeInt(<span class="tok-type">u32</span>, self.adler.final(), .big);</span>
<span class="line" id="L59"> }</span>
<span class="line" id="L60"> };</span>
<span class="line" id="L61">}</span>
<span class="line" id="L62"></span>
</code></pre></body>
</html>

View file

@ -8,12 +8,7 @@ const vaxis = @import("vaxis");
const log = std.log.scoped(.main);
/// Active TUI Section
<<<<<<< HEAD
const ActiveSection = enum {
=======
const ActiveSection = enum{
>>>>>>> b015a5d (Added the `table.zig` example)
top,
mid,
btm,

View file

@ -3,6 +3,7 @@ const testing = std.testing;
const Key = @This();
/// Modifier Keys for a Key Match Event.
pub const Modifiers = packed struct(u8) {
shift: bool = false,
alt: bool = false,
@ -14,6 +15,7 @@ pub const Modifiers = packed struct(u8) {
num_lock: bool = false,
};
/// Flags for the Kitty Protocol.
pub const KittyFlags = packed struct(u5) {
disambiguate: bool = true,
report_events: bool = false,
@ -61,7 +63,7 @@ pub fn matches(self: Key, cp: u21, mods: Modifiers) bool {
return false;
}
// matches against any of the provided codepoints.
/// matches against any of the provided codepoints.
pub fn matchesAny(self: Key, cps: []const u21, mods: Modifiers) bool {
for (cps) |cp| {
if (self.matches(cp, mods)) return true;
@ -69,16 +71,16 @@ pub fn matchesAny(self: Key, cps: []const u21, mods: Modifiers) bool {
return false;
}
// matches base layout codes, useful for shortcut matching when an alternate key
// layout is used
/// matches base layout codes, useful for shortcut matching when an alternate key
/// layout is used
pub fn matchShortcut(self: Key, cp: u21, mods: Modifiers) bool {
if (self.base_layout_codepoint == null) return false;
return cp == self.base_layout_codepoint.? and std.meta.eql(self.mods, mods);
}
// matches keys that aren't upper case versions when shifted. For example, shift
// + semicolon produces a colon. The key can be matched against shift +
// semicolon or just colon...or shift + ctrl + ; or just ctrl + :
/// matches keys that aren't upper case versions when shifted. For example, shift
/// + semicolon produces a colon. The key can be matched against shift +
/// semicolon or just colon...or shift + ctrl + ; or just ctrl + :
pub fn matchShiftedCodepoint(self: Key, cp: u21, mods: Modifiers) bool {
if (self.shifted_codepoint == null) return false;
if (!self.mods.shift) return false;
@ -92,8 +94,8 @@ pub fn matchShiftedCodepoint(self: Key, cp: u21, mods: Modifiers) bool {
return cp == self.shifted_codepoint.? and std.meta.eql(self_mods, mods);
}
// matches when the utf8 encoding of the codepoint and relevant mods matches the
// text of the key. This function will consume Shift and Caps Lock when matching
/// matches when the utf8 encoding of the codepoint and relevant mods matches the
/// text of the key. This function will consume Shift and Caps Lock when matching
pub fn matchText(self: Key, cp: u21, mods: Modifiers) bool {
// return early if we have no text
if (self.text == null) return false;
@ -147,8 +149,8 @@ pub const space: u21 = 0x20;
pub const enter: u21 = 0x6D;
pub const backspace: u21 = 0x7F;
// multicodepoint is a key which generated text but cannot be expressed as a
// single codepoint. The value is the maximum unicode codepoint + 1
/// multicodepoint is a key which generated text but cannot be expressed as a
/// single codepoint. The value is the maximum unicode codepoint + 1
pub const multicodepoint: u21 = 1_114_112 + 1;
// kitty encodes these keys directly in the private use area. We reuse those

View file

@ -12,7 +12,6 @@ const log = std.log.scoped(.tty);
const Tty = @This();
const Writer = std.io.Writer(posix.fd_t, posix.WriteError, posix.write);
const BufferedWriter = std.io.BufferedWriter(4096, Writer);
/// the original state of the terminal, prior to calling makeRaw

713
src/vaxis.zig Normal file
View file

@ -0,0 +1,713 @@
const std = @import("std");
const builtin = @import("builtin");
const atomic = std.atomic;
const base64 = std.base64.standard.Encoder;
pub const Cell = @import("Cell.zig");
pub const Image = @import("Image.zig");
pub const InternalScreen = @import("InternalScreen.zig");
pub const Key = @import("Key.zig");
pub const Mouse = @import("Mouse.zig");
pub const Options = @import("Options.zig");
pub const Queue = @import("queue.zig").Queue;
pub const Screen = @import("Screen.zig");
pub const Tty = @import("Tty.zig");
pub const Window = @import("Window.zig");
pub const ctlseqs = @import("ctlseqs.zig");
pub const gwidth = @import("gwidth.zig");
pub const widgets = @import("widgets.zig");
const zigimg = @import("zigimg");
/// Initialize a Vaxis application.
pub fn init(comptime Event: type, opts: Options) !Vaxis(Event) {
return Vaxis(Event).init(opts);
}
test {
std.testing.refAllDecls(@This());
}
/// Vaxis is the entrypoint for a Vaxis application. The provided type T should
/// be a tagged union which contains all of the events the application will
/// handle. Vaxis will look for the following fields on the union and, if
/// found, emit them via the "nextEvent" method
///
/// The following events are available:
/// - `key_press: Key`, for key press events
/// - `winsize: Winsize`, for resize events. Must call app.resize when receiving
/// this event
/// - `focus_in` and `focus_out` for focus events
pub fn Vaxis(comptime T: type) type {
return struct {
const Self = @This();
const log = std.log.scoped(.vaxis);
pub const Event = T;
pub const Capabilities = struct {
kitty_keyboard: bool = false,
kitty_graphics: bool = false,
rgb: bool = false,
unicode: bool = false,
};
/// the event queue for Vaxis
//
// TODO: is 512 ok?
queue: Queue(T, 512),
tty: ?Tty,
read_thread: ?std.Thread,
/// the screen we write to
screen: Screen,
/// The last screen we drew. We keep this so we can efficiently update on
/// the next render
screen_last: InternalScreen = undefined,
state: struct {
/// if we are in the alt screen
alt_screen: bool = false,
/// if we have entered kitty keyboard
kitty_keyboard: bool = false,
bracketed_paste: bool = false,
mouse: bool = false,
} = .{},
caps: Capabilities = .{},
/// if we should redraw the entire screen on the next render
refresh: bool = false,
/// blocks the main thread until a DA1 query has been received, or the
/// futex times out
query_futex: atomic.Value(u32) = atomic.Value(u32).init(0),
// images
next_img_id: u32 = 1,
// statistics
renders: usize = 0,
render_dur: i128 = 0,
render_timer: std.time.Timer,
/// Initialize Vaxis with runtime options
pub fn init(_: Options) !Self {
return .{
.queue = .{},
.tty = null,
.screen = .{},
.screen_last = .{},
.render_timer = try std.time.Timer.start(),
.read_thread = null,
};
}
/// Resets the terminal to it's original state. If an allocator is
/// passed, this will free resources associated with Vaxis. This is left as an
/// optional so applications can choose to not free resources when the
/// application will be exiting anyways
pub fn deinit(self: *Self, alloc: ?std.mem.Allocator) void {
if (self.tty) |_| {
var tty = &self.tty.?;
if (self.state.kitty_keyboard) {
_ = tty.write(ctlseqs.csi_u_pop) catch {};
}
if (self.state.mouse) {
_ = tty.write(ctlseqs.mouse_reset) catch {};
}
if (self.state.bracketed_paste) {
_ = tty.write(ctlseqs.bp_reset) catch {};
}
if (self.state.alt_screen) {
_ = tty.write(ctlseqs.rmcup) catch {};
}
// always show the cursor on exit
_ = tty.write(ctlseqs.show_cursor) catch {};
tty.flush() catch {};
tty.deinit();
}
if (alloc) |a| {
self.screen.deinit(a);
self.screen_last.deinit(a);
}
if (self.renders > 0) {
const tpr = @divTrunc(self.render_dur, self.renders);
log.debug("total renders = {d}", .{self.renders});
log.debug("microseconds per render = {d}", .{tpr});
}
}
/// spawns the input thread to start listening to the tty for input
pub fn startReadThread(self: *Self) !void {
self.tty = try Tty.init();
// run our tty read loop in it's own thread
self.read_thread = try std.Thread.spawn(.{}, Tty.run, .{ &self.tty.?, T, self });
}
/// stops reading from the tty
pub fn stopReadThread(self: *Self) void {
if (self.tty) |_| {
var tty = &self.tty.?;
tty.stop();
if (self.read_thread) |thread| {
thread.join();
self.read_thread = null;
}
}
}
/// returns the next available event, blocking until one is available
pub fn nextEvent(self: *Self) T {
return self.queue.pop();
}
/// blocks until an event is available. Useful when your application is
/// operating on a poll + drain architecture (see tryEvent)
pub fn pollEvent(self: *Self) void {
self.queue.poll();
}
/// returns an event if one is available, otherwise null. Non-blocking.
pub fn tryEvent(self: *Self) ?Event {
return self.queue.tryPop();
}
/// posts an event into the event queue. Will block if there is not
/// capacity for the event
pub fn postEvent(self: *Self, event: T) void {
self.queue.push(event);
}
/// resize allocates a slice of cells equal to the number of cells
/// required to display the screen (ie width x height). Any previous screen is
/// freed when resizing
pub fn resize(self: *Self, alloc: std.mem.Allocator, winsize: Tty.Winsize) !void {
log.debug("resizing screen: width={d} height={d}", .{ winsize.cols, winsize.rows });
self.screen.deinit(alloc);
self.screen = try Screen.init(alloc, winsize);
self.screen.unicode = self.caps.unicode;
// try self.screen.int(alloc, winsize.cols, winsize.rows);
// we only init our current screen. This has the effect of redrawing
// every cell
self.screen_last.deinit(alloc);
self.screen_last = try InternalScreen.init(alloc, winsize.cols, winsize.rows);
// try self.screen_last.resize(alloc, winsize.cols, winsize.rows);
}
/// returns a Window comprising of the entire terminal screen
pub fn window(self: *Self) Window {
return .{
.x_off = 0,
.y_off = 0,
.width = self.screen.width,
.height = self.screen.height,
.screen = &self.screen,
};
}
/// enter the alternate screen. The alternate screen will automatically
/// be exited if calling deinit while in the alt screen
pub fn enterAltScreen(self: *Self) !void {
if (self.state.alt_screen) return;
var tty = self.tty orelse return;
_ = try tty.write(ctlseqs.smcup);
try tty.flush();
self.state.alt_screen = true;
}
/// exit the alternate screen
pub fn exitAltScreen(self: *Self) !void {
if (!self.state.alt_screen) return;
var tty = self.tty orelse return;
_ = try tty.write(ctlseqs.rmcup);
try tty.flush();
self.state.alt_screen = false;
}
/// write queries to the terminal to determine capabilities. Individual
/// capabilities will be delivered to the client and possibly intercepted by
/// Vaxis to enable features
pub fn queryTerminal(self: *Self) !void {
var tty = self.tty orelse return;
const colorterm = std.posix.getenv("COLORTERM") orelse "";
if (std.mem.eql(u8, colorterm, "truecolor") or
std.mem.eql(u8, colorterm, "24bit"))
{
if (@hasField(Event, "cap_rgb")) {
self.postEvent(.cap_rgb);
}
}
// TODO: decide if we actually want to query for focus and sync. It
// doesn't hurt to blindly use them
// _ = try tty.write(ctlseqs.decrqm_focus);
// _ = try tty.write(ctlseqs.decrqm_sync);
_ = try tty.write(ctlseqs.decrqm_unicode);
_ = try tty.write(ctlseqs.decrqm_color_theme);
// TODO: XTVERSION has a DCS response. uncomment when we can parse
// that
// _ = try tty.write(ctlseqs.xtversion);
_ = try tty.write(ctlseqs.csi_u_query);
_ = try tty.write(ctlseqs.kitty_graphics_query);
// TODO: sixel geometry query interferes with F4 keys.
// _ = try tty.write(ctlseqs.sixel_geometry_query);
// TODO: XTGETTCAP queries ("RGB", "Smulx")
_ = try tty.write(ctlseqs.primary_device_attrs);
try tty.flush();
// 1 second timeout
std.Thread.Futex.timedWait(&self.query_futex, 0, 1 * std.time.ns_per_s) catch {};
// enable detected features
if (self.caps.kitty_keyboard) {
try self.enableKittyKeyboard(.{});
}
if (self.caps.unicode) {
_ = try tty.write(ctlseqs.unicode_set);
}
}
// the next render call will refresh the entire screen
pub fn queueRefresh(self: *Self) void {
self.refresh = true;
}
/// draws the screen to the terminal
pub fn render(self: *Self) !void {
var tty = self.tty orelse return;
self.renders += 1;
self.render_timer.reset();
defer {
self.render_dur += self.render_timer.read() / std.time.ns_per_us;
}
defer self.refresh = false;
defer tty.flush() catch {};
// Set up sync before we write anything
// TODO: optimize sync so we only sync _when we have changes_. This
// requires a smarter buffered writer, we'll probably have to write
// our own
_ = try tty.write(ctlseqs.sync_set);
defer _ = tty.write(ctlseqs.sync_reset) catch {};
// Send the cursor to 0,0
// TODO: this needs to move after we optimize writes. We only do
// this if we have an update to make. We also need to hide cursor
// and then reshow it if needed
_ = try tty.write(ctlseqs.hide_cursor);
_ = try tty.write(ctlseqs.home);
_ = try tty.write(ctlseqs.sgr_reset);
// initialize some variables
var reposition: bool = false;
var row: usize = 0;
var col: usize = 0;
var cursor: Cell.Style = .{};
var link: Cell.Hyperlink = .{};
// Clear all images
_ = try tty.write(ctlseqs.kitty_graphics_clear);
var i: usize = 0;
while (i < self.screen.buf.len) {
const cell = self.screen.buf[i];
defer {
// advance by the width of this char mod 1
const w = blk: {
if (cell.char.width != 0) break :blk cell.char.width;
const method: gwidth.Method = if (self.caps.unicode) .unicode else .wcwidth;
const width = gwidth.gwidth(cell.char.grapheme, method) catch 1;
break :blk @max(1, width);
};
std.debug.assert(w > 0);
var j = i + 1;
while (j < i + w) : (j += 1) {
if (j >= self.screen_last.buf.len) break;
self.screen_last.buf[j].skipped = true;
}
col += w;
i += w;
}
if (col >= self.screen.width) {
row += 1;
col = 0;
reposition = true;
}
// If cell is the same as our last frame, we don't need to do
// anything
const last = self.screen_last.buf[i];
if (!self.refresh and last.eql(cell) and !last.skipped and cell.image == null) {
reposition = true;
// Close any osc8 sequence we might be in before
// repositioning
if (link.uri.len > 0) {
_ = try tty.write(ctlseqs.osc8_clear);
}
continue;
}
self.screen_last.buf[i].skipped = false;
defer {
cursor = cell.style;
link = cell.link;
}
// Set this cell in the last frame
self.screen_last.writeCell(col, row, cell);
// reposition the cursor, if needed
if (reposition) {
try std.fmt.format(tty.buffered_writer.writer(), ctlseqs.cup, .{ row + 1, col + 1 });
}
if (cell.image) |img| {
if (img.size) |size| {
try std.fmt.format(
tty.buffered_writer.writer(),
ctlseqs.kitty_graphics_scale,
.{ img.img_id, img.z_index, size.cols, size.rows },
);
} else {
try std.fmt.format(
tty.buffered_writer.writer(),
ctlseqs.kitty_graphics_place,
.{ img.img_id, img.z_index },
);
}
}
// something is different, so let's loop through everything and
// find out what
// foreground
if (!std.meta.eql(cursor.fg, cell.style.fg)) {
const writer = tty.buffered_writer.writer();
switch (cell.style.fg) {
.default => _ = try tty.write(ctlseqs.fg_reset),
.index => |idx| {
switch (idx) {
0...7 => try std.fmt.format(writer, ctlseqs.fg_base, .{idx}),
8...15 => try std.fmt.format(writer, ctlseqs.fg_bright, .{idx - 8}),
else => try std.fmt.format(writer, ctlseqs.fg_indexed, .{idx}),
}
},
.rgb => |rgb| {
try std.fmt.format(writer, ctlseqs.fg_rgb, .{ rgb[0], rgb[1], rgb[2] });
},
}
}
// background
if (!std.meta.eql(cursor.bg, cell.style.bg)) {
const writer = tty.buffered_writer.writer();
switch (cell.style.bg) {
.default => _ = try tty.write(ctlseqs.bg_reset),
.index => |idx| {
switch (idx) {
0...7 => try std.fmt.format(writer, ctlseqs.bg_base, .{idx}),
8...15 => try std.fmt.format(writer, ctlseqs.bg_bright, .{idx - 8}),
else => try std.fmt.format(writer, ctlseqs.bg_indexed, .{idx}),
}
},
.rgb => |rgb| {
try std.fmt.format(writer, ctlseqs.bg_rgb, .{ rgb[0], rgb[1], rgb[2] });
},
}
}
// underline color
if (!std.meta.eql(cursor.ul, cell.style.ul)) {
const writer = tty.buffered_writer.writer();
switch (cell.style.bg) {
.default => _ = try tty.write(ctlseqs.ul_reset),
.index => |idx| {
try std.fmt.format(writer, ctlseqs.ul_indexed, .{idx});
},
.rgb => |rgb| {
try std.fmt.format(writer, ctlseqs.ul_rgb, .{ rgb[0], rgb[1], rgb[2] });
},
}
}
// underline style
if (!std.meta.eql(cursor.ul_style, cell.style.ul_style)) {
const seq = switch (cell.style.ul_style) {
.off => ctlseqs.ul_off,
.single => ctlseqs.ul_single,
.double => ctlseqs.ul_double,
.curly => ctlseqs.ul_curly,
.dotted => ctlseqs.ul_dotted,
.dashed => ctlseqs.ul_dashed,
};
_ = try tty.write(seq);
}
// bold
if (cursor.bold != cell.style.bold) {
const seq = switch (cell.style.bold) {
true => ctlseqs.bold_set,
false => ctlseqs.bold_dim_reset,
};
_ = try tty.write(seq);
if (cell.style.dim) {
_ = try tty.write(ctlseqs.dim_set);
}
}
// dim
if (cursor.dim != cell.style.dim) {
const seq = switch (cell.style.dim) {
true => ctlseqs.dim_set,
false => ctlseqs.bold_dim_reset,
};
_ = try tty.write(seq);
if (cell.style.bold) {
_ = try tty.write(ctlseqs.bold_set);
}
}
// dim
if (cursor.italic != cell.style.italic) {
const seq = switch (cell.style.italic) {
true => ctlseqs.italic_set,
false => ctlseqs.italic_reset,
};
_ = try tty.write(seq);
}
// dim
if (cursor.blink != cell.style.blink) {
const seq = switch (cell.style.blink) {
true => ctlseqs.blink_set,
false => ctlseqs.blink_reset,
};
_ = try tty.write(seq);
}
// reverse
if (cursor.reverse != cell.style.reverse) {
const seq = switch (cell.style.reverse) {
true => ctlseqs.reverse_set,
false => ctlseqs.reverse_reset,
};
_ = try tty.write(seq);
}
// invisible
if (cursor.invisible != cell.style.invisible) {
const seq = switch (cell.style.invisible) {
true => ctlseqs.invisible_set,
false => ctlseqs.invisible_reset,
};
_ = try tty.write(seq);
}
// strikethrough
if (cursor.strikethrough != cell.style.strikethrough) {
const seq = switch (cell.style.strikethrough) {
true => ctlseqs.strikethrough_set,
false => ctlseqs.strikethrough_reset,
};
_ = try tty.write(seq);
}
// url
if (!std.meta.eql(link.uri, cell.link.uri)) {
var ps = cell.link.params;
if (cell.link.uri.len == 0) {
// Empty out the params no matter what if we don't have
// a url
ps = "";
}
const writer = tty.buffered_writer.writer();
try std.fmt.format(writer, ctlseqs.osc8, .{ ps, cell.link.uri });
}
_ = try tty.write(cell.char.grapheme);
}
if (self.screen.cursor_vis) {
try std.fmt.format(
tty.buffered_writer.writer(),
ctlseqs.cup,
.{
self.screen.cursor_row + 1,
self.screen.cursor_col + 1,
},
);
_ = try tty.write(ctlseqs.show_cursor);
}
if (self.screen.mouse_shape != self.screen_last.mouse_shape) {
try std.fmt.format(
tty.buffered_writer.writer(),
ctlseqs.osc22_mouse_shape,
.{@tagName(self.screen.mouse_shape)},
);
self.screen_last.mouse_shape = self.screen.mouse_shape;
}
}
fn enableKittyKeyboard(self: *Self, flags: Key.KittyFlags) !void {
self.state.kitty_keyboard = true;
const flag_int: u5 = @bitCast(flags);
try std.fmt.format(
self.tty.?.buffered_writer.writer(),
ctlseqs.csi_u_push,
.{
flag_int,
},
);
try self.tty.?.flush();
}
/// send a system notification
pub fn notify(self: *Self, title: ?[]const u8, body: []const u8) !void {
if (self.tty == null) return;
if (title) |t| {
try std.fmt.format(
self.tty.?.buffered_writer.writer(),
ctlseqs.osc777_notify,
.{ t, body },
);
} else {
try std.fmt.format(
self.tty.?.buffered_writer.writer(),
ctlseqs.osc9_notify,
.{body},
);
}
try self.tty.?.flush();
}
/// sets the window title
pub fn setTitle(self: *Self, title: []const u8) !void {
if (self.tty == null) return;
try std.fmt.format(
self.tty.?.buffered_writer.writer(),
ctlseqs.osc2_set_title,
.{title},
);
try self.tty.?.flush();
}
// turn bracketed paste on or off. An event will be sent at the
// beginning and end of a detected paste. All keystrokes between these
// events were pasted
pub fn setBracketedPaste(self: *Self, enable: bool) !void {
if (self.tty == null) return;
self.state.bracketed_paste = enable;
const seq = if (enable) {
self.state.bracketed_paste = true;
ctlseqs.bp_set;
} else {
self.state.bracketed_paste = true;
ctlseqs.bp_reset;
};
_ = try self.tty.?.write(seq);
try self.tty.?.flush();
}
/// set the mouse shape
pub fn setMouseShape(self: *Self, shape: Mouse.Shape) void {
self.screen.mouse_shape = shape;
}
/// turn mouse reporting on or off
pub fn setMouseMode(self: *Self, enable: bool) !void {
var tty = self.tty orelse return;
self.state.mouse = enable;
if (enable) {
_ = try tty.write(ctlseqs.mouse_set);
try tty.flush();
} else {
_ = try tty.write(ctlseqs.mouse_reset);
try tty.flush();
}
}
pub fn loadImage(
self: *Self,
alloc: std.mem.Allocator,
src: Image.Source,
) !Image {
if (!self.caps.kitty_graphics) return error.NoGraphicsCapability;
var tty = self.tty orelse return error.NoTTY;
defer self.next_img_id += 1;
const writer = tty.buffered_writer.writer();
var img = switch (src) {
.path => |path| try zigimg.Image.fromFilePath(alloc, path),
.mem => |bytes| try zigimg.Image.fromMemory(alloc, bytes),
};
defer img.deinit();
const png_buf = try alloc.alloc(u8, img.imageByteSize());
defer alloc.free(png_buf);
const png = try img.writeToMemory(png_buf, .{ .png = .{} });
const b64_buf = try alloc.alloc(u8, base64.calcSize(png.len));
const encoded = base64.encode(b64_buf, png);
defer alloc.free(b64_buf);
const id = self.next_img_id;
log.debug("transmitting kitty image: id={d}, len={d}", .{ id, encoded.len });
if (encoded.len < 4096) {
try std.fmt.format(
writer,
"\x1b_Gf=100,i={d};{s}\x1b\\",
.{
id,
encoded,
},
);
} else {
var n: usize = 4096;
try std.fmt.format(
writer,
"\x1b_Gf=100,i={d},m=1;{s}\x1b\\",
.{ id, encoded[0..n] },
);
while (n < encoded.len) : (n += 4096) {
const end: usize = @min(n + 4096, encoded.len);
const m: u2 = if (end == encoded.len) 0 else 1;
try std.fmt.format(
writer,
"\x1b_Gm={d};{s}\x1b\\",
.{
m,
encoded[n..end],
},
);
}
}
try tty.buffered_writer.flush();
return .{
.id = id,
.width = img.width,
.height = img.height,
};
}
/// deletes an image from the terminal's memory
pub fn freeImage(self: Self, id: u32) void {
var tty = self.tty orelse return;
const writer = tty.buffered_writer.writer();
std.fmt.format(writer, "\x1b_Ga=d,d=I,i={d};\x1b\\", .{id}) catch |err| {
log.err("couldn't delete image {d}: {}", .{ id, err });
return;
};
tty.buffered_writer.flush() catch |err| {
log.err("couldn't flush writer: {}", .{err});
};
}
};
}
// test "Vaxis: event queueing" {
// const Event = union(enum) {
// key: void,
// };
// var vx: Vaxis(Event) = try Vaxis(Event).init(.{});
// defer vx.deinit(null);
// vx.postEvent(.{ .key = {} });
// const event = vx.nextEvent();
// try std.testing.expect(event == .key);
// }

View file

@ -4,7 +4,7 @@ const heap = std.heap;
const mem = std.mem;
const meta = std.meta;
const vaxis = @import("../main.zig");
const vaxis = @import("../vaxis.zig");
/// Table Context for maintaining state and drawing Tables with `drawTable()`.
pub const TableContext = struct{