Skip to content
This repository was archived by the owner on Oct 7, 2020. It is now read-only.

Commit 2edbc23

Browse files
committed
Add documentation and use MaybeT
1 parent 7de610b commit 2edbc23

File tree

1 file changed

+69
-38
lines changed

1 file changed

+69
-38
lines changed

src/Haskell/Ide/Engine/Plugin/HieExtras.hs

Lines changed: 69 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
{-# LANGUAGE ScopedTypeVariables #-}
44
{-# LANGUAGE OverloadedStrings #-}
55
{-# LANGUAGE TypeFamilies #-}
6+
{-# LANGUAGE LambdaCase #-}
67
module Haskell.Ide.Engine.Plugin.HieExtras
78
( getDynFlags
89
, WithSnippets(..)
@@ -29,6 +30,7 @@ import Control.Lens.Prism ( _Just )
2930
import Control.Lens.Setter ((%~))
3031
import Control.Lens.Traversal (traverseOf)
3132
import Control.Monad.Reader
33+
import Control.Monad.Trans.Maybe
3234
import Data.Aeson
3335
import qualified Data.Aeson.Types as J
3436
import Data.Char
@@ -478,6 +480,9 @@ getTypeForName n = do
478480
getSymbolsAtPoint :: Position -> CachedInfo -> [(Range,Name)]
479481
getSymbolsAtPoint pos info = maybe [] (`getArtifactsAtPos` locMap info) $ newPosToOld info pos
480482

483+
-- |Get a symbol from the given location map at the given location.
484+
-- Retrieves the name and range of the symbol at the given location
485+
-- from the cached location map.
481486
symbolFromTypecheckedModule
482487
:: LocMap
483488
-> Position
@@ -540,6 +545,12 @@ getModule df n = do
540545

541546
-- ---------------------------------------------------------------------
542547
-- TODO: there has to be a simpler way, using the appropriate GHC internals
548+
-- |Find the Id for a given Name.
549+
-- Requires an already TypecheckedModule.
550+
-- A TypecheckedModule can be obtained by using the functions
551+
-- @ifCachedModuleAndData@ or @withCachedModuleAndData@.
552+
--
553+
-- Function is copied from @HaRe/src/Language/Haskell/Refact/Utils/TypeUtils.hs:2954@.
543554
findIdForName :: TypecheckedModule -> Name -> IdeM (Maybe Id)
544555
findIdForName tm n = do
545556
let t = GHC.tm_typechecked_source tm
@@ -550,60 +561,80 @@ findIdForName tm n = do
550561

551562
-- ---------------------------------------------------------------------
552563

564+
-- | Get the type for a name.
565+
-- Requires an already TypecheckedModule.
566+
-- A TypecheckedModule can be obtained by using the functions
567+
-- @ifCachedModuleAndData@ or @withCachedModuleAndData@.
568+
--
569+
-- Returns the type of a variable or a sum type constructor.
570+
--
571+
-- Function is taken from @HaRe/src/Language/Haskell/Refact/Utils/TypeUtils.hs:2966@.
553572
getTypeForName' :: TypecheckedModule -> Name -> IdeM (Maybe Type)
554573
getTypeForName' tm n = do
555574
mId <- findIdForName tm n
556575
case mId of
557576
Nothing -> getTypeForName n
558577
Just i -> return $ Just (varType i)
559578

560-
-- | Return the type definition
579+
-- | Return the type definition of the symbol at the given position.
580+
-- Works for Datatypes, Newtypes and Type Definitions.
581+
-- The latter is only possible, if the type that is defined is defined in the project.
582+
-- Sum Types can also be searched.
561583
findTypeDef :: Uri -> Position -> IdeDeferM (IdeResult [Location])
562584
findTypeDef uri pos = pluginGetFile "findTypeDef: " uri $ \file ->
563-
ifCachedModuleAndData
564-
file
565-
(IdeResultOk [])
585+
ifCachedModuleAndData -- Dont wait on this function if the module is not cached.
586+
file
587+
(IdeResultOk []) -- Default result
566588
(\tm info NMD{} -> do
567589
let rfm = revMap info
568590
lm = locMap info
569591
mm = moduleMap info
570592
oldPos = newPosToOld info pos
571593
case (\x -> Just $ getArtifactsAtPos x mm) =<< oldPos of
572594
Just ((_, mn) : _) -> gotoModule rfm mn
573-
_ -> case symbolFromTypecheckedModule lm =<< oldPos of
574-
Nothing -> return $ IdeResultOk []
575-
Just (_, n) -> do
576-
mayType <- lift $ getTypeForName' tm n
577-
case mayType of
578-
Nothing ->
579-
return $ IdeResultOk []
580-
Just t -> case tyConAppTyCon_maybe t of
581-
Nothing ->
582-
return $ IdeResultOk []
583-
Just tyCon ->
584-
case nameSrcSpan (getName tyCon) of
585-
UnhelpfulSpan _ -> return $ IdeResultOk []
586-
realSpan -> do
587-
res <- srcSpan2Loc rfm realSpan
588-
case res of
589-
Right l@(J.Location luri range) -> case uriToFilePath luri of
590-
Nothing -> return $ IdeResultOk [l]
591-
Just fp ->
592-
ifCachedModule fp (IdeResultOk [l])
593-
$ \(_ :: ParsedModule) info' ->
594-
case oldRangeToNew info' range of
595-
Just r ->
596-
return $ IdeResultOk [J.Location luri r]
597-
Nothing -> return $ IdeResultOk [l]
598-
Left x -> do
599-
debugm "findTypeDef: name srcspan not found/valid"
600-
pure
601-
(IdeResultFail
602-
(IdeError PluginError
603-
("hare:findTypeDef" <> ": \"" <> x <> "\"")
604-
Null
605-
)
606-
)
595+
_ -> do
596+
let
597+
-- | Get SrcSpan of the name at the given position.
598+
-- If the old position is Nothing, e.g. there is no cached info about it,
599+
-- Nothing is returned.
600+
--
601+
-- Otherwise, searches for the Type of the given position
602+
-- and retrieves its SrcSpan.
603+
getSrcSpanFromPosition :: Maybe Position -> MaybeT IdeDeferM SrcSpan
604+
getSrcSpanFromPosition oldPosition = do
605+
(_, n) <- MaybeT $ return $ symbolFromTypecheckedModule lm =<< oldPosition
606+
t <- MaybeT $ lift $ getTypeForName' tm n
607+
tyCon <- MaybeT $ return $ tyConAppTyCon_maybe t
608+
case nameSrcSpan (getName tyCon) of
609+
UnhelpfulSpan _ -> fail "Unhelpful Span" -- this message is never shown
610+
realSpan -> return realSpan
611+
612+
runMaybeT (getSrcSpanFromPosition oldPos) >>= \case
613+
Nothing -> return $ IdeResultOk []
614+
Just realSpan -> do
615+
-- Since we found a real SrcSpan, we now translate it
616+
-- to the position in the file
617+
res <- srcSpan2Loc rfm realSpan
618+
case res of
619+
Right l@(J.Location luri range) -> case uriToFilePath luri of
620+
Nothing -> return $ IdeResultOk [l]
621+
Just fp ->
622+
ifCachedModule fp (IdeResultOk [l])
623+
$ \(_ :: ParsedModule) info' ->
624+
case oldRangeToNew info' range of
625+
Just r ->
626+
return $ IdeResultOk [J.Location luri r]
627+
Nothing -> return $ IdeResultOk [l]
628+
Left x -> do
629+
-- SrcSpan does not have a file location!
630+
debugm "findTypeDef: name srcspan not found/valid"
631+
pure
632+
(IdeResultFail
633+
(IdeError PluginError
634+
("hare:findTypeDef" <> ": \"" <> x <> "\"")
635+
Null
636+
)
637+
)
607638
)
608639

609640
-- | Return the definition

0 commit comments

Comments
 (0)