core: copy the proper format to the clipboard as configured
parent
9a198b47a0
commit
f3352dd90b
158
src/Surface.zig
158
src/Surface.zig
|
|
@ -1958,20 +1958,103 @@ fn copySelectionToClipboards(
|
||||||
self: *Surface,
|
self: *Surface,
|
||||||
sel: terminal.Selection,
|
sel: terminal.Selection,
|
||||||
clipboards: []const apprt.Clipboard,
|
clipboards: []const apprt.Clipboard,
|
||||||
) void {
|
format: input.Binding.Action.CopyToClipboard,
|
||||||
const buf = self.io.terminal.screen.selectionString(self.alloc, .{
|
) !void {
|
||||||
.sel = sel,
|
// Create an arena to simplify memory management here.
|
||||||
.trim = self.config.clipboard_trim_trailing_spaces,
|
var arena = ArenaAllocator.init(self.alloc);
|
||||||
}) catch |err| {
|
errdefer arena.deinit();
|
||||||
log.err("error reading selection string err={}", .{err});
|
const alloc = arena.allocator();
|
||||||
return;
|
|
||||||
};
|
|
||||||
defer self.alloc.free(buf);
|
|
||||||
|
|
||||||
for (clipboards) |clipboard| self.rt_surface.setClipboard(clipboard, &.{.{
|
// The options we'll use for all formatting. We'll just override the
|
||||||
.mime = "text/plain",
|
// emit format.
|
||||||
.data = buf,
|
const opts: terminal.formatter.Options = .{
|
||||||
}}, false) catch |err| {
|
.emit = .plain, // We'll override this below
|
||||||
|
.unwrap = true,
|
||||||
|
.trim = self.config.clipboard_trim_trailing_spaces,
|
||||||
|
.background = self.io.terminal.colors.background.get(),
|
||||||
|
.foreground = self.io.terminal.colors.foreground.get(),
|
||||||
|
.palette = &self.io.terminal.colors.palette.current,
|
||||||
|
};
|
||||||
|
|
||||||
|
const ScreenFormatter = terminal.formatter.ScreenFormatter;
|
||||||
|
var aw: std.Io.Writer.Allocating = .init(alloc);
|
||||||
|
var contents: std.ArrayList(apprt.ClipboardContent) = .empty;
|
||||||
|
switch (format) {
|
||||||
|
.plain => {
|
||||||
|
var formatter: ScreenFormatter = .init(&self.io.terminal.screen, opts);
|
||||||
|
formatter.content = .{ .selection = sel };
|
||||||
|
try formatter.format(&aw.writer);
|
||||||
|
try contents.append(alloc, .{
|
||||||
|
.mime = "text/plain",
|
||||||
|
.data = try aw.toOwnedSliceSentinel(0),
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
.vt => {
|
||||||
|
var formatter: ScreenFormatter = .init(&self.io.terminal.screen, opts: {
|
||||||
|
var copy = opts;
|
||||||
|
copy.emit = .vt;
|
||||||
|
break :opts copy;
|
||||||
|
});
|
||||||
|
formatter.content = .{ .selection = sel };
|
||||||
|
try formatter.format(&aw.writer);
|
||||||
|
try contents.append(alloc, .{
|
||||||
|
.mime = "text/plain",
|
||||||
|
.data = try aw.toOwnedSliceSentinel(0),
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
.html => {
|
||||||
|
var formatter: ScreenFormatter = .init(&self.io.terminal.screen, opts: {
|
||||||
|
var copy = opts;
|
||||||
|
copy.emit = .html;
|
||||||
|
break :opts copy;
|
||||||
|
});
|
||||||
|
formatter.content = .{ .selection = sel };
|
||||||
|
try formatter.format(&aw.writer);
|
||||||
|
try contents.append(alloc, .{
|
||||||
|
.mime = "text/html",
|
||||||
|
.data = try aw.toOwnedSliceSentinel(0),
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
.mixed => {
|
||||||
|
var formatter: ScreenFormatter = .init(&self.io.terminal.screen, opts);
|
||||||
|
formatter.content = .{ .selection = sel };
|
||||||
|
try formatter.format(&aw.writer);
|
||||||
|
try contents.append(alloc, .{
|
||||||
|
.mime = "text/plain",
|
||||||
|
.data = try aw.toOwnedSliceSentinel(0),
|
||||||
|
});
|
||||||
|
|
||||||
|
assert(aw.written().len == 0);
|
||||||
|
formatter = .init(&self.io.terminal.screen, opts: {
|
||||||
|
var copy = opts;
|
||||||
|
copy.emit = .html;
|
||||||
|
|
||||||
|
// We purposely don't emit background/foreground for mixed
|
||||||
|
// mode because the HTML contents is often used for rich text
|
||||||
|
// input and with trimmed spaces it looks pretty bad.
|
||||||
|
copy.background = null;
|
||||||
|
copy.foreground = null;
|
||||||
|
|
||||||
|
break :opts copy;
|
||||||
|
});
|
||||||
|
formatter.content = .{ .selection = sel };
|
||||||
|
try formatter.format(&aw.writer);
|
||||||
|
try contents.append(alloc, .{
|
||||||
|
.mime = "text/html",
|
||||||
|
.data = try aw.toOwnedSliceSentinel(0),
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(contents.items.len > 0);
|
||||||
|
for (clipboards) |clipboard| self.rt_surface.setClipboard(
|
||||||
|
clipboard,
|
||||||
|
contents.items,
|
||||||
|
false,
|
||||||
|
) catch |err| {
|
||||||
log.err(
|
log.err(
|
||||||
"error setting clipboard string clipboard={} err={}",
|
"error setting clipboard string clipboard={} err={}",
|
||||||
.{ clipboard, err },
|
.{ clipboard, err },
|
||||||
|
|
@ -2000,9 +2083,11 @@ fn setSelection(self: *Surface, sel_: ?terminal.Selection) !void {
|
||||||
.false => unreachable, // handled above with an early exit
|
.false => unreachable, // handled above with an early exit
|
||||||
|
|
||||||
// Both standard and selection clipboards are set.
|
// Both standard and selection clipboards are set.
|
||||||
.clipboard => {
|
.clipboard => try self.copySelectionToClipboards(
|
||||||
self.copySelectionToClipboards(sel, &.{ .standard, .selection });
|
sel,
|
||||||
},
|
&.{ .standard, .selection },
|
||||||
|
.mixed,
|
||||||
|
),
|
||||||
|
|
||||||
// The selection clipboard is set if supported, otherwise the standard.
|
// The selection clipboard is set if supported, otherwise the standard.
|
||||||
.true => {
|
.true => {
|
||||||
|
|
@ -2010,7 +2095,11 @@ fn setSelection(self: *Surface, sel_: ?terminal.Selection) !void {
|
||||||
.selection
|
.selection
|
||||||
else
|
else
|
||||||
.standard;
|
.standard;
|
||||||
self.copySelectionToClipboards(sel, &.{clipboard});
|
try self.copySelectionToClipboards(
|
||||||
|
sel,
|
||||||
|
&.{clipboard},
|
||||||
|
.mixed,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3748,14 +3837,22 @@ pub fn mouseButtonCallback(
|
||||||
},
|
},
|
||||||
.copy => {
|
.copy => {
|
||||||
if (self.io.terminal.screen.selection) |sel| {
|
if (self.io.terminal.screen.selection) |sel| {
|
||||||
self.copySelectionToClipboards(sel, &.{.standard});
|
try self.copySelectionToClipboards(
|
||||||
|
sel,
|
||||||
|
&.{.standard},
|
||||||
|
.mixed,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
try self.setSelection(null);
|
try self.setSelection(null);
|
||||||
try self.queueRender();
|
try self.queueRender();
|
||||||
},
|
},
|
||||||
.@"copy-or-paste" => if (self.io.terminal.screen.selection) |sel| {
|
.@"copy-or-paste" => if (self.io.terminal.screen.selection) |sel| {
|
||||||
self.copySelectionToClipboards(sel, &.{.standard});
|
try self.copySelectionToClipboards(
|
||||||
|
sel,
|
||||||
|
&.{.standard},
|
||||||
|
.mixed,
|
||||||
|
);
|
||||||
try self.setSelection(null);
|
try self.setSelection(null);
|
||||||
try self.queueRender();
|
try self.queueRender();
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -4659,26 +4756,15 @@ pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !bool
|
||||||
self.renderer_state.terminal.fullReset();
|
self.renderer_state.terminal.fullReset();
|
||||||
},
|
},
|
||||||
|
|
||||||
.copy_to_clipboard => {
|
.copy_to_clipboard => |format| {
|
||||||
// We can read from the renderer state without holding
|
// We can read from the renderer state without holding
|
||||||
// the lock because only we will write to this field.
|
// the lock because only we will write to this field.
|
||||||
if (self.io.terminal.screen.selection) |sel| {
|
if (self.io.terminal.screen.selection) |sel| {
|
||||||
const buf = self.io.terminal.screen.selectionString(self.alloc, .{
|
try self.copySelectionToClipboards(
|
||||||
.sel = sel,
|
sel,
|
||||||
.trim = self.config.clipboard_trim_trailing_spaces,
|
&.{.standard},
|
||||||
}) catch |err| {
|
format,
|
||||||
log.err("error reading selection string err={}", .{err});
|
);
|
||||||
return true;
|
|
||||||
};
|
|
||||||
defer self.alloc.free(buf);
|
|
||||||
|
|
||||||
self.rt_surface.setClipboard(.standard, &.{.{
|
|
||||||
.mime = "text/plain",
|
|
||||||
.data = buf,
|
|
||||||
}}, false) catch |err| {
|
|
||||||
log.err("error setting clipboard string err={}", .{err});
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Clear the selection if configured to do so.
|
// Clear the selection if configured to do so.
|
||||||
if (self.config.selection_clear_on_copy) {
|
if (self.config.selection_clear_on_copy) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue