mirror of
https://github.com/TECHNOFAB11/tmux-copyrat.git
synced 2025-12-12 16:10:07 +01:00
feat: capture in copy mode
This commit is contained in:
parent
7550895602
commit
b049fba642
2 changed files with 38 additions and 28 deletions
|
|
@ -40,6 +40,10 @@ fn main() -> Result<(), error::ParseError> {
|
||||||
output_destination,
|
output_destination,
|
||||||
}) => {
|
}) => {
|
||||||
if uppercased {
|
if uppercased {
|
||||||
|
if active_pane.is_copy_mode {
|
||||||
|
// break out of copy mode
|
||||||
|
duct::cmd!("tmux", "copy-mode", "-t", active_pane.id.as_str(), "-q").run()?;
|
||||||
|
}
|
||||||
duct::cmd!("tmux", "send-keys", "-t", active_pane.id.as_str(), &text).run()?;
|
duct::cmd!("tmux", "send-keys", "-t", active_pane.id.as_str(), &text).run()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
54
src/tmux.rs
54
src/tmux.rs
|
|
@ -15,16 +15,16 @@ use crate::error::ParseError;
|
||||||
pub struct Pane {
|
pub struct Pane {
|
||||||
/// Pane identifier, e.g. `%37`.
|
/// Pane identifier, e.g. `%37`.
|
||||||
pub id: PaneId,
|
pub id: PaneId,
|
||||||
/// Describes if the pane is in some mode.
|
/// Describes if the pane is in copy mode.
|
||||||
pub in_mode: bool,
|
pub is_copy_mode: bool,
|
||||||
/// Number of lines in the pane.
|
/// Number of lines in the pane.
|
||||||
pub height: u32,
|
pub height: i32,
|
||||||
/// Optional offset from the bottom if the pane is in some mode.
|
/// Optional offset from the bottom if the pane is in some mode.
|
||||||
///
|
///
|
||||||
/// When a pane is in copy mode, scrolling up changes the
|
/// When a pane is in copy mode, scrolling up changes the
|
||||||
/// `scroll_position`. If the pane is in normal mode, or unscrolled,
|
/// `scroll_position`. If the pane is in normal mode, or unscrolled,
|
||||||
/// then `0` is returned.
|
/// then `0` is returned.
|
||||||
pub scroll_position: u32,
|
pub scroll_position: i32,
|
||||||
/// Describes if the pane is currently active (focused).
|
/// Describes if the pane is currently active (focused).
|
||||||
pub is_active: bool,
|
pub is_active: bool,
|
||||||
}
|
}
|
||||||
|
|
@ -59,9 +59,9 @@ impl FromStr for Pane {
|
||||||
// let id = id_str[1..].parse::<u32>()?;
|
// let id = id_str[1..].parse::<u32>()?;
|
||||||
// let id = format!("%{}", id);
|
// let id = format!("%{}", id);
|
||||||
|
|
||||||
let in_mode = iter.next().unwrap().parse::<bool>()?;
|
let is_copy_mode = iter.next().unwrap().parse::<bool>()?;
|
||||||
|
|
||||||
let height = iter.next().unwrap().parse::<u32>()?;
|
let height = iter.next().unwrap().parse::<i32>()?;
|
||||||
|
|
||||||
let scroll_position = iter.next().unwrap();
|
let scroll_position = iter.next().unwrap();
|
||||||
let scroll_position = if scroll_position.is_empty() {
|
let scroll_position = if scroll_position.is_empty() {
|
||||||
|
|
@ -69,13 +69,13 @@ impl FromStr for Pane {
|
||||||
} else {
|
} else {
|
||||||
scroll_position
|
scroll_position
|
||||||
};
|
};
|
||||||
let scroll_position = scroll_position.parse::<u32>()?;
|
let scroll_position = scroll_position.parse::<i32>()?;
|
||||||
|
|
||||||
let is_active = iter.next().unwrap().parse::<bool>()?;
|
let is_active = iter.next().unwrap().parse::<bool>()?;
|
||||||
|
|
||||||
Ok(Pane {
|
Ok(Pane {
|
||||||
id,
|
id,
|
||||||
in_mode,
|
is_copy_mode,
|
||||||
height,
|
height,
|
||||||
scroll_position,
|
scroll_position,
|
||||||
is_active,
|
is_active,
|
||||||
|
|
@ -167,35 +167,41 @@ pub fn get_options(prefix: &str) -> Result<HashMap<String, String>, ParseError>
|
||||||
/// The provided `region` specifies if the visible area is captured, or the
|
/// The provided `region` specifies if the visible area is captured, or the
|
||||||
/// entire history.
|
/// entire history.
|
||||||
///
|
///
|
||||||
/// # TODO
|
|
||||||
///
|
|
||||||
/// Capture with `capture-pane -J` joins wrapped lines.
|
|
||||||
///
|
|
||||||
/// # Note
|
/// # Note
|
||||||
///
|
///
|
||||||
/// If the pane is in normal mode, capturing the visible area can be done
|
/// In Tmux, the start line is the line at the top of the pane. The end line
|
||||||
/// without extra arguments (default behavior of `capture-pane`), but if the
|
/// is the last line at the bottom of the pane.
|
||||||
/// pane is in copy mode, we need to take into account the current scroll
|
///
|
||||||
/// position. To support both cases, the implementation always provides those
|
/// - In normal mode, the index of the start line is always 0. The index of
|
||||||
/// parameters to tmux.
|
/// the end line is always the pane's height minus one. These do not need to
|
||||||
|
/// be specified when capturing the pane's content.
|
||||||
|
///
|
||||||
|
/// - If navigating history in copy mode, the index of the start line is the
|
||||||
|
/// opposite of the pane's scroll position. For instance a pane of 40 lines,
|
||||||
|
/// scrolled up by 3 lines. It is necessarily in copy mode. Its start line
|
||||||
|
/// index is `-3`. The index of the last line is `(40-1) - 3 = 36`.
|
||||||
|
///
|
||||||
pub fn capture_pane(pane: &Pane, region: &CaptureRegion) -> Result<String, ParseError> {
|
pub fn capture_pane(pane: &Pane, region: &CaptureRegion) -> Result<String, ParseError> {
|
||||||
let mut args = format!("capture-pane -t {pane_id} -J -p", pane_id = pane.id);
|
let mut args_str = format!("capture-pane -t {pane_id} -J -p", pane_id = pane.id);
|
||||||
|
|
||||||
let region_str = match region {
|
let region_str = match region {
|
||||||
CaptureRegion::VisibleArea => {
|
CaptureRegion::VisibleArea => {
|
||||||
// Providing start/end helps support both copy and normal modes.
|
if pane.is_copy_mode && pane.scroll_position > 0 {
|
||||||
format!(
|
format!(
|
||||||
" -S {start} -E {end}",
|
" -S {start} -E {end}",
|
||||||
start = pane.scroll_position,
|
start = -pane.scroll_position,
|
||||||
end = pane.height - pane.scroll_position - 1
|
end = pane.height - pane.scroll_position - 1
|
||||||
)
|
)
|
||||||
|
} else {
|
||||||
|
String::new()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
CaptureRegion::EntireHistory => String::from(" -S - -E -"),
|
CaptureRegion::EntireHistory => String::from(" -S - -E -"),
|
||||||
};
|
};
|
||||||
|
|
||||||
args.push_str(®ion_str);
|
args_str.push_str(®ion_str);
|
||||||
|
|
||||||
let args: Vec<&str> = args.split(' ').collect();
|
let args: Vec<&str> = args_str.split(' ').collect();
|
||||||
|
|
||||||
let output = duct::cmd("tmux", &args).read()?;
|
let output = duct::cmd("tmux", &args).read()?;
|
||||||
Ok(output)
|
Ok(output)
|
||||||
|
|
@ -226,7 +232,7 @@ mod tests {
|
||||||
let expected = vec![
|
let expected = vec![
|
||||||
Pane {
|
Pane {
|
||||||
id: PaneId::from_str("%52").unwrap(),
|
id: PaneId::from_str("%52").unwrap(),
|
||||||
in_mode: false,
|
is_copy_mode: false,
|
||||||
height: 62,
|
height: 62,
|
||||||
scroll_position: 3,
|
scroll_position: 3,
|
||||||
is_active: false,
|
is_active: false,
|
||||||
|
|
@ -234,7 +240,7 @@ mod tests {
|
||||||
Pane {
|
Pane {
|
||||||
// id: PaneId::from_str("%53").unwrap(),
|
// id: PaneId::from_str("%53").unwrap(),
|
||||||
id: PaneId(String::from("%53")),
|
id: PaneId(String::from("%53")),
|
||||||
in_mode: false,
|
is_copy_mode: false,
|
||||||
height: 23,
|
height: 23,
|
||||||
scroll_position: 0,
|
scroll_position: 0,
|
||||||
is_active: true,
|
is_active: true,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue