1 // Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 // Format string literals.
13 use utils::{make_indent, next_char, prev_char, round_up_to_power_of_two};
17 pub struct StringFormat<'a> {
20 pub line_start: &'a str,
21 pub line_end: &'a str,
27 // TODO: simplify this!
28 pub fn rewrite_string<'a>(s: &str, fmt: &StringFormat<'a>) -> String {
29 // FIXME I bet this stomps unicode escapes in the source string
30 // TODO if lo.col > IDEAL - 10, start a new line (need cur indent for that)
32 let indent = make_indent(fmt.offset);
35 let mut cur_start = 0;
36 let mut result = String::with_capacity(round_up_to_power_of_two(s.len()));
37 result.push_str(fmt.opener);
39 let ender_length = fmt.line_end.len();
40 let max_chars = fmt.width.checked_sub(fmt.opener.len()).unwrap_or(0)
41 .checked_sub(ender_length).unwrap_or(1);
44 let mut cur_end = cur_start + max_chars;
46 if cur_end >= s.len() {
47 result.push_str(&s[cur_start..]);
51 // Make sure we're on a char boundary.
52 cur_end = next_char(&s, cur_end);
54 // Push cur_end left until we reach whitespace.
55 while !s.char_at(cur_end - 1).is_whitespace() {
56 cur_end = prev_char(&s, cur_end);
58 if cur_end - cur_start < MIN_STRING {
59 // We can't break at whitespace, fall back to splitting
60 // anywhere that doesn't break an escape sequence.
61 cur_end = next_char(&s, cur_start + max_chars);
62 while s.char_at(prev_char(&s, cur_end)) == '\\' {
63 cur_end = prev_char(&s, cur_end);
68 // Make sure there is no whitespace to the right of the break.
69 while cur_end < s.len() && s.char_at(cur_end).is_whitespace() {
70 cur_end = next_char(&s, cur_end + 1);
73 let line: &str = if fmt.trim_end {
74 &s[cur_start..cur_end].trim_right_matches(char::is_whitespace)
76 &s[cur_start..cur_end]
79 result.push_str(line);
80 result.push_str(fmt.line_end);
82 result.push_str(indent);
83 result.push_str(fmt.line_start);
87 result.push_str(fmt.closer);