Skip to content

Commit a5d2e3a

Browse files
committed
add textobject for change
1 parent b36b28e commit a5d2e3a

File tree

3 files changed

+53
-0
lines changed

3 files changed

+53
-0
lines changed

book/src/usage.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ though, we climb the syntax tree and then take the previous selection. So
143143
| `a` | Argument/parameter |
144144
| `o` | Comment |
145145
| `t` | Test |
146+
| `g` | Change |
146147

147148
> NOTE: `f`, `c`, etc need a tree-sitter grammar active for the current
148149
document and a special tree-sitter query file to work properly. [Only

helix-term/src/commands.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4608,6 +4608,27 @@ fn select_textobject(cx: &mut Context, objtype: textobject::TextObject) {
46084608
)
46094609
};
46104610

4611+
if ch == 'g' && doc.diff_handle().is_none() {
4612+
editor.set_status("Diff is not available in current buffer");
4613+
return;
4614+
}
4615+
4616+
let textobject_change = |range: Range| -> Range {
4617+
let diff_handle = doc.diff_handle().unwrap();
4618+
let hunks = diff_handle.hunks();
4619+
let line = range.cursor_line(text);
4620+
let hunk_idx = if let Some(hunk_idx) = hunks.hunk_at(line as u32, false) {
4621+
hunk_idx
4622+
} else {
4623+
return range;
4624+
};
4625+
let hunk = hunks.nth_hunk(hunk_idx).after;
4626+
4627+
let start = text.line_to_char(hunk.start as usize);
4628+
let end = text.line_to_char(hunk.end as usize);
4629+
Range::new(start, end).with_direction(range.direction())
4630+
};
4631+
46114632
let selection = doc.selection(view.id).clone().transform(|range| {
46124633
match ch {
46134634
'w' => textobject::textobject_word(text, range, objtype, count, false),
@@ -4621,6 +4642,7 @@ fn select_textobject(cx: &mut Context, objtype: textobject::TextObject) {
46214642
'm' => textobject::textobject_pair_surround_closest(
46224643
text, range, objtype, count,
46234644
),
4645+
'g' => textobject_change(range),
46244646
// TODO: cancel new ranges if inconsistent surround matches across lines
46254647
ch if !ch.is_ascii_alphanumeric() => {
46264648
textobject::textobject_pair_surround(text, range, objtype, ch, count)

helix-vcs/src/diff.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,4 +246,34 @@ impl FileHunks<'_> {
246246
Err(pos) | Ok(pos) => Some(pos as u32 - 1),
247247
}
248248
}
249+
250+
pub fn hunk_at(&self, line: u32, include_removal: bool) -> Option<u32> {
251+
let hunk_range = if self.inverted {
252+
|hunk: &Hunk| hunk.before.clone()
253+
} else {
254+
|hunk: &Hunk| hunk.after.clone()
255+
};
256+
257+
let res = self
258+
.hunks
259+
.binary_search_by_key(&line, |hunk| hunk_range(hunk).start);
260+
261+
match res {
262+
// Search found a hunk that starts exactly at this line, return it
263+
Ok(pos) => Some(pos as u32),
264+
265+
// No hunk starts exactly at this line, so the search returns
266+
// the position where a hunk starting at this line should be inserted.
267+
// The previous hunk contains this hunk if it exists and doesn't end before this line
268+
Err(0) => None,
269+
Err(pos) => {
270+
let hunk = hunk_range(&self.hunks[pos - 1]);
271+
if hunk.end > line || include_removal && hunk.start == line && hunk.is_empty() {
272+
Some(pos as u32 - 1)
273+
} else {
274+
None
275+
}
276+
}
277+
}
278+
}
249279
}

0 commit comments

Comments
 (0)