Support staging individual lines
starcraft66 opened this issue · comments
My favourite magit
feature is the ability to individually stage lines. This tool only seems to let me stage stuff down to the hunk and I'd like for it to allow drilling deeper!
Inside magit
, you can open a hunk and then enter visual mode and select lines.
I am incredibly interested in having some functionality like this implemented. git add -p
is an essential part of my workflow so not having an equivalent is one of the only barriers I can see for integrating gitu into my workflow.
I've been casually looking at what it'd take to implement this (although I haven't used magit, so I'm not familiar with how it handles this), although I haven't had much time to look into it.
I had this working in an earlier version. Will try do a write-up soon
So basically, what the old implementation did to achieve this was to look at a Hunk
and assemble a new patch from it (that then would be fed into git apply
just like any Hunk
).
A patch would look like this (this should all be accessible from the Hunk struct in Gitu.
Concat the file header
, hunk header
and all the lines.
diff --git a/src/lib.rs b/src/lib.rs
index 6a433cd..08f79de 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -31,7 +31,8 @@ pub(crate) struct CmdMetaBuffer {
pub(crate) struct ErrorBuffer(String);
-fn command_args(cmd: &Command) -> Cow<'static, str> {
+// added
+
iter::once(cmd.get_program().to_string_lossy())
.chain(cmd.get_args().map(|arg| arg.to_string_lossy()))
.join(" ")
One would then modify this (just like when modifying a diff in git add -p
:
# Manual hunk edit mode -- see bottom for a quick guide.
@@ -31,7 +31,8 @@ pub(crate) struct CmdMetaBuffer {
pub(crate) struct ErrorBuffer(String);
-fn command_args(cmd: &Command) -> Cow<'static, str> {
+// added
+
iter::once(cmd.get_program().to_string_lossy())
.chain(cmd.get_args().map(|arg| arg.to_string_lossy()))
.join(" ")
# ---
# To remove '-' lines, make them ' ' lines (context).
# To remove '+' lines, delete them.
- So any selected line would remain intact
- Any line not selected would:
- be removed if it's a
+
- have its
-
replaced with a
- be removed if it's a
Any edits made will invalidate the hunk header, which keeps track of the line start/count of the old/new versions. Could either recalculate this (is there any gain in doing this?), else I noticed there's the --recount
flag for git apply
that does this for us.
I suppose it could work by adding a new TargetData variant, DiffLine
or something. When the stage/unstage actions are invoked on it, it would produce a patch and apply it.
Lines within a Hunk are created here.
There will need to be some mechanism to navigate line-by-line (ctrl-down/n/j & ctr-up/p/k ?).
There's a hack in where diffs are made twice (Once with 'libgit2', and again with 'similar' to highlight). It makes it more difficult to correlate visual lines seen on the display to lines in the actual diff.
Fixing this first would help in staging individual lines.
relates to: #49
edit: this has been fixed in master!