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>
|
<gresources>
|
||||||
<gresource prefix="/dev/greyson/playpen/icons">
|
<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/document-edit-symbolic.svg</file>
|
||||||
<file compressed="true">scalable/actions/edit-undo-symbolic.svg</file>
|
<file compressed="true">scalable/actions/edit-undo-symbolic.svg</file>
|
||||||
<file compressed="true">scalable/actions/emblem-system-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, .{});
|
_ = gtk.Button.signals.clicked.connect(review_button, *Pane, &onReviewClicked, self, .{});
|
||||||
header.append(review_button.as(gtk.Widget));
|
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
|
// 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.
|
// is expected and the zoom toggle sits with the other view controls.
|
||||||
self.zoom.as(gtk.Widget).addCssClass("flat");
|
self.zoom.as(gtk.Widget).addCssClass("flat");
|
||||||
@@ -765,6 +772,10 @@ fn onReviewClicked(_: *gtk.Button, self: *Pane) callconv(.c) void {
|
|||||||
self.view.requestReview();
|
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 {
|
fn onZoomClicked(_: *gtk.Button, self: *Pane) callconv(.c) void {
|
||||||
self.view.toggleZoom(self);
|
self.view.toggleZoom(self);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -355,6 +355,56 @@ pub fn requestReview(self: *View) void {
|
|||||||
self.on_review(self.ctx);
|
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 {
|
pub fn closePane(self: *View, pane: *Pane) void {
|
||||||
if (self.closing) return;
|
if (self.closing) return;
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user