summaryrefslogtreecommitdiff
path: root/src/ide/jump.rs
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2023-03-16 17:36:04 +0100
committerLaurenz <laurmaedje@gmail.com>2023-03-17 11:30:58 +0100
commite8435df5ec718e8ecc8a2ad48e4eb3ddd1f92a72 (patch)
tree58d8356ec1c615f898e342a479b5f967a8177468 /src/ide/jump.rs
parentecb5543985cc0788d9c01e8c2e28d8ca6d8e19b6 (diff)
More jump targets
Diffstat (limited to 'src/ide/jump.rs')
-rw-r--r--src/ide/jump.rs107
1 files changed, 67 insertions, 40 deletions
diff --git a/src/ide/jump.rs b/src/ide/jump.rs
index 95f2fa02..0aa97b56 100644
--- a/src/ide/jump.rs
+++ b/src/ide/jump.rs
@@ -1,7 +1,7 @@
use std::num::NonZeroUsize;
use crate::doc::{Destination, Element, Frame, Location, Meta};
-use crate::geom::{Point, Size};
+use crate::geom::{Geometry, Point, Size};
use crate::model::Introspector;
use crate::syntax::{LinkedNode, Source, SourceId, Span, SyntaxKind};
use crate::World;
@@ -15,6 +15,14 @@ pub enum Jump {
Dest(Destination),
}
+impl Jump {
+ fn from_span(world: &dyn World, span: Span) -> Self {
+ let source = world.source(span.source());
+ let node = source.find(span);
+ Self::Source(source.id(), node.offset())
+ }
+}
+
/// Determine where to jump to based on a click in a frame.
pub fn jump_from_click(
world: &dyn World,
@@ -24,55 +32,74 @@ pub fn jump_from_click(
) -> Option<Jump> {
let mut introspector = None;
- for (mut pos, element) in frame.elements() {
- if let Element::Group(group) = element {
- // TODO: Handle transformation.
- if let Some(span) = jump_from_click(world, frames, &group.frame, click - pos)
- {
- return Some(span);
+ // Prefer metadata.
+ for (pos, element) in frame.elements() {
+ if let Element::Meta(Meta::Link(link), size) = element {
+ if is_in_rect(*pos, *size, click) {
+ let dest = link.resolve(|| {
+ introspector.get_or_insert_with(|| Introspector::new(frames))
+ });
+
+ let Some(dest) = dest else { continue };
+ return Some(Jump::Dest(dest));
}
}
+ }
- if let Element::Text(text) = element {
- for glyph in &text.glyphs {
- if glyph.span.is_detached() {
- continue;
+ for (mut pos, element) in frame.elements().rev() {
+ match element {
+ Element::Group(group) => {
+ // TODO: Handle transformation.
+ if let Some(span) =
+ jump_from_click(world, frames, &group.frame, click - pos)
+ {
+ return Some(span);
}
+ }
- let width = glyph.x_advance.at(text.size);
- if is_in_rect(
- Point::new(pos.x, pos.y - text.size),
- Size::new(width, text.size),
- click,
- ) {
- let source = world.source(glyph.span.source());
- let node = source.find(glyph.span);
- let pos = if node.kind() == SyntaxKind::Text {
- let range = node.range();
- let mut offset = range.start + usize::from(glyph.offset);
- if (click.x - pos.x) > width / 2.0 {
- offset += glyph.c.len_utf8();
- }
- offset.min(range.end)
- } else {
- node.offset()
- };
- return Some(Jump::Source(source.id(), pos));
+ Element::Text(text) => {
+ for glyph in &text.glyphs {
+ if glyph.span.is_detached() {
+ continue;
+ }
+
+ let width = glyph.x_advance.at(text.size);
+ if is_in_rect(
+ Point::new(pos.x, pos.y - text.size),
+ Size::new(width, text.size),
+ click,
+ ) {
+ let source = world.source(glyph.span.source());
+ let node = source.find(glyph.span);
+ let pos = if node.kind() == SyntaxKind::Text {
+ let range = node.range();
+ let mut offset = range.start + usize::from(glyph.offset);
+ if (click.x - pos.x) > width / 2.0 {
+ offset += glyph.c.len_utf8();
+ }
+ offset.min(range.end)
+ } else {
+ node.offset()
+ };
+ return Some(Jump::Source(source.id(), pos));
+ }
+
+ pos.x += width;
}
-
- pos.x += width;
}
- }
- if let Element::Meta(Meta::Link(link), size) = element {
- if is_in_rect(pos, *size, click) {
- let dest = link.resolve(|| {
- introspector.get_or_insert_with(|| Introspector::new(frames))
- });
+ Element::Shape(shape, span) => {
+ let Geometry::Rect(size) = shape.geometry else { continue };
+ if is_in_rect(pos, size, click) {
+ return Some(Jump::from_span(world, *span));
+ }
+ }
- let Some(dest) = dest else { continue };
- return Some(Jump::Dest(dest));
+ Element::Image(_, size, span) if is_in_rect(pos, *size, click) => {
+ return Some(Jump::from_span(world, *span));
}
+
+ _ => {}
}
}