attr.rs 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. use super::algorithm::Printer;
  2. use super::INDENT;
  3. use proc_macro2::{Delimiter, TokenStream, TokenTree};
  4. use syn::{AttrStyle, Attribute, Lit, PathArguments};
  5. impl Printer {
  6. pub fn outer_attrs(&mut self, attrs: &[Attribute]) {
  7. for attr in attrs {
  8. if let AttrStyle::Outer = attr.style {
  9. self.attr(attr);
  10. }
  11. }
  12. }
  13. pub fn inner_attrs(&mut self, attrs: &[Attribute]) {
  14. for attr in attrs {
  15. if let AttrStyle::Inner(_) = attr.style {
  16. self.attr(attr);
  17. }
  18. }
  19. }
  20. fn attr(&mut self, attr: &Attribute) {
  21. if let Some(doc) = value_of_attribute("doc", attr) {
  22. if doc.contains('\n') {
  23. self.word(match attr.style {
  24. AttrStyle::Outer => "/**",
  25. AttrStyle::Inner(_) => "/*!",
  26. });
  27. self.word(doc);
  28. self.word("*/");
  29. } else {
  30. self.word(match attr.style {
  31. AttrStyle::Outer => "///",
  32. AttrStyle::Inner(_) => "//!",
  33. });
  34. self.word(doc);
  35. }
  36. self.hardbreak();
  37. } else if let Some(comment) = value_of_attribute("comment", attr) {
  38. if comment.contains('\n') {
  39. self.word("/*");
  40. self.word(comment);
  41. self.word("*/");
  42. } else {
  43. self.word("//");
  44. self.word(comment);
  45. }
  46. self.hardbreak();
  47. } else {
  48. self.word(match attr.style {
  49. AttrStyle::Outer => "#",
  50. AttrStyle::Inner(_) => "#!",
  51. });
  52. self.word("[");
  53. self.path(&attr.path);
  54. self.attr_tokens(attr.tokens.clone());
  55. self.word("]");
  56. self.space();
  57. }
  58. }
  59. fn attr_tokens(&mut self, tokens: TokenStream) {
  60. let mut stack = Vec::new();
  61. stack.push((tokens.into_iter().peekable(), Delimiter::None));
  62. let mut space = Self::nbsp as fn(&mut Self);
  63. #[derive(PartialEq)]
  64. enum State {
  65. Word,
  66. Punct,
  67. TrailingComma,
  68. }
  69. use State::*;
  70. let mut state = Word;
  71. while let Some((tokens, delimiter)) = stack.last_mut() {
  72. match tokens.next() {
  73. Some(TokenTree::Ident(ident)) => {
  74. if let Word = state {
  75. space(self);
  76. }
  77. self.ident(&ident);
  78. state = Word;
  79. }
  80. Some(TokenTree::Punct(punct)) => {
  81. let ch = punct.as_char();
  82. if let (Word, '=') = (state, ch) {
  83. self.nbsp();
  84. }
  85. if ch == ',' && tokens.peek().is_none() {
  86. self.trailing_comma(true);
  87. state = TrailingComma;
  88. } else {
  89. self.token_punct(ch);
  90. if ch == '=' {
  91. self.nbsp();
  92. } else if ch == ',' {
  93. space(self);
  94. }
  95. state = Punct;
  96. }
  97. }
  98. Some(TokenTree::Literal(literal)) => {
  99. if let Word = state {
  100. space(self);
  101. }
  102. self.token_literal(&literal);
  103. state = Word;
  104. }
  105. Some(TokenTree::Group(group)) => {
  106. let delimiter = group.delimiter();
  107. let stream = group.stream();
  108. match delimiter {
  109. Delimiter::Parenthesis => {
  110. self.word("(");
  111. self.cbox(INDENT);
  112. self.zerobreak();
  113. state = Punct;
  114. }
  115. Delimiter::Brace => {
  116. self.word("{");
  117. state = Punct;
  118. }
  119. Delimiter::Bracket => {
  120. self.word("[");
  121. state = Punct;
  122. }
  123. Delimiter::None => {}
  124. }
  125. stack.push((stream.into_iter().peekable(), delimiter));
  126. space = Self::space;
  127. }
  128. None => {
  129. match delimiter {
  130. Delimiter::Parenthesis => {
  131. if state != TrailingComma {
  132. self.zerobreak();
  133. }
  134. self.offset(-INDENT);
  135. self.end();
  136. self.word(")");
  137. state = Punct;
  138. }
  139. Delimiter::Brace => {
  140. self.word("}");
  141. state = Punct;
  142. }
  143. Delimiter::Bracket => {
  144. self.word("]");
  145. state = Punct;
  146. }
  147. Delimiter::None => {}
  148. }
  149. stack.pop();
  150. if stack.is_empty() {
  151. space = Self::nbsp;
  152. }
  153. }
  154. }
  155. }
  156. }
  157. }
  158. fn value_of_attribute(requested: &str, attr: &Attribute) -> Option<String> {
  159. let is_doc = attr.path.leading_colon.is_none()
  160. && attr.path.segments.len() == 1
  161. && matches!(attr.path.segments[0].arguments, PathArguments::None)
  162. && attr.path.segments[0].ident == requested;
  163. if !is_doc {
  164. return None;
  165. }
  166. let mut tokens = attr.tokens.clone().into_iter();
  167. match tokens.next() {
  168. Some(TokenTree::Punct(punct)) if punct.as_char() == '=' => {}
  169. _ => return None,
  170. }
  171. let literal = match tokens.next() {
  172. Some(TokenTree::Literal(literal)) => literal,
  173. _ => return None,
  174. };
  175. if tokens.next().is_some() {
  176. return None;
  177. }
  178. match Lit::new(literal) {
  179. Lit::Str(string) => Some(string.value()),
  180. _ => None,
  181. }
  182. }
  183. pub fn has_outer(attrs: &[Attribute]) -> bool {
  184. for attr in attrs {
  185. if let AttrStyle::Outer = attr.style {
  186. return true;
  187. }
  188. }
  189. false
  190. }
  191. pub fn has_inner(attrs: &[Attribute]) -> bool {
  192. for attr in attrs {
  193. if let AttrStyle::Inner(_) = attr.style {
  194. return true;
  195. }
  196. }
  197. false
  198. }