Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 375c878

Browse files
committed
rewrite_string: detect when a url is being split and place the new line
after it
1 parent c0b7222 commit 375c878

File tree

5 files changed

+147
-2
lines changed

5 files changed

+147
-2
lines changed

src/string.rs

Lines changed: 75 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,31 @@ pub fn rewrite_string<'a>(orig: &str, fmt: &StringFormat<'a>) -> Option<String>
158158
wrap_str(result, fmt.config.max_width(), fmt.shape)
159159
}
160160

161+
/// Returns the index to the end of the url if the given string includes an
162+
/// URL or alike. Otherwise, returns None;
163+
fn detect_url(s: &[&str], index: usize) -> Option<usize> {
164+
let start = match s[..=index].iter().rposition(|g| is_whitespace(g)) {
165+
Some(pos) => pos + 1,
166+
None => 0,
167+
};
168+
if s.len() < start + 8 {
169+
return None;
170+
}
171+
let prefix = s[start..start + 8].join("");
172+
if prefix.starts_with("https://")
173+
|| prefix.starts_with("http://")
174+
|| prefix.starts_with("ftp://")
175+
|| prefix.starts_with("file://")
176+
{
177+
match s[index..].iter().position(|g| is_whitespace(g)) {
178+
Some(pos) => Some(index + pos - 1),
179+
None => Some(s.len() - 1),
180+
}
181+
} else {
182+
None
183+
}
184+
}
185+
161186
/// Trims whitespaces to the right except for the line feed character.
162187
fn trim_right_but_line_feed(trim_end: bool, result: String) -> String {
163188
let whitespace_except_line_feed = |c: char| c.is_whitespace() && c != '\n';
@@ -193,13 +218,16 @@ enum SnippetState {
193218
EndWithLineFeed(String, usize),
194219
}
195220

221+
fn not_whitespace_except_line_feed(g: &str) -> bool {
222+
is_line_feed(g) || !is_whitespace(g)
223+
}
224+
196225
/// Break the input string at a boundary character around the offset `max_chars`. A boundary
197226
/// character is either a punctuation or a whitespace.
198227
fn break_string(max_chars: usize, trim_end: bool, line_end: &str, input: &[&str]) -> SnippetState {
199228
let break_at = |index /* grapheme at index is included */| {
200229
// Take in any whitespaces to the left/right of `input[index]` while
201230
// preserving line feeds
202-
let not_whitespace_except_line_feed = |g| is_line_feed(g) || !is_whitespace(g);
203231
let index_minus_ws = input[0..=index]
204232
.iter()
205233
.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]
258286
// - extra whitespaces to the right can be trimmed
259287
return break_at(max_chars - 1);
260288
}
289+
if let Some(url_index_end) = detect_url(input, max_chars) {
290+
let index_plus_ws = url_index_end + input[url_index_end..]
291+
.iter()
292+
.skip(1)
293+
.position(|grapheme| not_whitespace_except_line_feed(grapheme))
294+
.unwrap_or(0);
295+
return if trim_end {
296+
SnippetState::LineEnd(
297+
input[..=url_index_end].join("").to_string(),
298+
index_plus_ws + 1,
299+
)
300+
} else {
301+
return SnippetState::LineEnd(
302+
input[..=index_plus_ws].join("").to_string(),
303+
index_plus_ws + 1,
304+
);
305+
};
306+
}
261307
match input[0..max_chars]
262308
.iter()
263309
.rposition(|grapheme| is_whitespace(grapheme))
@@ -303,7 +349,7 @@ fn is_punctuation(grapheme: &str) -> bool {
303349

304350
#[cfg(test)]
305351
mod test {
306-
use super::{break_string, rewrite_string, SnippetState, StringFormat};
352+
use super::{break_string, detect_url, rewrite_string, SnippetState, StringFormat};
307353
use config::Config;
308354
use shape::{Indent, Shape};
309355
use unicode_segmentation::UnicodeSegmentation;
@@ -610,4 +656,31 @@ mod test {
610656
Some("Vestibulum\\\n // ac lacus.".to_string())
611657
);
612658
}
659+
660+
#[test]
661+
fn detect_urls() {
662+
let string = "aaa http://example.org something";
663+
let graphemes = UnicodeSegmentation::graphemes(&*string, false).collect::<Vec<&str>>();
664+
assert_eq!(detect_url(&graphemes, 8), Some(21));
665+
666+
let string = "https://example.org something";
667+
let graphemes = UnicodeSegmentation::graphemes(&*string, false).collect::<Vec<&str>>();
668+
assert_eq!(detect_url(&graphemes, 0), Some(18));
669+
670+
let string = "aaa ftp://example.org something";
671+
let graphemes = UnicodeSegmentation::graphemes(&*string, false).collect::<Vec<&str>>();
672+
assert_eq!(detect_url(&graphemes, 8), Some(20));
673+
674+
let string = "aaa file://example.org something";
675+
let graphemes = UnicodeSegmentation::graphemes(&*string, false).collect::<Vec<&str>>();
676+
assert_eq!(detect_url(&graphemes, 8), Some(21));
677+
678+
let string = "aaa http not an url";
679+
let graphemes = UnicodeSegmentation::graphemes(&*string, false).collect::<Vec<&str>>();
680+
assert_eq!(detect_url(&graphemes, 6), None);
681+
682+
let string = "aaa file://example.org";
683+
let graphemes = UnicodeSegmentation::graphemes(&*string, false).collect::<Vec<&str>>();
684+
assert_eq!(detect_url(&graphemes, 8), Some(21));
685+
}
613686
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// rustfmt-wrap_comments: true
2+
// rustfmt-max_width: 50
3+
4+
// This example shows how to configure fern to output really nicely colored logs
5+
// - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
6+
// - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
7+
// - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
8+
// - when the log level is info, the level name is green and the rest of the line is white
9+
// - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
10+
// - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
11+
fn func1() {}

tests/source/itemized-blocks/urls.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// rustfmt-wrap_comments: true
2+
// rustfmt-max_width: 79
3+
4+
//! CMSIS: Cortex Microcontroller Software Interface Standard
5+
//!
6+
//! The version 5 of the standard can be found at:
7+
//!
8+
//! http://arm-software.github.io/CMSIS_5/Core/html/index.html
9+
//!
10+
//! The API reference of the standard can be found at:
11+
//!
12+
//! - example -- http://example.org -- something something something something something something
13+
//! - something something something something something something more -- http://example.org
14+
//! - http://example.org/something/something/something/something/something/something and the rest
15+
//! - Core function access -- http://arm-software.github.io/CMSIS_5/Core/html/group__Core__Register__gr.html
16+
//! - Intrinsic functions for CPU instructions -- http://arm-software.github.io/CMSIS_5/Core/html/group__intrinsic__CPU__gr.html
17+
//! - Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Vestibulum sem lacus, commodo vitae.
18+
//!
19+
//! The reference C implementation used as the base of this Rust port can be
20+
//! found at
21+
//!
22+
//! https://github.com/ARM-software/CMSIS_5/blob/5.3.0/CMSIS/Core/Include/cmsis_gcc.h
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// rustfmt-wrap_comments: true
2+
// rustfmt-max_width: 50
3+
4+
// This example shows how to configure fern to
5+
// output really nicely colored logs
6+
// - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
7+
// - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
8+
// - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
9+
// - when the log level is info, the level
10+
// name is green and the rest of the line is
11+
// white
12+
// - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
13+
// - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
14+
fn func1() {}

tests/target/itemized-blocks/urls.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// rustfmt-wrap_comments: true
2+
// rustfmt-max_width: 79
3+
4+
//! CMSIS: Cortex Microcontroller Software Interface Standard
5+
//!
6+
//! The version 5 of the standard can be found at:
7+
//!
8+
//! http://arm-software.github.io/CMSIS_5/Core/html/index.html
9+
//!
10+
//! The API reference of the standard can be found at:
11+
//!
12+
//! - example -- http://example.org -- something something something something
13+
//! something something
14+
//! - something something something something something something more -- http://example.org
15+
//! - http://example.org/something/something/something/something/something/something
16+
//! and the rest
17+
//! - Core function access -- http://arm-software.github.io/CMSIS_5/Core/html/group__Core__Register__gr.html
18+
//! - Intrinsic functions for CPU instructions -- http://arm-software.github.io/CMSIS_5/Core/html/group__intrinsic__CPU__gr.html
19+
//! - Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Vestibulum sem
20+
//! lacus, commodo vitae.
21+
//!
22+
//! The reference C implementation used as the base of this Rust port can be
23+
//! found at
24+
//!
25+
//! https://github.com/ARM-software/CMSIS_5/blob/5.3.0/CMSIS/Core/Include/cmsis_gcc.h

0 commit comments

Comments
 (0)