rewrite_string: detect when a url is being split and place the new line

after it
This commit is contained in:
Stéphane Campinas 2018-10-09 21:47:32 +02:00
parent c0b7222e2d
commit 375c87820f
No known key found for this signature in database
GPG Key ID: 6D5620D908210133
5 changed files with 147 additions and 2 deletions

View File

@ -158,6 +158,31 @@ pub fn rewrite_string<'a>(orig: &str, fmt: &StringFormat<'a>) -> Option<String>
wrap_str(result, fmt.config.max_width(), fmt.shape)
}
/// Returns the index to the end of the url if the given string includes an
/// URL or alike. Otherwise, returns None;
fn detect_url(s: &[&str], index: usize) -> Option<usize> {
let start = match s[..=index].iter().rposition(|g| is_whitespace(g)) {
Some(pos) => pos + 1,
None => 0,
};
if s.len() < start + 8 {
return None;
}
let prefix = s[start..start + 8].join("");
if prefix.starts_with("https://")
|| prefix.starts_with("http://")
|| prefix.starts_with("ftp://")
|| prefix.starts_with("file://")
{
match s[index..].iter().position(|g| is_whitespace(g)) {
Some(pos) => Some(index + pos - 1),
None => Some(s.len() - 1),
}
} else {
None
}
}
/// Trims whitespaces to the right except for the line feed character.
fn trim_right_but_line_feed(trim_end: bool, result: String) -> String {
let whitespace_except_line_feed = |c: char| c.is_whitespace() && c != '\n';
@ -193,13 +218,16 @@ enum SnippetState {
EndWithLineFeed(String, usize),
}
fn not_whitespace_except_line_feed(g: &str) -> bool {
is_line_feed(g) || !is_whitespace(g)
}
/// Break the input string at a boundary character around the offset `max_chars`. A boundary
/// character is either a punctuation or a whitespace.
fn break_string(max_chars: usize, trim_end: bool, line_end: &str, input: &[&str]) -> SnippetState {
let break_at = |index /* grapheme at index is included */| {
// Take in any whitespaces to the left/right of `input[index]` while
// preserving line feeds
let not_whitespace_except_line_feed = |g| is_line_feed(g) || !is_whitespace(g);
let index_minus_ws = input[0..=index]
.iter()
.rposition(|grapheme| not_whitespace_except_line_feed(grapheme))
@ -258,6 +286,24 @@ fn break_string(max_chars: usize, trim_end: bool, line_end: &str, input: &[&str]
// - extra whitespaces to the right can be trimmed
return break_at(max_chars - 1);
}
if let Some(url_index_end) = detect_url(input, max_chars) {
let index_plus_ws = url_index_end + input[url_index_end..]
.iter()
.skip(1)
.position(|grapheme| not_whitespace_except_line_feed(grapheme))
.unwrap_or(0);
return if trim_end {
SnippetState::LineEnd(
input[..=url_index_end].join("").to_string(),
index_plus_ws + 1,
)
} else {
return SnippetState::LineEnd(
input[..=index_plus_ws].join("").to_string(),
index_plus_ws + 1,
);
};
}
match input[0..max_chars]
.iter()
.rposition(|grapheme| is_whitespace(grapheme))
@ -303,7 +349,7 @@ fn is_punctuation(grapheme: &str) -> bool {
#[cfg(test)]
mod test {
use super::{break_string, rewrite_string, SnippetState, StringFormat};
use super::{break_string, detect_url, rewrite_string, SnippetState, StringFormat};
use config::Config;
use shape::{Indent, Shape};
use unicode_segmentation::UnicodeSegmentation;
@ -610,4 +656,31 @@ fn boundary_on_edge() {
Some("Vestibulum\\\n // ac lacus.".to_string())
);
}
#[test]
fn detect_urls() {
let string = "aaa http://example.org something";
let graphemes = UnicodeSegmentation::graphemes(&*string, false).collect::<Vec<&str>>();
assert_eq!(detect_url(&graphemes, 8), Some(21));
let string = "https://example.org something";
let graphemes = UnicodeSegmentation::graphemes(&*string, false).collect::<Vec<&str>>();
assert_eq!(detect_url(&graphemes, 0), Some(18));
let string = "aaa ftp://example.org something";
let graphemes = UnicodeSegmentation::graphemes(&*string, false).collect::<Vec<&str>>();
assert_eq!(detect_url(&graphemes, 8), Some(20));
let string = "aaa file://example.org something";
let graphemes = UnicodeSegmentation::graphemes(&*string, false).collect::<Vec<&str>>();
assert_eq!(detect_url(&graphemes, 8), Some(21));
let string = "aaa http not an url";
let graphemes = UnicodeSegmentation::graphemes(&*string, false).collect::<Vec<&str>>();
assert_eq!(detect_url(&graphemes, 6), None);
let string = "aaa file://example.org";
let graphemes = UnicodeSegmentation::graphemes(&*string, false).collect::<Vec<&str>>();
assert_eq!(detect_url(&graphemes, 8), Some(21));
}
}

View File

@ -0,0 +1,11 @@
// rustfmt-wrap_comments: true
// rustfmt-max_width: 50
// This example shows how to configure fern to output really nicely colored logs
// - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
// - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
// - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
// - when the log level is info, the level name is green and the rest of the line is white
// - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
// - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
fn func1() {}

View File

@ -0,0 +1,22 @@
// rustfmt-wrap_comments: true
// rustfmt-max_width: 79
//! CMSIS: Cortex Microcontroller Software Interface Standard
//!
//! The version 5 of the standard can be found at:
//!
//! http://arm-software.github.io/CMSIS_5/Core/html/index.html
//!
//! The API reference of the standard can be found at:
//!
//! - example -- http://example.org -- something something something something something something
//! - something something something something something something more -- http://example.org
//! - http://example.org/something/something/something/something/something/something and the rest
//! - Core function access -- http://arm-software.github.io/CMSIS_5/Core/html/group__Core__Register__gr.html
//! - Intrinsic functions for CPU instructions -- http://arm-software.github.io/CMSIS_5/Core/html/group__intrinsic__CPU__gr.html
//! - Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Vestibulum sem lacus, commodo vitae.
//!
//! The reference C implementation used as the base of this Rust port can be
//! found at
//!
//! https://github.com/ARM-software/CMSIS_5/blob/5.3.0/CMSIS/Core/Include/cmsis_gcc.h

View File

@ -0,0 +1,14 @@
// rustfmt-wrap_comments: true
// rustfmt-max_width: 50
// This example shows how to configure fern to
// output really nicely colored logs
// - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
// - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
// - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
// - when the log level is info, the level
// name is green and the rest of the line is
// white
// - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
// - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
fn func1() {}

View File

@ -0,0 +1,25 @@
// rustfmt-wrap_comments: true
// rustfmt-max_width: 79
//! CMSIS: Cortex Microcontroller Software Interface Standard
//!
//! The version 5 of the standard can be found at:
//!
//! http://arm-software.github.io/CMSIS_5/Core/html/index.html
//!
//! The API reference of the standard can be found at:
//!
//! - example -- http://example.org -- something something something something
//! something something
//! - something something something something something something more -- http://example.org
//! - http://example.org/something/something/something/something/something/something
//! and the rest
//! - Core function access -- http://arm-software.github.io/CMSIS_5/Core/html/group__Core__Register__gr.html
//! - Intrinsic functions for CPU instructions -- http://arm-software.github.io/CMSIS_5/Core/html/group__intrinsic__CPU__gr.html
//! - Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Vestibulum sem
//! lacus, commodo vitae.
//!
//! The reference C implementation used as the base of this Rust port can be
//! found at
//!
//! https://github.com/ARM-software/CMSIS_5/blob/5.3.0/CMSIS/Core/Include/cmsis_gcc.h