module Unison.LSP.DocumentSymbols
  ( documentSymbolsHandler,
  )
where

import Control.Lens hiding (List)
import Language.LSP.Protocol.Lens hiding (error)
import Language.LSP.Protocol.Message qualified as Msg
import Language.LSP.Protocol.Types
import Unison.LSP.FileAnalysis
import Unison.LSP.FileAnalysis qualified as FileAnalysis
import Unison.LSP.Types
import Unison.Prelude
import Unison.PrettyPrintEnv (PrettyPrintEnv)
import Unison.PrettyPrintEnvDecl qualified as PPED
import Unison.Syntax.Name qualified as Name
import Unison.Syntax.TypePrinter qualified as TypePrinter
import Unison.Util.Pretty qualified as Pretty

-- | Go to Definition handler
documentSymbolsHandler :: Msg.TRequestMessage 'Msg.Method_TextDocumentDocumentSymbol -> (Either Msg.ResponseError (Msg.MessageResult 'Msg.Method_TextDocumentDocumentSymbol) -> Lsp ()) -> Lsp ()
documentSymbolsHandler :: TRequestMessage 'Method_TextDocumentDocumentSymbol
-> (Either
      ResponseError (MessageResult 'Method_TextDocumentDocumentSymbol)
    -> Lsp ())
-> Lsp ()
documentSymbolsHandler TRequestMessage 'Method_TextDocumentDocumentSymbol
m Either
  ResponseError (MessageResult 'Method_TextDocumentDocumentSymbol)
-> Lsp ()
respond = do
  Either
  ResponseError ([SymbolInformation] |? ([DocumentSymbol] |? Null))
-> Lsp ()
Either
  ResponseError (MessageResult 'Method_TextDocumentDocumentSymbol)
-> Lsp ()
respond (Either
   ResponseError ([SymbolInformation] |? ([DocumentSymbol] |? Null))
 -> Lsp ())
-> (Maybe [DocumentSymbol]
    -> Either
         ResponseError ([SymbolInformation] |? ([DocumentSymbol] |? Null)))
-> Maybe [DocumentSymbol]
-> Lsp ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([SymbolInformation] |? ([DocumentSymbol] |? Null))
-> Either
     ResponseError ([SymbolInformation] |? ([DocumentSymbol] |? Null))
forall a b. b -> Either a b
Right (([SymbolInformation] |? ([DocumentSymbol] |? Null))
 -> Either
      ResponseError ([SymbolInformation] |? ([DocumentSymbol] |? Null)))
-> (Maybe [DocumentSymbol]
    -> [SymbolInformation] |? ([DocumentSymbol] |? Null))
-> Maybe [DocumentSymbol]
-> Either
     ResponseError ([SymbolInformation] |? ([DocumentSymbol] |? Null))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([SymbolInformation] |? ([DocumentSymbol] |? Null))
-> ([DocumentSymbol]
    -> [SymbolInformation] |? ([DocumentSymbol] |? Null))
-> Maybe [DocumentSymbol]
-> [SymbolInformation] |? ([DocumentSymbol] |? Null)
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (([DocumentSymbol] |? Null)
-> [SymbolInformation] |? ([DocumentSymbol] |? Null)
forall a b. b -> a |? b
InR (([DocumentSymbol] |? Null)
 -> [SymbolInformation] |? ([DocumentSymbol] |? Null))
-> ([DocumentSymbol] -> [DocumentSymbol] |? Null)
-> [DocumentSymbol]
-> [SymbolInformation] |? ([DocumentSymbol] |? Null)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [DocumentSymbol] -> [DocumentSymbol] |? Null
forall a b. a -> a |? b
InL ([DocumentSymbol]
 -> [SymbolInformation] |? ([DocumentSymbol] |? Null))
-> [DocumentSymbol]
-> [SymbolInformation] |? ([DocumentSymbol] |? Null)
forall a b. (a -> b) -> a -> b
$ []) (([DocumentSymbol] |? Null)
-> [SymbolInformation] |? ([DocumentSymbol] |? Null)
forall a b. b -> a |? b
InR (([DocumentSymbol] |? Null)
 -> [SymbolInformation] |? ([DocumentSymbol] |? Null))
-> ([DocumentSymbol] -> [DocumentSymbol] |? Null)
-> [DocumentSymbol]
-> [SymbolInformation] |? ([DocumentSymbol] |? Null)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [DocumentSymbol] -> [DocumentSymbol] |? Null
forall a b. a -> a |? b
InL) (Maybe [DocumentSymbol] -> Lsp ())
-> Lsp (Maybe [DocumentSymbol]) -> Lsp ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< MaybeT Lsp [DocumentSymbol] -> Lsp (Maybe [DocumentSymbol])
forall (m :: * -> *) a. MaybeT m a -> m (Maybe a)
runMaybeT do
    let fileUri :: Uri
fileUri = TRequestMessage 'Method_TextDocumentDocumentSymbol
m TRequestMessage 'Method_TextDocumentDocumentSymbol
-> Getting
     Uri (TRequestMessage 'Method_TextDocumentDocumentSymbol) Uri
-> Uri
forall s a. s -> Getting a s a -> a
^. (DocumentSymbolParams -> Const Uri DocumentSymbolParams)
-> TRequestMessage 'Method_TextDocumentDocumentSymbol
-> Const Uri (TRequestMessage 'Method_TextDocumentDocumentSymbol)
forall s a. HasParams s a => Lens' s a
Lens'
  (TRequestMessage 'Method_TextDocumentDocumentSymbol)
  DocumentSymbolParams
params ((DocumentSymbolParams -> Const Uri DocumentSymbolParams)
 -> TRequestMessage 'Method_TextDocumentDocumentSymbol
 -> Const Uri (TRequestMessage 'Method_TextDocumentDocumentSymbol))
-> ((Uri -> Const Uri Uri)
    -> DocumentSymbolParams -> Const Uri DocumentSymbolParams)
-> Getting
     Uri (TRequestMessage 'Method_TextDocumentDocumentSymbol) Uri
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (TextDocumentIdentifier -> Const Uri TextDocumentIdentifier)
-> DocumentSymbolParams -> Const Uri DocumentSymbolParams
forall s a. HasTextDocument s a => Lens' s a
Lens' DocumentSymbolParams TextDocumentIdentifier
textDocument ((TextDocumentIdentifier -> Const Uri TextDocumentIdentifier)
 -> DocumentSymbolParams -> Const Uri DocumentSymbolParams)
-> ((Uri -> Const Uri Uri)
    -> TextDocumentIdentifier -> Const Uri TextDocumentIdentifier)
-> (Uri -> Const Uri Uri)
-> DocumentSymbolParams
-> Const Uri DocumentSymbolParams
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Uri -> Const Uri Uri)
-> TextDocumentIdentifier -> Const Uri TextDocumentIdentifier
forall s a. HasUri s a => Lens' s a
Lens' TextDocumentIdentifier Uri
uri
    FileAnalysis {[UDocumentSymbol]
documentSymbols :: [UDocumentSymbol]
$sel:documentSymbols:FileAnalysis :: FileAnalysis -> [UDocumentSymbol]
documentSymbols} <- Uri -> MaybeT Lsp FileAnalysis
forall (m :: * -> *). Lspish m => Uri -> MaybeT m FileAnalysis
FileAnalysis.getFileAnalysis Uri
fileUri
    PrettyPrintEnv
ppe <- PrettyPrintEnvDecl -> PrettyPrintEnv
PPED.suffixifiedPPE (PrettyPrintEnvDecl -> PrettyPrintEnv)
-> MaybeT Lsp PrettyPrintEnvDecl -> MaybeT Lsp PrettyPrintEnv
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Lsp PrettyPrintEnvDecl -> MaybeT Lsp PrettyPrintEnvDecl
forall (m :: * -> *) a. Monad m => m a -> MaybeT m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (Uri -> Lsp PrettyPrintEnvDecl
forall (m :: * -> *). Lspish m => Uri -> m PrettyPrintEnvDecl
ppedForFile Uri
fileUri)
    [DocumentSymbol] -> MaybeT Lsp [DocumentSymbol]
forall a. a -> MaybeT Lsp a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (PrettyPrintEnv -> UDocumentSymbol -> DocumentSymbol
asLspDocumentSymbols PrettyPrintEnv
ppe (UDocumentSymbol -> DocumentSymbol)
-> [UDocumentSymbol] -> [DocumentSymbol]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [UDocumentSymbol]
documentSymbols)

asLspDocumentSymbols :: PrettyPrintEnv -> UDocumentSymbol -> DocumentSymbol
asLspDocumentSymbols :: PrettyPrintEnv -> UDocumentSymbol -> DocumentSymbol
asLspDocumentSymbols
  PrettyPrintEnv
ppe
  UDocumentSymbol
    { Name
symbolName :: Name
$sel:symbolName:UDocumentSymbol :: UDocumentSymbol -> Name
symbolName,
      Maybe (Type Symbol Ann)
symbolSignature :: Maybe (Type Symbol Ann)
$sel:symbolSignature:UDocumentSymbol :: UDocumentSymbol -> Maybe (Type Symbol Ann)
symbolSignature,
      USymbolKind
symbolKind :: USymbolKind
$sel:symbolKind:UDocumentSymbol :: UDocumentSymbol -> USymbolKind
symbolKind,
      Range
symbolRange :: Range
$sel:symbolRange:UDocumentSymbol :: UDocumentSymbol -> Range
symbolRange,
      [UDocumentSymbol]
symbolChildren :: [UDocumentSymbol]
$sel:symbolChildren:UDocumentSymbol :: UDocumentSymbol -> [UDocumentSymbol]
symbolChildren
    } =
    DocumentSymbol
      { $sel:_name:DocumentSymbol :: Text
_name = Name -> Text
Name.toText Name
symbolName,
        $sel:_detail:DocumentSymbol :: Maybe Text
_detail = do
          Type Symbol Ann
typ <- Maybe (Type Symbol Ann)
symbolSignature
          Text -> Maybe Text
forall a. a -> Maybe a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Text -> Maybe Text) -> Text -> Maybe Text
forall a b. (a -> b) -> a -> b
$ Text
": " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> (Width -> PrettyPrintEnv -> Type Symbol Ann -> Text
forall v a. Var v => Width -> PrettyPrintEnv -> Type v a -> Text
TypePrinter.prettyStr Width
typeWidth PrettyPrintEnv
ppe Type Symbol Ann
typ),
        $sel:_kind:DocumentSymbol :: SymbolKind
_kind = USymbolKind -> SymbolKind
lspSymbolKind USymbolKind
symbolKind,
        $sel:_tags:DocumentSymbol :: Maybe [SymbolTag]
_tags = [SymbolTag] -> Maybe [SymbolTag]
forall a. a -> Maybe a
Just [],
        $sel:_deprecated:DocumentSymbol :: Maybe Bool
_deprecated = Maybe Bool
forall a. Maybe a
Nothing,
        $sel:_range:DocumentSymbol :: Range
_range = Range
symbolRange,
        $sel:_selectionRange:DocumentSymbol :: Range
_selectionRange = Range
symbolRange,
        $sel:_children:DocumentSymbol :: Maybe [DocumentSymbol]
_children = if [UDocumentSymbol] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [UDocumentSymbol]
symbolChildren then Maybe [DocumentSymbol]
forall a. Maybe a
Nothing else [DocumentSymbol] -> Maybe [DocumentSymbol]
forall a. a -> Maybe a
Just (PrettyPrintEnv -> UDocumentSymbol -> DocumentSymbol
asLspDocumentSymbols PrettyPrintEnv
ppe (UDocumentSymbol -> DocumentSymbol)
-> [UDocumentSymbol] -> [DocumentSymbol]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [UDocumentSymbol]
symbolChildren)
      }
    where
      typeWidth :: Width
typeWidth = Int -> Width
Pretty.Width Int
120
      lspSymbolKind :: USymbolKind -> SymbolKind
lspSymbolKind = \case
        USymbolKind
DataDeclSymbol -> SymbolKind
SymbolKind_Class
        USymbolKind
EffectDeclSymbol -> SymbolKind
SymbolKind_Interface
        USymbolKind
TermSymbol -> SymbolKind
SymbolKind_Function