@@ -19,8 +19,8 @@ module Development.IDE.Plugin.CodeAction
19
19
20
20
import Control.Applicative ((<|>) )
21
21
import Control.Arrow (second ,
22
- (>>> ) ,
23
- (&&& ) )
22
+ (&&& ) ,
23
+ (>>> ) )
24
24
import Control.Concurrent.STM.Stats (atomically )
25
25
import Control.Monad (guard , join ,
26
26
msum )
@@ -41,6 +41,7 @@ import qualified Data.Rope.UTF16 as Rope
41
41
import qualified Data.Set as S
42
42
import qualified Data.Text as T
43
43
import Data.Tuple.Extra (fst3 )
44
+ import Debug.Trace
44
45
import Development.IDE.Core.Rules
45
46
import Development.IDE.Core.RuleTypes
46
47
import Development.IDE.Core.Service
@@ -58,6 +59,12 @@ import Development.IDE.Plugin.TypeLenses (suggestSigna
58
59
import Development.IDE.Types.Exports
59
60
import Development.IDE.Types.Location
60
61
import Development.IDE.Types.Options
62
+ import GHC (AddEpAnn (AddEpAnn ),
63
+ Anchor (anchor ),
64
+ AnnsModule (am_main ),
65
+ DeltaPos (.. ),
66
+ EpAnn (.. ),
67
+ EpaLocation (.. ))
61
68
import qualified GHC.LanguageExtensions as Lang
62
69
import Ide.PluginUtils (subRange )
63
70
import Ide.Types
@@ -1386,34 +1393,66 @@ newImportToEdit (unNewImport -> imp) ps fileContents
1386
1393
-- the import will be inserted at line zero if there are no pragmas,
1387
1394
-- * otherwise inserted one line after the last file-header pragma
1388
1395
newImportInsertRange :: ParsedSource -> T. Text -> Maybe (Range , Int )
1389
- newImportInsertRange (L _ HsModule {.. }) fileContents
1396
+ newImportInsertRange ps @ (L _ HsModule {.. }) fileContents
1390
1397
| Just ((l, c), col) <- case hsmodImports of
1391
- [] -> findPositionNoImports ( fmap reLoc hsmodName) ( fmap reLoc hsmodExports) fileContents
1392
- _ -> findPositionFromImportsOrModuleDecl (map reLoc hsmodImports) last True
1398
+ [] -> ( \ line -> ((line, 0 ), 0 )) <$> findPositionNoImports ps fileContents
1399
+ _ -> findPositionFromImportsOrModuleDecl (map reLoc hsmodImports) last
1393
1400
, let insertPos = Position (fromIntegral l) (fromIntegral c)
1394
1401
= Just (Range insertPos insertPos, col)
1395
1402
| otherwise = Nothing
1396
1403
1397
1404
-- | Insert the import under the Module declaration exports if they exist, otherwise just under the module declaration.
1398
1405
-- If no module declaration exists, then no exports will exist either, in that case
1399
1406
-- insert the import after any file-header pragmas or at position zero if there are no pragmas
1400
- findPositionNoImports :: Maybe (Located ModuleName ) -> Maybe (Located [LIE name ]) -> T. Text -> Maybe ((Int , Int ), Int )
1401
- findPositionNoImports Nothing _ fileContents = findNextPragmaPosition fileContents
1402
- findPositionNoImports _ (Just hsmodExports) _ = findPositionFromImportsOrModuleDecl hsmodExports id False
1403
- findPositionNoImports (Just hsmodName) _ _ = findPositionFromImportsOrModuleDecl hsmodName id False
1407
+ findPositionNoImports :: ParsedSource -> T. Text -> Maybe Int
1408
+ findPositionNoImports (L _ HsModule {.. }) fileContents =
1409
+ case hsmodName of
1410
+ Nothing -> Just $ findNextPragmaPosition fileContents
1411
+ Just hsmodName' -> case hsmodAnn of
1412
+ EpAnn _ annsModule _ ->
1413
+ let prevSrcSpan = maybe (getLoc hsmodName') getLoc hsmodExports
1414
+ in do
1415
+ whereLocation <- fmap NE. head . NE. nonEmpty . mapMaybe filterWhere . am_main $ annsModule
1416
+ epaLocationToLine prevSrcSpan whereLocation
1417
+ EpAnnNotUsed -> Nothing
1418
+ where
1419
+ filterWhere (AddEpAnn AnnWhere loc) = Just loc
1420
+ filterWhere _ = Nothing
1421
+
1422
+ epaLocationToLine :: SrcSpan -> EpaLocation -> Maybe Int
1423
+ epaLocationToLine _ (EpaSpan sp) =
1424
+ let loc = realSrcSpanEnd sp
1425
+ in Just $ srcLocLine loc
1426
+ epaLocationToLine (UnhelpfulSpan _) _ = Nothing
1427
+ epaLocationToLine (RealSrcSpan prevSrcSpan _) (EpaDelta deltaPos _) =
1428
+ case deltaPos of
1429
+ SameLine _ -> Just prevEndLine
1430
+ DifferentLine line _ -> Just $ prevEndLine + line
1431
+ where
1432
+ prevEndLine = srcLocLine (realSrcSpanEnd prevSrcSpan)
1433
+
1434
+ showAddEpAnns :: [AddEpAnn ] -> String
1435
+ showAddEpAnns = unlines . fmap showAddEpAnn
1436
+
1437
+ showAddEpAnn :: AddEpAnn -> String
1438
+ showAddEpAnn (AddEpAnn keywordId loc) = show keywordId ++ " ," ++ showEpaLocation loc
1439
+
1440
+ showEpaLocation :: EpaLocation -> String
1441
+ showEpaLocation (EpaDelta pos _) = show pos
1442
+ showEpaLocation _ = error " should not be EpaSpan"
1404
1443
1405
- findPositionFromImportsOrModuleDecl :: HasSrcSpan a => t -> (t -> a ) -> Bool -> Maybe ((Int , Int ), Int )
1406
- findPositionFromImportsOrModuleDecl hsField f hasImports = case getLoc (f hsField) of
1444
+ findPositionFromImportsOrModuleDecl :: HasSrcSpan a => t -> (t -> a ) -> Maybe ((Int , Int ), Int )
1445
+ findPositionFromImportsOrModuleDecl hsField f = case getLoc (f hsField) of
1407
1446
RealSrcSpan s _ ->
1408
1447
let col = calcCol s
1409
1448
in Just ((srcLocLine (realSrcSpanEnd s), col), col)
1410
1449
_ -> Nothing
1411
- where calcCol s = if hasImports then srcLocCol (realSrcSpanStart s) - 1 else 0
1450
+ where calcCol s = srcLocCol (realSrcSpanStart s) - 1
1412
1451
1413
1452
-- | Find the position one after the last file-header pragma
1414
1453
-- Defaults to zero if there are no pragmas in file
1415
- findNextPragmaPosition :: T. Text -> Maybe (( Int , Int ), Int )
1416
- findNextPragmaPosition contents = Just (( lineNumber, 0 ), 0 )
1454
+ findNextPragmaPosition :: T. Text -> Int
1455
+ findNextPragmaPosition contents = lineNumber
1417
1456
where
1418
1457
lineNumber = afterLangPragma . afterOptsGhc $ afterShebang
1419
1458
afterLangPragma = afterPragma " LANGUAGE" contents'
0 commit comments