Skip to content
Merged

Wrap #1215

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 12 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
### next
- fix panic when previewing an image with 16 bits per channel, or HDR - Fix #1209
- alt-arrows are bound like ctrl-arrows (panels, root up/down), as macOS captures ctrl-arrows; hints and help show the alt ones on macOS

#### Major Feature: preview wrapping
By default, long lines in preview are now wrapped.
This impacts text previews, with or without syntactic coloring, unified diffs, and TTY previews
This can be toogled with `:toggle_preview_wrap` (shortcut `:wrap`), and `wrap_previews: false` in the conf disables it on start
#### Major Feature: git diff preview, and many git related enhancements
The `libgit2` library has been replaced by `gix`. With this change, broot becomes pure Rust, which simplifies compilation (no C compiler needed anymore).
A unified diff preview is now the default preview of a file with a git change (modified, staged, added, renamed or in conflict) when git statuses are displayed. `:preview_diff` shows it for any file.
Expand All @@ -16,7 +17,14 @@ A unified diff preview is now the default preview of a file with a git change (m
- `{git-root}` and `{git-name}` now work when the selection is a file
- alt-g toggles the git status filter (`:toggle_git_status`). Status line suggests using it in git repo.
- `-gg` shows only the files with a git status (same as `--git-status`), `-G` removes one level of git information
- the Kitty keyboard protocol is now used by default when the terminal supports it, which notably makes `alt` combinations work on macOS terminals; multi-key combinations without modifier still need `enable_kitty_keyboard: true`
- the Kitty keyboard protocol is now used by default when the terminal supports it, which notably makes `alt` combinations work on macOS terminals; multi-key combinations without modifier still need `enable_kitty_keyboard: true` - I'll watch this as this may have unwanted effects, like time related difficulty for some combinations - feedback welcome
#### Other Changes
- fix panic when previewing an image with 16 bits per channel, or HDR - Fix #1209
- alt-arrows are bound like ctrl-arrows (panels, root up/down), as macOS captures ctrl-arrows; hints and help show the alt ones on macOS
- arrow keys scroll the tty preview
- `:select_last` goes to the end of a directory preview
- the tty preview shows its line count
- `:preview_auto` cancels the effect of eg `:preview_text`, going back to automatically choosing the preview mode

<a name="v1.59.0"></a>
### v1.59.0 - 2026-08-22
Expand Down
20 changes: 10 additions & 10 deletions Cargo.lock

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

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ splitty = "1.0.2"
strict = "0.2"
syntect = { package = "syntect-no-panic", version = "6.0", default-features = false, features = ["default-fancy"] } # see https://github.com/Canop/broot/pull/968
tempfile = "3.2"
termimad = "0.35.2"
termimad = "0.35.3"
terminal-clipboard = { version = "0.4.1", optional = true }
terminal-light = "1.8"
toml = "1.1"
Expand Down
6 changes: 6 additions & 0 deletions resources/default-conf/conf.hjson
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,12 @@
#
show_selection_mark: true

###############################################################
# Whether to wrap long lines in previews. Default is true;
# you can toggle wrapping at runtime with the :wrap verb.
#
# wrap_previews: false

###############################################################
# Column order
# cols_order, if specified, must be a permutation of the following
Expand Down
7 changes: 7 additions & 0 deletions src/app/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,12 @@ impl App {
self.panels.clear_input_invocation(con);
}
}
Internal::toggle_preview_wrap => {
app_state.preview_overflow.toggle();
if is_input_invocation {
self.panels.clear_input_invocation(con);
}
}
_ => {
let cmd = self.panels.on_input_internal(internal);
if cmd.is_none() {
Expand Down Expand Up @@ -484,6 +490,7 @@ impl App {
let mut dam = Dam::from(rx_events);
let skin = AppSkin::new(conf, con.launch_args.color == TriBool::No);
let mut app_state = AppState::new(&con.initial_root);
app_state.preview_overflow = con.preview_overflow;
terminal::update_title(w, &app_state, con);

self.panels
Expand Down
9 changes: 8 additions & 1 deletion src/app/app_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ use {
},
conf::*,
content_search,
display::LayoutInstructions,
display::{
LayoutInstructions,
Overflow,
},
errors::*,
file_sum,
icon::*,
Expand Down Expand Up @@ -78,6 +81,9 @@ pub struct AppContext {
/// whether to show a triangle left to selected lines
pub show_selection_mark: bool,

/// how to deal with preview lines longer than the panel width
pub preview_overflow: Overflow,

/// mapping from file extension to colors (comes from conf)
pub ext_colors: ExtColorMap,

Expand Down Expand Up @@ -260,6 +266,7 @@ impl AppContext {
special_paths,
search_modes,
show_selection_mark: config.show_selection_mark.unwrap_or(false),
preview_overflow: config.wrap_previews.map(Overflow::from_wrap_bool).unwrap_or_default(),
ext_colors,
syntax_theme: config.syntax_theme,
standard_status,
Expand Down
9 changes: 8 additions & 1 deletion src/app/app_state.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
use {
crate::stage::Stage,
crate::{
display::Overflow,
stage::Stage,
},
std::path::PathBuf,
};

Expand All @@ -19,6 +22,9 @@ pub struct AppState {
/// the selected path in another panel than the currently
/// active one, if any
pub other_panel_path: Option<PathBuf>,

/// How to deal with preview lines longer than the panel width
pub preview_overflow: Overflow,
}

impl AppState {
Expand All @@ -28,6 +34,7 @@ impl AppState {
root: root.into(),
watch_tree: false,
other_panel_path: None,
preview_overflow: Overflow::Wrap,
}
}
}
4 changes: 4 additions & 0 deletions src/app/panel_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,7 @@ pub trait PanelState {
}
}
Internal::open_preview => self.open_preview(None, false, cc),
Internal::preview_auto => self.open_preview(None, false, cc),
Internal::preview_image => self.open_preview(Some(PreviewMode::Image), false, cc),
Internal::preview_text => self.open_preview(Some(PreviewMode::Text), false, cc),
Internal::preview_tty => self.open_preview(Some(PreviewMode::Tty), false, cc),
Expand Down Expand Up @@ -631,6 +632,9 @@ pub trait PanelState {
}
Internal::toggle_second_tree => CmdResult::HandleInApp(Internal::toggle_second_tree),
Internal::toggle_watch => CmdResult::HandleInApp(Internal::toggle_watch),
Internal::toggle_preview_wrap => {
CmdResult::HandleInApp(Internal::toggle_preview_wrap)
}
Internal::clear_stage => {
app_state.stage.clear();
if let Some(panel_id) = cc.app.stage_panel {
Expand Down
32 changes: 32 additions & 0 deletions src/cli/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ use {
event::{
DisableMouseCapture,
EnableMouseCapture,
PopKeyboardEnhancementFlags,
},
terminal::{
EnterAlternateScreen,
Expand Down Expand Up @@ -178,13 +179,19 @@ pub fn run() -> Result<Option<Launchable>, ProgramError> {

let mut w = display::writer();
let app = App::new(&context)?;
install_panic_hook(context.capture_mouse);
w.queue(EnterAlternateScreen)?;
w.queue(cursor::Hide)?;
if context.capture_mouse {
w.queue(EnableMouseCapture)?;
}
let r = app.run(&mut w, &mut context, &config);
w.flush()?;
if context.keyboard_enhanced {
// the event source pushed keyboard enhancement flags and
// doesn't pop them itself
w.queue(PopKeyboardEnhancementFlags)?;
}
if context.capture_mouse {
w.queue(DisableMouseCapture)?;
}
Expand All @@ -203,6 +210,31 @@ fn clear_resources() {
graphics::manager().lock().unwrap().delete_temp_files();
}

/// Install a panic hook which restores the terminal to a usable
/// state before the panic message is printed
fn install_panic_hook(capture_mouse: bool) {
let hook = std::panic::take_hook();
std::panic::set_hook(Box::new(move |panic_info| {
use crokey::crossterm::{
event::PopKeyboardEnhancementFlags,
terminal,
};
let mut w = std::io::stderr();
let _ = terminal::disable_raw_mode();
// popping when nothing was pushed is a no-op for terminals
// supporting the keyboard enhancement protocol, and ignored
// by the other ones
let _ = w.queue(PopKeyboardEnhancementFlags);
if capture_mouse {
let _ = w.queue(DisableMouseCapture);
}
let _ = w.queue(cursor::Show);
let _ = w.queue(LeaveAlternateScreen);
let _ = w.flush();
hook(panic_info);
}));
}

/// wait for user input, return `true` if they didn't answer 'n'
pub fn ask_authorization() -> io::Result<bool> {
let mut answer = String::new();
Expand Down
4 changes: 4 additions & 0 deletions src/conf/conf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,9 @@ pub struct Conf {
#[serde(alias = "update-work-dir")]
pub update_work_dir: Option<bool>,

#[serde(alias = "wrap-previews")]
pub wrap_previews: Option<bool>,

#[serde(default)]
pub verbs: Vec<VerbConf>,

Expand Down Expand Up @@ -263,6 +266,7 @@ impl Conf {
overwrite!(self, terminal_title, conf);
overwrite!(self, reset_terminal_title_on_exit, conf);
overwrite!(self, update_work_dir, conf);
overwrite!(self, wrap_previews, conf);
overwrite!(self, enable_kitty_keyboard, conf);
overwrite!(self, kitty_graphics_transmission, conf);
overwrite!(self, kitty_graphics_display, conf);
Expand Down
6 changes: 6 additions & 0 deletions src/display/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ mod luma;
mod matched_string;
mod num_format;
mod screen;
mod viewport;
mod wrap;
pub mod status_line;

#[cfg(not(any(target_family = "windows", target_os = "android")))]
Expand Down Expand Up @@ -97,3 +99,7 @@ pub type W = std::io::BufWriter<std::io::Stderr>;
pub fn writer() -> W {
std::io::BufWriter::new(std::io::stderr())
}
pub use {
viewport::*,
wrap::*,
};
Loading
Loading