mirror of
				https://github.com/sharkdp/bat.git
				synced 2025-11-04 09:01:56 +00:00 
			
		
		
		
	Merge pull request #3345 from cavanaug/master
Support context in line ranges
This commit is contained in:
		@@ -5,6 +5,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
- Add paging to `--list-themes`, see PR #3239 (@einfachIrgendwer0815)
 | 
					- Add paging to `--list-themes`, see PR #3239 (@einfachIrgendwer0815)
 | 
				
			||||||
- Support negative relative line ranges, e.g. `bat -r :-10` / `bat -r='-10:'`, see #3068 (@ajesipow)
 | 
					- Support negative relative line ranges, e.g. `bat -r :-10` / `bat -r='-10:'`, see #3068 (@ajesipow)
 | 
				
			||||||
 | 
					- Support context in line ranges, e.g. `bat -r 30::5` /  `bat -r 30:40:5`, see #3345 (@cavanaug)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Bugfixes
 | 
					## Bugfixes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -194,6 +194,8 @@ Options:
 | 
				
			|||||||
            '--line-range 40:' prints lines 40 to the end of the file
 | 
					            '--line-range 40:' prints lines 40 to the end of the file
 | 
				
			||||||
            '--line-range 40' only prints line 40
 | 
					            '--line-range 40' only prints line 40
 | 
				
			||||||
            '--line-range 30:+10' prints lines 30 to 40
 | 
					            '--line-range 30:+10' prints lines 30 to 40
 | 
				
			||||||
 | 
					            '--line-range 35::5' prints lines 30 to 40 (line 35 with 5 lines of context)
 | 
				
			||||||
 | 
					            '--line-range 30:40:2' prints lines 28 to 42 (range 30-40 with 2 lines of context)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  -L, --list-languages
 | 
					  -L, --list-languages
 | 
				
			||||||
          Display a list of supported languages for syntax highlighting.
 | 
					          Display a list of supported languages for syntax highlighting.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -525,7 +525,9 @@ pub fn build_app(interactive_output: bool) -> Command {
 | 
				
			|||||||
                     '--line-range :40' prints lines 1 to 40\n  \
 | 
					                     '--line-range :40' prints lines 1 to 40\n  \
 | 
				
			||||||
                     '--line-range 40:' prints lines 40 to the end of the file\n  \
 | 
					                     '--line-range 40:' prints lines 40 to the end of the file\n  \
 | 
				
			||||||
                     '--line-range 40' only prints line 40\n  \
 | 
					                     '--line-range 40' only prints line 40\n  \
 | 
				
			||||||
                     '--line-range 30:+10' prints lines 30 to 40",
 | 
					                     '--line-range 30:+10' prints lines 30 to 40\n  \
 | 
				
			||||||
 | 
					                     '--line-range 35::5' prints lines 30 to 40 (line 35 with 5 lines of context)\n  \
 | 
				
			||||||
 | 
					                     '--line-range 30:40:2' prints lines 28 to 42 (range 30-40 with 2 lines of context)",
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        .arg(
 | 
					        .arg(
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -98,8 +98,33 @@ impl LineRange {
 | 
				
			|||||||
                new_range.upper = RangeBound::Absolute(upper_absolute_bound);
 | 
					                new_range.upper = RangeBound::Absolute(upper_absolute_bound);
 | 
				
			||||||
                Ok(new_range)
 | 
					                Ok(new_range)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					            3 => {
 | 
				
			||||||
 | 
					                // Handle context syntax: N::C or N:M:C
 | 
				
			||||||
 | 
					                if line_numbers[1].is_empty() {
 | 
				
			||||||
 | 
					                    // Format: N::C - single line with context
 | 
				
			||||||
 | 
					                    let line_number: usize = line_numbers[0].parse()
 | 
				
			||||||
 | 
					                        .map_err(|_| "Invalid line number in N::C format")?;
 | 
				
			||||||
 | 
					                    let context: usize = line_numbers[2].parse()
 | 
				
			||||||
 | 
					                        .map_err(|_| "Invalid context number in N::C format")?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    new_range.lower = RangeBound::Absolute(line_number.saturating_sub(context));
 | 
				
			||||||
 | 
					                    new_range.upper = RangeBound::Absolute(line_number.saturating_add(context));
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    // Format: N:M:C - range with context
 | 
				
			||||||
 | 
					                    let start_line: usize = line_numbers[0].parse()
 | 
				
			||||||
 | 
					                        .map_err(|_| "Invalid start line number in N:M:C format")?;
 | 
				
			||||||
 | 
					                    let end_line: usize = line_numbers[1].parse()
 | 
				
			||||||
 | 
					                        .map_err(|_| "Invalid end line number in N:M:C format")?;
 | 
				
			||||||
 | 
					                    let context: usize = line_numbers[2].parse()
 | 
				
			||||||
 | 
					                        .map_err(|_| "Invalid context number in N:M:C format")?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    new_range.lower = RangeBound::Absolute(start_line.saturating_sub(context));
 | 
				
			||||||
 | 
					                    new_range.upper = RangeBound::Absolute(end_line.saturating_add(context));
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                Ok(new_range)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
            _ => Err(
 | 
					            _ => Err(
 | 
				
			||||||
                "Line range contained more than one ':' character. Expected format: 'N' or 'N:M'"
 | 
					                "Line range contained too many ':' characters. Expected format: 'N', 'N:M', 'N::C', or 'N:M:C'"
 | 
				
			||||||
                    .into(),
 | 
					                    .into(),
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -210,14 +235,17 @@ fn test_parse_single() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#[test]
 | 
					#[test]
 | 
				
			||||||
fn test_parse_fail() {
 | 
					fn test_parse_fail() {
 | 
				
			||||||
    let range = LineRange::from("40:50:80");
 | 
					    // Test 4+ colon parts should still fail
 | 
				
			||||||
    assert!(range.is_err());
 | 
					    let range = LineRange::from("40:50:80:90");
 | 
				
			||||||
    let range = LineRange::from("40::80");
 | 
					 | 
				
			||||||
    assert!(range.is_err());
 | 
					    assert!(range.is_err());
 | 
				
			||||||
 | 
					    // Test invalid formats that should still fail
 | 
				
			||||||
    let range = LineRange::from("-2:5");
 | 
					    let range = LineRange::from("-2:5");
 | 
				
			||||||
    assert!(range.is_err());
 | 
					    assert!(range.is_err());
 | 
				
			||||||
    let range = LineRange::from(":40:");
 | 
					    let range = LineRange::from(":40:");
 | 
				
			||||||
    assert!(range.is_err());
 | 
					    assert!(range.is_err());
 | 
				
			||||||
 | 
					    // Test completely malformed input
 | 
				
			||||||
 | 
					    let range = LineRange::from("abc:def");
 | 
				
			||||||
 | 
					    assert!(range.is_err());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[test]
 | 
					#[test]
 | 
				
			||||||
@@ -274,6 +302,57 @@ fn test_parse_minus_fail() {
 | 
				
			|||||||
    assert!(range.is_err());
 | 
					    assert!(range.is_err());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[test]
 | 
				
			||||||
 | 
					fn test_parse_context_single_line() {
 | 
				
			||||||
 | 
					    let range = LineRange::from("35::5").expect("Shouldn't fail on test!");
 | 
				
			||||||
 | 
					    assert_eq!(RangeBound::Absolute(30), range.lower);
 | 
				
			||||||
 | 
					    assert_eq!(RangeBound::Absolute(40), range.upper);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[test]
 | 
				
			||||||
 | 
					fn test_parse_context_range() {
 | 
				
			||||||
 | 
					    let range = LineRange::from("30:40:2").expect("Shouldn't fail on test!");
 | 
				
			||||||
 | 
					    assert_eq!(RangeBound::Absolute(28), range.lower);
 | 
				
			||||||
 | 
					    assert_eq!(RangeBound::Absolute(42), range.upper);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Test the case that used to fail but should now work
 | 
				
			||||||
 | 
					    let range = LineRange::from("40:50:80").expect("Shouldn't fail on test!");
 | 
				
			||||||
 | 
					    assert_eq!(RangeBound::Absolute(0), range.lower); // 40 - 80 = 0 (saturated)
 | 
				
			||||||
 | 
					    assert_eq!(RangeBound::Absolute(130), range.upper); // 50 + 80 = 130
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[test]
 | 
				
			||||||
 | 
					fn test_parse_context_edge_cases() {
 | 
				
			||||||
 | 
					    // Test with small line numbers that would underflow
 | 
				
			||||||
 | 
					    let range = LineRange::from("5::10").expect("Shouldn't fail on test!");
 | 
				
			||||||
 | 
					    assert_eq!(RangeBound::Absolute(0), range.lower);
 | 
				
			||||||
 | 
					    assert_eq!(RangeBound::Absolute(15), range.upper);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Test with zero context
 | 
				
			||||||
 | 
					    let range = LineRange::from("50::0").expect("Shouldn't fail on test!");
 | 
				
			||||||
 | 
					    assert_eq!(RangeBound::Absolute(50), range.lower);
 | 
				
			||||||
 | 
					    assert_eq!(RangeBound::Absolute(50), range.upper);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Test range with zero context
 | 
				
			||||||
 | 
					    let range = LineRange::from("30:40:0").expect("Shouldn't fail on test!");
 | 
				
			||||||
 | 
					    assert_eq!(RangeBound::Absolute(30), range.lower);
 | 
				
			||||||
 | 
					    assert_eq!(RangeBound::Absolute(40), range.upper);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[test]
 | 
				
			||||||
 | 
					fn test_parse_context_fail() {
 | 
				
			||||||
 | 
					    let range = LineRange::from("40::z");
 | 
				
			||||||
 | 
					    assert!(range.is_err());
 | 
				
			||||||
 | 
					    let range = LineRange::from("::5");
 | 
				
			||||||
 | 
					    assert!(range.is_err());
 | 
				
			||||||
 | 
					    let range = LineRange::from("40::");
 | 
				
			||||||
 | 
					    assert!(range.is_err());
 | 
				
			||||||
 | 
					    let range = LineRange::from("30:40:z");
 | 
				
			||||||
 | 
					    assert!(range.is_err());
 | 
				
			||||||
 | 
					    let range = LineRange::from("30::40:5");
 | 
				
			||||||
 | 
					    assert!(range.is_err());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 | 
					#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 | 
				
			||||||
pub enum RangeCheckResult {
 | 
					pub enum RangeCheckResult {
 | 
				
			||||||
    // Within one of the given ranges
 | 
					    // Within one of the given ranges
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										6
									
								
								tests/examples/multiline.txt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								tests/examples/multiline.txt
									
									
									
									
										vendored
									
									
								
							@@ -2,3 +2,9 @@ line 1
 | 
				
			|||||||
line 2
 | 
					line 2
 | 
				
			||||||
line 3
 | 
					line 3
 | 
				
			||||||
line 4
 | 
					line 4
 | 
				
			||||||
 | 
					line 5
 | 
				
			||||||
 | 
					line 6
 | 
				
			||||||
 | 
					line 7
 | 
				
			||||||
 | 
					line 8
 | 
				
			||||||
 | 
					line 9
 | 
				
			||||||
 | 
					line 10
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -163,7 +163,7 @@ fn line_numbers() {
 | 
				
			|||||||
        .arg("--decorations=always")
 | 
					        .arg("--decorations=always")
 | 
				
			||||||
        .assert()
 | 
					        .assert()
 | 
				
			||||||
        .success()
 | 
					        .success()
 | 
				
			||||||
        .stdout("   1 line 1\n   2 line 2\n   3 line 3\n   4 line 4\n");
 | 
					        .stdout("   1 line 1\n   2 line 2\n   3 line 3\n   4 line 4\n   5 line 5\n   6 line 6\n   7 line 7\n   8 line 8\n   9 line 9\n  10 line 10\n");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[test]
 | 
					#[test]
 | 
				
			||||||
@@ -183,7 +183,7 @@ fn line_range_up_to_2_from_back() {
 | 
				
			|||||||
        .arg("--line-range=:-2")
 | 
					        .arg("--line-range=:-2")
 | 
				
			||||||
        .assert()
 | 
					        .assert()
 | 
				
			||||||
        .success()
 | 
					        .success()
 | 
				
			||||||
        .stdout("line 1\nline 2\n");
 | 
					        .stdout("line 1\nline 2\nline 3\nline 4\nline 5\nline 6\nline 7\nline 8\n");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[test]
 | 
					#[test]
 | 
				
			||||||
@@ -203,7 +203,7 @@ fn line_range_from_back_last_two() {
 | 
				
			|||||||
        .arg("--line-range=-2:")
 | 
					        .arg("--line-range=-2:")
 | 
				
			||||||
        .assert()
 | 
					        .assert()
 | 
				
			||||||
        .success()
 | 
					        .success()
 | 
				
			||||||
        .stdout("line 3\nline 4\n");
 | 
					        .stdout("line 9\nline 10\n");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[test]
 | 
					#[test]
 | 
				
			||||||
@@ -230,10 +230,10 @@ fn line_range_first_two() {
 | 
				
			|||||||
fn line_range_last_3() {
 | 
					fn line_range_last_3() {
 | 
				
			||||||
    bat()
 | 
					    bat()
 | 
				
			||||||
        .arg("multiline.txt")
 | 
					        .arg("multiline.txt")
 | 
				
			||||||
        .arg("--line-range=2:")
 | 
					        .arg("--line-range=8:")
 | 
				
			||||||
        .assert()
 | 
					        .assert()
 | 
				
			||||||
        .success()
 | 
					        .success()
 | 
				
			||||||
        .stdout("line 2\nline 3\nline 4\n");
 | 
					        .stdout("line 8\nline 9\nline 10\n");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[test]
 | 
					#[test]
 | 
				
			||||||
@@ -247,6 +247,137 @@ fn line_range_multiple() {
 | 
				
			|||||||
        .stdout("line 1\nline 2\nline 4\n");
 | 
					        .stdout("line 1\nline 2\nline 4\n");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[test]
 | 
				
			||||||
 | 
					fn line_range_multiple_with_context() {
 | 
				
			||||||
 | 
					    bat()
 | 
				
			||||||
 | 
					        .arg("multiline.txt")
 | 
				
			||||||
 | 
					        .arg("--line-range=2::1")
 | 
				
			||||||
 | 
					        .arg("--line-range=8::1")
 | 
				
			||||||
 | 
					        .assert()
 | 
				
			||||||
 | 
					        .success()
 | 
				
			||||||
 | 
					        .stdout("line 1\nline 2\nline 3\nline 7\nline 8\nline 9\n");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[test]
 | 
				
			||||||
 | 
					fn line_range_context_around_single_line() {
 | 
				
			||||||
 | 
					    bat()
 | 
				
			||||||
 | 
					        .arg("multiline.txt")
 | 
				
			||||||
 | 
					        .arg("--line-range=5::2")
 | 
				
			||||||
 | 
					        .assert()
 | 
				
			||||||
 | 
					        .success()
 | 
				
			||||||
 | 
					        .stdout("line 3\nline 4\nline 5\nline 6\nline 7\n");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[test]
 | 
				
			||||||
 | 
					fn line_range_context_around_single_line_minimal() {
 | 
				
			||||||
 | 
					    bat()
 | 
				
			||||||
 | 
					        .arg("multiline.txt")
 | 
				
			||||||
 | 
					        .arg("--line-range=5::1")
 | 
				
			||||||
 | 
					        .assert()
 | 
				
			||||||
 | 
					        .success()
 | 
				
			||||||
 | 
					        .stdout("line 4\nline 5\nline 6\n");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[test]
 | 
				
			||||||
 | 
					fn line_range_context_around_range() {
 | 
				
			||||||
 | 
					    bat()
 | 
				
			||||||
 | 
					        .arg("multiline.txt")
 | 
				
			||||||
 | 
					        .arg("--line-range=4:6:2")
 | 
				
			||||||
 | 
					        .assert()
 | 
				
			||||||
 | 
					        .success()
 | 
				
			||||||
 | 
					        .stdout("line 2\nline 3\nline 4\nline 5\nline 6\nline 7\nline 8\n");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[test]
 | 
				
			||||||
 | 
					fn line_range_context_at_file_boundaries() {
 | 
				
			||||||
 | 
					    bat()
 | 
				
			||||||
 | 
					        .arg("multiline.txt")
 | 
				
			||||||
 | 
					        .arg("--line-range=1::2")
 | 
				
			||||||
 | 
					        .assert()
 | 
				
			||||||
 | 
					        .success()
 | 
				
			||||||
 | 
					        .stdout("line 1\nline 2\nline 3\n");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[test]
 | 
				
			||||||
 | 
					fn line_range_context_at_end_of_file() {
 | 
				
			||||||
 | 
					    bat()
 | 
				
			||||||
 | 
					        .arg("multiline.txt")
 | 
				
			||||||
 | 
					        .arg("--line-range=10::2")
 | 
				
			||||||
 | 
					        .assert()
 | 
				
			||||||
 | 
					        .success()
 | 
				
			||||||
 | 
					        .stdout("line 8\nline 9\nline 10\n");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[test]
 | 
				
			||||||
 | 
					fn line_range_context_zero() {
 | 
				
			||||||
 | 
					    bat()
 | 
				
			||||||
 | 
					        .arg("multiline.txt")
 | 
				
			||||||
 | 
					        .arg("--line-range=5::0")
 | 
				
			||||||
 | 
					        .assert()
 | 
				
			||||||
 | 
					        .success()
 | 
				
			||||||
 | 
					        .stdout("line 5\n");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[test]
 | 
				
			||||||
 | 
					fn line_range_context_negative_single_line() {
 | 
				
			||||||
 | 
					    bat()
 | 
				
			||||||
 | 
					        .arg("multiline.txt")
 | 
				
			||||||
 | 
					        .arg("--line-range=5::-1")
 | 
				
			||||||
 | 
					        .assert()
 | 
				
			||||||
 | 
					        .failure()
 | 
				
			||||||
 | 
					        .stderr(predicate::str::contains(
 | 
				
			||||||
 | 
					            "Invalid context number in N::C format",
 | 
				
			||||||
 | 
					        ));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[test]
 | 
				
			||||||
 | 
					fn line_range_context_negative_range() {
 | 
				
			||||||
 | 
					    bat()
 | 
				
			||||||
 | 
					        .arg("multiline.txt")
 | 
				
			||||||
 | 
					        .arg("--line-range=5:6:-1")
 | 
				
			||||||
 | 
					        .assert()
 | 
				
			||||||
 | 
					        .failure()
 | 
				
			||||||
 | 
					        .stderr(predicate::str::contains(
 | 
				
			||||||
 | 
					            "Invalid context number in N:M:C format",
 | 
				
			||||||
 | 
					        ));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[test]
 | 
				
			||||||
 | 
					fn line_range_context_non_numeric_single_line() {
 | 
				
			||||||
 | 
					    bat()
 | 
				
			||||||
 | 
					        .arg("multiline.txt")
 | 
				
			||||||
 | 
					        .arg("--line-range=10::abc")
 | 
				
			||||||
 | 
					        .assert()
 | 
				
			||||||
 | 
					        .failure()
 | 
				
			||||||
 | 
					        .stderr(predicate::str::contains(
 | 
				
			||||||
 | 
					            "Invalid context number in N::C format",
 | 
				
			||||||
 | 
					        ));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[test]
 | 
				
			||||||
 | 
					fn line_range_context_non_numeric_range() {
 | 
				
			||||||
 | 
					    bat()
 | 
				
			||||||
 | 
					        .arg("multiline.txt")
 | 
				
			||||||
 | 
					        .arg("--line-range=10:12:xyz")
 | 
				
			||||||
 | 
					        .assert()
 | 
				
			||||||
 | 
					        .failure()
 | 
				
			||||||
 | 
					        .stderr(predicate::str::contains(
 | 
				
			||||||
 | 
					            "Invalid context number in N:M:C format",
 | 
				
			||||||
 | 
					        ));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[test]
 | 
				
			||||||
 | 
					fn line_range_context_very_large() {
 | 
				
			||||||
 | 
					    bat()
 | 
				
			||||||
 | 
					        .arg("multiline.txt")
 | 
				
			||||||
 | 
					        .arg("--line-range=10::999999")
 | 
				
			||||||
 | 
					        .assert()
 | 
				
			||||||
 | 
					        .success()
 | 
				
			||||||
 | 
					        .stdout(
 | 
				
			||||||
 | 
					            "line 1\nline 2\nline 3\nline 4\nline 5\nline 6\nline 7\nline 8\nline 9\nline 10\n",
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[test]
 | 
					#[test]
 | 
				
			||||||
fn squeeze_blank() {
 | 
					fn squeeze_blank() {
 | 
				
			||||||
    bat()
 | 
					    bat()
 | 
				
			||||||
@@ -1523,6 +1654,12 @@ fn snip() {
 | 
				
			|||||||
   2 line 2
 | 
					   2 line 2
 | 
				
			||||||
 ...─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ 8< ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
 | 
					 ...─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ 8< ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
 | 
				
			||||||
   4 line 4
 | 
					   4 line 4
 | 
				
			||||||
 | 
					   5 line 5
 | 
				
			||||||
 | 
					   6 line 6
 | 
				
			||||||
 | 
					   7 line 7
 | 
				
			||||||
 | 
					   8 line 8
 | 
				
			||||||
 | 
					   9 line 9
 | 
				
			||||||
 | 
					  10 line 10
 | 
				
			||||||
",
 | 
					",
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user