summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--example.zig68
-rw-r--r--examples/example.zig24
-rw-r--r--examples/keys.zig38
-rw-r--r--examples/pong.zig64
-rw-r--r--src/main.zig152
5 files changed, 227 insertions, 119 deletions
diff --git a/example.zig b/example.zig
index 046564b..cbbf7b6 100644
--- a/example.zig
+++ b/example.zig
@@ -1,38 +1,44 @@
const std = @import("std");
-const ascii = std.ascii;
-const print = std.debug.warn;
-const curses = @import("src/main.zig");
+pub const curses = @import("src/main.zig");
+
+const examples = .{
+ .example = @import("examples/example.zig"),
+ .keys = @import("examples/keys.zig"),
+ .pong = @import("examples/pong.zig"),
+};
+
+const mem = std.mem;
pub fn main() anyerror!void {
- const in_stream = std.io.getStdOut().inStream();
-
- var w = try curses.Window.init(std.testing.allocator);
- while (true) {
- var c: u8 = undefined;
- c = try in_stream.readByte();
-
- if (ascii.isCntrl(c)) {
- print("It's control! {}\r\n", .{c});
- var text = "hi\n";
-
- try w.mvprint(0, 0, text[0..]);
- } else {
- print("{}\r\n", .{c});
- }
-
- if (ascii.isCntrl(c) and c == 'q') {
- break;
- }
-
- if (c == 'c') {
- try w.clear();
- }
- //warn("{}\n", .{CTRL_KEY(c)});
- if (c == 17) {
- break;
- }
+ const argv = std.os.argv;
+
+ if (argv.len == 1) {
+ std.debug.warn("Usage: example NAME\n", .{});
+ return;
+ }
+
+ const arg = argv[1];
+
+ var found = false;
+
+ found = try example(arg, "example", examples.example.main);
+ if (!found)
+ found = try example(arg, "pong", examples.pong.main);
+ if (!found)
+ found = try example(arg, "keys", examples.keys.main);
+
+ //if (example(arg, "pong")) {
+ // std.debug.warn("Starting pong example\n", .{});
+ // try @import("examples/pong.zig").main();
+ //}
+}
+
+fn example(arg: [*:0]const u8, name: []const u8, func: fn () anyerror!void) anyerror!bool {
+ if (mem.eql(u8, arg[0..name.len], name)) {
+ try func();
+ return true;
}
- try w.end();
+ return false;
}
diff --git a/examples/example.zig b/examples/example.zig
new file mode 100644
index 0000000..523589d
--- /dev/null
+++ b/examples/example.zig
@@ -0,0 +1,24 @@
+const std = @import("std");
+
+const print = std.debug.warn;
+
+const curses = @import("root").curses;
+
+const stdout = std.io.getStdOut().outStream();
+const in_stream = std.io.getStdOut().inStream();
+
+pub fn readKey() !u8 {
+ var c: u8 = try in_stream.readByte();
+ return c;
+}
+
+pub fn main() anyerror!void {
+ var w = try curses.Window.init(std.testing.allocator);
+
+ var c: u8 = undefined;
+ while (c != 'q') {
+ c = try readKey();
+ }
+
+ try w.end();
+}
diff --git a/examples/keys.zig b/examples/keys.zig
new file mode 100644
index 0000000..fa7eafe
--- /dev/null
+++ b/examples/keys.zig
@@ -0,0 +1,38 @@
+const std = @import("std");
+const ascii = std.ascii;
+const print = std.debug.warn;
+
+const curses = @import("root").curses;
+
+pub fn main() anyerror!void {
+ const in_stream = std.io.getStdOut().inStream();
+
+ var w = try curses.Window.init(std.testing.allocator);
+ while (true) {
+ var c: u8 = undefined;
+ c = try in_stream.readByte();
+
+ if (ascii.isCntrl(c)) {
+ print("It's control! {}\r\n", .{c});
+ var text = "hi\n";
+
+ try w.mvprint(0, 0, text[0..]);
+ } else {
+ print("{}\r\n", .{c});
+ }
+
+ if (ascii.isCntrl(c) and c == 'q') {
+ break;
+ }
+
+ if (c == 'c') {
+ try w.clear();
+ }
+ //warn("{}\n", .{CTRL_KEY(c)});
+ if (c == 17) {
+ break;
+ }
+ }
+
+ try w.end();
+}
diff --git a/examples/pong.zig b/examples/pong.zig
new file mode 100644
index 0000000..f4e7849
--- /dev/null
+++ b/examples/pong.zig
@@ -0,0 +1,64 @@
+const std = @import("std");
+const print = std.debug.warn;
+
+const curses = @import("root").curses;
+
+// Doesn't work due to a Zig error when linking libc
+const c = @cImport({
+ //@cDefine("_NO_CRT_STDIO_INLINE", "1");
+ //@cInclude("stdio.h");
+ //@cInclude("stdlib.h");
+});
+
+pub fn main() !void {
+ const DELAY = 3000;
+
+ //_ = c.printf("%d\n", c.rand());
+
+ var ball = .{
+ .x = 10,
+ .y = 10,
+
+ .direction = enum {
+ Right,
+ Left,
+ },
+ };
+
+ var lives: usize = 0;
+ var hits: usize = 0;
+
+ var paddle = .{
+ .x = 5, // will never change
+ .y = 15,
+
+ .size = 5,
+ .speed = 4,
+ };
+
+ var w = curses.Window.init(std.testing.allocator) catch |e| {
+ print("Failed to initialize window: {}\n", .{e});
+ return e;
+ };
+
+ var play = true;
+
+ const maxloop = 100000000;
+ var i: usize = 0;
+
+ while (play == true and i < maxloop) : (i += 1) {
+ try w.clear();
+ w.mvprint(10, 10, "Hello") catch |err| {
+ try w.end();
+ return err;
+ };
+ w.refresh() catch |err| {
+ try w.end();
+ return err;
+ };
+ std.time.sleep(40000);
+ //play = false;
+ }
+
+ try w.end();
+}
diff --git a/src/main.zig b/src/main.zig
index 1030dba..d314907 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -1,34 +1,49 @@
const std = @import("std");
+
+const ascii = std.ascii;
+const io = std.io;
+const fmt = std.fmt;
const os = std.os;
-const warn = std.debug.warn;
const print = warn;
const termios = os.termios;
-const ascii = std.ascii;
+const warn = std.debug.warn;
const STDIN_FILENO = 0;
const stdout = std.io.getStdOut().outStream();
const in_stream = std.io.getStdOut().inStream();
-//pub fn new(allocator: *Allocator) !Window {}
+const VMIN = 5;
+const VTIME = 6;
pub const Window = struct {
+ /// the saved termios that is used to restore the terminal to its original state
original: termios,
+
+ /// the height (in characters) of the window
height: usize,
+ /// the width (in characters) of the window
width: usize,
- buffer: []u8,
- /// buf contains a dynamic array of slices that will be combined upon print
- buf: std.ArrayList([]const u8),
+ // an idea that is not implemented (use height and width for now)
+ //max: struct {
+ // x: usize,
+ // y: usize,
+ //},
+ //
+ /// buf contains a dynamic array of characters that will be combined upon print
+ buf: std.ArrayList(u8),
- //allocator: *std.mem.Allocator,
+ allocator: *std.mem.Allocator,
/// init puts the window in raw mode and saves the original termios for switching back to normal mode
pub fn init(allocator: *std.mem.Allocator) !Window {
var window = Window{
.original = try os.tcgetattr(STDIN_FILENO),
- .buffer = "",
- .buf = undefined,
+ .buf = std.ArrayList(u8).init(allocator),
+
.height = 0,
.width = 0,
+
+ .allocator = allocator,
};
var raw = window.original;
@@ -38,9 +53,8 @@ pub const Window = struct {
raw.cflag |= (os.CS8);
raw.lflag &= ~(@as(u16, os.ECHO | os.ICANON | os.IEXTEN | os.ISIG));
- // My attempt at VTIME and VMIN
- raw.cc[5] = 0;
- raw.cc[7] = 1;
+ raw.cc[VMIN] = 0;
+ raw.cc[VTIME] = 1;
try os.tcsetattr(STDIN_FILENO, os.TCSA.FLUSH, raw);
@@ -48,45 +62,9 @@ pub const Window = struct {
return error.NotATTY;
}
- const arrayList = std.ArrayList([]const u8);
-
- var what = "hello";
- var buf = arrayList.init(allocator);
- _ = try buf.append(what[0..]);
- _ = try buf.append("i"[0..]);
- print("What? {}\n", .{buf.items});
-
- window.buf = buf;
-
- //const wh = try getmax();
// fill in the height and width information
try window.updatehw();
- var text = try allocator.alloc(u8, window.height * window.width);
- //warn("{}", .{text});
- defer allocator.free(text);
-
- var n: usize = 0;
- while (n < window.height) : (n += 1) {
- print("{}", .{n});
- text[n] = 'h';
-
- //warn("{}", .{});
-
- if (n % window.width == 0) {
- text[n * window.width] = 'c';
- }
-
- // var i: usize = 0;
- // while (i < window.width) : (i += 1) {
- // if (i == window.width) {
- // text[n] = '\n';
- // }
- // }
- }
-
- print("{}", .{text});
-
// initialize text with spaces and newlines
//for ([]usize{ 0, 1, 2, 3, 4, 10 }) |i| {}
@@ -95,12 +73,11 @@ pub const Window = struct {
// disable cursor
_ = try stdout.write("\x1B[?25l");
- var i: usize = 0;
-
- while (i < window.height) {
- _ = try stdout.write("\r\n~");
- i += 1;
- }
+ //var i: usize = 0;
+ //while (i < window.height) {
+ // _ = try stdout.write("\r\n~");
+ // i += 1;
+ //}
return window;
}
@@ -109,61 +86,60 @@ pub const Window = struct {
pub fn updatehw(self: *Window) !void {
// TODO: support other platforms and provide fallback
var wsz: os.winsize = undefined;
- // TODO: test for false and return error
- _ = std.os.linux.syscall3(.ioctl, @bitCast(usize, @as(isize, 0)), os.TIOCGWINSZ, @ptrToInt(&wsz)) == 0;
- //const te = [2]u32{ wsz.ws_col, wsz.ws_row };
+ // test for failure
+ if (std.os.linux.syscall3(.ioctl, @bitCast(usize, @as(isize, 0)), os.TIOCGWINSZ, @ptrToInt(&wsz)) != 0) {
+ return error.WinsizeSyscallFailure;
+ }
+
self.height = wsz.ws_row;
self.width = wsz.ws_col;
}
- /// setchar puts a character at a specific point in the text based on height and width
- pub fn setchar(self: *Window, x: u32, y: u32, insert: u8) !void {
- if (x > self.width or y > self.height) {
- return error.InvalidRange;
- }
+ pub fn mvprint(self: *Window, x: usize, y: usize, text: []const u8) !void {
+ var buf = try self.allocator.alloc(u8, 10); // TODO: remove allocation
+ defer self.allocator.free(buf);
+ _ = try fmt.bufPrint(buf, "\x1b[{};{}H", .{ x, y });
- var newlines: usize = 0;
- for (self.buffer) |char, i| {
- if (newlines == y) {
- for (self.buffer[i + 1 .. hw[1]]) |character, n| {
- if (character == '\n' or character == '\r') {
- break;
- }
-
- self.buffer[n] = insert;
- }
- }
- }
+ try self.buf.appendSlice(buf);
+ try self.buf.appendSlice(text);
}
- pub fn mvprint(self: Window, x: usize, y: usize, text: []const u8) !void {
- self.buf.append("\x1b[10;10H"[0..]);
- self.buf.append([]u8{@as(u8, x)});
- self.buf.append(text);
- self.buf.append();
- //_ = try buf.append('');
- }
+ /// erases the buffer and clears the screen, can be expensive and cause flickering
+ pub fn clear(self: *Window) !void {
+ self.buf.deinit();
+ self.buf = std.ArrayList(u8).init(self.allocator);
- pub fn clear(self: Window) !void {
_ = try stdout.write("\x1b[2J");
_ = try stdout.write("\x1b[H");
}
+ /// lazily prints to the screen, decreasing flickering
pub fn erase() !void {}
- pub fn flush() !void {}
+ pub fn flush(self: Window) !void {
+ self.buf.items;
+ }
pub fn refresh(self: Window) !void {
- _ = stdout.write(self.buffer);
+ var buf = try self.allocator.alloc(u8, self.buf.items.len); // TODO: remove allocator
+ defer self.allocator.free(buf);
+
+ _ = try fmt.bufPrint(buf, "{}", .{self.buf.items});
+ _ = try stdout.write(buf);
}
- pub fn end(self: Window) !void {
+ pub fn end(self: *Window) !void {
+ // free the memory first in case the next ones fail
+ self.buf.deinit();
+
+ // clear screen
+ _ = try stdout.write("\x1b[2J");
+ _ = try stdout.write("\x1b[H");
+
// re-enable cursor
_ = try stdout.write("\x1B[?25h");
- self.buf.deinit();
-
- try self.clear();
+ // Restore the original termios
try os.tcsetattr(STDIN_FILENO, os.TCSA.FLUSH, self.original);
}
};