summaryrefslogtreecommitdiff
path: root/src/ide/jump.rs
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2023-07-02 19:59:52 +0200
committerLaurenz <laurmaedje@gmail.com>2023-07-02 20:07:43 +0200
commitebfdb1dafa430786db10dad2ef7d5467c1bdbed1 (patch)
tree2bbc24ddb4124c4bb14dec0e536129d4de37b056 /src/ide/jump.rs
parent3ab19185093d7709f824b95b979060ce125389d8 (diff)
Move everything into `crates/` directory
Diffstat (limited to 'src/ide/jump.rs')
-rw-r--r--src/ide/jump.rs173
1 files changed, 0 insertions, 173 deletions
diff --git a/src/ide/jump.rs b/src/ide/jump.rs
deleted file mode 100644
index 14a82e26..00000000
--- a/src/ide/jump.rs
+++ /dev/null
@@ -1,173 +0,0 @@
-use std::num::NonZeroUsize;
-
-use ecow::EcoString;
-
-use crate::doc::{Destination, Frame, FrameItem, Meta, Position};
-use crate::file::FileId;
-use crate::geom::{Geometry, Point, Size};
-use crate::model::Introspector;
-use crate::syntax::{LinkedNode, Source, Span, SyntaxKind};
-use crate::World;
-
-/// Where to [jump](jump_from_click) to.
-#[derive(Debug, Clone, Eq, PartialEq)]
-pub enum Jump {
- /// Jump to a position in a source file.
- Source(FileId, usize),
- /// Jump to an external URL.
- Url(EcoString),
- /// Jump to a point on a page.
- Position(Position),
-}
-
-impl Jump {
- fn from_span(world: &dyn World, span: Span) -> Option<Self> {
- let source = world.source(span.id()).ok()?;
- let node = source.find(span)?;
- Some(Self::Source(span.id(), node.offset()))
- }
-}
-
-/// Determine where to jump to based on a click in a frame.
-pub fn jump_from_click(
- world: &dyn World,
- frames: &[Frame],
- frame: &Frame,
- click: Point,
-) -> Option<Jump> {
- let mut introspector = None;
-
- // Try to find a link first.
- for (pos, item) in frame.items() {
- if let FrameItem::Meta(Meta::Link(dest), size) = item {
- if is_in_rect(*pos, *size, click) {
- return Some(match dest {
- Destination::Url(url) => Jump::Url(url.clone()),
- Destination::Position(pos) => Jump::Position(*pos),
- Destination::Location(loc) => Jump::Position(
- introspector
- .get_or_insert_with(|| Introspector::new(frames))
- .position(*loc),
- ),
- });
- }
- }
- }
-
- // If there's no link, search for a jump target.
- for (mut pos, item) in frame.items().rev() {
- match item {
- FrameItem::Group(group) => {
- // TODO: Handle transformation.
- if let Some(span) =
- jump_from_click(world, frames, &group.frame, click - pos)
- {
- return Some(span);
- }
- }
-
- FrameItem::Text(text) => {
- for glyph in &text.glyphs {
- let (span, span_offset) = glyph.span;
- if 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(span.id()).ok()?;
- let node = source.find(span)?;
- let pos = if node.kind() == SyntaxKind::Text {
- let range = node.range();
- let mut offset = range.start + usize::from(span_offset);
- if (click.x - pos.x) > width / 2.0 {
- offset += glyph.range().len();
- }
- offset.min(range.end)
- } else {
- node.offset()
- };
- return Some(Jump::Source(source.id(), pos));
- }
-
- pos.x += width;
- }
- }
-
- FrameItem::Shape(shape, span) => {
- let Geometry::Rect(size) = shape.geometry else { continue };
- if is_in_rect(pos, size, click) {
- return Jump::from_span(world, *span);
- }
- }
-
- FrameItem::Image(_, size, span) if is_in_rect(pos, *size, click) => {
- return Jump::from_span(world, *span);
- }
-
- _ => {}
- }
- }
-
- None
-}
-
-/// Find the output location in the document for a cursor position.
-pub fn jump_from_cursor(
- frames: &[Frame],
- source: &Source,
- cursor: usize,
-) -> Option<Position> {
- let node = LinkedNode::new(source.root()).leaf_at(cursor)?;
- if node.kind() != SyntaxKind::Text {
- return None;
- }
-
- let span = node.span();
- for (i, frame) in frames.iter().enumerate() {
- if let Some(pos) = find_in_frame(frame, span) {
- return Some(Position {
- page: NonZeroUsize::new(i + 1).unwrap(),
- point: pos,
- });
- }
- }
-
- None
-}
-
-/// Find the position of a span in a frame.
-fn find_in_frame(frame: &Frame, span: Span) -> Option<Point> {
- for (mut pos, item) in frame.items() {
- if let FrameItem::Group(group) = item {
- // TODO: Handle transformation.
- if let Some(point) = find_in_frame(&group.frame, span) {
- return Some(point + pos);
- }
- }
-
- if let FrameItem::Text(text) = item {
- for glyph in &text.glyphs {
- if glyph.span.0 == span {
- return Some(pos);
- }
- pos.x += glyph.x_advance.at(text.size);
- }
- }
- }
-
- None
-}
-
-/// Whether a rectangle with the given size at the given position contains the
-/// click position.
-fn is_in_rect(pos: Point, size: Size, click: Point) -> bool {
- pos.x <= click.x
- && pos.x + size.x >= click.x
- && pos.y <= click.y
- && pos.y + size.y >= click.y
-}