-
-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* add night shift * tidy * add args for night-shift * update CI * fix macos build * bump to macos-13 * debug * fix header * disable night-shift in CI
- Loading branch information
1 parent
eccf284
commit 5771935
Showing
5 changed files
with
313 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
#+TITLE: Zigcli | ||
#+DATE: 2022-09-20T22:55:17+0800 | ||
#+LASTMOD: 2023-06-29T20:22:28+0800 | ||
#+LASTMOD: 2023-07-04T22:26:07+0800 | ||
#+AUTHOR: Jiacai Liu | ||
#+EMAIL: [email protected] | ||
#+OPTIONS: toc:nil num:nil | ||
|
@@ -14,6 +14,7 @@ Command line programs written in Zig. Currently there are: | |
- =tree=, list contents of directories in a tree-like format. | ||
- =yes=, output a string repeatedly until killed. | ||
- =pidof=, like [[https://man7.org/linux/man-pages/man1/pidof.1.html][pidof]], but for macOS. | ||
- =night-shift=, control [[https://support.apple.com/guide/mac-help/use-night-shift-mchl97bc676d/mac][Night Shift]] in cli, build for macOS. | ||
|
||
Prebuilt binaries can be found in [[https://github.com/jiacai2050/loc/actions/workflows/binary.yml][CI's artifacts]], or you can build from source: | ||
#+begin_src bash | ||
|
@@ -63,6 +64,30 @@ Ruby 1 8 5 2 1 201.00B | |
-------- ---- ---- ---- ------- ----- ------- | ||
Total 17 1260 1072 42 146 34.46K | ||
#+end_src | ||
* Night shift | ||
#+begin_src bash :results verbatim code :exports both | ||
./zig-out/bin/night-shift -h | ||
#+end_src | ||
|
||
#+RESULTS: | ||
#+begin_src bash | ||
USAGE: | ||
./zig-out/bin/night-shift [OPTIONS] [--] <command> | ||
|
||
Available commands by category: | ||
Manual on/off control: | ||
on Turn Night Shift on | ||
off Turn Night Shift off | ||
toggle Toggle Night Shift | ||
|
||
Color temperature: | ||
temp View temperature preference | ||
temp <0-100> Set temperature preference | ||
|
||
OPTIONS: | ||
-v, --version Print version | ||
-h, --help Print help information | ||
#+end_src | ||
|
||
* Roadmap | ||
** Loc | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,212 @@ | ||
//! Control Night shift in cli, build for macOS. | ||
//! | ||
const std = @import("std"); | ||
const simargs = @import("simargs"); | ||
const util = @import("util.zig"); | ||
const c = @cImport({ | ||
@cInclude("objc/objc.h"); | ||
@cInclude("objc/message.h"); | ||
}); | ||
|
||
const Time = extern struct { | ||
hour: c_int, | ||
minute: c_int, | ||
}; | ||
const Schedule = extern struct { | ||
from_time: Time, | ||
to_time: Time, | ||
}; | ||
|
||
// Refer https://github.com/smudge/nightlight/blob/03595a642f0876388db11b9f5a3bd8261ab178d5/src/macos/status.rs#L21 | ||
const Status = extern struct { | ||
active: bool, | ||
enabled: bool, | ||
sun_schedule_permitted: bool, | ||
mode: c_int, | ||
schedule: Schedule, | ||
disable_flags: c_ulonglong, | ||
available: bool, | ||
}; | ||
|
||
const Client = struct { | ||
inner: c.id, | ||
allocator: std.mem.Allocator, | ||
|
||
const Self = @This(); | ||
|
||
fn init(allocator: std.mem.Allocator) Self { | ||
// https://developer.limneos.net/?ios=14.4&framework=CoreBrightness.framework&header=CBBlueLightClient.h | ||
const clazz = c.objc_getClass("CBBlueLightClient"); | ||
const call: *fn (c.id, c.SEL) callconv(.C) c.id = @constCast(@ptrCast(&c.objc_msgSend)); | ||
|
||
return Self{ | ||
.inner = call( | ||
call(@alignCast(@ptrCast(clazz.?)), c.sel_registerName("alloc")), | ||
c.sel_registerName("init"), | ||
), | ||
.allocator = allocator, | ||
}; | ||
} | ||
|
||
fn getStatus(self: Self) !*Status { | ||
var status = try self.allocator.create(Status); | ||
const call: *fn (c.id, c.SEL, *Status) callconv(.C) bool = | ||
@constCast(@ptrCast(&c.objc_msgSend)); | ||
const ret = call(self.inner, c.sel_registerName("getBlueLightStatus:"), status); | ||
if (!ret) { | ||
return error.getBlueLightStatus; | ||
} | ||
|
||
return status; | ||
} | ||
|
||
fn setEnabled(self: Self, enabled: bool) !void { | ||
const call: *fn (c.id, c.SEL, bool) callconv(.C) bool = @constCast(@ptrCast(&c.objc_msgSend)); | ||
const ret = call(self.inner, c.sel_registerName("setEnabled:"), enabled); | ||
if (!ret) { | ||
return error.getStrength; | ||
} | ||
} | ||
|
||
fn turnOn(self: Self) !void { | ||
return self.setEnabled(true); | ||
} | ||
|
||
fn turnOff(self: Self) !void { | ||
return self.setEnabled(false); | ||
} | ||
|
||
fn getStrength(self: Self) !f32 { | ||
var strength: f32 = 0; | ||
const call: *fn (c.id, c.SEL, *f32) callconv(.C) bool = @constCast(@ptrCast(&c.objc_msgSend)); | ||
const ret = call(self.inner, c.sel_registerName("getStrength:"), &strength); | ||
if (!ret) { | ||
return error.getStrength; | ||
} | ||
|
||
return strength; | ||
} | ||
|
||
fn setStrength(self: Self, strength: f32) !void { | ||
const call: *fn (c.id, c.SEL, f32, bool) callconv(.C) bool = @constCast(@ptrCast(&c.objc_msgSend)); | ||
const ret = call(self.inner, c.sel_registerName("setStrength:commit:"), strength, true); | ||
if (!ret) { | ||
return error.setStrength; | ||
} | ||
} | ||
|
||
fn destroyStatus(self: Self, status: *Status) void { | ||
self.allocator.destroy(status); | ||
} | ||
}; | ||
|
||
const Action = enum { | ||
Status, | ||
On, | ||
Off, | ||
Toggle, | ||
Temp, | ||
|
||
const FromString = std.ComptimeStringMap(@This(), .{ | ||
.{ "status", .Status }, | ||
.{ "on", .On }, | ||
.{ "off", .Off }, | ||
.{ "toggle", .Toggle }, | ||
.{ "temp", .Temp }, | ||
}); | ||
}; | ||
|
||
pub fn main() !void { | ||
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); | ||
defer arena.deinit(); | ||
const allocator = arena.allocator(); | ||
|
||
const opt = try simargs.parse(allocator, struct { | ||
version: bool = false, | ||
help: bool = false, | ||
|
||
pub const __shorts__ = .{ | ||
.version = .v, | ||
.help = .h, | ||
}; | ||
|
||
pub const __messages__ = .{ | ||
.help = "Print help information", | ||
.version = "Print version", | ||
}; | ||
}, | ||
\\<command> | ||
\\ | ||
\\ Available commands by category: | ||
\\ Manual on/off control: | ||
\\ on Turn Night Shift on | ||
\\ off Turn Night Shift off | ||
\\ toggle Toggle Night Shift | ||
\\ | ||
\\ Color temperature: | ||
\\ temp View temperature preference | ||
\\ temp <0-100> Set temperature preference | ||
, util.get_build_info()); | ||
defer opt.deinit(); | ||
|
||
const action: Action = if (opt.positional_args.items.len == 0) | ||
.Status | ||
else | ||
Action.FromString.get(opt.positional_args.items[0]) orelse .Status; | ||
|
||
const client = Client.init(allocator); | ||
var wtr = std.io.getStdOut().writer(); | ||
|
||
switch (action) { | ||
.Status => { | ||
var status = try client.getStatus(); | ||
defer client.destroyStatus(status); | ||
|
||
if (!status.enabled) { | ||
try wtr.writeAll("enabled: off"); | ||
return; | ||
} | ||
|
||
const schedule = switch (status.mode) { | ||
0 => "Off", | ||
1 => "SunsetToSunrise", | ||
2 => try std.fmt.allocPrint(allocator, "Custom({d}:{d}-{d}:{d})", .{ | ||
status.schedule.from_time.hour, | ||
status.schedule.from_time.minute, | ||
status.schedule.to_time.hour, | ||
status.schedule.to_time.minute, | ||
}), | ||
else => "Unknown", | ||
}; | ||
try wtr.print( | ||
\\Enabled: on | ||
\\Schedule: {s} | ||
\\Temperature: {d:.0} | ||
, .{ schedule, try client.getStrength() * 100 }); | ||
}, | ||
.Temp => { | ||
if (opt.positional_args.items.len == 2) { | ||
const strength = try std.fmt.parseFloat(f32, opt.positional_args.items[1]); | ||
try client.setStrength(strength / 100.0); | ||
return; | ||
} | ||
|
||
const strength = try client.getStrength(); | ||
try wtr.print("{d:.0}\n", .{strength * 100}); | ||
}, | ||
.Toggle => { | ||
var status = try client.getStatus(); | ||
if (status.enabled) { | ||
try client.turnOff(); | ||
} else { | ||
try client.turnOn(); | ||
} | ||
}, | ||
.On => { | ||
try client.turnOn(); | ||
}, | ||
.Off => { | ||
try client.turnOff(); | ||
}, | ||
} | ||
} |
Oops, something went wrong.