diff options
Diffstat (limited to 'crates/ra_ide/src/syntax_highlighting.rs')
-rw-r--r-- | crates/ra_ide/src/syntax_highlighting.rs | 64 |
1 files changed, 46 insertions, 18 deletions
diff --git a/crates/ra_ide/src/syntax_highlighting.rs b/crates/ra_ide/src/syntax_highlighting.rs index 448645bdc..028b55902 100644 --- a/crates/ra_ide/src/syntax_highlighting.rs +++ b/crates/ra_ide/src/syntax_highlighting.rs | |||
@@ -236,7 +236,7 @@ pub(crate) fn highlight( | |||
236 | }); | 236 | }); |
237 | } | 237 | } |
238 | } | 238 | } |
239 | stack.pop_and_inject(false); | 239 | stack.pop_and_inject(None); |
240 | } | 240 | } |
241 | } else if let Some(string) = | 241 | } else if let Some(string) = |
242 | element_to_highlight.as_token().cloned().and_then(ast::RawString::cast) | 242 | element_to_highlight.as_token().cloned().and_then(ast::RawString::cast) |
@@ -324,16 +324,27 @@ impl HighlightedRangeStack { | |||
324 | cloned | 324 | cloned |
325 | } | 325 | } |
326 | 326 | ||
327 | /// Remove the `HighlightRange` of `parent` that's currently covered by `child`. | ||
328 | fn intersect_partial(parent: &mut HighlightedRange, child: &HighlightedRange) { | ||
329 | assert!( | ||
330 | parent.range.start() <= child.range.start() | ||
331 | && parent.range.end() >= child.range.start() | ||
332 | && child.range.end() > parent.range.end() | ||
333 | ); | ||
334 | |||
335 | parent.range = TextRange::new(parent.range.start(), child.range.start()); | ||
336 | } | ||
337 | |||
327 | /// Similar to `pop`, but can modify arbitrary prior ranges (where `pop`) | 338 | /// Similar to `pop`, but can modify arbitrary prior ranges (where `pop`) |
328 | /// can only modify the last range currently on the stack. | 339 | /// can only modify the last range currently on the stack. |
329 | /// Can be used to do injections that span multiple ranges, like the | 340 | /// Can be used to do injections that span multiple ranges, like the |
330 | /// doctest injection below. | 341 | /// doctest injection below. |
331 | /// If `delete` is set to true, the parent range is deleted instead of | 342 | /// If `overwrite_parent` is non-optional, the highlighting of the parent range |
332 | /// intersected. | 343 | /// is overwritten with the argument. |
333 | /// | 344 | /// |
334 | /// Note that `pop` can be simulated by `pop_and_inject(false)` but the | 345 | /// Note that `pop` can be simulated by `pop_and_inject(false)` but the |
335 | /// latter is computationally more expensive. | 346 | /// latter is computationally more expensive. |
336 | fn pop_and_inject(&mut self, delete: bool) { | 347 | fn pop_and_inject(&mut self, overwrite_parent: Option<Highlight>) { |
337 | let mut children = self.stack.pop().unwrap(); | 348 | let mut children = self.stack.pop().unwrap(); |
338 | let prev = self.stack.last_mut().unwrap(); | 349 | let prev = self.stack.last_mut().unwrap(); |
339 | children.sort_by_key(|range| range.range.start()); | 350 | children.sort_by_key(|range| range.range.start()); |
@@ -343,26 +354,45 @@ impl HighlightedRangeStack { | |||
343 | if let Some(idx) = | 354 | if let Some(idx) = |
344 | prev.iter().position(|parent| parent.range.contains_range(child.range)) | 355 | prev.iter().position(|parent| parent.range.contains_range(child.range)) |
345 | { | 356 | { |
357 | if let Some(tag) = overwrite_parent { | ||
358 | prev[idx].highlight = tag; | ||
359 | } | ||
360 | |||
346 | let cloned = Self::intersect(&mut prev[idx], &child); | 361 | let cloned = Self::intersect(&mut prev[idx], &child); |
347 | let insert_idx = if delete || prev[idx].range.is_empty() { | 362 | let insert_idx = if prev[idx].range.is_empty() { |
348 | prev.remove(idx); | 363 | prev.remove(idx); |
349 | idx | 364 | idx |
350 | } else { | 365 | } else { |
351 | idx + 1 | 366 | idx + 1 |
352 | }; | 367 | }; |
353 | prev.insert(insert_idx, child); | 368 | prev.insert(insert_idx, child); |
354 | if !delete && !cloned.range.is_empty() { | 369 | if !cloned.range.is_empty() { |
355 | prev.insert(insert_idx + 1, cloned); | 370 | prev.insert(insert_idx + 1, cloned); |
356 | } | 371 | } |
357 | } else if let Some(_idx) = | ||
358 | prev.iter().position(|parent| parent.range.contains(child.range.start())) | ||
359 | { | ||
360 | unreachable!("child range should be completely contained in parent range"); | ||
361 | } else { | 372 | } else { |
362 | let idx = prev | 373 | let maybe_idx = |
363 | .binary_search_by_key(&child.range.start(), |range| range.range.start()) | 374 | prev.iter().position(|parent| parent.range.contains(child.range.start())); |
364 | .unwrap_or_else(|x| x); | 375 | match (overwrite_parent, maybe_idx) { |
365 | prev.insert(idx, child); | 376 | (Some(_), Some(idx)) => { |
377 | Self::intersect_partial(&mut prev[idx], &child); | ||
378 | let insert_idx = if prev[idx].range.is_empty() { | ||
379 | prev.remove(idx); | ||
380 | idx | ||
381 | } else { | ||
382 | idx + 1 | ||
383 | }; | ||
384 | prev.insert(insert_idx, child); | ||
385 | } | ||
386 | (_, None) => { | ||
387 | let idx = prev | ||
388 | .binary_search_by_key(&child.range.start(), |range| range.range.start()) | ||
389 | .unwrap_or_else(|x| x); | ||
390 | prev.insert(idx, child); | ||
391 | } | ||
392 | _ => { | ||
393 | unreachable!("child range should be completely contained in parent range"); | ||
394 | } | ||
395 | } | ||
366 | } | 396 | } |
367 | } | 397 | } |
368 | } | 398 | } |
@@ -516,11 +546,9 @@ fn highlight_element( | |||
516 | let ty = sema.type_of_expr(&expr)?; | 546 | let ty = sema.type_of_expr(&expr)?; |
517 | if !ty.is_raw_ptr() { | 547 | if !ty.is_raw_ptr() { |
518 | return None; | 548 | return None; |
549 | } else { | ||
550 | HighlightTag::Operator | HighlightModifier::Unsafe | ||
519 | } | 551 | } |
520 | |||
521 | let mut h = Highlight::new(HighlightTag::Operator); | ||
522 | h |= HighlightModifier::Unsafe; | ||
523 | h | ||
524 | } | 552 | } |
525 | T![!] if element.parent().and_then(ast::MacroCall::cast).is_some() => { | 553 | T![!] if element.parent().and_then(ast::MacroCall::cast).is_some() => { |
526 | Highlight::new(HighlightTag::Macro) | 554 | Highlight::new(HighlightTag::Macro) |