Implement read command (#10447)

Co-authored-by: Michael Davis <mcarsondavis@gmail.com>
Co-authored-by: Ibrahim Dursun <ibrahim@dursun.cc>
This commit is contained in:
Sean Perry 2024-04-17 15:57:57 -07:00 committed by GitHub
parent 521accaf00
commit 30baff907d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 67 additions and 1 deletions

View file

@ -87,3 +87,4 @@
| `:redraw` | Clear and re-render the whole UI |
| `:move` | Move the current buffer and its corresponding file to a different path |
| `:yank-diagnostic` | Yank diagnostic(s) under primary cursor to register, or clipboard by default |
| `:read`, `:r` | Load a file into buffer |

View file

@ -1,4 +1,5 @@
use std::fmt::Write;
use std::io::BufReader;
use std::ops::Deref;
use crate::job::Job;
@ -8,7 +9,7 @@ use super::*;
use helix_core::fuzzy::fuzzy_match;
use helix_core::indent::MAX_INDENT;
use helix_core::{line_ending, shellwords::Shellwords};
use helix_view::document::DEFAULT_LANGUAGE_NAME;
use helix_view::document::{read_to_string, DEFAULT_LANGUAGE_NAME};
use helix_view::editor::{CloseError, ConfigEvent};
use serde_json::Value;
use ui::completers::{self, Completer};
@ -2454,6 +2455,39 @@ fn yank_diagnostic(
Ok(())
}
fn read(cx: &mut compositor::Context, args: &[Cow<str>], event: PromptEvent) -> anyhow::Result<()> {
if event != PromptEvent::Validate {
return Ok(());
}
let scrolloff = cx.editor.config().scrolloff;
let (view, doc) = current!(cx.editor);
ensure!(!args.is_empty(), "file name is expected");
ensure!(args.len() == 1, "only the file name is expected");
let filename = args.get(0).unwrap();
let path = PathBuf::from(filename.to_string());
ensure!(
path.exists() && path.is_file(),
"path is not a file: {:?}",
path
);
let file = std::fs::File::open(path).map_err(|err| anyhow!("error opening file: {}", err))?;
let mut reader = BufReader::new(file);
let (contents, _, _) = read_to_string(&mut reader, Some(doc.encoding()))
.map_err(|err| anyhow!("error reading file: {}", err))?;
let contents = Tendril::from(contents);
let selection = doc.selection(view.id);
let transaction = Transaction::insert(doc.text(), selection, contents);
doc.apply(&transaction, view.id);
doc.append_changes_to_history(view);
view.ensure_cursor_in_view(doc, scrolloff);
Ok(())
}
pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[
TypableCommand {
name: "quit",
@ -3068,6 +3102,13 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[
fun: yank_diagnostic,
signature: CommandSignature::all(completers::register),
},
TypableCommand {
name: "read",
aliases: &["r"],
doc: "Load a file into buffer",
fun: read,
signature: CommandSignature::positional(&[completers::filename]),
},
];
pub static TYPABLE_COMMAND_MAP: Lazy<HashMap<&'static str, &'static TypableCommand>> =

View file

@ -640,3 +640,27 @@ async fn test_join_selections_space() -> anyhow::Result<()> {
Ok(())
}
#[tokio::test(flavor = "multi_thread")]
async fn test_read_file() -> anyhow::Result<()> {
let mut file = tempfile::NamedTempFile::new()?;
let contents_to_read = "some contents";
let output_file = helpers::temp_file_with_contents(contents_to_read)?;
test_key_sequence(
&mut helpers::AppBuilder::new()
.with_file(file.path(), None)
.build()?,
Some(&format!(":r {:?}<ret><esc>:w<ret>", output_file.path())),
Some(&|app| {
assert!(!app.editor.is_err(), "error: {:?}", app.editor.get_status());
}),
false,
)
.await?;
let expected_contents = LineFeedHandling::Native.apply(contents_to_read);
helpers::assert_file_has_content(&mut file, &expected_contents)?;
Ok(())
}