Unknown state [2025-08-04]
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -0,0 +1,2 @@
|
|||||||
|
.zig-cache/
|
||||||
|
zig-out/
|
||||||
|
1
loader/.envrc
Normal file
1
loader/.envrc
Normal file
@@ -0,0 +1 @@
|
|||||||
|
PATH_add zig-out/bin
|
47
loader/main.zig
Normal file
47
loader/main.zig
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
const Hook = *const fn (i32, i32) callconv(.c) i32;
|
||||||
|
|
||||||
|
pub fn main() !void {
|
||||||
|
std.log.debug("setting up watches...", .{});
|
||||||
|
|
||||||
|
var event: std.os.linux.inotify_event = undefined;
|
||||||
|
const event_buf = std.mem.asBytes(&event);
|
||||||
|
|
||||||
|
const fd: i32 = @intCast(std.os.linux.inotify_init1(std.os.linux.IN.NONBLOCK));
|
||||||
|
defer _ = std.os.linux.close(fd);
|
||||||
|
|
||||||
|
_ = std.os.linux.inotify_add_watch(fd, "./libroot.so", std.os.linux.IN.MODIFY);
|
||||||
|
|
||||||
|
std.log.debug("loading dylib...", .{});
|
||||||
|
|
||||||
|
var lib = try std.DynLib.open("./libroot.so");
|
||||||
|
defer lib.close();
|
||||||
|
|
||||||
|
var hook: Hook = lib.lookup(Hook, "hook").?;
|
||||||
|
|
||||||
|
var polls = [_]std.os.linux.pollfd{
|
||||||
|
.{ .fd = fd, .events = std.os.linux.POLL.IN, .revents = 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
const eps = std.os.linux.poll(&polls, polls.len, 0);
|
||||||
|
std.log.debug("eps: {d}", .{eps});
|
||||||
|
if (eps > 0) {
|
||||||
|
std.log.debug("event!", .{});
|
||||||
|
while (std.os.linux.read(fd, event_buf.ptr, event_buf.len) > 0) {
|
||||||
|
std.log.debug("consume.", .{});
|
||||||
|
}
|
||||||
|
std.log.debug("reloading.", .{});
|
||||||
|
lib.close();
|
||||||
|
lib = try std.DynLib.open("./libroot.so");
|
||||||
|
hook = lib.lookup(Hook, "hook").?;
|
||||||
|
}
|
||||||
|
|
||||||
|
std.log.debug("update", .{});
|
||||||
|
const res = hook(5, 7);
|
||||||
|
std.log.debug("hook(5, 7) = {d}", .{res});
|
||||||
|
|
||||||
|
std.time.sleep(std.time.ns_per_s);
|
||||||
|
}
|
||||||
|
}
|
6
loader/root.zig
Normal file
6
loader/root.zig
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
pub export fn hook(a: i32, b: i32) i32 {
|
||||||
|
return a * b;
|
||||||
|
}
|
||||||
|
|
5
loader/sample.txt
Normal file
5
loader/sample.txt
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
content
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
4
loader/test.zig
Normal file
4
loader/test.zig
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
comptime{
|
||||||
|
@compileLog(std.math.maxInt(u64));
|
||||||
|
}
|
41
loader/watch.zig
Normal file
41
loader/watch.zig
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const linux = std.os.linux;
|
||||||
|
|
||||||
|
pub fn main() !void {
|
||||||
|
std.log.debug("setting up watches.", .{});
|
||||||
|
|
||||||
|
var event: linux.inotify_event = undefined;
|
||||||
|
const event_buf = std.mem.asBytes(&event);
|
||||||
|
|
||||||
|
const fd: i32 = @intCast(linux.inotify_init1(linux.IN.NONBLOCK));
|
||||||
|
defer _ = linux.close(fd);
|
||||||
|
|
||||||
|
const wd: i32 = @intCast(linux.inotify_add_watch(
|
||||||
|
fd,
|
||||||
|
"sample.txt",
|
||||||
|
linux.IN.MODIFY | linux.IN.CLOSE_WRITE,
|
||||||
|
));
|
||||||
|
defer _ = linux.inotify_rm_watch(fd, wd);
|
||||||
|
|
||||||
|
var fds = [_]linux.pollfd{
|
||||||
|
.{ .fd = fd, .events = linux.POLL.IN, .revents = 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
const k = linux.poll(&fds, fds.len, 1000);
|
||||||
|
std.log.debug("poll -> {d}", .{k});
|
||||||
|
|
||||||
|
if (k > 0) {
|
||||||
|
while (true) {
|
||||||
|
const n: isize = @bitCast(linux.read(
|
||||||
|
fd,
|
||||||
|
event_buf.ptr,
|
||||||
|
event_buf.len,
|
||||||
|
));
|
||||||
|
std.log.debug("read -> {d}", .{n});
|
||||||
|
std.time.sleep(500 * std.time.ns_per_ms);
|
||||||
|
if (n < 0) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1
md/.tool-versions
Normal file
1
md/.tool-versions
Normal file
@@ -0,0 +1 @@
|
|||||||
|
zig 0.15.0-dev.905+edf785db0
|
13601
md/CommonMark Spec.html
Normal file
13601
md/CommonMark Spec.html
Normal file
File diff suppressed because it is too large
Load Diff
52
md/build.zig
Normal file
52
md/build.zig
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
pub fn build(b: *std.Build) void {
|
||||||
|
const target = b.standardTargetOptions(.{});
|
||||||
|
const optimize = b.standardOptimizeOption(.{});
|
||||||
|
|
||||||
|
const mod = b.addModule("md", .{
|
||||||
|
.root_source_file = b.path("src/root.zig"),
|
||||||
|
.target = target,
|
||||||
|
});
|
||||||
|
|
||||||
|
const exe = b.addExecutable(.{
|
||||||
|
.name = "md",
|
||||||
|
.root_module = b.createModule(.{
|
||||||
|
.root_source_file = b.path("src/main.zig"),
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
.imports = &.{
|
||||||
|
.{ .name = "md", .module = mod },
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
b.installArtifact(exe);
|
||||||
|
|
||||||
|
const run_step = b.step("run", "Run the app");
|
||||||
|
|
||||||
|
const run_cmd = b.addRunArtifact(exe);
|
||||||
|
run_step.dependOn(&run_cmd.step);
|
||||||
|
|
||||||
|
run_cmd.step.dependOn(b.getInstallStep());
|
||||||
|
|
||||||
|
if (b.args) |args| {
|
||||||
|
run_cmd.addArgs(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
const mod_tests = b.addTest(.{
|
||||||
|
.root_module = mod,
|
||||||
|
});
|
||||||
|
|
||||||
|
const run_mod_tests = b.addRunArtifact(mod_tests);
|
||||||
|
|
||||||
|
const exe_tests = b.addTest(.{
|
||||||
|
.root_module = exe.root_module,
|
||||||
|
});
|
||||||
|
|
||||||
|
const run_exe_tests = b.addRunArtifact(exe_tests);
|
||||||
|
|
||||||
|
const test_step = b.step("test", "Run tests");
|
||||||
|
test_step.dependOn(&run_mod_tests.step);
|
||||||
|
test_step.dependOn(&run_exe_tests.step);
|
||||||
|
}
|
81
md/build.zig.zon
Normal file
81
md/build.zig.zon
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
.{
|
||||||
|
// This is the default name used by packages depending on this one. For
|
||||||
|
// example, when a user runs `zig fetch --save <url>`, this field is used
|
||||||
|
// as the key in the `dependencies` table. Although the user can choose a
|
||||||
|
// different name, most users will stick with this provided value.
|
||||||
|
//
|
||||||
|
// It is redundant to include "zig" in this name because it is already
|
||||||
|
// within the Zig package namespace.
|
||||||
|
.name = .md,
|
||||||
|
// This is a [Semantic Version](https://semver.org/).
|
||||||
|
// In a future version of Zig it will be used for package deduplication.
|
||||||
|
.version = "0.0.0",
|
||||||
|
// Together with name, this represents a globally unique package
|
||||||
|
// identifier. This field is generated by the Zig toolchain when the
|
||||||
|
// package is first created, and then *never changes*. This allows
|
||||||
|
// unambiguous detection of one package being an updated version of
|
||||||
|
// another.
|
||||||
|
//
|
||||||
|
// When forking a Zig project, this id should be regenerated (delete the
|
||||||
|
// field and run `zig build`) if the upstream project is still maintained.
|
||||||
|
// Otherwise, the fork is *hostile*, attempting to take control over the
|
||||||
|
// original project's identity. Thus it is recommended to leave the comment
|
||||||
|
// on the following line intact, so that it shows up in code reviews that
|
||||||
|
// modify the field.
|
||||||
|
.fingerprint = 0xdb55a2544fdebaae, // Changing this has security and trust implications.
|
||||||
|
// Tracks the earliest Zig version that the package considers to be a
|
||||||
|
// supported use case.
|
||||||
|
.minimum_zig_version = "0.15.0-dev.905+edf785db0",
|
||||||
|
// This field is optional.
|
||||||
|
// Each dependency must either provide a `url` and `hash`, or a `path`.
|
||||||
|
// `zig build --fetch` can be used to fetch all dependencies of a package, recursively.
|
||||||
|
// Once all dependencies are fetched, `zig build` no longer requires
|
||||||
|
// internet connectivity.
|
||||||
|
.dependencies = .{
|
||||||
|
// See `zig fetch --save <url>` for a command-line interface for adding dependencies.
|
||||||
|
//.example = .{
|
||||||
|
// // When updating this field to a new URL, be sure to delete the corresponding
|
||||||
|
// // `hash`, otherwise you are communicating that you expect to find the old hash at
|
||||||
|
// // the new URL. If the contents of a URL change this will result in a hash mismatch
|
||||||
|
// // which will prevent zig from using it.
|
||||||
|
// .url = "https://example.com/foo.tar.gz",
|
||||||
|
//
|
||||||
|
// // This is computed from the file contents of the directory of files that is
|
||||||
|
// // obtained after fetching `url` and applying the inclusion rules given by
|
||||||
|
// // `paths`.
|
||||||
|
// //
|
||||||
|
// // This field is the source of truth; packages do not come from a `url`; they
|
||||||
|
// // come from a `hash`. `url` is just one of many possible mirrors for how to
|
||||||
|
// // obtain a package matching this `hash`.
|
||||||
|
// //
|
||||||
|
// // Uses the [multihash](https://multiformats.io/multihash/) format.
|
||||||
|
// .hash = "...",
|
||||||
|
//
|
||||||
|
// // When this is provided, the package is found in a directory relative to the
|
||||||
|
// // build root. In this case the package's hash is irrelevant and therefore not
|
||||||
|
// // computed. This field and `url` are mutually exclusive.
|
||||||
|
// .path = "foo",
|
||||||
|
//
|
||||||
|
// // When this is set to `true`, a package is declared to be lazily
|
||||||
|
// // fetched. This makes the dependency only get fetched if it is
|
||||||
|
// // actually used.
|
||||||
|
// .lazy = false,
|
||||||
|
//},
|
||||||
|
},
|
||||||
|
// Specifies the set of files and directories that are included in this package.
|
||||||
|
// Only files and directories listed here are included in the `hash` that
|
||||||
|
// is computed for this package. Only files listed here will remain on disk
|
||||||
|
// when using the zig package manager. As a rule of thumb, one should list
|
||||||
|
// files required for compilation plus any license(s).
|
||||||
|
// Paths are relative to the build root. Use the empty string (`""`) to refer to
|
||||||
|
// the build root itself.
|
||||||
|
// A directory listed here means that all files within, recursively, are included.
|
||||||
|
.paths = .{
|
||||||
|
"build.zig",
|
||||||
|
"build.zig.zon",
|
||||||
|
"src",
|
||||||
|
// For example...
|
||||||
|
//"LICENSE",
|
||||||
|
//"README.md",
|
||||||
|
},
|
||||||
|
}
|
194
md/python.md
Normal file
194
md/python.md
Normal file
@@ -0,0 +1,194 @@
|
|||||||
|
Title: Python from Scratch
|
||||||
|
Date: 2025-02-01
|
||||||
|
Summary: Building up the Python Data Model from scratch.
|
||||||
|
|
||||||
|
* ** * ** * ** * ** * ** * ** * ** * ** * ** * **
|
||||||
|
|
||||||
|
# Learning to Read
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**First:** A Python program is made up of _tokens_; you can think of these as "
|
||||||
|
words". Some examples of tokens:
|
||||||
|
|
||||||
|
- `"hello world"`
|
||||||
|
- `6`
|
||||||
|
- `(`
|
||||||
|
- `while`
|
||||||
|
- `print`
|
||||||
|
|
||||||
|
Generally there are four types of token in Python, although in practice the
|
||||||
|
lines between them get blurred a little bit.
|
||||||
|
|
||||||
|
- _Literals_ literally represent some value. `"hello world"` and `6` and `4.2`
|
||||||
|
are examples of such literals; the first represents some text and the others
|
||||||
|
represent numbers. This is _literal_ as opposed to some indirect
|
||||||
|
representation like `4 + 2` or `"hello" + " " + "world"`.
|
||||||
|
|
||||||
|
- _Operators_ include things like math operators `+`, `-`, `*`, but also things
|
||||||
|
like the function call operator `( )`, boolean operators `and`, and myriad
|
||||||
|
other operators. [There's a comprehensive list here][expressions] but beware -
|
||||||
|
there's a lot and some of them are pretty technical. The main point is that
|
||||||
|
`( )` and `+` are the same _kind of thing_ as far as the Python interpreter is
|
||||||
|
concerned.
|
||||||
|
|
||||||
|
- _Keywords_ are special directives that tell Python how to behave. This
|
||||||
|
includes things like `if` and `def` and `while`. Technically, operators are
|
||||||
|
also keywords (for example `and` is a keyword) but that's not super relevant
|
||||||
|
here.
|
||||||
|
|
||||||
|
- ___Names___ are the last - and most important - kind of token. `print` is a
|
||||||
|
name. Variable names are names. Function names are names. Class names are
|
||||||
|
names. Module names are names. In all cases, a name represents some _thing_,
|
||||||
|
and Python can fetch that thing if given its name.
|
||||||
|
|
||||||
|
[expressions]: https://docs.python.org/3/reference/expressions.html
|
||||||
|
|
||||||
|
So if I give Python this code:
|
||||||
|
|
||||||
|
```py
|
||||||
|
x = "world"
|
||||||
|
print("hello " + x)
|
||||||
|
```
|
||||||
|
|
||||||
|
You should first identify the tokens:
|
||||||
|
|
||||||
|
- _Name_ `x`
|
||||||
|
- _Operator_ `=`
|
||||||
|
- _Literal_ `"world"`
|
||||||
|
- _Name_ `print`
|
||||||
|
- _Operator_ `( )`
|
||||||
|
- _Literal_ `"hello "`
|
||||||
|
- _Operator_ `+`
|
||||||
|
- _Name_ `x`
|
||||||
|
|
||||||
|
The first line of code binds `"world"` to the name `x`.
|
||||||
|
|
||||||
|
The expression `"hello " + x` looks up the value named by `x` and concatenates
|
||||||
|
it with the literal value `"hello "`. This produces the string `"hello world"`.
|
||||||
|
|
||||||
|
The expression `print( ... )` looks up the value - the function - named by
|
||||||
|
`print` and uses the `( )` operator to call it with the string `"hello world"`.
|
||||||
|
|
||||||
|
To be crystal clear: `x` and `print` _are the same kind of token_, it's just
|
||||||
|
that their named values have different types. One is a string, the other a
|
||||||
|
function. The string can be _operated on_ with the `+` operator, and the
|
||||||
|
function can be _operated on_ with the `( )` operator.
|
||||||
|
|
||||||
|
It is valid to write `print(print)`; here we are looking up the name `print`,
|
||||||
|
and passing that value to the function named by `print`. This should be no more
|
||||||
|
or less surprising than being able to write `x + x` or `5 * 4`.
|
||||||
|
|
||||||
|
# Namespaces
|
||||||
|
|
||||||
|
**First-and-a-half:** A _namespace_ is a collection of names.
|
||||||
|
|
||||||
|
You might also hear this called a "scope". This is the reason I say "maybe three
|
||||||
|
or four, depending how you count"; this is really part of that fundamental idea
|
||||||
|
of a _name_, but I'll list it separately to be extra clear.
|
||||||
|
|
||||||
|
There are some special structures in Python that introduce new namespaces. Each
|
||||||
|
_module_ has a "global" namespace; these are names that can be referenced
|
||||||
|
anywhere in a given file or script. Each _function_ has a "local" namespace;
|
||||||
|
these are names that can only be accessed within the function.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
```py
|
||||||
|
x = "eggs"
|
||||||
|
|
||||||
|
|
||||||
|
def spam():
|
||||||
|
y = "ham"
|
||||||
|
|
||||||
|
# I can print(x) here.
|
||||||
|
|
||||||
|
# But I cannot print(y) here.
|
||||||
|
```
|
||||||
|
|
||||||
|
Objects also have namespaces. Names on objects are called "attributes", and they
|
||||||
|
may be simple values or functions, just how regular names might be simple
|
||||||
|
values (`x`, `y`) or functions (`print`, `spam`). You access attributes with the
|
||||||
|
`.` operator.
|
||||||
|
|
||||||
|
```py
|
||||||
|
obj = range(10)
|
||||||
|
print(
|
||||||
|
obj.stop) # find the value named by `obj`, then find the value named by `stop`. 10.
|
||||||
|
```
|
||||||
|
|
||||||
|
Finally, there is the built-in namespace. These are names that are accessible
|
||||||
|
always, from anywhere, by default. Names like `print` and `range` are defined
|
||||||
|
here. [Here's a comprehensive list of built-in names](https://docs.python.org/3/library/functions.html).
|
||||||
|
|
||||||
|
# Strings
|
||||||
|
|
||||||
|
**Second:** you asked about characters and letters, so you may appreciate some
|
||||||
|
background on strings.
|
||||||
|
|
||||||
|
A _string_ is a sequence of characters. A _character_ is simply a number to
|
||||||
|
which we, by convention, assign some meaning. For example, by convention, we've
|
||||||
|
all agreed that the number `74` means `J`. This convention is called an
|
||||||
|
_encoding_. The default encoding is called UTF-8 and is specified by a committee
|
||||||
|
called the _Unicode Consortium_. This encoding includes characters from many
|
||||||
|
current and ancient languages, various symbols and typographical marks, emojis,
|
||||||
|
flags, etc. The important thing to remember is each one of these things, really,
|
||||||
|
is just an integer. And all our devices just agree that when they see a given
|
||||||
|
integer they will look up the appropriate symbol in an appropriate font.
|
||||||
|
|
||||||
|
You can switch between the string representation and the numerical
|
||||||
|
representation with the `encode` and `decode` methods on strings. Really, these
|
||||||
|
are the same, you're just telling Python to tell your console to draw them
|
||||||
|
differently.
|
||||||
|
|
||||||
|
```py
|
||||||
|
>> > list('Fizz'.encode())
|
||||||
|
[70, 105, 122, 122]
|
||||||
|
>> > bytes([66, 117, 122, 122]).decode()
|
||||||
|
'Buzz'
|
||||||
|
```
|
||||||
|
|
||||||
|
For continuity: `list`, `encode`, `decode`, and `bytes` are all names. `( )`,
|
||||||
|
`[ ]`, `,`, and `.` are all operators. The numbers and `'Fizz'` are literals.
|
||||||
|
|
||||||
|
† Technically, `[66, 117, 122, 122]` in its entirety is a literal - `,` is a
|
||||||
|
keyword, not an operator - but that's neither here nor there for these purposes.
|
||||||
|
|
||||||
|
‡ The symbol `†` is number 8224 and the symbol `‡` is number 8225.
|
||||||
|
|
||||||
|
# Names
|
||||||
|
|
||||||
|
**Second-and-a-half:** names are strings.
|
||||||
|
|
||||||
|
Names are just strings, and namespaces are just `dict`. You can access them with
|
||||||
|
`locals()` and `globals()`, although in practice you almost never need to do
|
||||||
|
this directly. It's better to just use the name itself.
|
||||||
|
|
||||||
|
```py
|
||||||
|
import pprint
|
||||||
|
|
||||||
|
x = range(10)
|
||||||
|
function = print
|
||||||
|
pprint.pprint(globals())
|
||||||
|
```
|
||||||
|
|
||||||
|
This outputs:
|
||||||
|
|
||||||
|
```
|
||||||
|
{'__annotations__': {},
|
||||||
|
'__builtins__': <module 'builtins' (built-in)>,
|
||||||
|
'__cached__': None,
|
||||||
|
'__doc__': None,
|
||||||
|
'__file__': '<stdin>',
|
||||||
|
'__loader__': <class '_frozen_importlib.BuiltinImporter'>,
|
||||||
|
'__name__': '__main__',
|
||||||
|
'__package__': None,
|
||||||
|
'__spec__': None,
|
||||||
|
'function': <built-in function print>,
|
||||||
|
'pprint': <module 'pprint' from 'python3.12/pprint.py'>,
|
||||||
|
'x': range(0, 10)}
|
||||||
|
```
|
||||||
|
|
||||||
|
For continuity: `import pprint` binds the name `pprint` to the module
|
||||||
|
`pprint.py` from the standard library. The line `pprint.pprint( ... )` fetches
|
||||||
|
the function `pprint` from that module, and calls it.
|
9756
md/spec-0.31.2.md
Normal file
9756
md/spec-0.31.2.md
Normal file
File diff suppressed because it is too large
Load Diff
156
md/src/main.zig
Normal file
156
md/src/main.zig
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
//! Markdown Parser.
|
||||||
|
//!
|
||||||
|
//! Leaf blocks
|
||||||
|
//! Thematic Breaks
|
||||||
|
//! ATX headings
|
||||||
|
//! Setext headings
|
||||||
|
//! Indented code blocks
|
||||||
|
//! Fenced code blocks
|
||||||
|
//! HTML blocks
|
||||||
|
//! Link reference definitions
|
||||||
|
//! Paragraphs
|
||||||
|
//! Blank lines
|
||||||
|
//!
|
||||||
|
//! Container blocks
|
||||||
|
//! Block Quotes
|
||||||
|
//! List Items
|
||||||
|
//! Lists
|
||||||
|
//!
|
||||||
|
//! Inlines
|
||||||
|
//! Code spans
|
||||||
|
//! emph, strong
|
||||||
|
//! Links
|
||||||
|
//! Images
|
||||||
|
//! Autolinks
|
||||||
|
//! Raw HTML
|
||||||
|
//! Hard line breaks
|
||||||
|
//! Soft line breaks
|
||||||
|
//! Text
|
||||||
|
|
||||||
|
const BlockType = enum {
|
||||||
|
// Leaf Blocks
|
||||||
|
Break,
|
||||||
|
Heading,
|
||||||
|
Code,
|
||||||
|
HTML,
|
||||||
|
LinkDefinition,
|
||||||
|
Paragraph,
|
||||||
|
Blank,
|
||||||
|
|
||||||
|
// Container Blocks
|
||||||
|
Quote,
|
||||||
|
List,
|
||||||
|
// ListItem,
|
||||||
|
};
|
||||||
|
|
||||||
|
const Block = struct {
|
||||||
|
type: BlockType,
|
||||||
|
text: []const u8,
|
||||||
|
depth: u8 = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
|
const md = @import("md");
|
||||||
|
|
||||||
|
pub fn render(src: []const u8, alloc: std.mem.Allocator) !void {
|
||||||
|
var it = std.mem.splitScalar(u8, src, '\n');
|
||||||
|
|
||||||
|
var blocks = std.ArrayList(Block).init(alloc);
|
||||||
|
defer blocks.deinit();
|
||||||
|
|
||||||
|
line_search: while (it.next()) |line| {
|
||||||
|
// early check for blank line
|
||||||
|
for (line) |ch| {
|
||||||
|
if (!std.ascii.isWhitespace(ch)) break;
|
||||||
|
} else {
|
||||||
|
try blocks.append(.{ .type = .Blank, .text = line });
|
||||||
|
continue :line_search;
|
||||||
|
}
|
||||||
|
|
||||||
|
// figure out indentation
|
||||||
|
var depth: u8 = 0;
|
||||||
|
var start: u8 = 0;
|
||||||
|
|
||||||
|
for (line) |ch| {
|
||||||
|
switch (ch) {
|
||||||
|
' ' => depth += 1,
|
||||||
|
'\t' => depth += 4,
|
||||||
|
else => break,
|
||||||
|
}
|
||||||
|
start += 1;
|
||||||
|
}
|
||||||
|
// at this point, start will not be line.len because we checked
|
||||||
|
// it is not blank
|
||||||
|
|
||||||
|
if (depth >= 4) {
|
||||||
|
// todo something special has to happen. lists and code blocks.
|
||||||
|
}
|
||||||
|
|
||||||
|
// test thematic break
|
||||||
|
switch (line[start]) {
|
||||||
|
'*', '-', '_' => |kind| {
|
||||||
|
var count: u8 = 0;
|
||||||
|
for (line[start..]) |ch| {
|
||||||
|
if (ch == kind) {
|
||||||
|
count += 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (std.ascii.isWhitespace(ch)) continue;
|
||||||
|
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
if (count >= 3) {
|
||||||
|
try blocks.append(.{ .type = .Break, .text = line });
|
||||||
|
continue :line_search;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (blocks.items) |block| {
|
||||||
|
std.debug.print("{any}\n", .{block});
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO split into paragraphs, list elements
|
||||||
|
//
|
||||||
|
|
||||||
|
// const State = enum {
|
||||||
|
// Block,
|
||||||
|
// };
|
||||||
|
|
||||||
|
// mach: switch (State.Block) {
|
||||||
|
// .Block => {
|
||||||
|
// continue :mach .Block;
|
||||||
|
// },
|
||||||
|
// }
|
||||||
|
|
||||||
|
// while (it.next()) |line| {}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn main() !void {
|
||||||
|
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||||
|
defer _ = gpa.deinit();
|
||||||
|
const alloc = gpa.allocator();
|
||||||
|
|
||||||
|
const args = try std.process.argsAlloc(alloc);
|
||||||
|
defer std.process.argsFree(alloc, args);
|
||||||
|
|
||||||
|
const buf = try alloc.alloc(u8, 1 << 20);
|
||||||
|
defer alloc.free(buf);
|
||||||
|
|
||||||
|
for (args[1..]) |path| {
|
||||||
|
const file = try std.fs.cwd().openFile(path, .{ .mode = .read_only });
|
||||||
|
defer file.close();
|
||||||
|
const stat = try file.stat();
|
||||||
|
if (stat.size > buf.len)
|
||||||
|
return error.FileTooBig;
|
||||||
|
|
||||||
|
const n = try file.readAll(buf);
|
||||||
|
const content = buf[0..n];
|
||||||
|
|
||||||
|
try render(content, alloc);
|
||||||
|
}
|
||||||
|
}
|
54
md/src/root.zig
Normal file
54
md/src/root.zig
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
pub fn parse(src: []const u8, alloc: std.mem.Allocator) ![][]const u8 {
|
||||||
|
var it = std.mem.splitScalar(u8, src, '\n');
|
||||||
|
|
||||||
|
var lines = std.ArrayList([]const u8).init(alloc);
|
||||||
|
|
||||||
|
while (it.next()) |line| {
|
||||||
|
try lines.append(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
return try lines.toOwnedSlice();
|
||||||
|
}
|
||||||
|
|
||||||
|
// pub fn render(src: []const u8, alloc: std.mem.Allocator) ![]const u8 {
|
||||||
|
// // std.mem.tokenizeScalar(comptime T: type, buffer: []const T, delimiter: T)
|
||||||
|
// }
|
||||||
|
|
||||||
|
test "split-lines" {
|
||||||
|
const alloc = std.testing.allocator;
|
||||||
|
|
||||||
|
const src =
|
||||||
|
\\hello world!
|
||||||
|
\\
|
||||||
|
\\this is some content!
|
||||||
|
\\
|
||||||
|
;
|
||||||
|
|
||||||
|
const lines = try parse(src, alloc);
|
||||||
|
defer alloc.free(lines);
|
||||||
|
|
||||||
|
const expect: []const []const u8 = &.{
|
||||||
|
"hello world!",
|
||||||
|
"",
|
||||||
|
"this is some content!",
|
||||||
|
"",
|
||||||
|
};
|
||||||
|
|
||||||
|
try std.testing.expectEqualDeep(
|
||||||
|
expect,
|
||||||
|
lines,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "2.2 Tabs" {
|
||||||
|
// const alloc = std.testing.allocator;
|
||||||
|
//
|
||||||
|
// const md = "\tfoo\tbaz\t\tbim";
|
||||||
|
|
||||||
|
// const expect = "<pre><code>foo\tbaz\t\tbim</code></pre>";
|
||||||
|
// const actual = try render(md, alloc);
|
||||||
|
// defer alloc.free(actual);
|
||||||
|
// std.testing.expectEqualStrings(expect, actual);
|
||||||
|
}
|
BIN
md/zig-out/bin/md
Executable file
BIN
md/zig-out/bin/md
Executable file
Binary file not shown.
1
statusline/.tool-versions
Normal file
1
statusline/.tool-versions
Normal file
@@ -0,0 +1 @@
|
|||||||
|
zig 0.15.0-dev.905+edf785db0
|
79
statusline/Cpu.zig
Normal file
79
statusline/Cpu.zig
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
fh: std.fs.File,
|
||||||
|
buf: []u8,
|
||||||
|
stats: Stats,
|
||||||
|
perc: u8 = 0,
|
||||||
|
|
||||||
|
pub fn init(self: *Self, alloc: std.mem.Allocator) !void {
|
||||||
|
self.fh = try std.fs.openFileAbsolute("/proc/stat", .{ .mode = .read_only });
|
||||||
|
errdefer self.fh.close();
|
||||||
|
|
||||||
|
self.buf = try alloc.alloc(u8, 256);
|
||||||
|
errdefer alloc.free(self.buf);
|
||||||
|
|
||||||
|
self.stats = try self.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const Stats = struct {
|
||||||
|
all: u32,
|
||||||
|
all_idle: u32,
|
||||||
|
all_active: u32,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn update(self: *Self) ![]const u8 {
|
||||||
|
const delta = try self.get_delta();
|
||||||
|
if (delta.all != 0) {
|
||||||
|
self.perc = @intCast(@divFloor(1 + 2 * 100 * delta.all_active, 2 * delta.all));
|
||||||
|
}
|
||||||
|
return try std.fmt.bufPrint(self.buf, "cpu: {d:0>2}%", .{self.perc});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: Self, alloc: std.mem.Allocator) void {
|
||||||
|
self.fh.close();
|
||||||
|
alloc.free(self.buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get(self: Self) !Stats {
|
||||||
|
try self.fh.seekTo(0);
|
||||||
|
const line = try self.fh.reader().readUntilDelimiter(self.buf, '\n');
|
||||||
|
|
||||||
|
var tokens = std.mem.tokenizeScalar(u8, line, ' ');
|
||||||
|
_ = tokens.next(); // skip "cpu"
|
||||||
|
|
||||||
|
var raw: struct {
|
||||||
|
user: u32,
|
||||||
|
nice: u32,
|
||||||
|
system: u32,
|
||||||
|
idle: u32,
|
||||||
|
iowait: u32,
|
||||||
|
irq: u32,
|
||||||
|
softirq: u32,
|
||||||
|
steal: u32,
|
||||||
|
guest: u32,
|
||||||
|
guest_nice: u32,
|
||||||
|
} = undefined;
|
||||||
|
|
||||||
|
inline for (std.meta.fields(@TypeOf(raw))) |f| {
|
||||||
|
const token = tokens.next() orelse return error.MissingStat;
|
||||||
|
@field(raw, f.name) = try std.fmt.parseInt(f.type, token, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
const idle = raw.idle + raw.iowait;
|
||||||
|
const active = raw.user + raw.nice + raw.system + raw.irq + raw.softirq + raw.steal;
|
||||||
|
|
||||||
|
return .{ .all = idle + active, .all_idle = idle, .all_active = active };
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_delta(self: *Self) !Stats {
|
||||||
|
const prev = self.stats;
|
||||||
|
const next = try self.get();
|
||||||
|
self.stats = next;
|
||||||
|
|
||||||
|
return .{
|
||||||
|
.all = next.all - prev.all,
|
||||||
|
.all_idle = next.all_idle - prev.all_idle,
|
||||||
|
.all_active = next.all_active - prev.all_active,
|
||||||
|
};
|
||||||
|
}
|
58
statusline/Mem.zig
Normal file
58
statusline/Mem.zig
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
fh: std.fs.File,
|
||||||
|
dat: []u8,
|
||||||
|
buf: []u8,
|
||||||
|
perc: u8 = 0,
|
||||||
|
|
||||||
|
pub fn init(self: *Self, alloc: std.mem.Allocator) !void {
|
||||||
|
self.fh = try std.fs.openFileAbsolute("/proc/meminfo", .{ .mode = .read_only });
|
||||||
|
errdefer self.fh.close();
|
||||||
|
|
||||||
|
self.dat = try alloc.alloc(u8, 256);
|
||||||
|
errdefer alloc.free(self.dat);
|
||||||
|
|
||||||
|
self.buf = try alloc.alloc(u8, 256);
|
||||||
|
errdefer alloc.free(self.buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update(self: *Self) ![]const u8 {
|
||||||
|
try self.fh.seekTo(0);
|
||||||
|
var br = std.io.bufferedReader(self.fh.reader());
|
||||||
|
const reader = br.reader();
|
||||||
|
|
||||||
|
var total: u32 = undefined;
|
||||||
|
var free: u32 = undefined;
|
||||||
|
var avail: u32 = undefined;
|
||||||
|
|
||||||
|
for (0..3) |_| {
|
||||||
|
const line = try reader.readUntilDelimiterOrEof(self.dat, '\n');
|
||||||
|
var tokens = std.mem.tokenizeAny(u8, line.?, ": ");
|
||||||
|
|
||||||
|
const label = tokens.next().?;
|
||||||
|
const value = try std.fmt.parseInt(u32, tokens.next().?, 10);
|
||||||
|
|
||||||
|
if (std.mem.eql(u8, label, "MemTotal")) {
|
||||||
|
total = value;
|
||||||
|
} else if (std.mem.eql(u8, label, "MemFree")) {
|
||||||
|
free = value;
|
||||||
|
} else if (std.mem.eql(u8, label, "MemAvailable")) {
|
||||||
|
avail = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const perc_used: u8 = @intCast(@divFloor(1 + 2 * 100 * (total - avail), 2 * total));
|
||||||
|
|
||||||
|
return try std.fmt.bufPrint(
|
||||||
|
self.buf,
|
||||||
|
"mem: {d: >2}%",
|
||||||
|
.{perc_used},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: Self, alloc: std.mem.Allocator) void {
|
||||||
|
self.fh.close();
|
||||||
|
alloc.free(self.dat);
|
||||||
|
alloc.free(self.buf);
|
||||||
|
}
|
29
statusline/Time.zig
Normal file
29
statusline/Time.zig
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
const time = @cImport({
|
||||||
|
@cInclude("time.h");
|
||||||
|
});
|
||||||
|
|
||||||
|
buf: []u8,
|
||||||
|
|
||||||
|
pub fn init(self: *Self, alloc: std.mem.Allocator) !void {
|
||||||
|
self.buf = try alloc.alloc(u8, 64);
|
||||||
|
errdefer alloc.free(self.buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update(self: *Self) ![]const u8 {
|
||||||
|
const tt: time.time_t = time.time(null);
|
||||||
|
const tp = time.localtime(&tt);
|
||||||
|
const n = time.strftime(
|
||||||
|
self.buf.ptr,
|
||||||
|
self.buf.len,
|
||||||
|
"%c",
|
||||||
|
tp,
|
||||||
|
);
|
||||||
|
return self.buf[0..n];
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *Self, alloc: std.mem.Allocator) void {
|
||||||
|
alloc.free(self.buf);
|
||||||
|
}
|
95
statusline/cpu.bak.zig
Normal file
95
statusline/cpu.bak.zig
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
const RawStats = struct {
|
||||||
|
user: u32,
|
||||||
|
nice: u32,
|
||||||
|
system: u32,
|
||||||
|
idle: u32,
|
||||||
|
iowait: u32,
|
||||||
|
irq: u32,
|
||||||
|
softirq: u32,
|
||||||
|
steal: u32,
|
||||||
|
guest: u32,
|
||||||
|
guest_nice: u32,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Stats = struct {
|
||||||
|
all: u32,
|
||||||
|
all_idle: u32,
|
||||||
|
all_active: u32,
|
||||||
|
|
||||||
|
pub fn active_ratio(self: Stats) f32 {
|
||||||
|
return @as(f32, @floatFromInt(self.all_active)) / @as(f32, @floatFromInt(self.all));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn active_perc(self: Stats) u8 {
|
||||||
|
return @intCast(100 * self.all_active / self.all);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fh: std.fs.File,
|
||||||
|
buf: []u8,
|
||||||
|
|
||||||
|
pub fn init(alloc: std.mem.Allocator) !Self {
|
||||||
|
const fh = try std.fs.openFileAbsolute("/proc/stat", .{ .mode = .read_only });
|
||||||
|
errdefer fh.close();
|
||||||
|
|
||||||
|
const buf = try alloc.alloc(u8, 512);
|
||||||
|
errdefer alloc.free(buf);
|
||||||
|
|
||||||
|
return .{ .fh = fh, .buf = buf };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: Self, alloc: std.mem.Allocator) void {
|
||||||
|
self.fh.close();
|
||||||
|
alloc.free(self.buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(self: Self) !Stats {
|
||||||
|
try self.fh.seekTo(0);
|
||||||
|
const line = try self.fh.reader().readUntilDelimiter(self.buf, '\n');
|
||||||
|
|
||||||
|
var tokens = std.mem.tokenizeScalar(u8, line, ' ');
|
||||||
|
_ = tokens.next(); // skip "cpu"
|
||||||
|
|
||||||
|
var raw: RawStats = undefined;
|
||||||
|
|
||||||
|
inline for (std.meta.fields(RawStats)) |f| {
|
||||||
|
const token = tokens.next() orelse return error.MissingStat;
|
||||||
|
@field(raw, f.name) = try std.fmt.parseInt(f.type, token, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
const idle = raw.idle + raw.iowait;
|
||||||
|
const active = raw.user + raw.nice + raw.system + raw.irq + raw.softirq + raw.steal;
|
||||||
|
|
||||||
|
return .{ .all = idle + active, .all_idle = idle, .all_active = active };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_delta(self: Self, prev: *Stats) !Stats {
|
||||||
|
const next = try self.get();
|
||||||
|
const delta: Stats = .{
|
||||||
|
.all = next.all - prev.all,
|
||||||
|
.all_idle = next.all_idle - prev.all_idle,
|
||||||
|
.all_active = next.all_active - prev.all_active,
|
||||||
|
};
|
||||||
|
prev.* = next;
|
||||||
|
return delta;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn main() !void {
|
||||||
|
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||||
|
defer _ = gpa.deinit();
|
||||||
|
const alloc = gpa.allocator();
|
||||||
|
|
||||||
|
const monitor = try Self.init(alloc);
|
||||||
|
defer monitor.deinit(alloc);
|
||||||
|
|
||||||
|
var stats = try monitor.get();
|
||||||
|
std.time.sleep(std.time.ns_per_s);
|
||||||
|
const delta = try monitor.get_delta(&stats);
|
||||||
|
|
||||||
|
std.debug.print("{any}\n", .{delta});
|
||||||
|
std.debug.print("{d:.6} {d}\n", .{ delta.active_ratio(), delta.active_perc() });
|
||||||
|
}
|
41
statusline/main.zig
Normal file
41
statusline/main.zig
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
const Frequency = 500;
|
||||||
|
const Mods = .{
|
||||||
|
@import("Mem.zig"),
|
||||||
|
@import("Cpu.zig"),
|
||||||
|
@import("Time.zig"),
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn main() !void {
|
||||||
|
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||||
|
defer _ = gpa.deinit();
|
||||||
|
const alloc = gpa.allocator();
|
||||||
|
|
||||||
|
var mods: std.meta.Tuple(&Mods) = undefined;
|
||||||
|
inline for (&mods) |*mod| {
|
||||||
|
try mod.init(alloc);
|
||||||
|
}
|
||||||
|
defer {
|
||||||
|
inline for (&mods) |*mod| {
|
||||||
|
mod.deinit(alloc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const stdout = std.io.getStdOut();
|
||||||
|
const buffer = try alloc.alloc(u8, 512);
|
||||||
|
defer alloc.free(buffer);
|
||||||
|
|
||||||
|
var outputs: [Mods.len][]const u8 = undefined;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
std.time.sleep(Frequency * std.time.ns_per_ms);
|
||||||
|
|
||||||
|
inline for (&mods, &outputs) |*mod, *out| {
|
||||||
|
out.* = try mod.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
const output = try std.fmt.bufPrint(buffer, "{s}\n", .{outputs});
|
||||||
|
try stdout.writeAll(output);
|
||||||
|
}
|
||||||
|
}
|
80
statusline/modules-wip.zig
Normal file
80
statusline/modules-wip.zig
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
const Module = struct {
|
||||||
|
init: *const fn (std.mem.Allocator) *anyopaque,
|
||||||
|
deinit: *const fn (*anyopaque, std.mem.Allocator) void,
|
||||||
|
update: *const fn (*anyopaque, std.mem.Allocator) void,
|
||||||
|
};
|
||||||
|
|
||||||
|
const Foo = struct {
|
||||||
|
fn init(alloc: std.mem.Allocator) *@This() {
|
||||||
|
return alloc.create(@This()) catch @panic("OOM");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deinit(self: *@This(), alloc: std.mem.Allocator) void {
|
||||||
|
alloc.destroy(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(self: *@This(), alloc: std.mem.Allocator) void {
|
||||||
|
_ = self;
|
||||||
|
_ = alloc;
|
||||||
|
|
||||||
|
std.log.debug("Hello, {s}", .{@typeName(@This())});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const Bar = struct {
|
||||||
|
fn init(alloc: std.mem.Allocator) *@This() {
|
||||||
|
return alloc.create(@This()) catch @panic("OOM");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deinit(self: *@This(), alloc: std.mem.Allocator) void {
|
||||||
|
alloc.destroy(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(self: *@This(), alloc: std.mem.Allocator) void {
|
||||||
|
_ = self;
|
||||||
|
_ = alloc;
|
||||||
|
|
||||||
|
std.log.debug("Hello, {s}", .{@typeName(@This())});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const Modules = .{
|
||||||
|
Foo,
|
||||||
|
Bar,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn main() !void {
|
||||||
|
// comptime var modules: [Modules.len]Module = undefined;
|
||||||
|
comptime var modules: [Modules.len]type = undefined;
|
||||||
|
|
||||||
|
inline for (Modules, &modules) |Mod, *mod| {
|
||||||
|
mod.* = struct {
|
||||||
|
pub fn init(alloc: std.mem.Allocator) void {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// mod.* = .{
|
||||||
|
// .init = @ptrCast(&Mod.init),
|
||||||
|
// .deinit = @ptrCast(&Mod.deinit),
|
||||||
|
// .update = @ptrCast(&Mod.update),
|
||||||
|
// };
|
||||||
|
}
|
||||||
|
|
||||||
|
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||||
|
defer _ = gpa.deinit();
|
||||||
|
const alloc = gpa.allocator();
|
||||||
|
|
||||||
|
var states: [Modules.len]*anyopaque = undefined;
|
||||||
|
for (modules, &states) |mod, *state| {
|
||||||
|
state.* = mod.init(alloc);
|
||||||
|
}
|
||||||
|
defer for (modules, states) |mod, state| {
|
||||||
|
mod.deinit(state, alloc);
|
||||||
|
};
|
||||||
|
|
||||||
|
std.log.debug("Performing update...", .{});
|
||||||
|
for (modules, states) |mod, state| {
|
||||||
|
mod.update(state, alloc);
|
||||||
|
}
|
||||||
|
}
|
73
statusline/status.zig
Normal file
73
statusline/status.zig
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
const Blocks = .{
|
||||||
|
@import("Cpu.zig").block(.{}),
|
||||||
|
@import("Cpu.zig").block(.{}), // just testing a second block
|
||||||
|
};
|
||||||
|
|
||||||
|
const freq_ms = 500;
|
||||||
|
|
||||||
|
pub fn main() !void {
|
||||||
|
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||||
|
defer _ = gpa.deinit();
|
||||||
|
const alloc = gpa.allocator();
|
||||||
|
|
||||||
|
var blocks: std.meta.Tuple(&Blocks) = undefined;
|
||||||
|
var arenas: [Blocks.len]std.heap.ArenaAllocator = undefined;
|
||||||
|
var outputs: [Blocks.len][]const u8 = undefined;
|
||||||
|
|
||||||
|
var combined_arena = std.heap.ArenaAllocator.init(alloc);
|
||||||
|
defer combined_arena.deinit();
|
||||||
|
|
||||||
|
inline for (Blocks, &blocks, &arenas) |Block, *block, *arena| {
|
||||||
|
block.* = try Block.init(alloc);
|
||||||
|
arena.* = std.heap.ArenaAllocator.init(alloc);
|
||||||
|
}
|
||||||
|
|
||||||
|
defer inline for (blocks, arenas) |block, arena| {
|
||||||
|
block.deinit(alloc);
|
||||||
|
arena.deinit();
|
||||||
|
};
|
||||||
|
|
||||||
|
std.time.sleep(std.time.ns_per_s);
|
||||||
|
|
||||||
|
inline for (&blocks, &arenas, &outputs) |*block, *arena, *output| {
|
||||||
|
output.* = try block.update(arena.allocator());
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = combined_arena.reset(.retain_capacity);
|
||||||
|
const combined = try std.mem.join(combined_arena.allocator(), " * ", &outputs);
|
||||||
|
try std.io.getStdOut().writeAll(combined);
|
||||||
|
try std.io.getStdOut().writeAll("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// pub fn main() !void {
|
||||||
|
// var arenas: [Blocks.len]std.heap.ArenaAllocator = undefined;
|
||||||
|
// inline for (&arenas) |*arena| {
|
||||||
|
// arena.* = std.heap.ArenaAllocator.init(alloc);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// var outs: [Blocks.len][]u8 = undefined;
|
||||||
|
//
|
||||||
|
// var buf = std.ArrayList(u8).init(alloc);
|
||||||
|
// defer buf.deinit();
|
||||||
|
// try buf.ensureTotalCapacity(512);
|
||||||
|
//
|
||||||
|
// while (true) {
|
||||||
|
// inline for (&blocks, &arenas, &outs) |*block, *arena, *out| {
|
||||||
|
// arena.reset(.{ .retain_with_limit = 100 });
|
||||||
|
// out.* = try block.update(arena.allocator());
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// std.mem.join(allocator: Allocator, separator: []const u8, slices: []const []const u8)
|
||||||
|
//
|
||||||
|
// // try buf.resize(0);
|
||||||
|
// // inline for (&blocks) |*block| {
|
||||||
|
// // try block.update();
|
||||||
|
// // try block.print(buf.fixedWriter().any());
|
||||||
|
// // }
|
||||||
|
// // std.debug.print("buf: {s}\n", .{buf.items});
|
||||||
|
// //
|
||||||
|
// // std.time.sleep(freq_ms * std.time.ns_per_ms);
|
||||||
|
// }
|
||||||
|
// }
|
1
zzd/.tool-versions
Normal file
1
zzd/.tool-versions
Normal file
@@ -0,0 +1 @@
|
|||||||
|
zig 0.15.0-dev.905+edf785db0
|
50
zzd/main.zig
Normal file
50
zzd/main.zig
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
pub fn main() !void {
|
||||||
|
var args = std.process.args();
|
||||||
|
defer args.deinit();
|
||||||
|
|
||||||
|
std.debug.assert(args.skip());
|
||||||
|
|
||||||
|
const filename = args.next() orelse {
|
||||||
|
std.debug.print("Invalid usage.\n", .{});
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
const cwd = std.fs.cwd();
|
||||||
|
const file = try cwd.openFileZ(filename, .{
|
||||||
|
.mode = .read_only,
|
||||||
|
.lock = .none,
|
||||||
|
});
|
||||||
|
defer file.close();
|
||||||
|
|
||||||
|
var rb = std.io.bufferedReader(file.reader());
|
||||||
|
const in = rb.reader();
|
||||||
|
|
||||||
|
var stdout = std.io.getStdOut();
|
||||||
|
var bw = std.io.bufferedWriter(stdout.writer());
|
||||||
|
|
||||||
|
const out = bw.writer();
|
||||||
|
|
||||||
|
const N = 16;
|
||||||
|
const B = 2;
|
||||||
|
|
||||||
|
var idx: usize = 0;
|
||||||
|
while (in.readByte() catch null) |b| {
|
||||||
|
idx += 1;
|
||||||
|
try out.print("{x:0>2}", .{b});
|
||||||
|
if (idx % N == 0) {
|
||||||
|
try out.print("\n", .{});
|
||||||
|
idx = 0;
|
||||||
|
} else if (idx % B == 0) {
|
||||||
|
try out.print(" ", .{});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (idx != 0) {
|
||||||
|
try out.print("\n", .{});
|
||||||
|
}
|
||||||
|
try out.writeByteNTimes('=', 2 * N + N / B - 1);
|
||||||
|
|
||||||
|
try bw.flush();
|
||||||
|
}
|
Reference in New Issue
Block a user