Skip to content

Commit

Permalink
Copy selection to clipboard in diff view
Browse files Browse the repository at this point in the history
  • Loading branch information
cruessler committed Aug 17, 2020
1 parent 14fab80 commit 8e1ac88
Show file tree
Hide file tree
Showing 6 changed files with 160 additions and 20 deletions.
9 changes: 9 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ jobs:
profile: minimal
components: clippy

- name: Install dependencies for clipboard access
if: matrix.os == 'ubuntu-latest'
run: |
sudo apt-get -qq install libxcb-shape0-dev libxcb-xfixes0-dev
- name: Build Debug
run: |
rustc --version
Expand Down Expand Up @@ -58,6 +63,10 @@ jobs:
profile: minimal
target: x86_64-unknown-linux-musl

- name: Install dependencies for clipboard access
run: |
sudo apt-get -qq install libxcb-shape0-dev libxcb-xfixes0-dev
- name: Setup MUSL
run: |
sudo apt-get -qq install musl-tools
Expand Down
86 changes: 86 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ serde = "1.0"
anyhow = "1.0.32"
unicode-width = "0.1"
textwrap = "0.12"
clipboard = "0.5"

[target.'cfg(not(windows))'.dependencies]
pprof = { version = "0.3", features = ["flamegraph"], optional = true }
Expand Down
81 changes: 62 additions & 19 deletions src/components/diff.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::{
CommandBlocking, DrawableComponent, ExtendType, ScrollType,
CommandBlocking, Direction, DrawableComponent, ScrollType,
};
use crate::{
components::{CommandInfo, Component},
Expand All @@ -10,6 +10,7 @@ use crate::{
};
use asyncgit::{hash, sync, DiffLine, DiffLineType, FileDiff, CWD};
use bytesize::ByteSize;
use clipboard::{ClipboardContext, ClipboardProvider};
use crossterm::event::Event;
use std::{borrow::Cow, cell::Cell, cmp, path::Path};
use tui::{
Expand Down Expand Up @@ -49,11 +50,30 @@ impl Selection {
}
}

fn modify(&mut self, direction: Direction, max: usize) {
let start = self.get_start();
let old_end = self.get_end();

*self = match direction {
Direction::Up => {
Self::Multiple(start, old_end.saturating_sub(1))
}

Direction::Down => {
Self::Multiple(start, cmp::min(old_end + 1, max))
}
};
}

fn contains(&self, index: usize) -> bool {
match self {
Self::Single(start) => index == *start,
Self::Multiple(start, end) => {
*start <= index && index <= *end
if start <= end {
*start <= index && index <= *end
} else {
*end <= index && index <= *start
}
}
}
}
Expand Down Expand Up @@ -177,26 +197,45 @@ impl DiffComponent {
Ok(())
}

fn extend_selection(
fn modify_selection(
&mut self,
extend_type: ExtendType,
direction: Direction,
) -> Result<()> {
if let Some(diff) = &self.diff {
let max = diff.lines.saturating_sub(1) as usize;
let start = self.selection.get_start();
let old_end = self.selection.get_end();

self.selection = match extend_type {
ExtendType::Up => Selection::Multiple(
start,
cmp::max(start, old_end.saturating_sub(1)),
),
self.selection.modify(direction, max);
}

ExtendType::Down => Selection::Multiple(
start,
cmp::min(old_end + 1, max),
),
};
Ok(())
}

fn copy_selection(&self) -> Result<()> {
if let Some(diff) = &self.diff {
let lines_to_copy: Vec<&str> = diff
.hunks
.iter()
.flat_map(|hunk| hunk.lines.iter())
.enumerate()
.filter_map(|(i, line)| {
if self.selection.contains(i) {
Some(
line.content
.trim_matches(|c| {
c == '\n' || c == '\r'
})
.as_ref(),
)
} else {
None
}
})
.collect();

let mut ctx: ClipboardContext = ClipboardProvider::new()
.expect("failed to get access to clipboard");
ctx.set_contents(lines_to_copy.join("\n"))
.expect("failed to set clipboard contents");
}

Ok(())
Expand Down Expand Up @@ -489,7 +528,7 @@ impl DrawableComponent for DiffComponent {
self.scroll_top.set(calc_scroll_top(
self.scroll_top.get(),
self.current_size.get().1 as usize,
self.selection.get_start(),
self.selection.get_end(),
));

let title =
Expand Down Expand Up @@ -570,11 +609,11 @@ impl Component for DiffComponent {
Ok(true)
}
keys::SHIFT_DOWN => {
self.extend_selection(ExtendType::Down)?;
self.modify_selection(Direction::Down)?;
Ok(true)
}
keys::SHIFT_UP => {
self.extend_selection(ExtendType::Up)?;
self.modify_selection(Direction::Up)?;
Ok(true)
}
keys::END => {
Expand Down Expand Up @@ -618,6 +657,10 @@ impl Component for DiffComponent {
}
Ok(true)
}
keys::COPY => {
self.copy_selection()?;
Ok(true)
}
_ => Ok(false),
};
}
Expand Down
2 changes: 1 addition & 1 deletion src/components/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ pub enum ScrollType {
}

#[derive(Copy, Clone)]
pub enum ExtendType {
pub enum Direction {
Up,
Down,
}
Expand Down
1 change: 1 addition & 0 deletions src/keys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ pub const SHIFT_UP: KeyEvent =
pub const SHIFT_DOWN: KeyEvent =
with_mod(KeyCode::Down, KeyModifiers::SHIFT);
pub const ENTER: KeyEvent = no_mod(KeyCode::Enter);
pub const COPY: KeyEvent = no_mod(KeyCode::Char('y'));
pub const EDIT_FILE: KeyEvent = no_mod(KeyCode::Char('e'));
pub const STATUS_STAGE_FILE: KeyEvent = no_mod(KeyCode::Enter);
pub const STATUS_STAGE_ALL: KeyEvent = no_mod(KeyCode::Char('a'));
Expand Down

0 comments on commit 8e1ac88

Please sign in to comment.