libcst_native/nodes/
whitespace.rs

1// Copyright (c) Meta Platforms, Inc. and affiliates.
2//
3// This source code is licensed under the MIT license found in the
4// LICENSE file in the root directory of this source tree.
5
6#[cfg(feature = "py")]
7use libcst_derive::TryIntoPy;
8
9use super::{Codegen, CodegenState};
10
11#[derive(Debug, Eq, PartialEq, Default, Clone)]
12#[cfg_attr(feature = "py", derive(TryIntoPy))]
13pub struct SimpleWhitespace<'a>(pub &'a str);
14
15impl<'a> Codegen<'a> for SimpleWhitespace<'a> {
16    fn codegen(&self, state: &mut CodegenState<'a>) {
17        state.add_token(self.0);
18    }
19}
20
21#[derive(Debug, Eq, PartialEq, Clone)]
22#[cfg_attr(feature = "py", derive(TryIntoPy))]
23pub struct Comment<'a>(pub &'a str);
24
25impl<'a> Default for Comment<'a> {
26    fn default() -> Self {
27        Self("#")
28    }
29}
30
31impl<'a> Codegen<'a> for Comment<'a> {
32    fn codegen(&self, state: &mut CodegenState<'a>) {
33        state.add_token(self.0);
34    }
35}
36
37#[derive(Debug, Eq, PartialEq, Default, Clone)]
38#[cfg_attr(feature = "py", derive(TryIntoPy))]
39pub struct Newline<'a>(pub Option<&'a str>, pub Fakeness);
40
41#[derive(Debug, PartialEq, Eq, Clone)]
42pub enum Fakeness {
43    Fake,
44    Real,
45}
46
47impl Default for Fakeness {
48    fn default() -> Self {
49        Self::Real
50    }
51}
52
53impl<'a> Codegen<'a> for Newline<'a> {
54    fn codegen(&self, state: &mut CodegenState<'a>) {
55        if let Fakeness::Fake = self.1 {
56            return;
57        }
58        if let Some(value) = self.0 {
59            state.add_token(value);
60        } else {
61            state.add_token(state.default_newline);
62        }
63    }
64}
65
66#[derive(Debug, Eq, PartialEq, Default, Clone)]
67#[cfg_attr(feature = "py", derive(TryIntoPy))]
68pub struct TrailingWhitespace<'a> {
69    pub whitespace: SimpleWhitespace<'a>,
70    pub comment: Option<Comment<'a>>,
71    pub newline: Newline<'a>,
72}
73
74impl<'a> Codegen<'a> for TrailingWhitespace<'a> {
75    fn codegen(&self, state: &mut CodegenState<'a>) {
76        self.whitespace.codegen(state);
77        if let Some(comment) = &self.comment {
78            comment.codegen(state);
79        }
80        self.newline.codegen(state);
81    }
82}
83
84#[derive(Debug, Clone, PartialEq, Eq)]
85#[cfg_attr(feature = "py", derive(TryIntoPy))]
86pub struct EmptyLine<'a> {
87    pub indent: bool,
88    pub whitespace: SimpleWhitespace<'a>,
89    pub comment: Option<Comment<'a>>,
90    pub newline: Newline<'a>,
91}
92
93impl<'a> Codegen<'a> for EmptyLine<'a> {
94    fn codegen(&self, state: &mut CodegenState<'a>) {
95        if self.indent {
96            state.add_indent()
97        }
98        self.whitespace.codegen(state);
99        if let Some(comment) = &self.comment {
100            comment.codegen(state);
101        }
102        self.newline.codegen(state);
103    }
104}
105
106impl<'a> Default for EmptyLine<'a> {
107    fn default() -> Self {
108        Self {
109            indent: true,
110            whitespace: Default::default(),
111            comment: Default::default(),
112            newline: Default::default(),
113        }
114    }
115}
116
117impl<'a> EmptyLine<'a> {
118    pub fn new(
119        indent: bool,
120        whitespace: SimpleWhitespace<'a>,
121        comment: Option<Comment<'a>>,
122        newline: Newline<'a>,
123    ) -> Self {
124        Self {
125            indent,
126            whitespace,
127            comment,
128            newline,
129        }
130    }
131}
132
133#[derive(Debug, Eq, PartialEq, Default, Clone)]
134#[cfg_attr(feature = "py", derive(TryIntoPy))]
135pub struct ParenthesizedWhitespace<'a> {
136    pub first_line: TrailingWhitespace<'a>,
137    pub empty_lines: Vec<EmptyLine<'a>>,
138    pub indent: bool,
139    pub last_line: SimpleWhitespace<'a>,
140}
141
142impl<'a> Codegen<'a> for ParenthesizedWhitespace<'a> {
143    fn codegen(&self, state: &mut CodegenState<'a>) {
144        self.first_line.codegen(state);
145        for line in &self.empty_lines {
146            line.codegen(state);
147        }
148        if self.indent {
149            state.add_indent()
150        }
151        self.last_line.codegen(state);
152    }
153}
154
155#[derive(Debug, Eq, PartialEq, Clone)]
156#[cfg_attr(feature = "py", derive(TryIntoPy))]
157pub enum ParenthesizableWhitespace<'a> {
158    SimpleWhitespace(SimpleWhitespace<'a>),
159    ParenthesizedWhitespace(ParenthesizedWhitespace<'a>),
160}
161
162impl<'a> Codegen<'a> for ParenthesizableWhitespace<'a> {
163    fn codegen(&self, state: &mut CodegenState<'a>) {
164        match self {
165            Self::SimpleWhitespace(w) => w.codegen(state),
166            Self::ParenthesizedWhitespace(w) => w.codegen(state),
167        }
168    }
169}
170
171impl<'a> Default for ParenthesizableWhitespace<'a> {
172    fn default() -> Self {
173        Self::SimpleWhitespace(SimpleWhitespace(""))
174    }
175}