packages feed

hs-tags (empty) → 0.1.5

raw patch · 7 files changed

+931/−0 lines, 7 filesdep +Cabaldep +basedep +containerssetup-changed

Dependencies added: Cabal, base, containers, directory, filepath, ghc, mtl, process, strict

Files

+ CHANGELOG.md view
@@ -0,0 +1,14 @@+# hs-tags++Version history.++## 0.1.5 released 2021-03-16++- initial release+- tested with GHC 8.0.2 - 9.0.1++## Prehistory++- originally written in Dec 2007 by Ulf Norell to generate ctags via GHC 6.8+- extended in Feb 2008 by Nils Anders Danielsson to etags+- since then, used in the Agda development process and updated to new GHC versions
+ LICENSE view
@@ -0,0 +1,21 @@+Copyright (c) 2009-2021 Ulf Norell, Nils Anders Danielsson,+  Andrés Sicard-Ramírez, Andreas Abel, Francesco Mazzoli, Paolo G. Giarrusso++Permission is hereby granted, free of charge, to any person obtaining+a copy of this software and associated documentation files (the+"Software"), to deal in the Software without restriction, including+without limitation the rights to use, copy, modify, merge, publish,+distribute, sublicense, and/or sell copies of the Software, and to+permit persons to whom the Software is furnished to do so, subject to+the following conditions:++The above copyright notice and this permission notice shall be+included in all copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ Main.hs view
@@ -0,0 +1,312 @@+{-# LANGUAGE CPP                 #-}+{-# LANGUAGE PatternSynonyms     #-}+{-# LANGUAGE ScopedTypeVariables #-}++module Main where++import Control.Arrow ((&&&))+import Control.Exception+import Control.Monad+import Control.Monad.Trans+import Data.Char+import qualified Data.Traversable as T+import Data.List+import Data.Maybe+import Data.Version ( showVersion )+import System.Environment+import System.IO+import qualified System.IO.Strict as Strict+import System.Exit+import System.FilePath+import System.Directory+import System.Process+import System.Console.GetOpt++import GHC+  ( DynFlags+  , HsModule+  , Located+  , RealSrcLoc+  , includePaths+  , getSession+  , getSessionDynFlags+  , setSessionDynFlags+  , runGhc+  )+#if MIN_VERSION_ghc(8,4,0)+import GHC (GhcPs)+#else+import GHC (RdrName)+#endif++-- In ghc-9.0, hierarchical modules were introduced,+-- so most modules got renamed.+#if MIN_VERSION_ghc(9,0,0)++import GHC.Data.FastString   ( mkFastString )+import GHC.Data.StringBuffer ( hGetStringBuffer )+import GHC.Driver.Monad      ( GhcT(..), Ghc(..) )+import GHC.Driver.Phases     ( pattern Cpp, pattern HsSrcFile )+import GHC.Driver.Pipeline   ( preprocess )+import GHC.Driver.Session    ( pattern IncludeSpecs, opt_P, parseDynamicFilePragma, sOpt_P, toolSettings )+import GHC.Parser            ( parseModule )+import GHC.Parser.Lexer      ( P(..), ParseResult(..), PState, mkPState, getErrorMessages )+import GHC.Settings          ( toolSettings_opt_P )+import GHC.Types.SrcLoc      ( mkRealSrcLoc, noLoc, unLoc )++-- THESE MODULES cannot be imported, it seems:+-- import GHC.Driver.Errors ( printBagOfErrors )+-- import GHC.Types.SourceError (throwErrors)+-- import GHC.Parser.Errors.Ppr (pprError)+-- import GHC.Utils.Error.ErrorMessages++#else++import DriverPhases   ( pattern Cpp, pattern HsSrcFile )+import DriverPipeline ( preprocess )+import DynFlags       ( opt_P, sOpt_P, settings, parseDynamicFilePragma )+import FastString     ( mkFastString )+import GhcMonad       ( GhcT(..), Ghc(..) )+import Lexer          ( P(..), ParseResult(..), PState, mkPState )+import Parser         ( parseModule )+import SrcLoc         ( mkRealSrcLoc, noLoc, unLoc )+import StringBuffer   ( hGetStringBuffer )++#if MIN_VERSION_ghc(8,6,1)+import DynFlags       ( pattern IncludeSpecs )+#endif++#if MIN_VERSION_ghc(8,10,1)+import GHC            ( toolSettings )+import ToolSettings   ( toolSettings_opt_P )+import Lexer          ( getErrorMessages )+import ErrUtils       ( printBagOfErrors )+#else+import ErrUtils       ( mkPlainErrMsg )+#endif++#endif++import Language.Haskell.Extension as LHE+import Distribution.PackageDescription.Configuration (flattenPackageDescription)+import Distribution.PackageDescription hiding (options)+#if MIN_VERSION_Cabal(2,2,0)+import qualified Distribution.PackageDescription.Parsec as PkgDescParse+import Distribution.PackageDescription.Parsec hiding (ParseResult)+#else+import qualified Distribution.PackageDescription.Parse as PkgDescParse+import Distribution.PackageDescription.Parse hiding (ParseResult)+#endif++import Tags+import Paths_hs_tags ( version )++instance MonadTrans GhcT where+  lift m = GhcT $ const m++fileLoc :: FilePath -> RealSrcLoc+fileLoc file = mkRealSrcLoc (mkFastString file) 1 0++filePState :: DynFlags -> FilePath -> IO PState+filePState dflags file = do+  buf <- hGetStringBuffer file+  return $+    mkPState dflags buf (fileLoc file)+++#if MIN_VERSION_ghc(9,0,0)+pMod :: P (Located HsModule)+#elif MIN_VERSION_ghc(8,4,0)+pMod :: P (Located (HsModule GhcPs))+#else+pMod :: P (Located (HsModule RdrName))+#endif+pMod = parseModule++parse :: PState -> P a -> ParseResult a+parse st p = unP p st++goFile :: FilePath -> Ghc [Tag]+goFile file = do+  liftIO $ hPutStrLn stderr $ "Processing " ++ file+  env <- getSession+#if MIN_VERSION_ghc(8,8,1)+  r <- liftIO $+       preprocess env file Nothing (Just $ Cpp HsSrcFile)+  let (dflags, srcFile) = case r of+                            Left _  -> error $ "preprocessing " ++ file+                            Right x -> x+#else+  (dflags, srcFile) <- liftIO $+      preprocess env (file, Just $ Cpp HsSrcFile)+#endif+  st <- liftIO $ filePState dflags srcFile+  case parse st pMod of+    POk _ m         -> return $ removeDuplicates $ tags $ unLoc m+#if MIN_VERSION_ghc(9,0,0)+    PFailed pState -> liftIO $ do+      -- Andreas, 2021-03-03, how can we print the errors with ghc-9.0?+      -- @printBagOfErrors@ does not seem to be exported,+      -- neither @pprError@...+      -- throwErrors $ fmap pprError $ getErrorMessages pState dflags+      hPutStrLn stderr "PARSE ERROR"+#elif MIN_VERSION_ghc(8,10,1)+    PFailed pState -> liftIO $ do+      printBagOfErrors dflags $ getErrorMessages pState dflags+#elif MIN_VERSION_ghc(8,4,0)+    PFailed _ loc err -> liftIO $ do+      print (mkPlainErrMsg dflags loc err)+#else+    PFailed loc err -> liftIO $ do+      print (mkPlainErrMsg dflags loc err)+#endif+      exitWith $ ExitFailure 1++runCmd :: String -> IO String+runCmd cmd = do+  (_, h, _, _) <- runInteractiveCommand cmd+  hGetContents h++-- XXX This is a quick hack; it will certainly work if the language description+-- is not conditional. Otherwise we'll need to figure out both the flags and the+-- build configuration to call `finalizePackageDescriptionSource`.+configurePackageDescription ::+  GenericPackageDescription -> PackageDescription+configurePackageDescription = flattenPackageDescription++extractLangSettings ::+  GenericPackageDescription+  -> ([Extension], Maybe LHE.Language)+extractLangSettings gpd =+  maybe ([], Nothing)+  ((defaultExtensions &&& defaultLanguage) . libBuildInfo)+  ((library . configurePackageDescription) gpd)++extToOpt :: Extension -> String+extToOpt (UnknownExtension e) = "-X" ++ e+extToOpt (EnableExtension e)  = "-X" ++ show e+extToOpt (DisableExtension e) = "-XNo" ++ show e++langToOpt :: LHE.Language -> String+langToOpt l = "-X" ++ show l++cabalConfToOpts :: GenericPackageDescription -> [String]+cabalConfToOpts desc = langOpts ++ extOpts+  where+    (exts, maybeLang) = extractLangSettings desc+    extOpts = map extToOpt exts+    langOpts = langToOpt <$> maybeToList maybeLang++main :: IO ()+main = do+  opts <- getOptions++  let agdaReadPackageDescription =+#if MIN_VERSION_Cabal(2,0,0)+        readGenericPackageDescription+#else+        readPackageDescription+#endif++  pkgDesc <- T.mapM (agdaReadPackageDescription minBound) $ optCabalPath opts+  let go | optHelp opts = do+            printUsage stdout+            exitSuccess+         | otherwise = do+            top : _ <- lines <$> runCmd "ghc --print-libdir"+            ts <- runGhc (Just top) $ do+              dynFlags <- getSessionDynFlags+              let dynFlags' =+                    dynFlags {+#if MIN_VERSION_ghc(8,10,1)+                    toolSettings = (toolSettings dynFlags) {+                        toolSettings_opt_P = concatMap (\i -> [i, "-include"]) (optIncludes opts) +++                                             opt_P dynFlags+                        }+#else+                    settings = (settings dynFlags) {+                        sOpt_P = concatMap (\i -> [i, "-include"]) (optIncludes opts) +++                                 opt_P dynFlags+                        }+#endif++#if MIN_VERSION_ghc(8,6,1)+                    , includePaths = case includePaths dynFlags of+                                       IncludeSpecs qs gs -> IncludeSpecs qs (optIncludePath opts ++ gs)+#else+                    , includePaths = optIncludePath opts ++ includePaths dynFlags+#endif+                    }+              (dynFlags'', _, _) <- parseDynamicFilePragma dynFlags' $ map noLoc $ concatMap cabalConfToOpts (maybeToList pkgDesc)+              setSessionDynFlags dynFlags''+              mapM (\f -> liftM2 ((,,) f) (liftIO $ Strict.readFile f)+                                          (goFile f)) $+                         optFiles opts+            when (optCTags opts) $+              let sts = sort $ concatMap (\(_, _, t) -> t) ts in+              writeFile (optCTagsFile opts) $ unlines $ map show sts+            when (optETags opts) $+              writeFile (optETagsFile opts) $ showETags ts+  go++getOptions :: IO Options+getOptions = do+  args <- getArgs+  case getOpt Permute options args of+    ([], [], []) -> do+      printUsage stdout+      exitSuccess+    (opts, files, []) -> return $ foldr ($) (defaultOptions files) opts+    (_, _, errs) -> do+      hPutStr stderr $ unlines errs+      printUsage stderr+      exitWith $ ExitFailure 1++printUsage h = do+  prog <- getProgName+  let header = unwords [ prog, "version", showVersion version ]+  hPutStrLn h $ usageInfo header options++data Options = Options+  { optCTags       :: Bool+  , optETags       :: Bool+  , optCTagsFile   :: String+  , optETagsFile   :: String+  , optHelp        :: Bool+  , optIncludes    :: [FilePath]+  , optFiles       :: [FilePath]+  , optIncludePath :: [FilePath]+  , optCabalPath   :: Maybe FilePath+  }++defaultOptions :: [FilePath] -> Options+defaultOptions files = Options+  { optCTags       = False+  , optETags       = False+  , optCTagsFile   = "tags"+  , optETagsFile   = "TAGS"+  , optHelp        = False+  , optIncludes    = []+  , optFiles       = files+  , optIncludePath = []+  , optCabalPath   = Nothing+  }++options :: [OptDescr (Options -> Options)]+options =+  [ Option []    ["help"]    (NoArg setHelp)  "Show help."+  , Option ['c'] ["ctags"]   (OptArg setCTagsFile "FILE") "Generate ctags (default file=tags)"+  , Option ['e'] ["etags"]   (OptArg setETagsFile "FILE") "Generate etags (default file=TAGS)"+  , Option ['i'] ["include"] (ReqArg addInclude   "FILE") "File to #include"+  , Option ['I'] []          (ReqArg addIncludePath "DIRECTORY") "Directory in the include path"+  , Option []    ["cabal"]   (ReqArg addCabal "CABAL FILE") "Cabal configuration to load additional language options from (library options are used)"+  ]+  where+    setHelp             o = o { optHelp        = True }+    setCTags            o = o { optCTags       = True }+    setETags            o = o { optETags       = True }+    setCTagsFile   file o = o { optCTagsFile   = fromMaybe "tags" file, optCTags = True }+    setETagsFile   file o = o { optETagsFile   = fromMaybe "TAGS" file, optETags = True }+    addInclude     file o = o { optIncludes    = file : optIncludes o }+    addIncludePath dir  o = o { optIncludePath = dir : optIncludePath o}+    addCabal       file o = o { optCabalPath   = Just file }
+ README.md view
@@ -0,0 +1,49 @@+hs-tags - Generate tags for Haskell code+========================================++Generate `tags` (ctags) or `TAGS` (etags) file for a bunch of Haskell files.+These files are used by editors (e.g. `TAGS` by Emacs) to implement _jump-to-definition_ (e.g. `M-.` in Emacs).++In contrast to [hasktags](http://hackage.haskell.org/package/hasktags), `hs-tags` uses the GHC Haskell parser to read the Haskell files and find definition sites.++Example use:+```+find src -name "*.*hs" | xargs \+  hs-tags --cabal Foo.cabal -i dist/build/autogen/cabal_macros.h -e+```+Creates Emacs `TAGS` from Haskell files residing in folder `src/` of the project as defined in `Foo.cabal`, using preprocessor definitions from `dist/build/autogen/cabal_macros.h`.++Command line reference:+```+hs-tags+                --help              Show help.+  -c[FILE]      --ctags[=FILE]      Generate ctags (default file=tags)+  -e[FILE]      --etags[=FILE]      Generate etags (default file=TAGS)+  -i FILE       --include=FILE      File to #include+  -I DIRECTORY                      Directory in the include path+                --cabal=CABAL FILE  Cabal configuration to load additional+                                    language options from+                                    (library options are used)+```++Some related projects:++- [hasktags](http://hackage.haskell.org/package/hasktags):+  popular ctags and etags generator, using its own parser.++- [fast-tags](https://hackage.haskell.org/package/fast-tags):+  ctags and etags, fast, incremental, using its own parser.++- [ghc-tags-plugin](https://hackage.haskell.org/package/ghc-tags-plugin):+  ctags and etags emitted during compilation by a ghc-plugin.++- [hothasktags](https://hackage.haskell.org/package/hothasktags)+  (_unmaintained_?):+  ctags generator, using the [haskell-src-exts](https://hackage.haskell.org/package/haskell-src-exts) parser.++- [htags](https://hackage.haskell.org/package/htags):+  ctags for Haskell 98, using the [haskell-src](https://hackage.haskell.org/package/haskell-src) parser.++- [codex](https://hackage.haskell.org/package/codex):+  ctags and etags for dependencies, using+  [hasktags](http://hackage.haskell.org/package/hasktags).
+ Setup.hs view
@@ -0,0 +1,4 @@++import Distribution.Simple++main = defaultMainWithHooks defaultUserHooks
+ Tags.hs view
@@ -0,0 +1,472 @@+{-# LANGUAGE CPP                  #-}+{-# LANGUAGE FlexibleInstances    #-}+{-# LANGUAGE TypeFamilies         #-}++{-# LANGUAGE UndecidableInstances #-}++module Tags where++import Data.Function+import Data.List+import Data.Maybe+import Data.Map (Map)+import qualified Data.Map as Map++#if MIN_VERSION_ghc(8,10,1)+import GHC.Hs+#else+import HsSyn+#endif++#if MIN_VERSION_ghc(9,0,0)+import GHC.Types.SrcLoc+import GHC.Types.Name.Reader+import GHC.Types.Name.Occurrence+import qualified GHC.Types.Name as Name+import GHC.Data.FastString+import GHC.Data.Bag+import qualified GHC.Types.Basic as BasicTypes+#else+import SrcLoc+import RdrName+import OccName+import qualified Name+import FastString+import Bag+import qualified BasicTypes+#endif+++data Pos = Pos { line, column :: Int }+           deriving (Eq, Ord)++data Tag = NoLoc String+         | Tag String FilePath Pos+  deriving (Eq, Ord)++-- | Removes duplicate /adjacent/ tags, ignoring the 'Pos' field.++removeDuplicates :: [Tag] -> [Tag]+removeDuplicates = map head . groupBy ((==) `on` everythingButPos)+  where+  dummyPos = Pos 0 0++  everythingButPos (Tag s f p) = Tag s f dummyPos+  everythingButPos t@NoLoc {}  = t++-- | Takes a list of (filename, file contents, tags) and generates+-- text for an etags file.++-- I found the etags file format on Wikipedia; I have not found an+-- authoritative definition of it.+--+-- For every file containing tags a section is generated.+-- Section header (two lines):+--   \x0c+--   <file name>,<size of the following lines in bytes>+-- This is followed by one line for every tag:+--   <text from start of line to end of tag>\x7f+--   <tag name>\x01+--   <line number>,<some form of offset in bytes>++showETags :: [(FilePath, String, [Tag])] -> String+showETags = concatMap showFile+  where+  showFile (f, contents, ts) =+    unlines ["\x0c", f ++ "," ++ show bytes] ++ ts'+    where+    ts' = unlines $ mapMaybe showTag ts++    -- TODO: This should be the length in _bytes_ of ts'. However,+    -- since the rest of this program seems to assume an 8-bit+    -- character encoding I just count the number of characters.+    bytes = length ts'++    lineMap = Map.fromList $ zip [1..] (lines contents)++    showTag (NoLoc _)   = Nothing+    showTag (Tag t f p) = Just $+      take' (column p) (lineMap ! line p) ++ t ++ "\x7f" +++      t ++ "\x01" +++      show (line p) ++ ",0"+      -- I don't know what the last offset is used for, so I have set+      -- it to 0. This seems to work.++    take' = tabAwareTake 0+    m ! k = Map.findWithDefault (error $ "Cannot find line " ++ show k ++ " in lineMap") k m++    -- A variant of take which is aware of tab characters. Uses tab+    -- size 8, and only recognises the ordinary ASCII horizontal tab+    -- ('\t'). The first argument is the position of the first+    -- character. Tabs are only expanded into spaces if necessary.+    tabAwareTake pos n s | n <= 0 = ""+    tabAwareTake pos n ""         = ""+    tabAwareTake pos n (c : s)+      | c /= '\t'    = c : tabAwareTake (pos + 1) (n - 1) s+      | stepSize > n = replicate n ' '+      | otherwise    = c : tabAwareTake nextTabStop (n - stepSize) s+      where+      tabSize     = 8+      nextTabStop = (pos `div` tabSize + 1) * tabSize+      stepSize    = nextTabStop - pos++instance Show Tag where+  show (Tag t f p) = intercalate "\t" [t, f, show (line p)]+  show (NoLoc t)   = unwords [t, ".", "0"]++srcLocTag :: SrcLoc -> Tag -> Tag+srcLocTag UnhelpfulLoc{} t         = t+#if MIN_VERSION_ghc(9,0,0)+srcLocTag (RealSrcLoc l _) (NoLoc t) =+#else+srcLocTag (RealSrcLoc l) (NoLoc t) =+#endif+  Tag t+      (unpackFS $ srcLocFile l)+      Pos { line   = srcLocLine l+            -- GHC 7 counts columns starting from 1.+          , column = srcLocCol l - 1+          }+srcLocTag _ t@Tag{}   = t++class TagName a where+  tagName :: a -> String++instance TagName RdrName where+  tagName x = case x of+    Unqual x  -> tagName x+    Qual _ x  -> tagName x+    Orig _ x  -> tagName x+    Exact x   -> tagName x++instance TagName OccName where+  tagName = unpackFS . occNameFS++instance TagName Name.Name where+  tagName = tagName . Name.nameOccName++#if MIN_VERSION_ghc(8,4,0)+instance (IdP pass ~ name, TagName name) => TagName (FieldOcc pass) where+#else+instance TagName a => TagName (FieldOcc a) where+#endif+#if MIN_VERSION_ghc(8,6,1)+  tagName (FieldOcc _ (L _ rdrName)) = tagName rdrName+  tagName (XFieldOcc _)              = missingImp "XFieldOcc"+#else+  tagName (FieldOcc (L _ rdrName) _) = tagName rdrName+#endif++class HasTags a where+  tags :: a -> [Tag]++instance HasTags Tag where+  tags x = [x]++instance HasTags a => HasTags [a] where+  tags = concatMap tags++instance (HasTags a, HasTags b) => HasTags (a, b) where+  tags (x, y) = tags x ++ tags y++instance HasTags a => HasTags (Maybe a) where+  tags = maybe [] tags++instance HasTags a => HasTags (Bag a) where+  tags = tags . bagToList++instance HasTags a => HasTags (Located a) where+  tags (L l x) = map (srcLocTag $ srcSpanStart l) $ tags x++newtype Name a = Name a++instance TagName name => HasTags (Name name) where+  tags (Name x) = [NoLoc $ tagName x]++tagsLN :: TagName name => Located name -> [Tag]+tagsLN = tags . fmap Name++tagsN :: TagName name => name -> [Tag]+tagsN = tags . Name++#if MIN_VERSION_ghc(9,0,0)+instance HasTags HsModule where+#else+#if MIN_VERSION_ghc(8,4,0)+instance ( IdP pass ~ name+         , TagName name+#if MIN_VERSION_ghc(8,10,1)+         , HasTags (XRec pass Pat)+#endif+         ) => HasTags (HsModule pass) where+#else+instance TagName name => HasTags (HsModule name) where+#endif+#endif+  tags HsModule{ hsmodExports = export+               , hsmodDecls   = decls+               } = tags decls -- TODO: filter exports++#if MIN_VERSION_ghc(8,4,0)+instance ( IdP pass ~ name+         , TagName name+#if MIN_VERSION_ghc(8,10,1)+         , HasTags (XRec pass Pat)+#endif+         ) => HasTags (HsDecl pass) where+#else+instance TagName name => HasTags (HsDecl name) where+#endif+  tags d = case d of+#if MIN_VERSION_ghc(8,10,1)+    KindSigD _ d  -> tags d+#endif+#if MIN_VERSION_ghc(8,6,1)+    TyClD _ d     -> tags d+    ValD _ d      -> tags d+    SigD _ d      -> tags d+    ForD _ d      -> tags d+    XHsDecl _     -> missingImp "XHsDecl"+#else+    TyClD d       -> tags d+    ValD d        -> tags d+    SigD d        -> tags d+    ForD d        -> tags d+#endif+    DocD{}        -> []+    SpliceD{}     -> []+    RuleD{}       -> []+    DefD{}        -> []+    InstD{}       -> []+    DerivD{}      -> []+    WarningD{}    -> []+    AnnD{}        -> []+    RoleAnnotD{}  -> []+#if !MIN_VERSION_ghc(8,6,1)+    VectD{}       -> []+#endif++#if MIN_VERSION_ghc(8,4,0)+instance (IdP pass ~ name, TagName name) => HasTags (FamilyDecl pass) where+#else+instance TagName name => HasTags (FamilyDecl name) where+#endif+  tags d = tagsLN (fdLName d)++instance HasTags (BasicTypes.Origin) where+  tags _ = []++#if MIN_VERSION_ghc(8,4,0)+instance (IdP pass ~ name, TagName name) => HasTags (TyClDecl pass) where+#else+instance TagName name => HasTags (TyClDecl name) where+#endif+#if MIN_VERSION_ghc(8,6,1)+  tags (FamDecl _ d) = tags d+#else+  tags (FamDecl d) = tags d+#endif+  tags d = tagsLN (tcdLName d) +++    case d of+      DataDecl { tcdDataDefn = HsDataDefn { dd_cons = cons } }+        -> tags cons+      ClassDecl { tcdSigs = meths+                , tcdATs  = ats+                } -> tags (meths, ats)+      _ -> []++#if MIN_VERSION_ghc(8,4,0)+instance (IdP pass ~ name, TagName name) => HasTags (ConDecl pass) where+#else+instance TagName name => HasTags (ConDecl name) where+#endif+#if MIN_VERSION_ghc(8,6,1)+    tags (ConDeclGADT _ cns _ _ _ _ _ _) = concatMap tagsLN cns+    tags (ConDeclH98 _ cn _ _ _ cd _)    = tagsLN cn ++ tags cd+    tags (XConDecl _)                    = missingImp "XConDecl"+#else+  tags (ConDeclGADT cns _ _)    = concatMap tagsLN cns+  tags (ConDeclH98 cn _ _ cd _) = tagsLN cn ++ tags cd+#endif++#if MIN_VERSION_ghc(8,4,0)+instance (IdP pass ~ name, TagName name) => HasTags (ConDeclField pass) where+#else+instance TagName name => HasTags (ConDeclField name) where+#endif+#if MIN_VERSION_ghc(8,6,1)+  tags (ConDeclField _ x _ _) = concatMap tagsLN x+  tags (XConDeclField _)      = missingImp "XConDeclField"+#else+  tags (ConDeclField x _ _) = concatMap tagsLN x+#endif++-- Dummy instance.+instance HasTags (HsType name) where+  tags _ = []++#if MIN_VERSION_ghc(8,4,0)+instance ( IdP pass ~ name+         , TagName name+#if MIN_VERSION_ghc(8,10,1)+         , HasTags (XRec pass Pat)+#endif+         ) => HasTags (HsBind pass) where+#else+instance TagName name => HasTags (HsBind name) where+#endif+  tags d = case d of+    FunBind  { fun_id    = x   }      -> tagsLN x+    PatBind  { pat_lhs   = lhs }      -> tags lhs+    VarBind  { var_id    = x   }      -> tagsN x+    AbsBinds { abs_binds = bs  }      -> tags bs+#if !MIN_VERSION_ghc(8,4,1)+    AbsBindsSig { abs_sig_bind = bs } -> tags bs+#endif+#if MIN_VERSION_ghc(8,6,1)+    PatSynBind _ (PSB { psb_id = x }) -> tagsLN x+    PatSynBind _ XPatSynBind{}        -> missingImp "XPatSynBindPSB"+    XHsBindsLR{}                      -> missingImp "XHsBindsLR"+#else+    PatSynBind (PSB { psb_id = x }) -> tagsLN x+#endif+++#if MIN_VERSION_ghc(8,4,0)+instance ( IdP pass ~ name+         , TagName name+#if MIN_VERSION_ghc(8,10,1)+         , HasTags (XRec pass Pat)+#endif+         ) => HasTags (Pat pass) where+#else+instance TagName name => HasTags (Pat name) where+#endif+  tags p = case p of+#if MIN_VERSION_ghc(8,6,1)+    VarPat _ x                 -> tagsLN x+#else+    VarPat x                   -> tagsLN x+#endif+#if MIN_VERSION_ghc(8,8,1)+    SigPat _ p _               -> tags p+#elif MIN_VERSION_ghc(8,6,1)+    SigPat _ p                 -> tags p+#endif+#if MIN_VERSION_ghc(8,6,1)+    LazyPat _ p                -> tags p+    AsPat _ x p                -> tags (fmap Name x, p)+    ParPat _ p                 -> tags p+    BangPat _ p                -> tags p+    ListPat _ ps               -> tags ps+    TuplePat _ ps _            -> tags ps+    XPat _                     -> missingImp "XPat"+#else+    LazyPat p                  -> tags p+    AsPat x p                  -> tags (fmap Name x, p)+    ParPat p                   -> tags p+    BangPat p                  -> tags p+    ListPat ps _ _             -> tags ps+    TuplePat ps _ _            -> tags ps+    SigPatIn p _               -> tags p+    SigPatOut p _              -> tags p+    PArrPat ps _               -> tags ps+#endif+#if MIN_VERSION_ghc(9,0,0)+    ConPat   { pat_args = ps } -> tags ps+#else+    ConPatIn _ ps              -> tags ps+    ConPatOut{ pat_args = ps } -> tags ps+    CoPat{}                    -> []+#endif+#if MIN_VERSION_ghc(8,6,1)+    NPlusKPat _ x _ _ _ _      -> tagsLN x+#else+    NPlusKPat x _ _ _ _ _      -> tagsLN x+#endif+    NPat{}                     -> []+    LitPat{}                   -> []+    WildPat{}                  -> []+    ViewPat{}                  -> []+    SplicePat{}                -> []+#if MIN_VERSION_ghc(8,2,0)+    SumPat{}                   -> missingImp "SumPat"+#endif++#if MIN_VERSION_ghc(9,0,0)+instance HasTags arg => HasTags (HsScaled pass arg) where+  tags = tags . hsScaledThing+#endif++instance (HasTags arg, HasTags recc) => HasTags (HsConDetails arg recc) where+  tags d = case d of+    PrefixCon as   -> tags as+    RecCon r       -> tags r+    InfixCon a1 a2 -> tags [a1, a2]++instance HasTags arg => HasTags (HsRecFields name arg) where+  tags (HsRecFields fs _) = tags fs++instance HasTags arg => HasTags (HsRecField name arg) where+  tags (HsRecField _ a _) = tags a++#if MIN_VERSION_ghc(8,4,0)+instance (IdP pass ~ name, TagName name) => HasTags (Sig pass) where+#else+instance TagName name => HasTags (Sig name) where+#endif+  tags d = case d of+#if MIN_VERSION_ghc(8,6,1)+    TypeSig _ x _       -> concatMap tagsLN x+#else+    TypeSig x _         -> concatMap tagsLN x+#endif+#if MIN_VERSION_ghc(8,6,1)+    PatSynSig _ x _      -> concatMap tagsLN x+#elif MIN_VERSION_ghc(8,2,0)+    PatSynSig x _       -> concatMap tagsLN x+#else+    PatSynSig x _       -> tagsLN x+#endif+#if MIN_VERSION_ghc(8,6,1)+    ClassOpSig _ _ x _   -> concatMap tagsLN x+#else+    ClassOpSig _ x _    -> concatMap tagsLN x+#endif+    FixSig{}            -> []+    InlineSig{}         -> []+    SpecSig{}           -> []+    SpecInstSig{}       -> []+    IdSig{}             -> []+    MinimalSig{}        -> []+#if MIN_VERSION_ghc(8,2,0)+    SCCFunSig{}         -> []+    CompleteMatchSig{}  -> []+#endif+#if MIN_VERSION_ghc(8,6,1)+    XSig{}              -> missingImp "XSig"+#endif++#if MIN_VERSION_ghc(8,4,0)+instance (IdP pass ~ name, TagName name) => HasTags (ForeignDecl pass) where+#else+instance TagName name => HasTags (ForeignDecl name) where+#endif+  tags d = case d of+#if MIN_VERSION_ghc(8,6,1)+    ForeignImport _ x _ _ -> tagsLN x+    XForeignDecl _        -> missingImp "XForeignDecl"+#else+    ForeignImport x _ _ _ -> tagsLN x+#endif+    ForeignExport{}       -> []++#if MIN_VERSION_ghc(8,10,1)+instance (IdP pass ~ name, TagName name) => HasTags (StandaloneKindSig pass) where+  tags d = case d of+    StandaloneKindSig _ x _ -> tagsLN x+    XStandaloneKindSig _    -> missingImp "XStandaloneKindSig"+#endif++missingImp :: String -> a+missingImp x = error $ "Missing implementation: " ++ x
+ hs-tags.cabal view
@@ -0,0 +1,59 @@+name:            hs-tags+version:         0.1.5+cabal-version:   >= 1.10+build-type:      Simple+license:         MIT+license-file:    LICENSE+copyright:       (c) 2005-2021 The Agda Team.+author:          Ulf Norell, Nils Anders Danielsson, Andrés Sicard-Ramírez, Andreas Abel, Francesco Mazzoli, Paolo G. Giarrusso+maintainer:      Andreas Abel <andreas.abel@gu.se>+bug-reports:     https://github.com/agda/hs-tags/issues+category:        Development+synopsis:        Create tag files (ctags and etags) for Haskell code.+description:     .+  Executable to generate a tags (ctags) or TAGS (etags) file+  for a bunch of Haskell files.+  These files are used by editors (e.g. TAGS by Emacs) to+  implement jump-to-definition (e.g. M-. in Emacs).++tested-with:+  GHC == 8.0.2+  GHC == 8.2.2+  GHC == 8.4.4+  GHC == 8.6.5+  GHC == 8.8.4+  GHC == 8.10.4+  GHC == 9.0.1++extra-source-files:+  CHANGELOG.md+  README.md++source-repository head+  type:     git+  location: https://github.com/agda/hs-tags.git++source-repository this+  type:     git+  location: https://github.com/agda/hs-tags.git+  tag:      v0.1.5++executable hs-tags+  main-is:          Main.hs+  other-modules:    Tags+                    Paths_hs_tags++  default-language: Haskell2010++  build-depends:+      base        >= 4.9.0.0   &&  < 4.16+    , Cabal       >= 1.24.0.0  &&  < 3.5+    , containers  >= 0.5.7.1   &&  < 0.7+    , directory   >= 1.2.6.2   &&  < 1.4+    , filepath    >= 1.4.1.0   &&  < 1.5+    , ghc         >= 8.0.2     &&  < 9.1+    , mtl         >= 2.2.1     &&  < 2.3+    , process     >= 1.4.2.0   &&  < 1.7+    , strict      >= 0.3.2     &&  < 0.5++  ghc-options: -fwarn-incomplete-patterns