@@ -190,10 +190,21 @@ pub fn add_cursor(text: &str, offset: TextSize) -> String {
190190 res
191191}
192192
193- /// Extracts `//^ some text` annotations
193+ /// Extracts `//^^^ some text` annotations.
194+ ///
195+ /// A run of `^^^` can be arbitrary long and points to the corresponding range
196+ /// in the line above.
197+ ///
198+ /// The `// ^file text` syntax can be used to attach `text` to the entirety of
199+ /// the file.
200+ ///
201+ /// Multiline string values are supported:
202+ ///
203+ /// // ^^^ first line
204+ /// // | second line
194205pub fn extract_annotations ( text : & str ) -> Vec < ( TextRange , String ) > {
195206 let mut res = Vec :: new ( ) ;
196- let mut prev_line_start: Option < TextSize > = None ;
207+ let mut prev_line_start: Option < TextSize > = Some ( 0 . into ( ) ) ;
197208 let mut line_start: TextSize = 0 . into ( ) ;
198209 let mut prev_line_annotations: Vec < ( TextSize , usize ) > = Vec :: new ( ) ;
199210 for line in text. split_inclusive ( '\n' ) {
@@ -202,10 +213,15 @@ pub fn extract_annotations(text: &str) -> Vec<(TextRange, String)> {
202213 let annotation_offset = TextSize :: of ( & line[ ..idx + "//" . len ( ) ] ) ;
203214 for annotation in extract_line_annotations ( & line[ idx + "//" . len ( ) ..] ) {
204215 match annotation {
205- LineAnnotation :: Annotation { mut range, content } => {
216+ LineAnnotation :: Annotation { mut range, content, file } => {
206217 range += annotation_offset;
207218 this_line_annotations. push ( ( range. end ( ) , res. len ( ) ) ) ;
208- res. push ( ( range + prev_line_start. unwrap ( ) , content) )
219+ let range = if file {
220+ TextRange :: up_to ( TextSize :: of ( text) )
221+ } else {
222+ range + prev_line_start. unwrap ( )
223+ } ;
224+ res. push ( ( range, content) )
209225 }
210226 LineAnnotation :: Continuation { mut offset, content } => {
211227 offset += annotation_offset;
@@ -226,11 +242,12 @@ pub fn extract_annotations(text: &str) -> Vec<(TextRange, String)> {
226242
227243 prev_line_annotations = this_line_annotations;
228244 }
245+
229246 res
230247}
231248
232249enum LineAnnotation {
233- Annotation { range : TextRange , content : String } ,
250+ Annotation { range : TextRange , content : String , file : bool } ,
234251 Continuation { offset : TextSize , content : String } ,
235252}
236253
@@ -251,12 +268,20 @@ fn extract_line_annotations(mut line: &str) -> Vec<LineAnnotation> {
251268 }
252269 let range = TextRange :: at ( offset, len. try_into ( ) . unwrap ( ) ) ;
253270 let next = line[ len..] . find ( marker) . map_or ( line. len ( ) , |it| it + len) ;
254- let content = line[ len..] [ ..next - len] . trim ( ) . to_string ( ) ;
271+ let mut content = & line[ len..] [ ..next - len] ;
272+
273+ let mut file = false ;
274+ if !continuation && content. starts_with ( "file" ) {
275+ file = true ;
276+ content = & content[ "file" . len ( ) ..]
277+ }
278+
279+ let content = content. trim ( ) . to_string ( ) ;
255280
256281 let annotation = if continuation {
257282 LineAnnotation :: Continuation { offset : range. end ( ) , content }
258283 } else {
259- LineAnnotation :: Annotation { range, content }
284+ LineAnnotation :: Annotation { range, content, file }
260285 } ;
261286 res. push ( annotation) ;
262287
@@ -277,16 +302,20 @@ fn main() {
277302 zoo + 1
278303} //^^^ type:
279304 // | i32
305+
306+ // ^file
280307 "# ,
281308 ) ;
282309 let res = extract_annotations ( & text)
283310 . into_iter ( )
284311 . map ( |( range, ann) | ( & text[ range] , ann) )
285312 . collect :: < Vec < _ > > ( ) ;
313+
286314 assert_eq ! (
287- res,
288- vec! [ ( "x" , "def" . into( ) ) , ( "y" , "def" . into( ) ) , ( "zoo" , "type:\n i32\n " . into( ) ) , ]
315+ res[ .. 3 ] ,
316+ [ ( "x" , "def" . into( ) ) , ( "y" , "def" . into( ) ) , ( "zoo" , "type:\n i32\n " . into( ) ) ]
289317 ) ;
318+ assert_eq ! ( res[ 3 ] . 0 . len( ) , 115 ) ;
290319}
291320
292321/// Returns `false` if slow tests should not run, otherwise returns `true` and
0 commit comments