luqui / hothasktags Goto Github PK
View Code? Open in Web Editor NEWA haskell ctags implementation that is aware of qualified imports, among other cool stuff
License: BSD 3-Clause "New" or "Revised" License
A haskell ctags implementation that is aware of qualified imports, among other cool stuff
License: BSD 3-Clause "New" or "Revised" License
Hi,
cpphs-1.19 has been released, please consider upgrading hothasktags and uploading that to hackage.
Also, consider joining stackage (http://www.stackage.org/authors) to streamline the process. This would help downstream packages (e.g. Debian) a lot.
Thanks,
Joachim
Hi,
it seems that hothasktags needs to be adjusted to work with the latest haskell-src-exts:
Main.hs:134:21:
Constructor `L.EVar' should have 2 arguments, but has been given 3
In the pattern: L.EVar _ _ (L.UnQual _ (L.Ident _ name'))
In an equation for `matchesSpec':
matchesSpec nm (L.EVar _ _ (L.UnQual _ (L.Ident _ name')))
= nm == name'
In an equation for `exported':
exported
mod'@(L.Module _
(Just (L.ModuleHead _ _ _ (Just (L.ExportSpecList _ specs))))
_
_
_)
name
= any (matchesSpec name) specs
where
matchesSpec nm (L.EVar _ _ (L.UnQual _ (L.Ident _ name')))
= nm == name'
matchesSpec nm (L.EAbs _ (L.UnQual _ (L.Ident _ name')))
= nm == name'
matchesSpec nm (L.EThingAll _ (L.UnQual _ (L.Ident _ name')))
= nm == name' || (nm `elem` thingMembers mod' name')
matchesSpec
nm
(L.EThingWith _ (L.UnQual _ (L.Ident _ name')) cnames)
= nm == name' || any (matchesCName nm) cnames
matchesSpec _ (L.EModuleContents _ (L.ModuleName _ _)) = False
matchesSpec _ _ = False
matchesCName nm (L.VarName _ (L.Ident _ name')) = nm == name'
matchesCName nm (L.ConName _ (L.Ident _ name')) = nm == name'
matchesCName _ _ = False
Main.hs:192:21:
Constructor `L.IVar' should have 2 arguments, but has been given 3
In the pattern: L.IVar _ _ (L.Ident _ name')
In an equation for `specName':
specName (L.IVar _ _ (L.Ident _ name')) = [name']
In an equation for `extractImport':
extractImport
decl@(L.ImportDecl {L.importModule = L.ModuleName _ name,
L.importSpecs = spec})
= let
extraExports
| Just (L.ModuleHead _
_
_
(Just (L.ExportSpecList _ especs))) <- modhead
= Map.unions ...
| otherwise = Map.empty
in
Map.unions
[if L.importQualified decl then Map.empty else names,
Map.mapKeys ((name ++ ".") ++) names, ....]
where
names
| Just (L.ImportSpecList _ True specs) <- spec
= let ... in normalExports `Map.difference` Map.fromList s
| Just (L.ImportSpecList _ False specs) <- spec
= let ... in Map.filterWithKey f normalExports
| otherwise = normalExports
normalExports = modExports db name
specName (L.IVar _ _ (L.Ident _ name')) = [name']
specName (L.IAbs _ (L.Ident _ name')) = [name']
specName (L.IThingAll _ (L.Ident _ name')) = [name']
specName (L.IThingWith _ (L.Ident _ name') cnames)
= name' : concatMap cname cnames
specName _ = []
cname (L.VarName _ (L.Ident _ name')) = [name']
cname (L.ConName _ (L.Ident _ name')) = [name']
cname _ = []
Furtheremore, upper bounds on haskell-src-exts would be prudent, given that they regularly change the API. And you might want to join stackage so that you will be notified of these issues before your users notice.
Thanks,
Joachim
Build fails, likely there is a missing upper bound on haskell-src-exts
.
$ cabal install hothasktags
Resolving dependencies...
Build profile: -w ghc-9.0.1 -O1
In order, the following will be built (use -v for more details):
- haskell-src-exts-1.23.1 (lib) (requires build)
- old-locale-1.0.0.7 (lib) (requires build)
- unix-compat-0.5.3 (lib) (requires build)
- old-time-1.1.0.3 (lib:old-time) (requires build)
- filemanip-0.3.6.3 (lib:filemanip) (requires build)
- cpphs-1.19.3 (lib:cpphs) (requires download & build)
- hothasktags-0.3.5 (exe:hothasktags) (requires download & build)
...
Building executable 'hothasktags' for hothasktags-0.3.5..
[1 of 1] Compiling Main ( Main.hs, dist/build/hothasktags/hothasktags-tmp/Main.o )
Main.hs:7:1: error:
Could not find module ‘Language.Haskell.Exts.Annotated’
Perhaps you meant
Language.Haskell.Exts.Syntax (needs flag -package-id haskell-src-exts-1.21.1)
Language.Haskell.Exts.Syntax (needs flag -package-id haskell-src-exts-1.23.1)
Language.Haskell.Exts.Syntax (from haskell-src-exts-1.23.1)
Use -v (or `:set -v` in ghci) to see a list of the files searched for.
|
7 | import qualified Language.Haskell.Exts.Annotated as L
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
cabal: Failed to build hothasktags-0.3.5.
The haskell-src-exts 1.15 supports for LambdaCase extension syntax.
I've built the hothasktags from the github with haskell-src-exts 1.15. It works ^^
So hothasktags doesn't seem to generate tags for with source files lacking module
declarations. Is that deliberate?
I have a fair number of code snippets sitting around, and I just realized that I wasn't able to jump around within such files as I can in normal ones. Might be nice. Presumably I can attack that by dealing with the Nothing
module name case when parsing, if you say it's ok to have a go at.
A related matter is that if you have files TheoreticalSnippet.hs and ExperimentalSnippet.hs both with
module Snippet where
then tags get generated for the first file but not the second. This would presumably be something to do with the Map being used. That might be a bit more involved to deal with, and I wanted to check with you that you weren't relying on the behaviour of keys being merged.
AfC
I've recently been working on a project at work that involves defining a lot of different datat ypes, all with similar class instances, so I decided to save a lot of work by using a CPP macro to define the data types and their instances. The problem with this is that these types now no longer show up when trying to jump to their tag. So I think it would be beneficial to check to see if CPP is one of the mentioned language extensions, and run that, then scan the file for definitions.
There's also no upper bound, so it will still pick it.
[1 of 1] Compiling Main ( Main.hs, dist/dist-sandbox-2474cf16/build/hothasktags/hothasktags-tmp/Main.o )
Main.hs:33:14:
Constructor ‘L.PatBind’ should have 4 arguments, but has been given 5
In the pattern: L.PatBind _ pat _ _ _
In an equation for ‘extract’:
extract (L.PatBind _ pat _ _ _) = extractPat pat
In an equation for ‘localDecls’:
localDecls (L.Module _ _ _ _ decls)
= Map.fromList $ concatMap extract decls
where
extract (L.TypeDecl _ head _) = extractDeclHead head
extract (L.TypeFamDecl _ head _) = extractDeclHead head
extract (L.DataDecl _ _ _ head decls _)
= extractDeclHead head ++ concatMap extractQualConDecl decls
extract (L.GDataDecl _ _ _ head _ decls _)
= extractDeclHead head ++ concatMap extractGadtDecl decls
extract (L.DataFamDecl _ _ head _) = extractDeclHead head
extract (L.ClassDecl _ _ head _ clsdecls)
= extractDeclHead head
++ concatMap extractClassDecl (fromMaybe [] clsdecls)
extract (L.TypeSig _ names _) = concatMap extractName names
extract (L.FunBind _ (L.Match _ name _ _ _ : _)) = extractName name
extract (L.FunBind _ (L.InfixMatch _ _ name _ _ _ : _))
= extractName name
extract (L.PatBind _ pat _ _ _) = extractPat pat
extract (L.ForImp _ _ _ _ name _) = extractName name
extract _ = []
extractDeclHead (L.DHead _ name _) = extractName name
extractDeclHead (L.DHInfix _ _ name _) = extractName name
extractDeclHead (L.DHParen _ head') = extractDeclHead head'
extractPat (L.PVar _ name) = extractName name
extractPat (L.PApp _ _ pats) = concatMap extractPat pats
extractPat (L.PTuple _ _ pats) = concatMap extractPat pats
extractPat (L.PList _ pats) = concatMap extractPat pats
extractPat (L.PParen _ pat) = extractPat pat
extractPat (L.PAsPat _ name pat)
= extractName name ++ extractPat pat
extractPat (L.PIrrPat _ pat) = extractPat pat
extractPat (L.PatTypeSig _ pat _) = extractPat pat
extractPat (L.PBangPat _ pat) = extractPat pat
extractPat _ = []
extractQualConDecl (L.QualConDecl _ _ _ (L.ConDecl _ name _))
= extractName name
extractQualConDecl (L.QualConDecl _ _ _ (L.RecDecl _ name fields))
= extractName name ++ concatMap extractFieldDecl fields
extractQualConDecl _ = []
....
Main.hs:37:22:
Constructor ‘L.DHead’ should have 2 arguments, but has been given 3
In the pattern: L.DHead _ name _
In an equation for ‘extractDeclHead’:
extractDeclHead (L.DHead _ name _) = extractName name
In an equation for ‘localDecls’:
localDecls (L.Module _ _ _ _ decls)
= Map.fromList $ concatMap extract decls
where
extract (L.TypeDecl _ head _) = extractDeclHead head
extract (L.TypeFamDecl _ head _) = extractDeclHead head
extract (L.DataDecl _ _ _ head decls _)
= extractDeclHead head ++ concatMap extractQualConDecl decls
extract (L.GDataDecl _ _ _ head _ decls _)
= extractDeclHead head ++ concatMap extractGadtDecl decls
extract (L.DataFamDecl _ _ head _) = extractDeclHead head
extract (L.ClassDecl _ _ head _ clsdecls)
= extractDeclHead head
++ concatMap extractClassDecl (fromMaybe [] clsdecls)
extract (L.TypeSig _ names _) = concatMap extractName names
extract (L.FunBind _ (L.Match _ name _ _ _ : _)) = extractName name
extract (L.FunBind _ (L.InfixMatch _ _ name _ _ _ : _))
= extractName name
extract (L.PatBind _ pat _ _ _) = extractPat pat
extract (L.ForImp _ _ _ _ name _) = extractName name
extract _ = []
extractDeclHead (L.DHead _ name _) = extractName name
extractDeclHead (L.DHInfix _ _ name _) = extractName name
extractDeclHead (L.DHParen _ head') = extractDeclHead head'
extractPat (L.PVar _ name) = extractName name
extractPat (L.PApp _ _ pats) = concatMap extractPat pats
extractPat (L.PTuple _ _ pats) = concatMap extractPat pats
extractPat (L.PList _ pats) = concatMap extractPat pats
extractPat (L.PParen _ pat) = extractPat pat
extractPat (L.PAsPat _ name pat)
= extractName name ++ extractPat pat
extractPat (L.PIrrPat _ pat) = extractPat pat
extractPat (L.PatTypeSig _ pat _) = extractPat pat
extractPat (L.PBangPat _ pat) = extractPat pat
extractPat _ = []
extractQualConDecl (L.QualConDecl _ _ _ (L.ConDecl _ name _))
= extractName name
extractQualConDecl (L.QualConDecl _ _ _ (L.RecDecl _ name fields))
= extractName name ++ concatMap extractFieldDecl fields
extractQualConDecl _ = []
....
Main.hs:58:22:
Constructor ‘L.GadtDecl’ should have 4 arguments, but has been given 3
In the pattern: L.GadtDecl _ name _
In an equation for ‘extractGadtDecl’:
extractGadtDecl (L.GadtDecl _ name _) = extractName name
In an equation for ‘localDecls’:
localDecls (L.Module _ _ _ _ decls)
= Map.fromList $ concatMap extract decls
where
extract (L.TypeDecl _ head _) = extractDeclHead head
extract (L.TypeFamDecl _ head _) = extractDeclHead head
extract (L.DataDecl _ _ _ head decls _)
= extractDeclHead head ++ concatMap extractQualConDecl decls
extract (L.GDataDecl _ _ _ head _ decls _)
= extractDeclHead head ++ concatMap extractGadtDecl decls
extract (L.DataFamDecl _ _ head _) = extractDeclHead head
extract (L.ClassDecl _ _ head _ clsdecls)
= extractDeclHead head
++ concatMap extractClassDecl (fromMaybe [] clsdecls)
extract (L.TypeSig _ names _) = concatMap extractName names
extract (L.FunBind _ (L.Match _ name _ _ _ : _)) = extractName name
extract (L.FunBind _ (L.InfixMatch _ _ name _ _ _ : _))
= extractName name
extract (L.PatBind _ pat _ _ _) = extractPat pat
extract (L.ForImp _ _ _ _ name _) = extractName name
extract _ = []
extractDeclHead (L.DHead _ name _) = extractName name
extractDeclHead (L.DHInfix _ _ name _) = extractName name
extractDeclHead (L.DHParen _ head') = extractDeclHead head'
extractPat (L.PVar _ name) = extractName name
extractPat (L.PApp _ _ pats) = concatMap extractPat pats
extractPat (L.PTuple _ _ pats) = concatMap extractPat pats
extractPat (L.PList _ pats) = concatMap extractPat pats
extractPat (L.PParen _ pat) = extractPat pat
extractPat (L.PAsPat _ name pat)
= extractName name ++ extractPat pat
extractPat (L.PIrrPat _ pat) = extractPat pat
extractPat (L.PatTypeSig _ pat _) = extractPat pat
extractPat (L.PBangPat _ pat) = extractPat pat
extractPat _ = []
extractQualConDecl (L.QualConDecl _ _ _ (L.ConDecl _ name _))
= extractName name
extractQualConDecl (L.QualConDecl _ _ _ (L.RecDecl _ name fields))
= extractName name ++ concatMap extractFieldDecl fields
extractQualConDecl _ = []
....
Main.hs:85:18:
Constructor ‘L.GadtDecl’ should have 4 arguments, but has been given 3
In the pattern: L.GadtDecl _ name _
In an equation for ‘getGadtDecl’:
getGadtDecl (L.GadtDecl _ name _) = getName name
In an equation for ‘thingMembers’:
thingMembers (L.Module _ _ _ _ decls) name
= concatMap extract decls
where
extract (L.DataDecl _ _ _ head condecls _)
| nameOfHead head == Just name = concatMap getQualConDecl condecls
extract (L.GDataDecl _ _ _ head _ condecls _)
| nameOfHead head == Just name = concatMap getGadtDecl condecls
extract (L.ClassDecl _ _ head _ (Just classdecls))
| nameOfHead head == Just name = concatMap getClassDecl classdecls
extract _ = []
getQualConDecl
(L.QualConDecl _ _ _ (L.ConDecl _ (L.Ident _ name) _))
= [name]
getQualConDecl
(L.QualConDecl _ _ _ (L.RecDecl _ (L.Ident _ name) fields))
= name : concatMap getField fields
getQualConDecl _ = []
getGadtDecl (L.GadtDecl _ name _) = getName name
getField (L.FieldDecl _ names _) = concatMap getName names
....
Main.hs:90:32:
Constructor ‘L.PatBind’ should have 4 arguments, but has been given 5
In the pattern: L.PatBind _ (L.PVar _ name) _ _ _
In the pattern: L.ClsDecl _ (L.PatBind _ (L.PVar _ name) _ _ _)
In an equation for ‘getClassDecl’:
getClassDecl (L.ClsDecl _ (L.PatBind _ (L.PVar _ name) _ _ _))
= getName name
Main.hs:96:17:
Constructor ‘L.DHead’ should have 2 arguments, but has been given 3
In the pattern: L.DHead _ (L.Ident _ name) _
In an equation for ‘nameOfHead’:
nameOfHead (L.DHead _ (L.Ident _ name) _) = Just name
In an equation for ‘thingMembers’:
thingMembers (L.Module _ _ _ _ decls) name
= concatMap extract decls
where
extract (L.DataDecl _ _ _ head condecls _)
| nameOfHead head == Just name = concatMap getQualConDecl condecls
extract (L.GDataDecl _ _ _ head _ condecls _)
| nameOfHead head == Just name = concatMap getGadtDecl condecls
extract (L.ClassDecl _ _ head _ (Just classdecls))
| nameOfHead head == Just name = concatMap getClassDecl classdecls
extract _ = []
getQualConDecl
(L.QualConDecl _ _ _ (L.ConDecl _ (L.Ident _ name) _))
= [name]
getQualConDecl
(L.QualConDecl _ _ _ (L.RecDecl _ (L.Ident _ name) fields))
= name : concatMap getField fields
getQualConDecl _ = []
getGadtDecl (L.GadtDecl _ name _) = getName name
getField (L.FieldDecl _ names _) = concatMap getName names
....
Main.hs:111:23:
Constructor ‘L.EVar’ should have 3 arguments, but has been given 2
In the pattern: L.EVar _ (L.UnQual _ (L.Ident _ name'))
In an equation for ‘matchesSpec’:
matchesSpec name (L.EVar _ (L.UnQual _ (L.Ident _ name')))
= name == name'
In an equation for ‘exported’:
exported
mod@(L.Module _
(Just (L.ModuleHead _ _ _ (Just (L.ExportSpecList _ specs))))
_
_
_)
name
= any (matchesSpec name) specs
where
matchesSpec name (L.EVar _ (L.UnQual _ (L.Ident _ name')))
= name == name'
matchesSpec name (L.EAbs _ (L.UnQual _ (L.Ident _ name')))
= name == name'
matchesSpec name (L.EThingAll _ (L.UnQual _ (L.Ident _ name')))
= name == name' || (name `elem` thingMembers mod name')
matchesSpec
name
(L.EThingWith _ (L.UnQual _ (L.Ident _ name')) cnames)
= name == name' || any (matchesCName name) cnames
matchesSpec _ (L.EModuleContents _ (L.ModuleName _ _)) = False
matchesSpec _ _ = False
matchesCName name (L.VarName _ (L.Ident _ name')) = name == name'
matchesCName name (L.ConName _ (L.Ident _ name')) = name == name'
matchesCName _ _ = False
Main.hs:154:19:
Constructor ‘L.IVar’ should have 3 arguments, but has been given 2
In the pattern: L.IVar _ (L.Ident _ name)
In an equation for ‘specName’:
specName (L.IVar _ (L.Ident _ name)) = [name]
In an equation for ‘extractImport’:
extractImport
decl@(L.ImportDecl {L.importModule = L.ModuleName _ name,
L.importSpecs = spec})
= Map.unions
[if L.importQualified decl then Map.empty else names,
Map.mapKeys ((name ++ ".") ++) names,
case L.importAs decl of {
Nothing -> Map.empty
Just (L.ModuleName _ name')
-> Map.mapKeys ((name' ++ ".") ++) names },
....]
where
names
| Just (L.ImportSpecList _ True specs) <- spec
= normalExports
`Map.difference`
(Map.fromList (map (flip (,) ()) (concatMap specName specs)))
| Just (L.ImportSpecList _ False specs) <- spec
= Map.filterWithKey
(\ k _ -> k `elem` concatMap specName specs) normalExports
| otherwise = normalExports
normalExports = modExports db name
specName (L.IVar _ (L.Ident _ name)) = [name]
specName (L.IAbs _ (L.Ident _ name)) = [name]
specName (L.IThingAll _ (L.Ident _ name)) = [name]
specName (L.IThingWith _ (L.Ident _ name) cnames)
= name : concatMap cname cnames
specName _ = []
cname (L.VarName _ (L.Ident _ name)) = [name]
cname (L.ConName _ (L.Ident _ name)) = [name]
cname _ = []
Is it possible to update a tags file by running hothasktags only on the changed Haskell source file, not on all source files?
This would be nice, than I could use an autocmd in Vim that updates the tags when a source file is written.
If I have a custom preprocessor specified with a pragma {-# OPTIONS_GHC -F -pgmF HListPP #-}
(or as a command line argument), hothasktags does not run it.
I used hothasktags to create a TAGS file, but Emacs says:
visit-tags-table-buffer: File /Users/johnw/src/haskell/TAGS is not a valid tags table
Are you expecting that it should work? Have I done something wrong? I ran:
find general-prelude gitlib hsubconvert stringable svndump -name '*.hs' | xargs hothasktags > TAGS
Looks like this package needs updating for src-exts 1.23.
It would be great if hothasktags were compatible with cpphs >=1.20 (the current release is 1.20.1). Thanks.
Hello,
hothasktags no longer compiles with the last version of haskell-src-exts. I've made a patch that solves the compatibility problems, but I didn't prepare a pull request because I wasn't sure about some of my solutions. Here you'll find the patch:
Cheers.
(not a bug report so much as a set of questions for you to comment on before I do some hacking)
It's a bit of a pain to have to:
$ find src | xargs hothasktags
if I look at the hasktags program from the the hasktags package (which I used to use), invocation is:
$ hasktags -c src tests
which raises another point; I can list multiple directories. Yes, you can be more clever about this with some fancier shell scripting, but thought I'd mention it, although, having done so,
$ hasktags -c .
works too, and so would find . -type -f -name '*.hs'
. Either way, it would be nice if hothasktags could take care of the recursive descent to find Haskell source files itself. I'll use filemanip for that if that's ok?
The second matter is that it's a bit obscure to have to redirect the output.
$ find ... | xargs hothasktags > tags
Surely just writing ./tags
would do the trick?
Anyway, right now I have the whole long invocation as a target in my Makefile, but it's a bit of a pain to run casually in the tree of someone else's project, which is why I raised this. Love to be able to just do
$ hothasktags .
or so.
AfC
hothasktags is not compatible with haskell-src-exts 1.18 nor haskell-src-exts 1.19.
Please consider updating it. Thanks!
I'm having problems like this:
hothasktags: Cannot expand #if directive in file Annex.hs at line 83 col 1:
MIN_VERSION_exceptions(a,b,c) is not a defined macro
(Oddly, earlier versions of hothasktags seemed to work.)
While I can work around with with -D 'MIN_VERSION_exceptions(1,1,1)', new version macros are added from time to time..
Seems that the solution could be to -c --include=dist/build/autogen/cabal_macros.h to get all the macros. But that fails:
Parse error: SrcLoc {srcFilename = "./dist/build/autogen/cabal_macros.h", srcLine = 1, srcColumn = 1}: Parse error: /*
The problem is the /* */ comments in the file.
I have worked around that by preprocessing the .h file before calling hothasktags, to remove the comments.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.