implement clipboard set, both windows and linux

This commit is contained in:
Emil Lerch 2022-01-06 12:16:22 -08:00
parent 113fb5e75c
commit a2a6302588
Signed by: lobo
GPG Key ID: A7B62D657EF764F8

View File

@ -56,6 +56,7 @@ fn addToClipboard(allocator: std.mem.Allocator, data: []const u8) !void {
}
};
std.log.debug("exec done", .{});
try std.io.getStdErr().writer().writeAll(result.stderr);
switch (result.term) {
.Exited => |code| if (code != 0) return error.NonZeroExit,
@ -66,8 +67,17 @@ fn addToClipboard(allocator: std.mem.Allocator, data: []const u8) !void {
}
fn execLinux(allocator: std.mem.Allocator, data: []const u8) !std.ChildProcess.ExecResult {
const xclip_cmd = try std.fmt.allocPrint(allocator, "echo -n '{s}'| xclip -selection c", .{data});
// we need to do this (maybe) because there is no real way to close stdin cleanly, which is what will
// kill xclip.
//
// Also, it seems xclip doesn't close stdout, which triggers ChildProcess.exec to know
// that the process is done. Redirecting stdout/stderr as below will get the job
// done, though
const escaped_data = try escape(allocator, data, "'", "'\"", "\"'");
defer allocator.free(escaped_data);
const xclip_cmd = try std.fmt.allocPrint(allocator, "echo -n '{s}'| xclip -selection c >/dev/null 2>&1", .{escaped_data});
defer allocator.free(xclip_cmd);
std.log.debug("cmd: {s}", .{xclip_cmd});
return std.ChildProcess.exec(.{
.allocator = allocator,
@ -81,15 +91,43 @@ fn execLinux(allocator: std.mem.Allocator, data: []const u8) !std.ChildProcess.E
}
fn execWindows(allocator: std.mem.Allocator, data: []const u8) !std.ChildProcess.ExecResult {
const clip_cmd = try std.fmt.allocPrint(allocator, "echo '{s}'| clip", .{data});
defer allocator.free(clip_cmd);
// we need to do this (maybe) because there is no real way to close stdin cleanly, which is what will
// kill clip.exe
// TODO: Create minimal repro and submit zig stdlib bug
const escaped_data = try escape(allocator, data, "'", "'", "");
defer allocator.free(escaped_data);
const cmd = try std.fmt.allocPrint(allocator, "write-output '{s}'| set-clipboard", .{escaped_data});
defer allocator.free(cmd);
std.log.debug("cmd: {s}", .{cmd});
return std.ChildProcess.exec(.{
.allocator = allocator,
.argv = &[_][]const u8{
"c:\\windows\\system32\\cmd.exe", // TODO: use Comspec
"/c",
clip_cmd,
"powershell",
"-Command",
cmd,
},
});
}
fn escape(allocator: std.mem.Allocator, data: []const u8, danger_chars: []const u8, prefix: []const u8, suffix: []const u8) ![]const u8 {
var escaped = try std.ArrayList(u8).initCapacity(allocator, data.len);
defer escaped.deinit();
for (data) |c| {
var needs_escape = false;
for (danger_chars) |dc| {
if (c == dc) {
needs_escape = true;
break;
}
}
if (needs_escape) {
try escaped.appendSlice(prefix);
try escaped.append(c);
try escaped.appendSlice(suffix);
} else {
try escaped.append(c);
}
}
return escaped.toOwnedSlice();
}