on master help sign in
Mark buffers created from stdin as modified (#7431)
636c91cMichael Davis
helix-view/src/document.rs+79−26
@@ -397,33 +397,11 @@ pub fn from_reader<R: std::io::Read + ?Sized>(
397 let mut buf_out = [0u8; BUF_SIZE];
397 let mut buf_out = [0u8; BUF_SIZE];
398 let mut builder = RopeBuilder::new();
398 let mut builder = RopeBuilder::new();
399
399
400− // By default, the encoding of the text is auto-detected by
401− // `encoding_rs` for_bom, and if it fails, from `chardetng`
402− // crate which requires sample data from the reader.
403− // As a manual override to this auto-detection is possible, the
404− // same data is read into `buf` to ensure symmetry in the upcoming
405− // loop.
406− let (encoding, has_bom, mut decoder, mut slice, mut is_empty) = {
400+ let (encoding, has_bom, mut decoder, read) =
407− let read = reader.read(&mut buf)?;
401+ read_and_detect_encoding(reader, encoding, &mut buf)?;
408− let is_empty = read == 0;
409− let (encoding, has_bom) = encoding
410− .map(|encoding| (encoding, false))
411− .or_else(|| {
412− encoding::Encoding::for_bom(&buf).map(|(encoding, _bom_size)| (encoding, true))
413− })
414− .unwrap_or_else(|| {
415− let mut encoding_detector = chardetng::EncodingDetector::new();
416− encoding_detector.feed(&buf, is_empty);
417− (encoding_detector.guess(None, true), false)
418− });
419−
420− let decoder = encoding.new_decoder();
421
402
422− // If the amount of bytes read from the reader is less than
423− // `buf.len()`, it is undesirable to read the bytes afterwards.
424− let slice = &buf[..read];
403+ let mut slice = &buf[..read];
425− (encoding, has_bom, decoder, slice, is_empty)
404+ let mut is_empty = read == 0;
426− };
427
405
428 // `RopeBuilder::append()` expects a `&str`, so this is the "real"
406 // `RopeBuilder::append()` expects a `&str`, so this is the "real"
429 // output buffer. When decoding, the number of bytes in the output
407 // output buffer. When decoding, the number of bytes in the output
@@ -493,6 +471,81 @@ pub fn from_reader<R: std::io::Read + ?Sized>(
493 Ok((rope, encoding, has_bom))
471 Ok((rope, encoding, has_bom))
494}
472}
495
473
474+pub fn read_to_string<R: std::io::Read + ?Sized>(
475+ reader: &mut R,
476+ encoding: Option<&'static Encoding>,
477+) -> Result<(String, &'static Encoding, bool), Error> {
478+ let mut buf = [0u8; BUF_SIZE];
479+
480+ let (encoding, has_bom, mut decoder, read) =
481+ read_and_detect_encoding(reader, encoding, &mut buf)?;
482+
483+ let mut slice = &buf[..read];
484+ let mut is_empty = read == 0;
485+ let mut buf_string = String::with_capacity(buf.len());
486+
487+ loop {
488+ let mut total_read = 0usize;
489+
490+ loop {
491+ let (result, read, ..) =
492+ decoder.decode_to_string(&slice[total_read..], &mut buf_string, is_empty);
493+
494+ total_read += read;
495+
496+ match result {
497+ encoding::CoderResult::InputEmpty => {
498+ debug_assert_eq!(slice.len(), total_read);
499+ break;
500+ }
501+ encoding::CoderResult::OutputFull => {
502+ debug_assert!(slice.len() > total_read);
503+ buf_string.reserve(buf.len())
504+ }
505+ }
506+ }
507+
508+ if is_empty {
509+ debug_assert_eq!(reader.read(&mut buf)?, 0);
510+ break;
511+ }
512+
513+ let read = reader.read(&mut buf)?;
514+ slice = &buf[..read];
515+ is_empty = read == 0;
516+ }
517+ Ok((buf_string, encoding, has_bom))
518+}
519+
520+/// Reads the first chunk from a Reader into the given buffer
521+/// and detects the encoding.
522+///
523+/// By default, the encoding of the text is auto-detected by
524+/// `encoding_rs` for_bom, and if it fails, from `chardetng`
525+/// crate which requires sample data from the reader.
526+/// As a manual override to this auto-detection is possible, the
527+/// same data is read into `buf` to ensure symmetry in the upcoming
528+/// loop.
529+fn read_and_detect_encoding<R: std::io::Read + ?Sized>(
530+ reader: &mut R,
531+ encoding: Option<&'static Encoding>,
532+ buf: &mut [u8],
533+) -> Result<(&'static Encoding, bool, encoding::Decoder, usize), Error> {
534+ let read = reader.read(buf)?;
535+ let is_empty = read == 0;
536+ let (encoding, has_bom) = encoding
537+ .map(|encoding| (encoding, false))
538+ .or_else(|| encoding::Encoding::for_bom(buf).map(|(encoding, _bom_size)| (encoding, true)))
539+ .unwrap_or_else(|| {
540+ let mut encoding_detector = chardetng::EncodingDetector::new();
541+ encoding_detector.feed(buf, is_empty);
542+ (encoding_detector.guess(None, true), false)
543+ });
544+ let decoder = encoding.new_decoder();
545+
546+ Ok((encoding, has_bom, decoder, read))
547+}
548+
496// The documentation and implementation of this function should be up-to-date with
549// The documentation and implementation of this function should be up-to-date with
497// its sibling function, `from_reader()`.
550// its sibling function, `from_reader()`.
498//
551//
helix-view/src/editor.rs+16−5
@@ -1386,11 +1386,22 @@ impl Editor {
1386 }
1386 }
1387
1387
1388 pub fn new_file_from_stdin(&mut self, action: Action) -> Result<DocumentId, Error> {
1388 pub fn new_file_from_stdin(&mut self, action: Action) -> Result<DocumentId, Error> {
1389− let (rope, encoding, has_bom) = crate::document::from_reader(&mut stdin(), None)?;
1389+ let (stdin, encoding, has_bom) = crate::document::read_to_string(&mut stdin(), None)?;
1390− Ok(self.new_file_from_document(
1390+ let doc = Document::from(
1391− action,
1391+ helix_core::Rope::default(),
1392− Document::from(rope, Some((encoding, has_bom)), self.config.clone()),
1392+ Some((encoding, has_bom)),
1393− ))
1393+ self.config.clone(),
1394+ );
1395+ let doc_id = self.new_file_from_document(action, doc);
1396+ let doc = doc_mut!(self, &doc_id);
1397+ let view = view_mut!(self);
1398+ doc.ensure_view_init(view.id);
1399+ let transaction =
1400+ helix_core::Transaction::insert(doc.text(), doc.selection(view.id), stdin.into())
1401+ .with_selection(Selection::point(0));
1402+ doc.apply(&transaction, view.id);
1403+ doc.append_changes_to_history(view);
1404+ Ok(doc_id)
1394 }
1405 }
1395
1406
1396 // ??? possible use for integration tests
1407 // ??? possible use for integration tests