-module(prequel@span). -compile([no_auto_import, nowarn_unused_vars]). -export([new/4, segment/3, point/2, merge/2, lines/1, max_line/1, min_line/1, columns/1, max_column/1, min_column/1, is_segment/1, starts_at_line/2, ends_on_line/2, contains_line/2, classify_line/2]). -export_type([span/0, position/0]). -type span() :: {span, integer(), integer(), integer(), integer()}. -type position() :: first | inside | last | outside. -spec new(integer(), integer(), integer(), integer()) -> span(). new(Start_line, End_line, Start_column, End_column) -> {span, Start_line, End_line, Start_column, End_column}. -spec segment(integer(), integer(), integer()) -> span(). segment(Line, Start_column, End_column) -> {span, Line, Line, Start_column, End_column}. -spec point(integer(), integer()) -> span(). point(Line, Column) -> {span, Line, Line, Column, Column}. -spec merge(span(), span()) -> span(). merge(One, Other) -> {span, gleam@int:min(erlang:element(2, One), erlang:element(2, Other)), gleam@int:max(erlang:element(3, One), erlang:element(3, Other)), gleam@int:min(erlang:element(4, One), erlang:element(4, Other)), gleam@int:max(erlang:element(5, One), erlang:element(5, Other))}. -spec lines(span()) -> non_empty_list:non_empty_list(integer()). lines(Span) -> _pipe = non_empty_list:new( erlang:element(2, Span), [erlang:element(3, Span)] ), non_empty_list:unique(_pipe). -spec max_line(non_empty_list:non_empty_list(span())) -> integer(). max_line(Spans) -> _pipe = non_empty_list:flat_map(Spans, fun lines/1), non_empty_list:reduce(_pipe, fun gleam@int:max/2). -spec min_line(non_empty_list:non_empty_list(span())) -> integer(). min_line(Spans) -> _pipe = non_empty_list:flat_map(Spans, fun lines/1), non_empty_list:reduce(_pipe, fun gleam@int:min/2). -spec columns(span()) -> non_empty_list:non_empty_list(integer()). columns(Span) -> _pipe = non_empty_list:new( erlang:element(4, Span), [erlang:element(5, Span)] ), non_empty_list:unique(_pipe). -spec max_column(non_empty_list:non_empty_list(span())) -> integer(). max_column(Spans) -> _pipe = non_empty_list:flat_map(Spans, fun columns/1), non_empty_list:reduce(_pipe, fun gleam@int:max/2). -spec min_column(non_empty_list:non_empty_list(span())) -> integer(). min_column(Spans) -> _pipe = non_empty_list:flat_map(Spans, fun columns/1), non_empty_list:reduce(_pipe, fun gleam@int:min/2). -spec is_segment(span()) -> boolean(). is_segment(Span) -> erlang:element(2, Span) =:= erlang:element(3, Span). -spec starts_at_line(span(), integer()) -> boolean(). starts_at_line(Span, Line) -> erlang:element(2, Span) =:= Line. -spec ends_on_line(span(), integer()) -> boolean(). ends_on_line(Span, Line) -> erlang:element(3, Span) =:= Line. -spec contains_line(span(), integer()) -> boolean(). contains_line(Span, Line) -> (erlang:element(2, Span) =< Line) andalso (Line =< erlang:element(3, Span)). -spec classify_line(span(), integer()) -> position(). classify_line(Span, Line) -> gleam@bool:guard( starts_at_line(Span, Line), first, fun() -> gleam@bool:guard( ends_on_line(Span, Line), last, fun() -> gleam@bool:guard( contains_line(Span, Line), inside, fun() -> outside end ) end ) end ).