Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Next Next commit
feat: add yank in text preview
  • Loading branch information
paullj committed Jan 26, 2026
commit 8849a86871fd4c8875a17014bb0d58cc592ec1e6
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ STU provides the following features:

- Recursive object downloads
- Previews with syntax highlighting for text files and inline rendering for images
- Yank text content to clipboard from preview
- Access to previous object versions
- Customizable key bindings
- Support for S3-compatible storage
Expand Down
1 change: 1 addition & 0 deletions assets/keybindings.toml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ download_as = ["shift-s"]
encoding = ["e"]
toggle_wrap = ["w"]
toggle_number = ["n"]
yank = ["y"]

[help]
close = ["?", "backspace"]
Expand Down
2 changes: 2 additions & 0 deletions docs/src/features/object-preview.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
- It must be enabled in the [config](../configurations/config-file-format.md#previewauto_detect_encoding)
- Download object
- Download a single selected object
- Yank content to clipboard
- Press <kbd>y</kbd> to copy the text content to clipboard

![Object Preview](https://raw.githubusercontent.com/lusingander/stu/refs/heads/master/img/object-preview.png)
![Object Preview Image](https://raw.githubusercontent.com/lusingander/stu/refs/heads/master/img/object-preview-image.png)
Expand Down
2 changes: 2 additions & 0 deletions src/keys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ pub enum UserEvent {
ObjectPreviewEncoding,
ObjectPreviewToggleWrap,
ObjectPreviewToggleNumber,
ObjectPreviewYank,
HelpClose,
InputDialogClose,
InputDialogApply,
Expand Down Expand Up @@ -183,6 +184,7 @@ fn build_user_event_mapper(
set_event_to_map(&mut map, &bindings, "object_preview", "encoding", UserEvent::ObjectPreviewEncoding)?;
set_event_to_map(&mut map, &bindings, "object_preview", "toggle_wrap", UserEvent::ObjectPreviewToggleWrap)?;
set_event_to_map(&mut map, &bindings, "object_preview", "toggle_number", UserEvent::ObjectPreviewToggleNumber)?;
set_event_to_map(&mut map, &bindings, "object_preview", "yank", UserEvent::ObjectPreviewYank)?;

set_event_to_map(&mut map, &bindings, "help", "close", UserEvent::HelpClose)?;

Expand Down
23 changes: 23 additions & 0 deletions src/pages/object_preview.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use crate::{
app::AppContext,
environment::ImagePicker,
event::{AppEventType, Sender},
file::copy_to_clipboard,
handle_user_events, handle_user_events_with_default,
help::{
build_help_spans, build_short_help_spans, BuildHelpsItem, BuildShortHelpsItem, Spans,
Expand Down Expand Up @@ -141,6 +142,9 @@ impl ObjectPreviewPage {
UserEvent::ObjectPreviewEncoding => {
self.open_encoding_dialog();
}
UserEvent::ObjectPreviewYank => {
self.yank_text_content();
}
UserEvent::Help => {
self.tx.send(AppEventType::OpenHelp);
}
Expand Down Expand Up @@ -264,6 +268,7 @@ impl ObjectPreviewPage {
BuildHelpsItem::new(UserEvent::ObjectPreviewDownload, "Download object"),
BuildHelpsItem::new(UserEvent::ObjectPreviewDownloadAs, "Download object as"),
BuildHelpsItem::new(UserEvent::ObjectPreviewEncoding, "Open encoding dialog"),
BuildHelpsItem::new(UserEvent::ObjectPreviewYank, "Yank content to clipboard"),
]
},
(ViewState::Default, PreviewType::Image(_)) => {
Expand Down Expand Up @@ -304,6 +309,7 @@ impl ObjectPreviewPage {
BuildShortHelpsItem::group(vec![UserEvent::ObjectPreviewGoToTop, UserEvent::ObjectPreviewGoToBottom], "Top/End", 5),
BuildShortHelpsItem::group(vec![UserEvent::ObjectPreviewDownload, UserEvent::ObjectPreviewDownloadAs], "Download", 3),
BuildShortHelpsItem::single(UserEvent::ObjectPreviewEncoding, "Encoding", 4),
BuildShortHelpsItem::single(UserEvent::ObjectPreviewYank, "Yank", 4),
BuildShortHelpsItem::single(UserEvent::ObjectPreviewBack, "Close", 1),
BuildShortHelpsItem::single(UserEvent::Help, "Help", 0),
]
Expand Down Expand Up @@ -342,6 +348,23 @@ impl ObjectPreviewPage {
self.view_state = ViewState::SaveDialog(InputDialogState::new(name));
}

fn yank_text_content(&mut self) {
if let PreviewType::Text(state) = &self.preview_type {
let encoding: &encoding_rs::Encoding = state.encoding.into();
let (content, _, _) = encoding.decode(&self.object.bytes);
let content_string = content.into_owned();

match copy_to_clipboard(content_string) {
Ok(_) => {
self.tx.send(AppEventType::NotifyInfo("Content yanked to clipboard".to_string()));
}
Err(e) => {
self.tx.send(AppEventType::NotifyError(e));
}
}
}
}

fn close_save_dialog(&mut self) {
self.view_state = ViewState::Default;
}
Expand Down