code_span/view/mod.rs
1use std::{fmt::Debug, ops::Range};
2
3use serde::{Deserialize, Serialize};
4
5mod convert;
6pub mod iter;
7
8/// Save the given code and store additional information on each character
9///
10/// # Examples
11///
12/// ```
13/// use code_span::CodeView;
14/// let _: CodeView<&'static str> = CodeView::from("public static class MyClass {}");
15/// ```
16#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
17pub struct CodeView<T> {
18 text: String,
19 info: Vec<Option<T>>,
20}
21
22/// Each character of these code stores the same information
23///
24/// # Examples
25///
26/// ```
27/// use code_span::CodeSpan;
28/// CodeSpan { text: "public".to_string(), info: Some("keyword".to_string()) };
29/// ```
30#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
31pub struct CodeSpan<T> {
32 /// text
33 pub text: String,
34 /// info
35 pub info: Option<T>,
36}
37
38impl<T> CodeView<T> {
39 /// Create a piece of code with no information
40 ///
41 /// # Examples
42 ///
43 /// ```
44 /// use code_span::CodeView;
45 /// let _: CodeView<&'static str> = CodeView::blank("public static class MyClass {}");
46 /// ```
47 pub fn blank(text: impl Into<String>) -> Self
48 where
49 T: Clone,
50 {
51 let text = text.into();
52 let count = text.chars().count();
53 Self { text, info: vec![None; count] }
54 }
55 /// Create a piece of code with specified information
56 ///
57 /// # Examples
58 ///
59 /// ```
60 /// use code_span::CodeView;
61 /// let _: CodeView<&'static str> = CodeView::new("public".to_string(), vec![Some("keyword"); 6]);
62 /// ```
63 pub fn new(text: String, info: Vec<Option<T>>) -> Self {
64 assert_eq!(text.chars().count(), info.len());
65 Self { text, info }
66 }
67 /// Get original code
68 ///
69 /// # Examples
70 ///
71 /// ```
72 /// use code_span::CodeView;
73 /// let view: CodeView<&'static str> = CodeView::blank("public static class MyClass {}");
74 /// assert_eq!(view.get_text(), "public static class MyClass {}");
75 /// ```
76 #[inline]
77 pub fn get_text(&self) -> &str {
78 &self.text
79 }
80 /// Modify the original code
81 ///
82 /// # Examples
83 ///
84 /// ```
85 /// use code_span::CodeView;
86 /// let mut view: CodeView<&'static str> = CodeView::blank("public static class MyClass {}");
87 /// assert_eq!(view.mut_text(), "public static class MyClass {}");
88 /// ```
89 #[inline]
90 pub fn mut_text(&mut self) -> &mut String {
91 &mut self.text
92 }
93 /// Get current information
94 ///
95 /// # Examples
96 ///
97 /// ```
98 /// use code_span::CodeView;
99 /// let view: CodeView<&'static str> = CodeView::blank("public static class MyClass {}");
100 /// assert_eq!(view.get_info(), vec![None; 30]);
101 /// ```
102 #[inline]
103 pub fn get_info(&self) -> &[Option<T>] {
104 &self.info
105 }
106 /// Modify current information
107 ///
108 /// # Examples
109 ///
110 /// ```
111 /// use code_span::CodeView;
112 /// let mut view: CodeView<&'static str> = CodeView::blank("public");
113 /// view.mut_info().iter_mut().for_each(|v| *v = Some("keyword"));
114 /// ```
115 #[inline]
116 pub fn mut_info(&mut self) -> &mut [Option<T>] {
117 &mut self.info
118 }
119
120 /// Mark the information of a piece of code according to the character range
121 ///
122 /// # Examples
123 ///
124 /// ```
125 /// use code_span::CodeView;
126 /// let mut view = CodeView::blank("public static class MyClass {}");
127 /// view.mark_position(0, 6, Some("keyword"));
128 /// ```
129 pub fn mark_position(&mut self, start: usize, end: usize, info: Option<T>)
130 where
131 T: Clone,
132 {
133 debug_assert!(start <= end);
134 let end = self.info.len().min(end);
135 let items = unsafe { self.info.get_unchecked_mut(Range { start, end }) };
136 for item in items {
137 *item = info.clone()
138 }
139 }
140 /// Mark the information of a piece of code according to the byte range
141 ///
142 /// # Examples
143 ///
144 /// ```
145 /// use code_span::CodeView;
146 /// let mut view = CodeView::blank("public static class MyClass {}");
147 /// view.mark_offset(0, 6, Some("keyword"));
148 /// ```
149 pub fn mark_offset(&mut self, start: usize, end: usize, info: Option<T>)
150 where
151 T: Clone,
152 {
153 debug_assert!(start <= end);
154 let end = self.text.len().min(end);
155 let start = self.text[..start].chars().count();
156 let end = start + self.text[start..end].chars().count();
157 self.mark_position(start, end, info)
158 }
159}