Add quick review button.
This commit is contained in:
1 parent
3db4123319
commit
c550169c83
4 files changed
+66
No files matched your search
@@ -7,6 +7,7 @@
|
||||
-->
|
||||
<gresources>
|
||||
<gresource prefix="/dev/greyson/playpen/icons">
|
||||
<file compressed="true">scalable/actions/chat-message-new-symbolic.svg</file>
|
||||
<file compressed="true">scalable/actions/document-edit-symbolic.svg</file>
|
||||
<file compressed="true">scalable/actions/edit-undo-symbolic.svg</file>
|
||||
<file compressed="true">scalable/actions/emblem-system-symbolic.svg</file>
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg height="16px" viewBox="0 0 16 16" width="16px" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="m 3 1 c -1.644531 0 -3 1.355469 -3 3 v 6 c 0 1.644531 1.355469 3 3 3 h 1 v 3 l 3 -3 v -1 c 0 -0.550781 -0.449219 -1 -1 -1 h -3 c -0.570312 0 -1 -0.429688 -1 -1 v -6 c 0 -0.554688 0.445312 -1 1 -1 h 10 c 0.554688 0 1 0.445312 1 1 v 4 c 0 0.550781 0.449219 1 1 1 s 1 -0.449219 1 -1 v -4 c 0 -1.644531 -1.355469 -3 -3 -3 z m 8 7 v 3 h -3 v 2 h 3 v 3 h 2 v -3 h 3 v -2 h -3 v -3 z m 0 0" fill="#2e3436"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 548 B |
@@ -506,6 +506,13 @@ fn buildHeader(self: *Pane) void {
|
||||
_ = gtk.Button.signals.clicked.connect(review_button, *Pane, &onReviewClicked, self, .{});
|
||||
header.append(review_button.as(gtk.Widget));
|
||||
|
||||
const agent_review = gtk.Button.newFromIconName("chat-message-new-symbolic");
|
||||
agent_review.as(gtk.Widget).addCssClass("flat");
|
||||
agent_review.as(gtk.Widget).addCssClass("playpen-pane-button");
|
||||
agent_review.as(gtk.Widget).setTooltipText("Have Claude review this tab's changes in the review pane");
|
||||
_ = gtk.Button.signals.clicked.connect(agent_review, *Pane, &onAgentReviewClicked, self, .{});
|
||||
header.append(agent_review.as(gtk.Widget));
|
||||
|
||||
// Last before close, so the destructive button stays on the end where it
|
||||
// is expected and the zoom toggle sits with the other view controls.
|
||||
self.zoom.as(gtk.Widget).addCssClass("flat");
|
||||
@@ -765,6 +772,10 @@ fn onReviewClicked(_: *gtk.Button, self: *Pane) callconv(.c) void {
|
||||
self.view.requestReview();
|
||||
}
|
||||
|
||||
fn onAgentReviewClicked(_: *gtk.Button, self: *Pane) callconv(.c) void {
|
||||
self.view.startAgentReview(self);
|
||||
}
|
||||
|
||||
fn onZoomClicked(_: *gtk.Button, self: *Pane) callconv(.c) void {
|
||||
self.view.toggleZoom(self);
|
||||
}
|
||||
|
||||
@@ -355,6 +355,56 @@ pub fn requestReview(self: *View) void {
|
||||
self.on_review(self.ctx);
|
||||
}
|
||||
|
||||
/// What the pane header's agent-review button types into the new shell.
|
||||
const agent_review_command = "claude '/pr-review using /leave-review'";
|
||||
|
||||
/// Open a Claude Code session beside `from`, in the directory `from` is working
|
||||
/// in, and have it review the tab's diff into the review pane.
|
||||
///
|
||||
/// `/leave-review` posts to this tab's review pane and stops if there isn't
|
||||
/// one, so a missing pane is opened first rather than leaving the session to
|
||||
/// fail on arrival. `from` is focused before that, so the review is bound to
|
||||
/// the same directory the session starts in.
|
||||
pub fn startAgentReview(self: *View, from: *Pane) void {
|
||||
var buf: [std.fs.max_path_bytes]u8 = undefined;
|
||||
const cwd = self.paneDirectory(from, &buf);
|
||||
|
||||
if (self.reviewPane() == null) {
|
||||
self.setFocused(from);
|
||||
self.requestReview();
|
||||
}
|
||||
|
||||
self.addPane(.{ .terminal = .{
|
||||
.cwd = cwd,
|
||||
.command = agent_review_command,
|
||||
} }) catch |err| {
|
||||
std.log.err("failed to open the agent review: {s}", .{@errorName(err)});
|
||||
};
|
||||
}
|
||||
|
||||
/// The directory `pane` is working in, copied into `buf`, or empty to leave it
|
||||
/// to the shell's default.
|
||||
///
|
||||
/// A terminal answers for itself, a review pane with the repository it is bound
|
||||
/// to; a web pane has no directory, so it borrows the first terminal's in the
|
||||
/// tab.
|
||||
fn paneDirectory(self: *View, pane: *Pane, buf: []u8) []const u8 {
|
||||
switch (pane.content) {
|
||||
.terminal => |t| if (t.session.cwd(buf)) |dir| return dir,
|
||||
.review => if (self.review_spec.repo.len > 0) {
|
||||
const n = @min(buf.len, self.review_spec.repo.len);
|
||||
@memcpy(buf[0..n], self.review_spec.repo[0..n]);
|
||||
return buf[0..n];
|
||||
},
|
||||
.web => {},
|
||||
}
|
||||
for (self.panes.items) |other| {
|
||||
const t = other.terminal() orelse continue;
|
||||
if (t.session.cwd(buf)) |dir| return dir;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
pub fn closePane(self: *View, pane: *Pane) void {
|
||||
if (self.closing) return;
|
||||
|
||||
|
||||
Reference in new issue
Block a user