bytebraise_syntax/syntax/ast/
quoted_value.rs1use std::borrow::Cow;
2use std::fmt::Debug;
3use std::ops::Range;
4
5use cow_utils::CowUtils;
6use derive_builder::Builder;
7use itertools::Itertools;
8use nested_intervals::IntervalSet;
9use rowan::{TextRange, TextSize};
10
11use crate::syntax::ast::AstToken;
12use crate::syntax::ast::tokens::{DoubleQuotedValue, SingleQuotedValue};
13use crate::syntax::make;
14use crate::syntax::syntax_kind::SyntaxKind;
15use crate::syntax::syntax_node::SyntaxToken;
16
17#[derive(Debug, Clone, PartialEq, Eq, Hash)]
18pub enum QuotedValue {
19 SingleQuoted(SingleQuotedValue),
20 DoubleQuoted(DoubleQuotedValue),
21}
22
23impl AstToken for QuotedValue {
24 fn can_cast(token: SyntaxKind) -> bool
25 where
26 Self: Sized,
27 {
28 match token {
29 SyntaxKind::DoubleQuotedValue | SyntaxKind::SingleQuotedValue => true,
30 _ => false,
31 }
32 }
33
34 fn cast(syntax: SyntaxToken) -> Option<Self>
35 where
36 Self: Sized,
37 {
38 let ret = match syntax.kind() {
39 SyntaxKind::DoubleQuotedValue => {
40 QuotedValue::DoubleQuoted(DoubleQuotedValue { syntax })
41 }
42 SyntaxKind::SingleQuotedValue => {
43 QuotedValue::SingleQuoted(SingleQuotedValue { syntax })
44 }
45 _ => return None,
46 };
47
48 Some(ret)
49 }
50
51 fn syntax(&self) -> &SyntaxToken {
52 match self {
53 QuotedValue::DoubleQuoted(it) => &it.syntax,
54 QuotedValue::SingleQuoted(it) => &it.syntax,
55 }
56 }
57}
58
59impl QuotedValue {
60 pub fn text_range_between_quotes(&self) -> TextRange {
61 let range = self.syntax().text_range();
62 let quote_size = TextSize::of("\"");
63 let (start, end) = (range.start() + quote_size, range.end() - quote_size);
64 TextRange::new(start, end)
65 }
66
67 pub fn raw_value(&self) -> &str {
68 &self.text()[self.text_range_between_quotes() - self.syntax().text_range().start()]
69 }
70
71 pub fn lines(&self) -> impl Iterator<Item = &str> {
72 self.line_ranges().into_iter().map(move |range| {
73 let start_offset = self.syntax().text_range().start();
74 let absolute_range = range - start_offset;
75 &self.text()[absolute_range]
76 })
77 }
78
79 pub fn sorted_lines(&self) -> Self {
80 let vals = self
81 .lines()
82 .filter_map(|v| match v.trim() {
83 "" => None,
84 v => Some(v.to_owned()),
85 })
86 .sorted()
87 .collect::<Vec<_>>();
88 make::quoted_value_from_slice(&vals)
89 }
90
91 pub fn value(&self) -> Cow<str> {
93 self.raw_value().cow_replace("\\\n", "")
95 }
96
97 pub fn line_ranges(&self) -> Vec<TextRange> {
99 let range = self.text_range_between_quotes();
101
102 let start_offset = self.syntax().text_range().start();
104
105 let relative_range =
107 TextRange::new(range.start() - start_offset, range.end() - start_offset);
108 assert_eq!(u32::from(relative_range.start()), 1);
109 assert_eq!(
110 u32::from(relative_range.end()),
111 self.text().len() as u32 - 1
112 );
113
114 let escaped_newline_size = TextSize::of("\\\n");
115
116 let intervals = self
118 .raw_value()
119 .match_indices("\\\n")
120 .map(|m| {
121 let start = m.0 as u32 + 1;
124 start..start + u32::from(escaped_newline_size)
125 })
126 .collect::<Vec<Range<u32>>>();
127
128 let interval = IntervalSet::new(intervals.as_slice()).unwrap();
129
130 interval
133 .invert(
134 u32::from(relative_range.start()),
135 u32::from(relative_range.end()),
136 )
137 .iter()
138 .map(|(range, _)| {
139 TextRange::new(
140 TextSize::from(range.start) + start_offset,
141 TextSize::from(range.end) + start_offset,
142 )
143 })
144 .collect::<Vec<_>>()
145 }
146}
147
148#[derive(Debug, Builder, Clone)]
149#[builder(setter(into))]
150pub struct QuotedValueFormat {
151 packing: SubValuePacking,
152 closing_quote_on_own_line: bool,
153 alignment: SubValueAlignment,
154}
155
156impl Default for QuotedValueFormat {
157 fn default() -> Self {
158 Self {
159 alignment: SubValueAlignment::default(),
160 closing_quote_on_own_line: true,
161 packing: SubValuePacking::default(),
162 }
163 }
164}
165
166#[derive(Debug, Default, Clone)]
168pub enum SubValuePacking {
169 Off,
170 #[default]
171 OnePerLine,
172 Wrapped {
173 line_width: usize,
174 },
175}
176
177#[derive(Debug, Clone)]
178pub enum SubValueAlignment {
179 WithOperator,
180 WithFirstSubValue,
181 Indented { indent: usize },
182}
183
184impl Default for SubValueAlignment {
185 fn default() -> Self {
186 SubValueAlignment::Indented { indent: 4 }
187 }
188}
189
190pub struct QuotedValueBuilder {
191 sub_values: Vec<String>,
192}
193
194fn ff() {
195 let _b = QuotedValueFormatBuilder::default()
196 .alignment(SubValueAlignment::WithFirstSubValue)
197 .build();
198}