aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_syntax/src/ast/tokens.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_syntax/src/ast/tokens.rs')
-rw-r--r--crates/ra_syntax/src/ast/tokens.rs113
1 files changed, 113 insertions, 0 deletions
diff --git a/crates/ra_syntax/src/ast/tokens.rs b/crates/ra_syntax/src/ast/tokens.rs
new file mode 100644
index 000000000..08882ea69
--- /dev/null
+++ b/crates/ra_syntax/src/ast/tokens.rs
@@ -0,0 +1,113 @@
1//! There are many AstNodes, but only a few tokens, so we hand-write them here.
2
3use crate::{
4 SyntaxToken,
5 SyntaxKind::{COMMENT, WHITESPACE},
6 ast::AstToken,
7};
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
10pub struct Comment<'a>(SyntaxToken<'a>);
11
12impl<'a> AstToken<'a> for Comment<'a> {
13 fn cast(token: SyntaxToken<'a>) -> Option<Self> {
14 if token.kind() == COMMENT {
15 Some(Comment(token))
16 } else {
17 None
18 }
19 }
20 fn syntax(&self) -> SyntaxToken<'a> {
21 self.0
22 }
23}
24
25impl<'a> Comment<'a> {
26 pub fn kind(&self) -> CommentKind {
27 kind_by_prefix(self.text())
28 }
29
30 pub fn prefix(&self) -> &'static str {
31 prefix_by_kind(self.kind())
32 }
33}
34
35#[derive(Debug, PartialEq, Eq, Clone, Copy)]
36pub struct CommentKind {
37 pub shape: CommentShape,
38 pub doc: Option<CommentPlacement>,
39}
40
41#[derive(Debug, PartialEq, Eq, Clone, Copy)]
42pub enum CommentShape {
43 Line,
44 Block,
45}
46
47impl CommentShape {
48 pub fn is_line(self) -> bool {
49 self == CommentShape::Line
50 }
51
52 pub fn is_block(self) -> bool {
53 self == CommentShape::Block
54 }
55}
56
57#[derive(Debug, PartialEq, Eq, Clone, Copy)]
58pub enum CommentPlacement {
59 Inner,
60 Outer,
61}
62
63const COMMENT_PREFIX_TO_KIND: &[(&str, CommentKind)] = {
64 use {CommentShape::*, CommentPlacement::*};
65 &[
66 ("///", CommentKind { shape: Line, doc: Some(Outer) }),
67 ("//!", CommentKind { shape: Line, doc: Some(Inner) }),
68 ("/**", CommentKind { shape: Block, doc: Some(Outer) }),
69 ("/*!", CommentKind { shape: Block, doc: Some(Inner) }),
70 ("//", CommentKind { shape: Line, doc: None }),
71 ("/*", CommentKind { shape: Block, doc: None }),
72 ]
73};
74
75fn kind_by_prefix(text: &str) -> CommentKind {
76 for (prefix, kind) in COMMENT_PREFIX_TO_KIND.iter() {
77 if text.starts_with(prefix) {
78 return *kind;
79 }
80 }
81 panic!("bad comment text: {:?}", text)
82}
83
84fn prefix_by_kind(kind: CommentKind) -> &'static str {
85 for (prefix, k) in COMMENT_PREFIX_TO_KIND.iter() {
86 if *k == kind {
87 return prefix;
88 }
89 }
90 unreachable!()
91}
92
93pub struct Whitespace<'a>(SyntaxToken<'a>);
94
95impl<'a> AstToken<'a> for Whitespace<'a> {
96 fn cast(token: SyntaxToken<'a>) -> Option<Self> {
97 if token.kind() == WHITESPACE {
98 Some(Whitespace(token))
99 } else {
100 None
101 }
102 }
103 fn syntax(&self) -> SyntaxToken<'a> {
104 self.0
105 }
106}
107
108impl<'a> Whitespace<'a> {
109 pub fn spans_multiple_lines(&self) -> bool {
110 let text = self.text();
111 text.find('\n').map_or(false, |idx| text[idx + 1..].contains('\n'))
112 }
113}