module Unison.LSP.Conversions where

import Control.Lens
import Data.IntervalMap.Interval qualified as Interval
import Language.LSP.Protocol.Types
import Unison.LSP.Orphans ()
import Unison.Parser.Ann (Ann)
import Unison.Parser.Ann qualified as Ann
import Unison.Syntax.Lexer qualified as Lex
import Unison.Util.Range qualified as Range

rangeToInterval :: Range -> Interval.Interval Position
rangeToInterval :: Range -> Interval Position
rangeToInterval (Range Position
start Position
end) =
  Position -> Position -> Interval Position
forall a. a -> a -> Interval a
Interval.ClosedInterval Position
start Position
end

annToInterval :: Ann -> Maybe (Interval.Interval Position)
annToInterval :: Ann -> Maybe (Interval Position)
annToInterval Ann
ann = Ann -> Maybe Range
annToRange Ann
ann Maybe Range
-> (Range -> Interval Position) -> Maybe (Interval Position)
forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> Range -> Interval Position
rangeToInterval

-- | Convert a Unison file-position where the first char is 1 and line is 1, to an LSP `Position`
-- where the first char is 0 and line is 0.
uToLspPos :: Lex.Pos -> Position
uToLspPos :: Pos -> Position
uToLspPos Pos
uPos =
  Position
    { $sel:_line:Position :: UInt
_line = Line -> UInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Line -> UInt) -> Line -> UInt
forall a b. (a -> b) -> a -> b
$ Line -> Line -> Line
forall a. Ord a => a -> a -> a
max Line
0 (Pos -> Line
Lex.line Pos
uPos Line -> Line -> Line
forall a. Num a => a -> a -> a
- Line
1),
      $sel:_character:Position :: UInt
_character = Line -> UInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Line -> UInt) -> Line -> UInt
forall a b. (a -> b) -> a -> b
$ Line -> Line -> Line
forall a. Ord a => a -> a -> a
max Line
0 (Pos -> Line
Lex.column Pos
uPos Line -> Line -> Line
forall a. Num a => a -> a -> a
- Line
1)
    }

-- | Convert an LSP `Position` where the first char is 0 and line is 0, to a Unison file-position
-- where the first char is 1 and line is 1.
lspToUPos :: Position -> Lex.Pos
lspToUPos :: Position -> Pos
lspToUPos Position {$sel:_line:Position :: Position -> UInt
_line = UInt
line, $sel:_character:Position :: Position -> UInt
_character = UInt
char} =
  Line -> Line -> Pos
Lex.Pos
    (UInt -> Line
forall a b. (Integral a, Num b) => a -> b
fromIntegral (UInt -> Line) -> UInt -> Line
forall a b. (a -> b) -> a -> b
$ UInt
line UInt -> UInt -> UInt
forall a. Num a => a -> a -> a
+ UInt
1)
    (UInt -> Line
forall a b. (Integral a, Num b) => a -> b
fromIntegral (UInt -> Line) -> UInt -> Line
forall a b. (a -> b) -> a -> b
$ UInt
char UInt -> UInt -> UInt
forall a. Num a => a -> a -> a
+ UInt
1)

-- | Convert a Unison `Range` where the first char is 1 and line is 1, to an LSP `Range`
-- where the first char is 0 and line is 0.
uToLspRange :: Range.Range -> Range
uToLspRange :: Range -> Range
uToLspRange (Range.Range Pos
start Pos
end) = Position -> Position -> Range
Range (Pos -> Position
uToLspPos Pos
start) (Pos -> Position
uToLspPos Pos
end)

-- | Convert an LSP `Range` where the first char is 0 and line is 0, to a Unison `Range`
-- where the first char is 1 and line is 1.
lspToURange :: Range -> Range.Range
lspToURange :: Range -> Range
lspToURange (Range Position
start Position
end) = Pos -> Pos -> Range
Range.Range (Position -> Pos
lspToUPos Position
start) (Position -> Pos
lspToUPos Position
end)

annToRange :: Ann -> Maybe Range
annToRange :: Ann -> Maybe Range
annToRange = \case
  Ann
Ann.Intrinsic -> Maybe Range
forall a. Maybe a
Nothing
  Ann
Ann.External -> Maybe Range
forall a. Maybe a
Nothing
  Ann.GeneratedFrom Ann
a -> Ann -> Maybe Range
annToRange Ann
a
  Ann.Ann Pos
start Pos
end -> Range -> Maybe Range
forall a. a -> Maybe a
Just (Range -> Maybe Range) -> Range -> Maybe Range
forall a b. (a -> b) -> a -> b
$ Position -> Position -> Range
Range (Pos -> Position
uToLspPos Pos
start) (Pos -> Position
uToLspPos Pos
end)

annToURange :: Ann.Ann -> Maybe Range.Range
annToURange :: Ann -> Maybe Range
annToURange = \case
  Ann
Ann.Intrinsic -> Maybe Range
forall a. Maybe a
Nothing
  Ann
Ann.External -> Maybe Range
forall a. Maybe a
Nothing
  Ann.GeneratedFrom Ann
a -> Ann -> Maybe Range
annToURange Ann
a
  Ann.Ann Pos
start Pos
end -> Range -> Maybe Range
forall a. a -> Maybe a
Just (Range -> Maybe Range) -> Range -> Maybe Range
forall a b. (a -> b) -> a -> b
$ Pos -> Pos -> Range
Range.Range Pos
start Pos
end