@@ -66,6 +66,8 @@ impl Rope {
66
66
67
67
/// Returns the byte at `byte_index`.
68
68
///
69
+ /// For a checked version, see [`get_byte`](Self::get_byte).
70
+ ///
69
71
/// # Panics
70
72
///
71
73
/// Panics if the byte index is out of bounds (i.e. greater than or equal
@@ -85,14 +87,40 @@ impl Rope {
85
87
#[ track_caller]
86
88
#[ inline]
87
89
pub fn byte ( & self , byte_index : usize ) -> u8 {
90
+ self . get_byte ( byte_index) . unwrap_or_else ( || {
91
+ panic:: byte_index_out_of_bounds ( byte_index, self . line_len ( ) )
92
+ } )
93
+ }
94
+
95
+ /// Returns the byte at `byte_index`, if it exists.
96
+ ///
97
+ /// If `byte_index` is out of bounds, returns `None`.
98
+ ///
99
+ /// For a panic'ing version, see [`byte`](Self::byte).
100
+ ///
101
+ /// # Examples
102
+ ///
103
+ /// ```
104
+ /// # use crop::Rope;
105
+ /// #
106
+ /// let r = Rope::from("bar");
107
+ ///
108
+ /// assert_eq!(r.get_byte(0), Some(b'b'));
109
+ /// assert_eq!(r.get_byte(1), Some(b'a'));
110
+ /// assert_eq!(r.get_byte(2), Some(b'r'));
111
+ /// assert_eq!(r.get_byte(3), None);
112
+ /// ```
113
+ #[ track_caller]
114
+ #[ inline]
115
+ pub fn get_byte ( & self , byte_index : usize ) -> Option < u8 > {
88
116
if byte_index >= self . byte_len ( ) {
89
- panic :: byte_index_out_of_bounds ( byte_index , self . byte_len ( ) ) ;
117
+ return None ;
90
118
}
91
119
92
120
let ( chunk, ByteMetric ( chunk_byte_offset) ) =
93
121
self . tree . leaf_at_measure ( ByteMetric ( byte_index + 1 ) ) ;
94
122
95
- chunk. byte ( byte_index - chunk_byte_offset)
123
+ Some ( chunk. byte ( byte_index - chunk_byte_offset) )
96
124
}
97
125
98
126
/// Returns the length of the `Rope` in bytes.
@@ -446,6 +474,9 @@ impl Rope {
446
474
/// [`line_slice()`](Self::line_slice()) in the
447
475
/// `line_index..line_index + 1` range.
448
476
///
477
+ /// For a checked version, see
478
+ /// [`get_line_slice()`](Self::get_line_slice()).
479
+ ///
449
480
/// # Panics
450
481
///
451
482
/// Panics if the line index is out of bounds (i.e. greater than or equal
@@ -465,8 +496,38 @@ impl Rope {
465
496
#[ track_caller]
466
497
#[ inline]
467
498
pub fn line ( & self , line_index : usize ) -> RopeSlice < ' _ > {
499
+ self . get_line ( line_index) . unwrap_or_else ( || {
500
+ panic:: line_index_out_of_bounds ( line_index, self . line_len ( ) )
501
+ } )
502
+ }
503
+
504
+ /// Returns the line at `line_index`, without its line terminator, if it exists.
505
+ ///
506
+ /// If `line_index` is out of bounds, returns `None`.
507
+ ///
508
+ /// If you want to include the line break consider calling
509
+ /// [`get_line_slice()`](Self::get_line_slice()) in the
510
+ /// `line_index..line_index + 1` range.
511
+ ///
512
+ /// For a panic'ing version, see [`line_slice()`](Self::line_slice()).
513
+ ///
514
+ /// # Examples
515
+ ///
516
+ /// ```
517
+ /// # use crop::Rope;
518
+ /// #
519
+ /// let r = Rope::from("foo\nbar\r\nbaz");
520
+ ///
521
+ /// assert_eq!(r.get_line(0).unwrap(), "foo");
522
+ /// assert_eq!(r.get_line(1).unwrap(), "bar");
523
+ /// assert_eq!(r.get_line(2).unwrap(), "baz");
524
+ /// assert_eq!(r.get_line(3), None);
525
+ /// ```
526
+ #[ track_caller]
527
+ #[ inline]
528
+ pub fn get_line ( & self , line_index : usize ) -> Option < RopeSlice < ' _ > > {
468
529
if line_index >= self . line_len ( ) {
469
- panic :: line_index_out_of_bounds ( line_index , self . line_len ( ) ) ;
530
+ return None ;
470
531
}
471
532
472
533
let tree_slice = self
@@ -479,7 +540,7 @@ impl Rope {
479
540
line. truncate_trailing_line_break ( ) ;
480
541
}
481
542
482
- line
543
+ Some ( line)
483
544
}
484
545
485
546
/// Returns the number of lines in the `Rope`.
@@ -551,6 +612,10 @@ impl Rope {
551
612
/// Returns an immutable slice of the `Rope` in the specified line range,
552
613
/// where the start and end of the range are interpreted as offsets.
553
614
///
615
+ /// If you want a single line, see [`line()`](Self::line).
616
+ ///
617
+ /// If you want a checked version, see [`get_line_slice()`](Self::get_line_slice).
618
+ ///
554
619
/// # Panics
555
620
///
556
621
/// Panics if the start is greater than the end or if the end is out of
@@ -566,6 +631,7 @@ impl Rope {
566
631
/// assert_eq!(r.line_slice(..1), "foo\n");
567
632
/// assert_eq!(r.line_slice(1..3), "bar\r\nbaz\n");
568
633
/// assert_eq!(r.line_slice(3..), "foobar\n");
634
+ /// assert_eq!(r.line_slice(4..), "");
569
635
/// ```
570
636
#[ track_caller]
571
637
#[ inline]
@@ -587,6 +653,49 @@ impl Rope {
587
653
self . tree . slice ( RawLineMetric ( start) ..RawLineMetric ( end) ) . into ( )
588
654
}
589
655
656
+ /// Returns an immutable slice of the `Rope` in the specified line range,
657
+ /// if it exists, where the start and end of the range are interpreted as
658
+ /// offsets.
659
+ ///
660
+ /// If `line_range` is out of bounds, returns `None`.
661
+ ///
662
+ /// If you want a single line, see [`get_line()`](Self::get_line).
663
+ ///
664
+ /// For a panic'ing version, see [`line_slice`](Self::line_slice).
665
+ ///
666
+ /// # Examples
667
+ ///
668
+ /// ```
669
+ /// # use crop::Rope;
670
+ /// #
671
+ /// let r = Rope::from("foo\nbar\r\nbaz\nfoobar\n");
672
+ ///
673
+ /// assert_eq!(r.get_line_slice(..1).unwrap(), "foo\n");
674
+ /// assert_eq!(r.get_line_slice(1..3).unwrap(), "bar\r\nbaz\n");
675
+ /// assert_eq!(r.get_line_slice(3..).unwrap(), "foobar\n");
676
+ /// assert_eq!(r.get_line_slice(4..).unwrap(), "");
677
+ /// assert_eq!(r.get_line_slice(5..), None);
678
+ /// ```
679
+ #[ track_caller]
680
+ #[ inline]
681
+ pub fn get_line_slice < R > ( & self , line_range : R ) -> Option < RopeSlice < ' _ > >
682
+ where
683
+ R : RangeBounds < usize > ,
684
+ {
685
+ let ( start, end) =
686
+ range_bounds_to_start_end ( line_range, 0 , self . line_len ( ) ) ;
687
+
688
+ if start > end {
689
+ return None ;
690
+ }
691
+
692
+ if end > self . line_len ( ) {
693
+ return None ;
694
+ }
695
+
696
+ Some ( self . tree . slice ( RawLineMetric ( start) ..RawLineMetric ( end) ) . into ( ) )
697
+ }
698
+
590
699
/// Returns an iterator over the lines of this `Rope`, not including the
591
700
/// line terminators.
592
701
///
0 commit comments