├── cabal.project ├── tests ├── inputFiles │ ├── ModuleTest0.hs │ ├── SymbolTest0.hs │ ├── ModuleTest1.hs │ ├── SymbolTest1.hs │ ├── ModuleTest10.hs │ ├── ModuleTest13.hs │ ├── SymbolTest26.hs │ ├── ModuleTest11.hs │ ├── ModuleTest12.hs │ ├── ModuleTest2.hs │ ├── SymbolTest2.hs │ ├── ModuleTest14.hs │ ├── SymbolTest17.hs │ ├── ModuleTest3.hs │ ├── SymbolTest3.hs │ ├── SymbolTest18.hs │ ├── SymbolTest19.hs │ ├── SymbolTest20.hs │ ├── SymbolTest24.hs │ ├── SymbolTest25.hs │ ├── ModuleTest15.hs │ ├── ModuleTest17.hs │ ├── ModuleTest4.hs │ ├── SymbolTest4.hs │ ├── SymbolTest21.hs │ ├── SymbolTest22.hs │ ├── SymbolTest23.hs │ ├── ModuleTest16.hs │ ├── SymbolTest5.hs │ ├── ModuleTest5.hs │ ├── SymbolTest10.hs │ ├── SymbolTest6.hs │ ├── ModuleTest9.hs │ ├── SymbolTest9.hs │ ├── ModuleTest8.hs │ ├── SymbolTest11.hs │ ├── SymbolTest7.hs │ ├── SymbolTest8.hs │ ├── SymbolTest12.hs │ ├── SymbolTest13.hs │ ├── SymbolTest14.hs │ ├── SymbolTest15.hs │ ├── ModuleTest6.hs │ ├── ModuleTest7.hs │ ├── ModuleTest18.hs │ ├── ModuleTest32.hs │ ├── ModuleTest35.hs │ ├── ModuleTest20.hs │ ├── ModuleTest19.hs │ ├── ParseTest2.hs │ ├── ModuleTest33.hs │ ├── ModuleTest36.hs │ ├── ReplaceCppTest3.hs │ ├── ModuleTest34.hs │ ├── ModuleTest21.hs │ ├── ModuleTest23.hs │ ├── ModuleTest25.hs │ ├── SymbolTest16.hs │ ├── SymbolTest30.hs │ ├── SymbolTest31.hs │ ├── SymbolTest41.hs │ ├── ModuleTest22.hs │ ├── SymbolTest32.hs │ ├── SymbolTest36.hs │ ├── SymbolTest37.hs │ ├── SymbolTest38.hs │ ├── SymbolTest39.hs │ ├── SymbolTest40.hs │ ├── SymbolTest42.hs │ ├── SymbolTest27.hs │ ├── ModuleTest24.hs │ ├── SymbolTest28.hs │ ├── SymbolTest29.hs │ ├── ModuleTest26.hs │ ├── ModuleTest27.hs │ ├── ModuleTest28.hs │ ├── ModuleTest31.hs │ ├── ParseTest1.hs │ ├── ModuleTest30.hs │ ├── ReplaceCppTest1.hs │ ├── ModuleTest38.hs │ ├── SymbolTest44.hs │ ├── SymbolTest45.hs │ ├── SymbolTest51.hs │ ├── SymbolTest46.hs │ ├── SymbolTest47.hs │ ├── SymbolTest49.hs │ ├── SymbolTest50.hs │ ├── SymbolTest33.hs │ ├── SymbolTest35.hs │ ├── SymbolTest48.hs │ ├── ModuleTest29.hs │ ├── SymbolTest43.hs │ ├── ModuleTest37.hs │ ├── ReplaceCppTest2.hs │ └── SymbolTest34.hs ├── goldenFiles │ ├── ModuleTest0.hs │ ├── SymbolTest0.hs │ ├── ModuleTest1.hs │ ├── SymbolTest1.hs │ ├── SymbolTest26.hs │ ├── ModuleTest10.hs │ ├── ModuleTest13.hs │ ├── ModuleTest11.hs │ ├── ModuleTest12.hs │ ├── ModuleTest2.hs │ ├── SymbolTest2.hs │ ├── ModuleTest14.hs │ ├── SymbolTest18.hs │ ├── ModuleTest3.hs │ ├── SymbolTest3.hs │ ├── ModuleTest17.hs │ ├── SymbolTest19.hs │ ├── ModuleTest15.hs │ ├── ModuleTest4.hs │ ├── SymbolTest20.hs │ ├── SymbolTest21.hs │ ├── SymbolTest22.hs │ ├── SymbolTest23.hs │ ├── SymbolTest24.hs │ ├── SymbolTest4.hs │ ├── SymbolTest17.hs │ ├── SymbolTest25.hs │ ├── ModuleTest5.hs │ ├── SymbolTest5.hs │ ├── SymbolTest10.hs │ ├── SymbolTest6.hs │ ├── SymbolTest11.hs │ ├── SymbolTest12.hs │ ├── ModuleTest16.hs │ ├── SymbolTest13.hs │ ├── SymbolTest14.hs │ ├── SymbolTest15.hs │ ├── ModuleTest6.hs │ ├── ModuleTest9.hs │ ├── ModuleTest7.hs │ ├── ModuleTest8.hs │ ├── ReplaceCppTest3.hs │ ├── SymbolTest9.hs │ ├── SymbolTest7.hs │ ├── SymbolTest8.hs │ ├── ParseTest2.hs │ ├── ModuleTest18.hs │ ├── ModuleTest32.hs │ ├── ModuleTest35.hs │ ├── SymbolTest28.hs │ ├── SymbolTest31.hs │ ├── ModuleTest20.hs │ ├── ModuleTest19.hs │ ├── ModuleTest33.hs │ ├── ModuleTest36.hs │ ├── ReplaceCppTest1.hs │ ├── ModuleTest34.hs │ ├── SymbolTest27.hs │ ├── SymbolTest42.hs │ ├── ModuleTest21.hs │ ├── ParseTest1.hs │ ├── ReplaceCppTest2.hs │ ├── SymbolTest41.hs │ ├── ModuleTest25.hs │ ├── SymbolTest30.hs │ ├── ModuleTest22.hs │ ├── ModuleTest23.hs │ ├── ModuleTest24.hs │ ├── ModuleTest38.hs │ ├── SymbolTest44.hs │ ├── SymbolTest48.hs │ ├── SymbolTest49.hs │ ├── SymbolTest32.hs │ ├── SymbolTest45.hs │ ├── SymbolTest46.hs │ ├── SymbolTest47.hs │ ├── SymbolTest50.hs │ ├── SymbolTest29.hs │ ├── SymbolTest35.hs │ ├── SymbolTest37.hs │ ├── SymbolTest43.hs │ ├── ModuleTest26.hs │ ├── SymbolTest16.hs │ ├── SymbolTest33.hs │ ├── SymbolTest38.hs │ ├── ModuleTest27.hs │ ├── ModuleTest28.hs │ ├── ModuleTest30.hs │ ├── ModuleTest31.hs │ ├── SymbolTest39.hs │ ├── ModuleTest29.hs │ ├── SymbolTest40.hs │ ├── SymbolTest36.hs │ ├── SymbolTest34.hs │ ├── ModuleTest37.hs │ └── SymbolTest51.hs ├── outputFiles │ └── .gitignore ├── diffOutputsWithGoldens └── Main.hs ├── Setup.hs ├── exe └── Main.hs ├── .lvimrc ├── lib ├── HsImport.hs └── HsImport │ ├── ModuleImport.hs │ ├── PrettyPrint.hs │ ├── Utils.hs │ ├── Config.hs │ ├── SymbolImport.hs │ ├── Types.hs │ ├── Args.hs │ ├── ImportPos.hs │ ├── HsImportSpec.hs │ ├── Main.hs │ ├── Parse.hs │ └── ImportChange.hs ├── .gitignore ├── .github └── workflows │ └── haskell.yml ├── LICENSE ├── CHANGELOG ├── hsimport.cabal ├── README.md └── .travis.yml /cabal.project: -------------------------------------------------------------------------------- 1 | packages: ./ -------------------------------------------------------------------------------- /tests/inputFiles/ModuleTest0.hs: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/inputFiles/SymbolTest0.hs: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/goldenFiles/ModuleTest0.hs: -------------------------------------------------------------------------------- 1 | import Foo.Bar 2 | -------------------------------------------------------------------------------- /tests/inputFiles/ModuleTest1.hs: -------------------------------------------------------------------------------- 1 | module Test where 2 | -------------------------------------------------------------------------------- /tests/inputFiles/SymbolTest1.hs: -------------------------------------------------------------------------------- 1 | module Test where 2 | -------------------------------------------------------------------------------- /tests/outputFiles/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /tests/goldenFiles/SymbolTest0.hs: -------------------------------------------------------------------------------- 1 | import Foo.Bar (foo) 2 | -------------------------------------------------------------------------------- /Setup.hs: -------------------------------------------------------------------------------- 1 | import Distribution.Simple 2 | main = defaultMain 3 | -------------------------------------------------------------------------------- /tests/inputFiles/ModuleTest10.hs: -------------------------------------------------------------------------------- 1 | f :: Int -> Int 2 | f = (+ 3) 3 | -------------------------------------------------------------------------------- /tests/inputFiles/ModuleTest13.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | -------------------------------------------------------------------------------- /tests/goldenFiles/ModuleTest1.hs: -------------------------------------------------------------------------------- 1 | module Test where 2 | import Foo.Bar 3 | -------------------------------------------------------------------------------- /tests/goldenFiles/SymbolTest1.hs: -------------------------------------------------------------------------------- 1 | module Test where 2 | import Foo.Bar (foo) 3 | -------------------------------------------------------------------------------- /tests/inputFiles/SymbolTest26.hs: -------------------------------------------------------------------------------- 1 | import Foo (foo) 2 | boo :: Int 3 | boo = 3 4 | -------------------------------------------------------------------------------- /tests/goldenFiles/SymbolTest26.hs: -------------------------------------------------------------------------------- 1 | import Foo (foo, bar) 2 | boo :: Int 3 | boo = 3 4 | -------------------------------------------------------------------------------- /tests/goldenFiles/ModuleTest10.hs: -------------------------------------------------------------------------------- 1 | import Control.Monad 2 | f :: Int -> Int 3 | f = (+ 3) 4 | -------------------------------------------------------------------------------- /tests/goldenFiles/ModuleTest13.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | import Control.Monad 3 | -------------------------------------------------------------------------------- /tests/inputFiles/ModuleTest11.hs: -------------------------------------------------------------------------------- 1 | import Control.Blub 2 | f :: Int -> Int 3 | f = (+ 3) 4 | -------------------------------------------------------------------------------- /tests/inputFiles/ModuleTest12.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub where 3 | -------------------------------------------------------------------------------- /tests/inputFiles/ModuleTest2.hs: -------------------------------------------------------------------------------- 1 | module Test where 2 | import Foo.Bar 3 | import Ugah.Argh 4 | -------------------------------------------------------------------------------- /tests/inputFiles/SymbolTest2.hs: -------------------------------------------------------------------------------- 1 | module Test where 2 | import Foo.Bar 3 | import Ugah.Argh 4 | -------------------------------------------------------------------------------- /tests/inputFiles/ModuleTest14.hs: -------------------------------------------------------------------------------- 1 | module Blub 2 | ( blub 3 | , foo 4 | , bar 5 | ) where 6 | -------------------------------------------------------------------------------- /tests/inputFiles/SymbolTest17.hs: -------------------------------------------------------------------------------- 1 | module Blub 2 | ( blub 3 | , foo 4 | , bar 5 | ) where 6 | -------------------------------------------------------------------------------- /tests/goldenFiles/ModuleTest11.hs: -------------------------------------------------------------------------------- 1 | import Control.Blub 2 | import Control.Monad 3 | f :: Int -> Int 4 | f = (+ 3) 5 | -------------------------------------------------------------------------------- /tests/goldenFiles/ModuleTest12.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub where 3 | import Control.Monad 4 | -------------------------------------------------------------------------------- /tests/goldenFiles/ModuleTest2.hs: -------------------------------------------------------------------------------- 1 | module Test where 2 | import Foo.Bar 3 | import Foo.Bar.Blub 4 | import Ugah.Argh 5 | -------------------------------------------------------------------------------- /tests/inputFiles/ModuleTest3.hs: -------------------------------------------------------------------------------- 1 | module Test where 2 | import Foo.Bar 3 | import Foo.Bar.Blub 4 | import Ugah.Argh 5 | -------------------------------------------------------------------------------- /tests/inputFiles/SymbolTest3.hs: -------------------------------------------------------------------------------- 1 | module Test where 2 | import Foo.Bar 3 | import Foo.Bar.Blub 4 | import Ugah.Argh 5 | -------------------------------------------------------------------------------- /exe/Main.hs: -------------------------------------------------------------------------------- 1 | 2 | module Main where 3 | 4 | import HsImport 5 | 6 | main :: IO () 7 | main = hsimport defaultConfig 8 | -------------------------------------------------------------------------------- /tests/goldenFiles/SymbolTest2.hs: -------------------------------------------------------------------------------- 1 | module Test where 2 | import Foo.Bar 3 | import Foo.Bar.Blub (foo) 4 | import Ugah.Argh 5 | -------------------------------------------------------------------------------- /tests/goldenFiles/ModuleTest14.hs: -------------------------------------------------------------------------------- 1 | module Blub 2 | ( blub 3 | , foo 4 | , bar 5 | ) where 6 | import Control.Monad 7 | -------------------------------------------------------------------------------- /tests/goldenFiles/SymbolTest18.hs: -------------------------------------------------------------------------------- 1 | module Blub 2 | ( blub 3 | , foo 4 | , bar 5 | ) where 6 | import Data.Text (Text) 7 | -------------------------------------------------------------------------------- /tests/inputFiles/SymbolTest18.hs: -------------------------------------------------------------------------------- 1 | module Blub 2 | ( blub 3 | , foo 4 | , bar 5 | ) where 6 | import Data.Text (Text) 7 | -------------------------------------------------------------------------------- /tests/inputFiles/SymbolTest19.hs: -------------------------------------------------------------------------------- 1 | module Blub 2 | ( blub 3 | , foo 4 | , bar 5 | ) where 6 | import Data.Text (Text) 7 | -------------------------------------------------------------------------------- /tests/inputFiles/SymbolTest20.hs: -------------------------------------------------------------------------------- 1 | module Blub 2 | ( blub 3 | , foo 4 | , bar 5 | ) where 6 | import Data.Text (Text) 7 | -------------------------------------------------------------------------------- /tests/inputFiles/SymbolTest24.hs: -------------------------------------------------------------------------------- 1 | module Blub 2 | ( blub 3 | , foo 4 | , bar 5 | ) where 6 | import Data.Text (Text) 7 | -------------------------------------------------------------------------------- /tests/inputFiles/SymbolTest25.hs: -------------------------------------------------------------------------------- 1 | module Blub 2 | ( blub 3 | , foo 4 | , bar 5 | ) where 6 | import Data.Text (Text) 7 | -------------------------------------------------------------------------------- /tests/inputFiles/ModuleTest15.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | -------------------------------------------------------------------------------- /tests/inputFiles/ModuleTest17.hs: -------------------------------------------------------------------------------- 1 | module Blub 2 | ( blub 3 | , foo 4 | , bar 5 | ) where 6 | f :: Int -> Int 7 | f = (+ 3) 8 | -------------------------------------------------------------------------------- /tests/goldenFiles/ModuleTest3.hs: -------------------------------------------------------------------------------- 1 | module Test where 2 | import Foo.Bar 3 | import Foo.Bar.Blub 4 | import Ugah.Argh 5 | import Control.Monad 6 | -------------------------------------------------------------------------------- /tests/inputFiles/ModuleTest4.hs: -------------------------------------------------------------------------------- 1 | module Test where 2 | import Foo.Bar 3 | import Foo.Bar.Blub 4 | import Ugah.Argh 5 | import Control.Monad 6 | -------------------------------------------------------------------------------- /tests/inputFiles/SymbolTest4.hs: -------------------------------------------------------------------------------- 1 | module Test where 2 | import Foo.Bar 3 | import Foo.Bar.Blub 4 | import Ugah.Argh 5 | import Control.Monad 6 | -------------------------------------------------------------------------------- /tests/goldenFiles/SymbolTest3.hs: -------------------------------------------------------------------------------- 1 | module Test where 2 | import Foo.Bar 3 | import Foo.Bar.Blub 4 | import Ugah.Argh 5 | import Control.Monad (when) 6 | -------------------------------------------------------------------------------- /tests/goldenFiles/ModuleTest17.hs: -------------------------------------------------------------------------------- 1 | module Blub 2 | ( blub 3 | , foo 4 | , bar 5 | ) where 6 | import Control.Monad 7 | f :: Int -> Int 8 | f = (+ 3) 9 | -------------------------------------------------------------------------------- /tests/goldenFiles/SymbolTest19.hs: -------------------------------------------------------------------------------- 1 | module Blub 2 | ( blub 3 | , foo 4 | , bar 5 | ) where 6 | import Data.Text (Text) 7 | import Data.List (foldl') 8 | -------------------------------------------------------------------------------- /tests/goldenFiles/ModuleTest15.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Control.Monad 8 | -------------------------------------------------------------------------------- /tests/goldenFiles/ModuleTest4.hs: -------------------------------------------------------------------------------- 1 | module Test where 2 | import Foo.Bar 3 | import Foo.Bar.Blub 4 | import Ugah.Argh 5 | import Ugah.Argh2 6 | import Control.Monad 7 | -------------------------------------------------------------------------------- /tests/goldenFiles/SymbolTest20.hs: -------------------------------------------------------------------------------- 1 | module Blub 2 | ( blub 3 | , foo 4 | , bar 5 | ) where 6 | import Data.Text (Text) 7 | import Data.Maybe (Maybe(..)) 8 | -------------------------------------------------------------------------------- /tests/goldenFiles/SymbolTest21.hs: -------------------------------------------------------------------------------- 1 | module Blub 2 | ( blub 3 | , foo 4 | , bar 5 | ) where 6 | import Data.Text (Text) 7 | import Data.Maybe (Maybe(..)) 8 | -------------------------------------------------------------------------------- /tests/goldenFiles/SymbolTest22.hs: -------------------------------------------------------------------------------- 1 | module Blub 2 | ( blub 3 | , foo 4 | , bar 5 | ) where 6 | import Data.Text (Text) 7 | import Data.Maybe (Maybe(..)) 8 | -------------------------------------------------------------------------------- /tests/goldenFiles/SymbolTest23.hs: -------------------------------------------------------------------------------- 1 | module Blub 2 | ( blub 3 | , foo 4 | , bar 5 | ) where 6 | import Data.Text (Text) 7 | import Data.Maybe (Maybe(..)) 8 | -------------------------------------------------------------------------------- /tests/goldenFiles/SymbolTest24.hs: -------------------------------------------------------------------------------- 1 | module Blub 2 | ( blub 3 | , foo 4 | , bar 5 | ) where 6 | import Data.Text (Text) 7 | import Data.Maybe (Maybe(Just)) 8 | -------------------------------------------------------------------------------- /tests/inputFiles/SymbolTest21.hs: -------------------------------------------------------------------------------- 1 | module Blub 2 | ( blub 3 | , foo 4 | , bar 5 | ) where 6 | import Data.Text (Text) 7 | import Data.Maybe (Maybe(..)) 8 | -------------------------------------------------------------------------------- /tests/inputFiles/SymbolTest22.hs: -------------------------------------------------------------------------------- 1 | module Blub 2 | ( blub 3 | , foo 4 | , bar 5 | ) where 6 | import Data.Text (Text) 7 | import Data.Maybe (Maybe(..)) 8 | -------------------------------------------------------------------------------- /tests/inputFiles/SymbolTest23.hs: -------------------------------------------------------------------------------- 1 | module Blub 2 | ( blub 3 | , foo 4 | , bar 5 | ) where 6 | import Data.Text (Text) 7 | import Data.Maybe (Maybe(..)) 8 | -------------------------------------------------------------------------------- /tests/goldenFiles/SymbolTest4.hs: -------------------------------------------------------------------------------- 1 | module Test where 2 | import Foo.Bar 3 | import Foo.Bar.Blub 4 | import Ugah.Argh 5 | import Ugah.Argh2 (argh) 6 | import Control.Monad 7 | -------------------------------------------------------------------------------- /tests/inputFiles/ModuleTest16.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | f :: Int -> Int 8 | f = (+ 3) 9 | -------------------------------------------------------------------------------- /.lvimrc: -------------------------------------------------------------------------------- 1 | " otherwise ghcid and quickfox doesn't work for the relative error paths of ghc 2 | set noautochdir 3 | 4 | let g:ghcid_command = 'cabal new-repl library-internal' 5 | -------------------------------------------------------------------------------- /tests/goldenFiles/SymbolTest17.hs: -------------------------------------------------------------------------------- 1 | module Blub 2 | ( blub 3 | , foo 4 | , bar 5 | ) where 6 | import Control.Monad (when) 7 | import qualified Control.Monad as CM 8 | -------------------------------------------------------------------------------- /tests/goldenFiles/SymbolTest25.hs: -------------------------------------------------------------------------------- 1 | module Blub 2 | ( blub 3 | , foo 4 | , bar 5 | ) where 6 | import Data.Text (Text) 7 | import Data.Maybe (Maybe(Nothing, Just)) 8 | -------------------------------------------------------------------------------- /tests/goldenFiles/ModuleTest5.hs: -------------------------------------------------------------------------------- 1 | module Test where 2 | import Foo.Bar 3 | import Foo.Bar.Blub 4 | import Ugah.Argh 5 | import Control.Monad 6 | 7 | f :: Int -> Int 8 | f = (+ 3) 9 | -------------------------------------------------------------------------------- /tests/goldenFiles/SymbolTest5.hs: -------------------------------------------------------------------------------- 1 | module Test where 2 | import Foo.Bar 3 | import Foo.Bar.Blub 4 | import Ugah.Argh 5 | import Control.Monad 6 | 7 | f :: Int -> Int 8 | f = (+ 3) 9 | -------------------------------------------------------------------------------- /tests/inputFiles/SymbolTest5.hs: -------------------------------------------------------------------------------- 1 | module Test where 2 | import Foo.Bar 3 | import Foo.Bar.Blub 4 | import Ugah.Argh 5 | import Control.Monad 6 | 7 | f :: Int -> Int 8 | f = (+ 3) 9 | -------------------------------------------------------------------------------- /tests/inputFiles/ModuleTest5.hs: -------------------------------------------------------------------------------- 1 | module Test where 2 | import Foo.Bar 3 | import Foo.Bar.Blub 4 | import Ugah.Argh 5 | import Control.Monad (when) 6 | 7 | f :: Int -> Int 8 | f = (+ 3) 9 | -------------------------------------------------------------------------------- /tests/inputFiles/SymbolTest10.hs: -------------------------------------------------------------------------------- 1 | module Test where 2 | import Foo.Bar 3 | import Foo.Bar.Blub 4 | import Ugah.Argh 5 | import Control.Applicative 6 | 7 | f :: Int -> Int 8 | f = (+ 3) 9 | -------------------------------------------------------------------------------- /tests/inputFiles/SymbolTest6.hs: -------------------------------------------------------------------------------- 1 | module Test where 2 | import Foo.Bar 3 | import Foo.Bar.Blub 4 | import Ugah.Argh 5 | import Control.Monad (when) 6 | 7 | f :: Int -> Int 8 | f = (+ 3) 9 | -------------------------------------------------------------------------------- /tests/goldenFiles/SymbolTest10.hs: -------------------------------------------------------------------------------- 1 | module Test where 2 | import Foo.Bar 3 | import Foo.Bar.Blub 4 | import Ugah.Argh 5 | import Control.Applicative 6 | 7 | f :: Int -> Int 8 | f = (+ 3) 9 | -------------------------------------------------------------------------------- /tests/inputFiles/ModuleTest9.hs: -------------------------------------------------------------------------------- 1 | module Test where 2 | import Foo.Bar 3 | import Foo.Bar.Blub 4 | import Ugah.Argh 5 | import qualified Control.Monad 6 | 7 | f :: Int -> Int 8 | f = (+ 3) 9 | -------------------------------------------------------------------------------- /tests/inputFiles/SymbolTest9.hs: -------------------------------------------------------------------------------- 1 | module Test where 2 | import Foo.Bar 3 | import Foo.Bar.Blub 4 | import Ugah.Argh 5 | import qualified Control.Monad 6 | 7 | f :: Int -> Int 8 | f = (+ 3) 9 | -------------------------------------------------------------------------------- /tests/goldenFiles/SymbolTest6.hs: -------------------------------------------------------------------------------- 1 | module Test where 2 | import Foo.Bar 3 | import Foo.Bar.Blub 4 | import Ugah.Argh 5 | import Control.Monad (when, unless) 6 | 7 | f :: Int -> Int 8 | f = (+ 3) 9 | -------------------------------------------------------------------------------- /tests/inputFiles/ModuleTest8.hs: -------------------------------------------------------------------------------- 1 | module Test where 2 | import Foo.Bar 3 | import Foo.Bar.Blub 4 | import Ugah.Argh 5 | import Control.Monad hiding (when) 6 | 7 | f :: Int -> Int 8 | f = (+ 3) 9 | -------------------------------------------------------------------------------- /tests/inputFiles/SymbolTest11.hs: -------------------------------------------------------------------------------- 1 | module Test where 2 | import Foo.Bar 3 | import Foo.Bar.Blub 4 | import Ugah.Argh 5 | import Control.Applicative (pure) 6 | 7 | f :: Int -> Int 8 | f = (+ 3) 9 | -------------------------------------------------------------------------------- /tests/inputFiles/SymbolTest7.hs: -------------------------------------------------------------------------------- 1 | module Test where 2 | import Foo.Bar 3 | import Foo.Bar.Blub 4 | import Ugah.Argh 5 | import qualified Control.Monad as M 6 | 7 | f :: Int -> Int 8 | f = (+ 3) 9 | -------------------------------------------------------------------------------- /tests/inputFiles/SymbolTest8.hs: -------------------------------------------------------------------------------- 1 | module Test where 2 | import Foo.Bar 3 | import Foo.Bar.Blub 4 | import Ugah.Argh 5 | import Control.Monad hiding (when) 6 | 7 | f :: Int -> Int 8 | f = (+ 3) 9 | -------------------------------------------------------------------------------- /tests/goldenFiles/SymbolTest11.hs: -------------------------------------------------------------------------------- 1 | module Test where 2 | import Foo.Bar 3 | import Foo.Bar.Blub 4 | import Ugah.Argh 5 | import Control.Applicative (pure, (<$>)) 6 | 7 | f :: Int -> Int 8 | f = (+ 3) 9 | -------------------------------------------------------------------------------- /tests/goldenFiles/SymbolTest12.hs: -------------------------------------------------------------------------------- 1 | module Test where 2 | import Foo.Bar 3 | import Foo.Bar.Blub 4 | import Ugah.Argh 5 | import Control.Applicative (pure, (<$>)) 6 | 7 | f :: Int -> Int 8 | f = (+ 3) 9 | -------------------------------------------------------------------------------- /tests/inputFiles/SymbolTest12.hs: -------------------------------------------------------------------------------- 1 | module Test where 2 | import Foo.Bar 3 | import Foo.Bar.Blub 4 | import Ugah.Argh 5 | import Control.Applicative (pure, (<$>)) 6 | 7 | f :: Int -> Int 8 | f = (+ 3) 9 | -------------------------------------------------------------------------------- /tests/inputFiles/SymbolTest13.hs: -------------------------------------------------------------------------------- 1 | module Test where 2 | import Foo.Bar 3 | import Foo.Bar.Blub 4 | import Ugah.Argh 5 | import Control.Applicative (pure, (<$>)) 6 | 7 | f :: Int -> Int 8 | f = (+ 3) 9 | -------------------------------------------------------------------------------- /tests/goldenFiles/ModuleTest16.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Control.Monad 8 | f :: Int -> Int 9 | f = (+ 3) 10 | -------------------------------------------------------------------------------- /tests/inputFiles/SymbolTest14.hs: -------------------------------------------------------------------------------- 1 | module Test where 2 | import Foo.Bar 3 | import Foo.Bar.Blub 4 | import Ugah.Argh 5 | import Control.Applicative (pure, (<$>), (<*)) 6 | 7 | f :: Int -> Int 8 | f = (+ 3) 9 | -------------------------------------------------------------------------------- /tests/inputFiles/SymbolTest15.hs: -------------------------------------------------------------------------------- 1 | module Test where 2 | import Foo.Bar 3 | import Foo.Bar.Blub 4 | import Ugah.Argh 5 | import Control.Applicative (pure, (<$>), (<*)) 6 | 7 | f :: Int -> Int 8 | f = (+ 3) 9 | -------------------------------------------------------------------------------- /tests/goldenFiles/SymbolTest13.hs: -------------------------------------------------------------------------------- 1 | module Test where 2 | import Foo.Bar 3 | import Foo.Bar.Blub 4 | import Ugah.Argh 5 | import Control.Applicative (pure, (<$>), (<*)) 6 | 7 | f :: Int -> Int 8 | f = (+ 3) 9 | -------------------------------------------------------------------------------- /tests/goldenFiles/SymbolTest14.hs: -------------------------------------------------------------------------------- 1 | module Test where 2 | import Foo.Bar 3 | import Foo.Bar.Blub 4 | import Ugah.Argh 5 | import Control.Applicative (pure, (<$>), (<*)) 6 | 7 | f :: Int -> Int 8 | f = (+ 3) 9 | -------------------------------------------------------------------------------- /tests/goldenFiles/SymbolTest15.hs: -------------------------------------------------------------------------------- 1 | module Test where 2 | import Foo.Bar 3 | import Foo.Bar.Blub 4 | import Ugah.Argh 5 | import Control.Applicative (pure, (<$>), (<*), (*>)) 6 | 7 | f :: Int -> Int 8 | f = (+ 3) 9 | -------------------------------------------------------------------------------- /tests/inputFiles/ModuleTest6.hs: -------------------------------------------------------------------------------- 1 | module Test where 2 | import Foo.Bar 3 | import Foo.Bar.Blub 4 | import Ugah.Argh 5 | import Control.Monad (when) 6 | import Control.Monad 7 | 8 | f :: Int -> Int 9 | f = (+ 3) 10 | -------------------------------------------------------------------------------- /tests/goldenFiles/ModuleTest6.hs: -------------------------------------------------------------------------------- 1 | module Test where 2 | import Foo.Bar 3 | import Foo.Bar.Blub 4 | import Ugah.Argh 5 | import Control.Monad (when) 6 | import Control.Monad 7 | 8 | f :: Int -> Int 9 | f = (+ 3) 10 | -------------------------------------------------------------------------------- /tests/goldenFiles/ModuleTest9.hs: -------------------------------------------------------------------------------- 1 | module Test where 2 | import Foo.Bar 3 | import Foo.Bar.Blub 4 | import Ugah.Argh 5 | import qualified Control.Monad 6 | import Control.Monad 7 | 8 | f :: Int -> Int 9 | f = (+ 3) 10 | -------------------------------------------------------------------------------- /tests/goldenFiles/ModuleTest7.hs: -------------------------------------------------------------------------------- 1 | module Test where 2 | import Foo.Bar 3 | import Foo.Bar.Blub 4 | import Ugah.Argh 5 | import Control.Monad 6 | import qualified Control.Monad as M 7 | 8 | f :: Int -> Int 9 | f = (+ 3) 10 | -------------------------------------------------------------------------------- /tests/goldenFiles/ModuleTest8.hs: -------------------------------------------------------------------------------- 1 | module Test where 2 | import Foo.Bar 3 | import Foo.Bar.Blub 4 | import Ugah.Argh 5 | import Control.Monad hiding (when) 6 | import Control.Monad 7 | 8 | f :: Int -> Int 9 | f = (+ 3) 10 | -------------------------------------------------------------------------------- /tests/goldenFiles/ReplaceCppTest3.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( f 4 | ) where 5 | 6 | import Ugah.Foo 7 | import Control.Applicative 8 | 9 | 10 | 11 | f :: Int -> Int 12 | f i = i + 3 13 | -------------------------------------------------------------------------------- /tests/goldenFiles/SymbolTest9.hs: -------------------------------------------------------------------------------- 1 | module Test where 2 | import Foo.Bar 3 | import Foo.Bar.Blub 4 | import Ugah.Argh 5 | import qualified Control.Monad 6 | import Control.Monad (unless) 7 | 8 | f :: Int -> Int 9 | f = (+ 3) 10 | -------------------------------------------------------------------------------- /tests/inputFiles/ModuleTest7.hs: -------------------------------------------------------------------------------- 1 | module Test where 2 | import Foo.Bar 3 | import Foo.Bar.Blub 4 | import Ugah.Argh 5 | import Control.Monad (when) 6 | import qualified Control.Monad as M 7 | 8 | f :: Int -> Int 9 | f = (+ 3) 10 | -------------------------------------------------------------------------------- /tests/goldenFiles/SymbolTest7.hs: -------------------------------------------------------------------------------- 1 | module Test where 2 | import Foo.Bar 3 | import Foo.Bar.Blub 4 | import Ugah.Argh 5 | import qualified Control.Monad as M 6 | import Control.Monad (unless) 7 | 8 | f :: Int -> Int 9 | f = (+ 3) 10 | -------------------------------------------------------------------------------- /tests/goldenFiles/SymbolTest8.hs: -------------------------------------------------------------------------------- 1 | module Test where 2 | import Foo.Bar 3 | import Foo.Bar.Blub 4 | import Ugah.Argh 5 | import Control.Monad hiding (when) 6 | import Control.Monad (unless) 7 | 8 | f :: Int -> Int 9 | f = (+ 3) 10 | -------------------------------------------------------------------------------- /tests/inputFiles/ModuleTest18.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Ugah.Foo 8 | import Control.Applicative 9 | import Ugah.Blub 10 | f :: Int -> Int 11 | f = (+ 3) 12 | -------------------------------------------------------------------------------- /tests/inputFiles/ModuleTest32.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | -- | Some Haddock doc 8 | f :: Int -> Int 9 | f = (+ 3) 10 | 11 | g :: Int -> Int 12 | g = 13 | where 14 | -------------------------------------------------------------------------------- /tests/inputFiles/ModuleTest35.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | f :: Int -> Int 8 | -- ^ Some Haddock doc 9 | f = (+ 3) 10 | 11 | g :: Int -> Int 12 | g = 13 | where 14 | -------------------------------------------------------------------------------- /tests/inputFiles/ModuleTest20.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Ugah.Foo 8 | import Control.Applicative 9 | import Ugah.Blub 10 | ddd 11 | f :: Int -> Int 12 | f = (+ 3) 13 | -------------------------------------------------------------------------------- /tests/inputFiles/ModuleTest19.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Ugah.Foo 8 | import Control.Applicative 9 | import Ugah.Blub 10 | f :: Int -> Int 11 | f = (+ 3) 12 | 13 | ddd 14 | -------------------------------------------------------------------------------- /tests/goldenFiles/ParseTest2.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( f 4 | ) where 5 | #include "Foo.h" 6 | import Ugah.Foo 7 | import Control.Applicative 8 | #ifdef FOO 9 | import Ugah.Blub 10 | #endif 11 | f :: Int -> Int 12 | f i = i + 3 13 | -------------------------------------------------------------------------------- /tests/inputFiles/ParseTest2.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( f 4 | ) where 5 | #include "Foo.h" 6 | import Ugah.Foo 7 | import Control.Applicative 8 | #ifdef FOO 9 | import Ugah.Blub 10 | #endif 11 | f :: Int -> Int 12 | f i = i + 3 13 | -------------------------------------------------------------------------------- /tests/goldenFiles/ModuleTest18.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Ugah.Foo 8 | import Control.Applicative 9 | import Control.Monad 10 | import Ugah.Blub 11 | f :: Int -> Int 12 | f = (+ 3) 13 | -------------------------------------------------------------------------------- /tests/inputFiles/ModuleTest33.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | -- | Some Haddock doc 8 | -- One line more 9 | f :: Int -> Int 10 | f = (+ 3) 11 | 12 | g :: Int -> Int 13 | g = 14 | where 15 | -------------------------------------------------------------------------------- /tests/inputFiles/ModuleTest36.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | f :: Int -> Int 8 | -- ^ Some Haddock doc 9 | -- One line more 10 | f = (+ 3) 11 | 12 | g :: Int -> Int 13 | g = 14 | where 15 | -------------------------------------------------------------------------------- /tests/inputFiles/ReplaceCppTest3.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( f 4 | ) where 5 | #include "Foo.h" 6 | import Ugah.Foo 7 | import Control.Applicative 8 | #ifdef FOO 9 | import Ugah.Blub 10 | #endif 11 | f :: Int -> Int 12 | f i = i + 3 13 | -------------------------------------------------------------------------------- /tests/goldenFiles/ModuleTest32.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Control.Monad 8 | -- | Some Haddock doc 9 | f :: Int -> Int 10 | f = (+ 3) 11 | 12 | g :: Int -> Int 13 | g = 14 | where 15 | -------------------------------------------------------------------------------- /tests/goldenFiles/ModuleTest35.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Control.Monad 8 | f :: Int -> Int 9 | -- ^ Some Haddock doc 10 | f = (+ 3) 11 | 12 | g :: Int -> Int 13 | g = 14 | where 15 | -------------------------------------------------------------------------------- /tests/goldenFiles/SymbolTest28.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Control.Applicative 8 | import Ugah.Blub (a, b, c, d) 9 | f :: Int -> Int 10 | f = (+ 3) 11 | 12 | r :: Int -> Int 13 | r = 14 | -------------------------------------------------------------------------------- /tests/goldenFiles/SymbolTest31.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Control.Applicative 8 | import Ugah.Blub (a, b, c, d) 9 | f :: Int -> Int 10 | f = (+ 3) 11 | 12 | r :: Int -> Int 13 | r = 14 | -------------------------------------------------------------------------------- /tests/goldenFiles/ModuleTest20.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Ugah.Foo 8 | import Control.Applicative 9 | import Control.Monad 10 | import Ugah.Blub 11 | ddd 12 | f :: Int -> Int 13 | f = (+ 3) 14 | -------------------------------------------------------------------------------- /tests/inputFiles/ModuleTest34.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | {-| 8 | Some Haddock doc 9 | One line more 10 | -} 11 | f :: Int -> Int 12 | f = (+ 3) 13 | 14 | g :: Int -> Int 15 | g = 16 | where 17 | -------------------------------------------------------------------------------- /tests/goldenFiles/ModuleTest19.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Ugah.Foo 8 | import Control.Applicative 9 | import Control.Monad 10 | import Ugah.Blub 11 | f :: Int -> Int 12 | f = (+ 3) 13 | 14 | ddd 15 | -------------------------------------------------------------------------------- /tests/inputFiles/ModuleTest21.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Ugah.Foo 8 | import Control.Applicative 9 | import Ugah.Blub 10 | f :: Int -> Int 11 | f = (+ 3) 12 | 13 | g :: Int -> Int 14 | g = 15 | where 16 | -------------------------------------------------------------------------------- /tests/inputFiles/ModuleTest23.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Ugah.Foo 8 | import Control.Applicative 9 | import Ugah.Blub 10 | f :: Int -> Int 11 | f = (+ 3) 12 | 13 | g :: Int -> Int 14 | g = 15 | where 16 | -------------------------------------------------------------------------------- /tests/inputFiles/ModuleTest25.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Ugah.Foo 8 | import Control.Applicative 9 | import Ugah.Blub 10 | f :: Int -> Int 11 | f = (+ 3) 12 | 13 | g :: Int -> Int 14 | g = 15 | where 16 | -------------------------------------------------------------------------------- /tests/inputFiles/SymbolTest16.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Ugah.Foo 8 | import Control.Applicative 9 | import Ugah.Blub 10 | f :: Int -> Int 11 | f = (+ 3) 12 | 13 | g :: Int -> Int 14 | g = 15 | where 16 | -------------------------------------------------------------------------------- /tests/goldenFiles/ModuleTest33.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Control.Monad 8 | -- | Some Haddock doc 9 | -- One line more 10 | f :: Int -> Int 11 | f = (+ 3) 12 | 13 | g :: Int -> Int 14 | g = 15 | where 16 | -------------------------------------------------------------------------------- /tests/goldenFiles/ModuleTest36.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Control.Monad 8 | f :: Int -> Int 9 | -- ^ Some Haddock doc 10 | -- One line more 11 | f = (+ 3) 12 | 13 | g :: Int -> Int 14 | g = 15 | where 16 | -------------------------------------------------------------------------------- /tests/goldenFiles/ReplaceCppTest1.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | 8 | import Ugah.Foo 9 | import Control.Applicative 10 | 11 | 12 | 13 | f :: Int -> Int 14 | f = (+ 3) 15 | 16 | g :: Int -> Int 17 | g = 18 | where 19 | -------------------------------------------------------------------------------- /tests/inputFiles/SymbolTest30.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Control.Applicative 8 | import Ugah.Blub 9 | ( a 10 | , b 11 | , c 12 | ) 13 | f :: Int -> Int 14 | f = (+ 3) 15 | 16 | r :: Int -> Int 17 | r = 18 | -------------------------------------------------------------------------------- /tests/inputFiles/SymbolTest31.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Control.Applicative 8 | import Ugah.Blub 9 | ( a 10 | , b 11 | , c 12 | ) 13 | f :: Int -> Int 14 | f = (+ 3) 15 | 16 | r :: Int -> Int 17 | r = 18 | -------------------------------------------------------------------------------- /tests/inputFiles/SymbolTest41.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Control.Applicative 8 | import Ugah.Blub 9 | ( a 10 | , b 11 | , c 12 | ) 13 | f :: Int -> Int 14 | f = (+ 3) 15 | 16 | r :: Int -> Int 17 | r = 18 | -------------------------------------------------------------------------------- /tests/diffOutputsWithGoldens: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | for output in `ls outputFiles` ; do 3 | # only call gvimdiff on files having a difference 4 | outputFile=outputFiles/$output 5 | goldenFile=goldenFiles/$output 6 | diff $outputFile $goldenFile > /dev/null || gvimdiff -f $outputFile $goldenFile 7 | done 8 | -------------------------------------------------------------------------------- /tests/goldenFiles/ModuleTest34.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Control.Monad 8 | {-| 9 | Some Haddock doc 10 | One line more 11 | -} 12 | f :: Int -> Int 13 | f = (+ 3) 14 | 15 | g :: Int -> Int 16 | g = 17 | where 18 | -------------------------------------------------------------------------------- /tests/goldenFiles/SymbolTest27.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Ugah.Foo 8 | import Control.Applicative 9 | import Ugah.Blub (a, b, c, d, e, f, g) 10 | f :: Int -> Int 11 | f = (+ 3) 12 | 13 | g :: Int 14 | g = 15 | where 16 | -------------------------------------------------------------------------------- /tests/inputFiles/ModuleTest22.hs: -------------------------------------------------------------------------------- 1 | module Blub where 2 | import qualified Language.Haskell.Exts as HS 3 | 4 | addSymbol :: HS.ImportDecl -> String -> HS.ImportDecl 5 | addSymbol (id@HS.ImportDecl {HS.importSpecs = specs}) symbolName = 6 | id {HS.importSpecs = specs & _Just . _2 %~ (++ [HS.IVar $ hsName symbolName])} 7 | -------------------------------------------------------------------------------- /tests/goldenFiles/SymbolTest42.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Control.Applicative (r, t) 8 | import Ugah.Blub 9 | ( a 10 | , b 11 | , c 12 | ) 13 | f :: Int -> Int 14 | f = (+ 3) 15 | 16 | r :: Int -> Int 17 | r = 18 | -------------------------------------------------------------------------------- /tests/goldenFiles/ModuleTest21.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Ugah.Foo 8 | import Control.Applicative 9 | import Control.Monad 10 | import Ugah.Blub 11 | f :: Int -> Int 12 | f = (+ 3) 13 | 14 | g :: Int -> Int 15 | g = 16 | where 17 | -------------------------------------------------------------------------------- /tests/goldenFiles/ParseTest1.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | #include "Foo.h" 8 | import Ugah.Foo 9 | import Control.Applicative 10 | #ifdef FOO 11 | import Ugah.Blub 12 | #endif 13 | f :: Int -> Int 14 | f = (+ 3) 15 | 16 | g :: Int -> Int 17 | -------------------------------------------------------------------------------- /tests/goldenFiles/ReplaceCppTest2.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | 8 | import Ugah.Foo 9 | import Control.Applicative 10 | 11 | 12 | 13 | 14 | 15 | 16 | f :: Int -> Int 17 | f = (+ 3) 18 | 19 | g :: Int -> Int 20 | g = 21 | where 22 | -------------------------------------------------------------------------------- /tests/goldenFiles/SymbolTest41.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Control.Applicative hiding (t) 8 | import Ugah.Blub 9 | ( a 10 | , b 11 | , c 12 | ) 13 | f :: Int -> Int 14 | f = (+ 3) 15 | 16 | r :: Int -> Int 17 | r = 18 | -------------------------------------------------------------------------------- /tests/inputFiles/SymbolTest32.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Control.Applicative 8 | (r, t, z) 9 | import Ugah.Blub 10 | ( a 11 | , b 12 | , c 13 | ) 14 | f :: Int -> Int 15 | f = (+ 3) 16 | 17 | r :: Int -> Int 18 | r = 19 | -------------------------------------------------------------------------------- /tests/inputFiles/SymbolTest36.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Control.Applicative 8 | (r, t, z) 9 | import Ugah.Blub 10 | ( a 11 | , b 12 | , c 13 | ) 14 | f :: Int -> Int 15 | f = (+ 3) 16 | 17 | r :: Int -> Int 18 | r = 19 | -------------------------------------------------------------------------------- /tests/inputFiles/SymbolTest37.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Control.Applicative 8 | (r, t, z) 9 | import Ugah.Blub 10 | ( a 11 | , b 12 | , c 13 | ) 14 | f :: Int -> Int 15 | f = (+ 3) 16 | 17 | r :: Int -> Int 18 | r = 19 | -------------------------------------------------------------------------------- /tests/inputFiles/SymbolTest38.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Control.Applicative 8 | (r, t, z) 9 | import Ugah.Blub 10 | ( a 11 | , b 12 | , c 13 | ) 14 | f :: Int -> Int 15 | f = (+ 3) 16 | 17 | r :: Int -> Int 18 | r = 19 | -------------------------------------------------------------------------------- /tests/inputFiles/SymbolTest39.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Control.Applicative 8 | (r, t, z) 9 | import Ugah.Blub 10 | ( a 11 | , b 12 | , c 13 | ) 14 | f :: Int -> Int 15 | f = (+ 3) 16 | 17 | r :: Int -> Int 18 | r = 19 | -------------------------------------------------------------------------------- /tests/inputFiles/SymbolTest40.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Control.Applicative 8 | (r, t, z) 9 | import Ugah.Blub 10 | ( a 11 | , b 12 | , c 13 | ) 14 | f :: Int -> Int 15 | f = (+ 3) 16 | 17 | r :: Int -> Int 18 | r = 19 | -------------------------------------------------------------------------------- /tests/inputFiles/SymbolTest42.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Control.Applicative 8 | (r, t, z) 9 | import Ugah.Blub 10 | ( a 11 | , b 12 | , c 13 | ) 14 | f :: Int -> Int 15 | f = (+ 3) 16 | 17 | r :: Int -> Int 18 | r = 19 | -------------------------------------------------------------------------------- /tests/goldenFiles/ModuleTest25.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Ugah.Foo 8 | import Control.Applicative 9 | import qualified Control.Monad 10 | import Ugah.Blub 11 | f :: Int -> Int 12 | f = (+ 3) 13 | 14 | g :: Int -> Int 15 | g = 16 | where 17 | -------------------------------------------------------------------------------- /tests/goldenFiles/SymbolTest30.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Control.Applicative 8 | import Ugah.Blub 9 | ( a 10 | , b 11 | , c 12 | ) 13 | import X.Y ( x ) 14 | f :: Int -> Int 15 | f = (+ 3) 16 | 17 | r :: Int -> Int 18 | r = 19 | -------------------------------------------------------------------------------- /tests/inputFiles/SymbolTest27.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Ugah.Foo 8 | import Control.Applicative 9 | import Ugah.Blub (a, b, c, 10 | d, e, f) 11 | f :: Int -> Int 12 | f = (+ 3) 13 | 14 | g :: Int 15 | g = 16 | where 17 | -------------------------------------------------------------------------------- /tests/inputFiles/ModuleTest24.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Ugah.Foo 8 | import Control.Applicative 9 | import qualified Control.Monad as CM 10 | import Ugah.Blub 11 | f :: Int -> Int 12 | f = (+ 3) 13 | 14 | g :: Int -> Int 15 | g = 16 | where 17 | -------------------------------------------------------------------------------- /tests/goldenFiles/ModuleTest22.hs: -------------------------------------------------------------------------------- 1 | module Blub where 2 | import qualified Language.Haskell.Exts as HS 3 | import Control.Monad 4 | 5 | addSymbol :: HS.ImportDecl -> String -> HS.ImportDecl 6 | addSymbol (id@HS.ImportDecl {HS.importSpecs = specs}) symbolName = 7 | id {HS.importSpecs = specs & _Just . _2 %~ (++ [HS.IVar $ hsName symbolName])} 8 | -------------------------------------------------------------------------------- /tests/goldenFiles/ModuleTest23.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Ugah.Foo 8 | import Control.Applicative 9 | import qualified Control.Monad as CM 10 | import Ugah.Blub 11 | f :: Int -> Int 12 | f = (+ 3) 13 | 14 | g :: Int -> Int 15 | g = 16 | where 17 | -------------------------------------------------------------------------------- /tests/goldenFiles/ModuleTest24.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Ugah.Foo 8 | import Control.Applicative 9 | import qualified Control.Monad as CM 10 | import Ugah.Blub 11 | f :: Int -> Int 12 | f = (+ 3) 13 | 14 | g :: Int -> Int 15 | g = 16 | where 17 | -------------------------------------------------------------------------------- /tests/inputFiles/SymbolTest28.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Control.Applicative 8 | import Ugah.Blub ( a 9 | , b 10 | , c 11 | ) 12 | f :: Int -> Int 13 | f = (+ 3) 14 | 15 | r :: Int -> Int 16 | r = 17 | -------------------------------------------------------------------------------- /tests/inputFiles/SymbolTest29.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Control.Applicative 8 | import Ugah.Blub ( a 9 | , b 10 | , c 11 | ) 12 | f :: Int -> Int 13 | f = (+ 3) 14 | 15 | r :: Int -> Int 16 | r = 17 | -------------------------------------------------------------------------------- /tests/goldenFiles/ModuleTest38.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Control.Applicative 8 | (r, t, z) 9 | import Ugah.Blub 10 | ( a 11 | , b 12 | , c 13 | ) 14 | import Data.Text 15 | f :: Int -> Int 16 | f = (+ 3) 17 | 18 | r :: Int -> Int 19 | r = 20 | -------------------------------------------------------------------------------- /tests/goldenFiles/SymbolTest44.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Control.Applicative 8 | (r, t, z) 9 | import Ugah.Blub 10 | ( a 11 | , b 12 | , c 13 | ) 14 | import Data.Text 15 | f :: Int -> Int 16 | f = (+ 3) 17 | 18 | r :: Int -> Int 19 | r = 20 | -------------------------------------------------------------------------------- /tests/goldenFiles/SymbolTest48.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Control.Applicative 8 | (r, t, z) 9 | import Ugah.Blub 10 | ( a 11 | , b 12 | , c 13 | ) 14 | import Data.Text 15 | f :: Int -> Int 16 | f = (+ 3) 17 | 18 | r :: Int -> Int 19 | r = 20 | -------------------------------------------------------------------------------- /tests/goldenFiles/SymbolTest49.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Control.Applicative 8 | (r, t, z) 9 | import Ugah.Blub 10 | ( a 11 | , b 12 | , c 13 | ) 14 | import Data.Text 15 | f :: Int -> Int 16 | f = (+ 3) 17 | 18 | r :: Int -> Int 19 | r = 20 | -------------------------------------------------------------------------------- /tests/inputFiles/ModuleTest26.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | #include "Foo.h" 8 | import Ugah.Foo 9 | import Control.Applicative 10 | #ifdef FOO 11 | import Ugah.Blub 12 | #endif 13 | f :: Int -> Int 14 | f = (+ 3) 15 | 16 | g :: Int -> Int 17 | g = 18 | where 19 | -------------------------------------------------------------------------------- /tests/inputFiles/ModuleTest27.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Ugah.Foo ( a 8 | , b 9 | ) 10 | import Control.Applicative 11 | import Ugah.Blub 12 | f :: Int -> Int 13 | f = (+ 3) 14 | 15 | g :: Int -> Int 16 | g = 17 | where 18 | -------------------------------------------------------------------------------- /tests/inputFiles/ModuleTest28.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Ugah.Foo ( a 8 | , b 9 | ) 10 | import Control.Applicative 11 | import Ugah.Blub 12 | f :: Int -> Int 13 | f = (+ 3) 14 | 15 | g :: Int -> Int 16 | g = 17 | where 18 | -------------------------------------------------------------------------------- /tests/inputFiles/ModuleTest31.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | #include "Foo.h" 8 | import Ugah.Foo 9 | import Control.Applicative 10 | #ifdef FOO 11 | import Ugah.Blub 12 | #endif 13 | f :: Int -> Int 14 | f = (+ 3) 15 | 16 | g :: Int -> Int 17 | g = 18 | where 19 | -------------------------------------------------------------------------------- /tests/inputFiles/ParseTest1.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | #include "Foo.h" 8 | import Ugah.Foo 9 | import Control.Applicative 10 | #ifdef FOO 11 | import Ugah.Blub 12 | #endif 13 | f :: Int -> Int 14 | f = (+ 3) 15 | 16 | g :: Int -> Int 17 | g = 18 | where 19 | -------------------------------------------------------------------------------- /tests/inputFiles/ModuleTest30.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Ugah.Foo 8 | import Control.Applicative 9 | import Ugah.Blub ( a 10 | , b 11 | ) 12 | f :: Int -> Int 13 | f = (+ 3) 14 | 15 | g :: Int -> Int 16 | g = 17 | where 18 | -------------------------------------------------------------------------------- /tests/inputFiles/ReplaceCppTest1.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | #include "Foo.h" 8 | import Ugah.Foo 9 | import Control.Applicative 10 | #ifdef FOO 11 | import Ugah.Blub 12 | #endif 13 | f :: Int -> Int 14 | f = (+ 3) 15 | 16 | g :: Int -> Int 17 | g = 18 | where 19 | -------------------------------------------------------------------------------- /tests/goldenFiles/SymbolTest32.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Control.Applicative 8 | (r, t, z) 9 | import Control.Foo (foo) 10 | import Ugah.Blub 11 | ( a 12 | , b 13 | , c 14 | ) 15 | f :: Int -> Int 16 | f = (+ 3) 17 | 18 | r :: Int -> Int 19 | r = 20 | -------------------------------------------------------------------------------- /tests/goldenFiles/SymbolTest45.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Control.Applicative 8 | (r, t, z) 9 | import Ugah.Blub 10 | ( a 11 | , b 12 | , c 13 | ) 14 | import Data.Text (Text()) 15 | f :: Int -> Int 16 | f = (+ 3) 17 | 18 | r :: Int -> Int 19 | r = 20 | -------------------------------------------------------------------------------- /tests/goldenFiles/SymbolTest46.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Control.Applicative 8 | (r, t, z) 9 | import Ugah.Blub 10 | ( a 11 | , b 12 | , c 13 | ) 14 | import Data.Text (Text(B)) 15 | f :: Int -> Int 16 | f = (+ 3) 17 | 18 | r :: Int -> Int 19 | r = 20 | -------------------------------------------------------------------------------- /tests/goldenFiles/SymbolTest47.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Control.Applicative 8 | (r, t, z) 9 | import Ugah.Blub 10 | ( a 11 | , b 12 | , c 13 | ) 14 | import Data.Text (Text()) 15 | f :: Int -> Int 16 | f = (+ 3) 17 | 18 | r :: Int -> Int 19 | r = 20 | -------------------------------------------------------------------------------- /tests/goldenFiles/SymbolTest50.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Control.Applicative 8 | (r, t, z) 9 | import Ugah.Blub 10 | ( a 11 | , b 12 | , c 13 | ) 14 | import Data.Text (Text(A)) 15 | f :: Int -> Int 16 | f = (+ 3) 17 | 18 | r :: Int -> Int 19 | r = 20 | -------------------------------------------------------------------------------- /tests/inputFiles/ModuleTest38.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Control.Applicative 8 | (r, t, z) 9 | import Ugah.Blub 10 | ( a 11 | , b 12 | , c 13 | ) 14 | import Data.Text (Text(..)) 15 | f :: Int -> Int 16 | f = (+ 3) 17 | 18 | r :: Int -> Int 19 | r = 20 | -------------------------------------------------------------------------------- /tests/inputFiles/SymbolTest44.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Control.Applicative 8 | (r, t, z) 9 | import Ugah.Blub 10 | ( a 11 | , b 12 | , c 13 | ) 14 | import Data.Text (Text(..)) 15 | f :: Int -> Int 16 | f = (+ 3) 17 | 18 | r :: Int -> Int 19 | r = 20 | -------------------------------------------------------------------------------- /tests/inputFiles/SymbolTest45.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Control.Applicative 8 | (r, t, z) 9 | import Ugah.Blub 10 | ( a 11 | , b 12 | , c 13 | ) 14 | import Data.Text (Text(A)) 15 | f :: Int -> Int 16 | f = (+ 3) 17 | 18 | r :: Int -> Int 19 | r = 20 | -------------------------------------------------------------------------------- /tests/inputFiles/SymbolTest51.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Control.Applicative 8 | (r, t, z) 9 | import Ugah.Blub 10 | ( a 11 | , b 12 | , c 13 | ) 14 | import Data.Text (Text(..)) 15 | f :: Int -> Int 16 | f = (+ 3) 17 | 18 | r :: Int -> Int 19 | r = 20 | -------------------------------------------------------------------------------- /lib/HsImport.hs: -------------------------------------------------------------------------------- 1 | 2 | module HsImport 3 | ( module HsImport.Main 4 | , module HsImport.Config 5 | , module HsImport.Args 6 | , ImportDecl 7 | , ImportPos(..) 8 | ) where 9 | 10 | import HsImport.Main 11 | import HsImport.Config 12 | import HsImport.Args 13 | import HsImport.Types (ImportDecl) 14 | import HsImport.ImportPos (ImportPos(..)) 15 | -------------------------------------------------------------------------------- /tests/inputFiles/SymbolTest46.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Control.Applicative 8 | (r, t, z) 9 | import Ugah.Blub 10 | ( a 11 | , b 12 | , c 13 | ) 14 | import Data.Text (Text(A, B)) 15 | f :: Int -> Int 16 | f = (+ 3) 17 | 18 | r :: Int -> Int 19 | r = 20 | -------------------------------------------------------------------------------- /tests/inputFiles/SymbolTest47.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Control.Applicative 8 | (r, t, z) 9 | import Ugah.Blub 10 | ( a 11 | , b 12 | , c 13 | ) 14 | import Data.Text (Text(A, B)) 15 | f :: Int -> Int 16 | f = (+ 3) 17 | 18 | r :: Int -> Int 19 | r = 20 | -------------------------------------------------------------------------------- /tests/inputFiles/SymbolTest49.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Control.Applicative 8 | (r, t, z) 9 | import Ugah.Blub 10 | ( a 11 | , b 12 | , c 13 | ) 14 | import Data.Text (Text(A, B)) 15 | f :: Int -> Int 16 | f = (+ 3) 17 | 18 | r :: Int -> Int 19 | r = 20 | -------------------------------------------------------------------------------- /tests/inputFiles/SymbolTest50.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Control.Applicative 8 | (r, t, z) 9 | import Ugah.Blub 10 | ( a 11 | , b 12 | , c 13 | ) 14 | import Data.Text (Text(A, B)) 15 | f :: Int -> Int 16 | f = (+ 3) 17 | 18 | r :: Int -> Int 19 | r = 20 | -------------------------------------------------------------------------------- /tests/goldenFiles/SymbolTest29.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Control.Applicative 8 | import Ugah.Blub ( a 9 | , b 10 | , c 11 | ) 12 | import X.Y ( x ) 13 | f :: Int -> Int 14 | f = (+ 3) 15 | 16 | r :: Int -> Int 17 | r = 18 | -------------------------------------------------------------------------------- /tests/goldenFiles/SymbolTest35.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Control.Applicative 8 | (r, t, z) 9 | import Data.Text hiding (isInfixOf) 10 | import Ugah.Blub 11 | ( a 12 | , b 13 | , c 14 | ) 15 | f :: Int -> Int 16 | f = (+ 3) 17 | 18 | r :: Int -> Int 19 | r = 20 | -------------------------------------------------------------------------------- /tests/goldenFiles/SymbolTest37.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Control.Applicative 8 | (r, t, z) 9 | import Ugah.Blub 10 | ( a 11 | , b 12 | , c 13 | ) 14 | import Data.Text hiding (Text(..)) 15 | f :: Int -> Int 16 | f = (+ 3) 17 | 18 | r :: Int -> Int 19 | r = 20 | -------------------------------------------------------------------------------- /tests/goldenFiles/SymbolTest43.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Control.Applicative 8 | (r, t, z) 9 | import Ugah.Blub 10 | ( a 11 | , b 12 | , c 13 | ) 14 | import Data.Text hiding (isPrefixOf) 15 | f :: Int -> Int 16 | f = (+ 3) 17 | 18 | r :: Int -> Int 19 | r = 20 | -------------------------------------------------------------------------------- /tests/inputFiles/SymbolTest33.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Control.Applicative 8 | (r, t, z) 9 | import Control.Monad hiding (when) 10 | import Ugah.Blub 11 | ( a 12 | , b 13 | , c 14 | ) 15 | f :: Int -> Int 16 | f = (+ 3) 17 | 18 | r :: Int -> Int 19 | r = 20 | -------------------------------------------------------------------------------- /tests/inputFiles/SymbolTest35.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Control.Applicative 8 | (r, t, z) 9 | import Data.Text hiding (isInfixOf) 10 | import Ugah.Blub 11 | ( a 12 | , b 13 | , c 14 | ) 15 | f :: Int -> Int 16 | f = (+ 3) 17 | 18 | r :: Int -> Int 19 | r = 20 | -------------------------------------------------------------------------------- /tests/inputFiles/SymbolTest48.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Control.Applicative 8 | (r, t, z) 9 | import Ugah.Blub 10 | ( a 11 | , b 12 | , c 13 | ) 14 | import Data.Text hiding (isInfixOf) 15 | f :: Int -> Int 16 | f = (+ 3) 17 | 18 | r :: Int -> Int 19 | r = 20 | -------------------------------------------------------------------------------- /tests/goldenFiles/ModuleTest26.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | #include "Foo.h" 8 | import Ugah.Foo 9 | import Control.Applicative 10 | import Control.Monad 11 | #ifdef FOO 12 | import Ugah.Blub 13 | #endif 14 | f :: Int -> Int 15 | f = (+ 3) 16 | 17 | g :: Int -> Int 18 | g = 19 | where 20 | -------------------------------------------------------------------------------- /tests/goldenFiles/SymbolTest16.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Ugah.Foo 8 | import Control.Applicative 9 | import qualified Control.Monad as CM 10 | import Control.Monad (when) 11 | import Ugah.Blub 12 | f :: Int -> Int 13 | f = (+ 3) 14 | 15 | g :: Int -> Int 16 | g = 17 | where 18 | -------------------------------------------------------------------------------- /tests/goldenFiles/SymbolTest33.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Control.Applicative 8 | (r, t, z) 9 | import Control.Monad hiding (when, mapM_) 10 | import Ugah.Blub 11 | ( a 12 | , b 13 | , c 14 | ) 15 | f :: Int -> Int 16 | f = (+ 3) 17 | 18 | r :: Int -> Int 19 | r = 20 | -------------------------------------------------------------------------------- /tests/goldenFiles/SymbolTest38.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Control.Applicative 8 | (r, t, z) 9 | import Ugah.Blub 10 | ( a 11 | , b 12 | , c 13 | ) 14 | import Data.Text hiding (Text(A, B, C)) 15 | f :: Int -> Int 16 | f = (+ 3) 17 | 18 | r :: Int -> Int 19 | r = 20 | -------------------------------------------------------------------------------- /tests/inputFiles/ModuleTest29.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Ugah.Foo 8 | import Control.Applicative ( a 9 | , b 10 | ) 11 | import Ugah.Blub 12 | f :: Int -> Int 13 | f = (+ 3) 14 | 15 | g :: Int -> Int 16 | g = 17 | where 18 | -------------------------------------------------------------------------------- /tests/goldenFiles/ModuleTest27.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Control.Monad 8 | import Ugah.Foo ( a 9 | , b 10 | ) 11 | import Control.Applicative 12 | import Ugah.Blub 13 | f :: Int -> Int 14 | f = (+ 3) 15 | 16 | g :: Int -> Int 17 | g = 18 | where 19 | -------------------------------------------------------------------------------- /tests/goldenFiles/ModuleTest28.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Ugah.Foo ( a 8 | , b 9 | ) 10 | import Control.Monad 11 | import Control.Applicative 12 | import Ugah.Blub 13 | f :: Int -> Int 14 | f = (+ 3) 15 | 16 | g :: Int -> Int 17 | g = 18 | where 19 | -------------------------------------------------------------------------------- /tests/goldenFiles/ModuleTest30.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Ugah.Foo 8 | import Control.Applicative 9 | import Ugah.Blub ( a 10 | , b 11 | ) 12 | import Control.Monad 13 | f :: Int -> Int 14 | f = (+ 3) 15 | 16 | g :: Int -> Int 17 | g = 18 | where 19 | -------------------------------------------------------------------------------- /tests/inputFiles/SymbolTest43.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Control.Applicative 8 | (r, t, z) 9 | import Ugah.Blub 10 | ( a 11 | , b 12 | , c 13 | ) 14 | import Data.Text hiding (isPrefixOf, isInfixOf) 15 | f :: Int -> Int 16 | f = (+ 3) 17 | 18 | r :: Int -> Int 19 | r = 20 | -------------------------------------------------------------------------------- /tests/goldenFiles/ModuleTest31.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | #include "Foo.h" 8 | import Ugah.Foo 9 | import Control.Applicative 10 | import Control.Monad as CM 11 | #ifdef FOO 12 | import Ugah.Blub 13 | #endif 14 | f :: Int -> Int 15 | f = (+ 3) 16 | 17 | g :: Int -> Int 18 | g = 19 | where 20 | -------------------------------------------------------------------------------- /tests/goldenFiles/SymbolTest39.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Control.Applicative 8 | (r, t, z) 9 | import Ugah.Blub 10 | ( a 11 | , b 12 | , c 13 | ) 14 | import Data.Text as T 15 | import Data.Text hiding (Text(..)) 16 | f :: Int -> Int 17 | f = (+ 3) 18 | 19 | r :: Int -> Int 20 | r = 21 | -------------------------------------------------------------------------------- /tests/goldenFiles/ModuleTest29.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Ugah.Foo 8 | import Control.Applicative ( a 9 | , b 10 | ) 11 | import Control.Monad 12 | import Ugah.Blub 13 | f :: Int -> Int 14 | f = (+ 3) 15 | 16 | g :: Int -> Int 17 | g = 18 | where 19 | -------------------------------------------------------------------------------- /tests/goldenFiles/SymbolTest40.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Control.Applicative 8 | (r, t, z) 9 | import Ugah.Blub 10 | ( a 11 | , b 12 | , c 13 | ) 14 | import Data.Text as T 15 | import Data.Text hiding (Text(A, B, C)) 16 | f :: Int -> Int 17 | f = (+ 3) 18 | 19 | r :: Int -> Int 20 | r = 21 | -------------------------------------------------------------------------------- /tests/inputFiles/ModuleTest37.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | #include "Foo.h" 8 | #ifdef FOO 9 | import Control.Applicative 10 | #endif 11 | 12 | import Control.BiFunctor 13 | 14 | f :: Int -> Int 15 | -- ^ Some Haddock doc 16 | -- One line more 17 | f = (+ 3) 18 | 19 | g :: Int -> Int 20 | g = 21 | where 22 | -------------------------------------------------------------------------------- /tests/inputFiles/ReplaceCppTest2.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | #include "Foo.h" 8 | import Ugah.Foo 9 | import Control.Applicative 10 | #ifdef FOO 11 | import Ugah.Blub 12 | #ifdef GOO 13 | import Ugah.Blub 14 | #endif 15 | #endif 16 | f :: Int -> Int 17 | f = (+ 3) 18 | 19 | g :: Int -> Int 20 | g = 21 | where 22 | -------------------------------------------------------------------------------- /tests/inputFiles/SymbolTest34.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Control.Applicative 8 | (r, t, z) 9 | import Data.Text (isPrefixOf) 10 | import Data.Text hiding (isInfixOf) 11 | import Ugah.Blub 12 | ( a 13 | , b 14 | , c 15 | ) 16 | f :: Int -> Int 17 | f = (+ 3) 18 | 19 | r :: Int -> Int 20 | r = 21 | -------------------------------------------------------------------------------- /tests/goldenFiles/SymbolTest36.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Control.Applicative 8 | (r, t, z) 9 | import Ugah.Blub 10 | ( a 11 | , b 12 | , c 13 | ) 14 | import qualified Data.Text as T 15 | import Data.Text hiding (isInfixOf) 16 | f :: Int -> Int 17 | f = (+ 3) 18 | 19 | r :: Int -> Int 20 | r = 21 | -------------------------------------------------------------------------------- /tests/goldenFiles/SymbolTest34.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | import Control.Applicative 8 | (r, t, z) 9 | import Data.Text (isPrefixOf) 10 | import Data.Text hiding (isInfixOf, isPrefixOf) 11 | import Ugah.Blub 12 | ( a 13 | , b 14 | , c 15 | ) 16 | f :: Int -> Int 17 | f = (+ 3) 18 | 19 | r :: Int -> Int 20 | r = 21 | -------------------------------------------------------------------------------- /tests/goldenFiles/ModuleTest37.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards #-} 2 | module Blub 3 | ( blub 4 | , foo 5 | , bar 6 | ) where 7 | #include "Foo.h" 8 | #ifdef FOO 9 | import Control.Applicative 10 | #endif 11 | 12 | import Control.BiFunctor 13 | import Control.Monad 14 | 15 | f :: Int -> Int 16 | -- ^ Some Haddock doc 17 | -- One line more 18 | f = (+ 3) 19 | 20 | g :: Int -> Int 21 | g = 22 | where 23 | -------------------------------------------------------------------------------- /lib/HsImport/ModuleImport.hs: -------------------------------------------------------------------------------- 1 | 2 | module HsImport.ModuleImport 3 | ( ModuleImport(..) 4 | , Name 5 | ) where 6 | 7 | type Name = String 8 | 9 | -- | How the module should be imported 10 | data ModuleImport = ModuleImport 11 | { moduleName :: Name -- ^ the name of the module to import 12 | , qualified :: Bool -- ^ if the module should be imported qualified 13 | , as :: Maybe Name -- ^ the module should be imported with this name 14 | } deriving (Show) 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.gitignore.io/api/haskell 2 | # Edit at https://www.gitignore.io/?templates=haskell 3 | 4 | ### Haskell ### 5 | dist 6 | dist-* 7 | cabal-dev 8 | *.o 9 | *.hi 10 | *.chi 11 | *.chs.h 12 | *.dyn_o 13 | *.dyn_hi 14 | .hpc 15 | .hsenv 16 | .cabal-sandbox/ 17 | cabal.sandbox.config 18 | *.prof 19 | *.aux 20 | *.hp 21 | *.eventlog 22 | .stack-work/ 23 | cabal.project.local 24 | cabal.project.local~ 25 | .HTF/ 26 | .ghc.environment.* 27 | 28 | # End of https://www.gitignore.io/api/haskell 29 | -------------------------------------------------------------------------------- /tests/goldenFiles/SymbolTest51.hs: -------------------------------------------------------------------------------- 1 | Tried to remove Constructors from a Type that exposed all Constructors. 2 | This does not work because other Constructors are not available for HsImport. 3 | Thus, this operation can not be performed. 4 | 5 | Example: 6 | import Foo.Bar (Baz(..)) 7 | 8 | > hsimport --hiding -m Foo.Bar -s Baz -w A 9 | 10 | The correct solution would be, assuming Constructors are A, B and C, to change the import to: 11 | import Foo.Bar (Baz(B,C)) 12 | 13 | However, this is not possible for this program, thus, we abort the program execution. 14 | 15 | -------------------------------------------------------------------------------- /lib/HsImport/PrettyPrint.hs: -------------------------------------------------------------------------------- 1 | {-# Language CPP #-} 2 | 3 | module HsImport.PrettyPrint 4 | ( prettyPrint 5 | ) where 6 | 7 | import qualified Language.Haskell.Exts as HS 8 | 9 | #if __GLASGOW_HASKELL__ < 710 10 | import Data.Monoid (mconcat) 11 | #endif 12 | 13 | import HsImport.Types 14 | 15 | prettyPrint :: ImportDecl -> String 16 | prettyPrint importDecl = 17 | -- remove newlines from pretty printed ImportDecl 18 | case lines $ HS.prettyPrint importDecl of 19 | (fst : [] ) -> fst 20 | (fst : rest) -> mconcat $ fst : (map (' ' :) . map (dropWhile (== ' ')) $ rest) 21 | _ -> "" 22 | -------------------------------------------------------------------------------- /lib/HsImport/Utils.hs: -------------------------------------------------------------------------------- 1 | 2 | module HsImport.Utils 3 | ( firstSrcLine 4 | , lastSrcLine 5 | , srcSpan 6 | , declSrcLoc 7 | , importDecls 8 | ) where 9 | 10 | import qualified Language.Haskell.Exts as HS 11 | import HsImport.Types 12 | 13 | declSrcLoc :: Decl -> SrcLoc 14 | declSrcLoc decl = HS.SrcLoc srcFile srcLine srcCol 15 | where 16 | declSrcSpan = srcSpan . HS.ann $ decl 17 | srcFile = HS.srcSpanFilename declSrcSpan 18 | srcLine = HS.srcSpanStartLine declSrcSpan 19 | srcCol = HS.srcSpanStartColumn declSrcSpan 20 | 21 | 22 | importDecls :: Module -> [ImportDecl] 23 | importDecls (HS.Module _ _ _ imports _) = imports 24 | importDecls (HS.XmlPage _ _ _ _ _ _ _) = [] 25 | importDecls (HS.XmlHybrid _ _ _ imports _ _ _ _ _) = imports 26 | -------------------------------------------------------------------------------- /lib/HsImport/Config.hs: -------------------------------------------------------------------------------- 1 | 2 | module HsImport.Config 3 | ( Config(..) 4 | , defaultConfig 5 | ) where 6 | 7 | import qualified HsImport.PrettyPrint as PP 8 | import qualified HsImport.ImportPos as IP 9 | import HsImport.Types 10 | 11 | -- | User definable configuration for hsImport. 12 | data Config = Config 13 | { -- | function for pretty printing of the import declarations 14 | prettyPrint :: ImportDecl -> String 15 | -- | function for finding the position of new import declarations 16 | , findImportPos :: ImportDecl -> [ImportDecl] -> Maybe IP.ImportPos 17 | -- | error during configuration of hsimport 18 | , configError :: Maybe String 19 | } 20 | 21 | 22 | defaultConfig :: Config 23 | defaultConfig = Config 24 | { prettyPrint = PP.prettyPrint 25 | , findImportPos = IP.findImportPos 26 | , configError = Nothing 27 | } 28 | -------------------------------------------------------------------------------- /lib/HsImport/SymbolImport.hs: -------------------------------------------------------------------------------- 1 | 2 | module HsImport.SymbolImport 3 | ( SymbolImport(..) 4 | , Symbol(..) 5 | , symbol 6 | , isHiding 7 | , toggleHiding 8 | ) 9 | where 10 | 11 | type Name = String 12 | 13 | -- | What of the symbol should be taken. 14 | data Symbol 15 | = Only Name -- ^ only the symbol should be taken 16 | | AllOf Name -- ^ all constructors or methods of the symbol should be taken: Symbol(..) 17 | | SomeOf Name [String] -- ^ some constructors or methods of the symbol should be taken: Symbol(X, Y) 18 | deriving (Show) 19 | 20 | 21 | -- | The imported or from the import hidden symbol. 22 | data SymbolImport 23 | = Import Symbol -- ^ the symbol to import 24 | | Hiding Symbol -- ^ the symbol to hide from the import 25 | deriving (Show) 26 | 27 | -- | Retrieve the symbol out of the symbol import 28 | symbol :: SymbolImport -> Symbol 29 | symbol (Hiding s) = s 30 | symbol (Import s) = s 31 | 32 | -- | Check whether this symbol import is meant to hide a symbol. 33 | isHiding :: SymbolImport -> Bool 34 | isHiding (Hiding _) = True 35 | isHiding (Import _) = False 36 | 37 | -- | Toogle the import style from hiding to import and vice versa. 38 | toggleHiding :: SymbolImport -> SymbolImport 39 | toggleHiding (Hiding s) = Import s 40 | toggleHiding (Import s) = Hiding s 41 | 42 | -------------------------------------------------------------------------------- /.github/workflows/haskell.yml: -------------------------------------------------------------------------------- 1 | name: Haskell CI 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: ${{ matrix.os }} 13 | strategy: 14 | matrix: 15 | ghc: ['8.10.7', '8.8.4', '8.6.5', '8.4.4'] 16 | cabal: ['3.4.0.0'] 17 | os: [ubuntu-latest] 18 | steps: 19 | - uses: actions/checkout@v2 20 | - uses: haskell/actions/setup@v1 21 | with: 22 | ghc-version: ${{ matrix.ghc }} 23 | cabal-version: ${{ matrix.cabal }} 24 | 25 | - name: Cache 26 | uses: actions/cache@v1 27 | env: 28 | cache-name: cache-cabal 29 | with: 30 | path: ~/.cabal 31 | key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/*.cabal') }}-${{ hashFiles('**/cabal.project') }} 32 | restore-keys: | 33 | ${{ runner.os }}-build-${{ env.cache-name }}- 34 | ${{ runner.os }}-build- 35 | ${{ runner.os }}- 36 | 37 | - name: Install dependencies 38 | run: | 39 | cabal update 40 | cabal build --only-dependencies --enable-tests --enable-benchmarks 41 | 42 | - name: Check for common haddock errors and sdist 43 | run: | 44 | cabal check 45 | cabal sdist 46 | - name: Build 47 | run: cabal build --enable-tests --enable-benchmarks all 48 | - name: Run tests 49 | run: cabal test all 50 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011, Daniel Trstenjak 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | * Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | * Neither the name of the nor the 12 | names of its contributors may be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL DANIEL TRSTENJAK BE LIABLE FOR ANY 19 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /CHANGELOG: -------------------------------------------------------------------------------- 1 | 0.11.0 2 | ------ 3 | * Add option '--hiding' to hide symbols from import 4 | 5 | 0.10.0 6 | ------ 7 | * Ensure that no imports are placed inbetween cpp directives 8 | 9 | 0.9.0 10 | ----- 11 | * Support haddock comments 12 | 13 | 0.8.8 14 | ----- 15 | * Update README 16 | 17 | 0.8.7 18 | ----- 19 | * Raise upper bound of 'haskell-src-exts' 20 | * Tested with ghc 8.6.3 21 | 22 | 0.8.6 23 | ----- 24 | * Raise upper bounds of tasty 25 | * Tested with GHC 8.4.2 26 | 27 | 0.8.5 28 | ----- 29 | * Raise upper bounds of tasty and haskell-src-exts 30 | 31 | 0.8.3 32 | ----- 33 | * Raise upper bound of directory 34 | 35 | 0.8.2 36 | ----- 37 | * Update README 38 | 39 | 0.8.1 40 | ----- 41 | * Use SrcSpan info of haskell-src-exts instead of parsing import declarations by hand 42 | 43 | 0.8.0 44 | ----- 45 | * Changes for haskell-src-exts 1.18.0 46 | * Support GHC 8.0.1 47 | 48 | 0.7.1 49 | ----- 50 | * Switch from lens to microlens (for faster compiling) 51 | 52 | 0.7 53 | --- 54 | * Changes for haskell-src-exts 1.17.0 55 | 56 | 0.6.7 57 | ----- 58 | * More robust handling of invalid Haskell source code 59 | 60 | 0.6.6 61 | ----- 62 | * Raise upper bounds of dependencies 63 | 64 | 0.6.5 65 | ----- 66 | * Support GHC 7.10.1 67 | 68 | 0.6.4 69 | ----- 70 | * Raise upper bounds of dependencies 71 | 72 | 0.6.3 73 | ----- 74 | * Raise upper bounds of dependencies 75 | 76 | 0.6.2 77 | ----- 78 | * Fixing build failure of tasty 0.8.1.3 79 | 80 | 0.6.1 81 | ----- 82 | * Changes for haskell-src-exts 1.16.0 83 | 84 | 0.6 85 | --- 86 | * Add option '--as' 87 | 88 | $> hsimport -m 'Control.Monad' --as 'CM' SomeSource.hs 89 | => import Control.Monad as CM 90 | 91 | 0.5.2 92 | ----- 93 | * Build/tested with GHC 7.8.3 94 | 95 | 0.5.1 96 | ----- 97 | * Better handling of multi line imports like: 98 | 99 | import Control.Monad 100 | (when) 101 | 102 | import Control.Monad 103 | ( when 104 | , unless 105 | ) 106 | -------------------------------------------------------------------------------- /lib/HsImport/Types.hs: -------------------------------------------------------------------------------- 1 | 2 | module HsImport.Types where 3 | 4 | import qualified Language.Haskell.Exts as HS 5 | 6 | type SrcLine = Int 7 | type SrcColumn = Int 8 | type SrcSpan = HS.SrcSpan 9 | type SrcLoc = HS.SrcLoc 10 | type Annotation = (HS.SrcSpanInfo, [HS.Comment]) 11 | type Decl = HS.Decl Annotation 12 | type ImportDecl = HS.ImportDecl Annotation 13 | type ImportSpec = HS.ImportSpec Annotation 14 | type ImportSpecList = HS.ImportSpecList Annotation 15 | type Name = HS.Name Annotation 16 | type CName = HS.CName Annotation 17 | type Module = HS.Module Annotation 18 | type ModuleName = String 19 | type ErrorMessage = String 20 | 21 | data ParseResult = ParseResult 22 | { -- | the parse result 23 | result :: HS.ParseResult Module 24 | 25 | -- | if the source file isn't completely parsable, because e.g. 26 | -- it contains incomplete Haskell code, then 'lastValidLine' 27 | -- contains the last line till the source is parsable 28 | , lastValidLine :: Maybe Int 29 | } 30 | 31 | firstSrcLine :: Annotation -> SrcLine 32 | firstSrcLine = minimum . map HS.srcSpanStartLine . srcSpans 33 | 34 | lastSrcLine :: Annotation -> SrcLine 35 | lastSrcLine = maximum . map HS.srcSpanEndLine . srcSpans 36 | 37 | firstSrcColumn :: Annotation -> SrcColumn 38 | firstSrcColumn = minimum . map HS.srcSpanStartColumn . srcSpans 39 | 40 | lastSrcColumn :: Annotation -> SrcColumn 41 | lastSrcColumn = maximum . map HS.srcSpanEndColumn . srcSpans 42 | 43 | srcSpan :: Annotation -> SrcSpan 44 | srcSpan ann@(HS.SrcSpanInfo srcSpan _, _) = 45 | srcSpan { HS.srcSpanStartLine = firstSrcLine ann 46 | , HS.srcSpanStartColumn = firstSrcColumn ann 47 | , HS.srcSpanEndLine = lastSrcLine ann 48 | , HS.srcSpanEndColumn = lastSrcColumn ann 49 | } 50 | 51 | srcSpans :: Annotation -> [SrcSpan] 52 | srcSpans (HS.SrcSpanInfo srcSpan _, comments) = srcSpan : commentSrcSpans 53 | where 54 | commentSrcSpans = map (\(HS.Comment _ srcSpan _) -> srcSpan) comments 55 | 56 | noAnnotation :: Annotation 57 | noAnnotation = (HS.noSrcSpan, []) 58 | -------------------------------------------------------------------------------- /lib/HsImport/Args.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE DeriveDataTypeable, CPP #-} 2 | 3 | module HsImport.Args 4 | ( HsImportArgs(..) 5 | , hsImportArgs 6 | , defaultArgs 7 | ) where 8 | 9 | import Prelude hiding (all) 10 | import System.Console.CmdArgs 11 | 12 | #ifdef CABAL 13 | import Data.Version (showVersion) 14 | import Paths_hsimport (version) 15 | #endif 16 | 17 | data HsImportArgs = HsImportArgs 18 | { moduleName :: String 19 | , symbolName :: String 20 | , hiding :: Bool 21 | , all :: Bool 22 | , with :: [String] 23 | , qualifiedName :: String 24 | , as :: String 25 | , inputSrcFile :: FilePath 26 | , outputSrcFile :: FilePath 27 | } deriving (Data, Typeable, Show, Eq) 28 | 29 | 30 | hsImportArgs :: IO HsImportArgs 31 | hsImportArgs = cmdArgs $ HsImportArgs 32 | { moduleName = def &= help "The module to import" 33 | , symbolName = def &= help "The symbol to import, if empty, the entire module is imported" 34 | , hiding = def &= help "Hide the given symbols from the import" 35 | &= name "hiding" &= name "H" 36 | , all = def &= help "All constructors or methods of the symbol should be imported: 'Symbol(..)'" 37 | &= name "all" &= name "a" 38 | , with = def &= help "Which constructors or methods of the symbol should be imported: 'Symbol(With)'" 39 | , qualifiedName = def &= help "The name to use for a qualified module import" 40 | , as = def &= help "The name to use for an unqualified module import" &= name "as" 41 | , outputSrcFile = def &= help "Save modified source file to file, if empty, the source file is modified inplace" &= typFile 42 | , inputSrcFile = def &= args &= typ "SOURCEFILE" 43 | } 44 | &= program "hsimport" 45 | &= summary summaryInfo 46 | &= help "A command line program for extending the import list of a Haskell source file." 47 | &= helpArg [explicit, name "help", name "h"] 48 | &= versionArg [explicit, name "version", name "v", summary versionInfo] 49 | where 50 | summaryInfo = "" 51 | 52 | 53 | defaultArgs :: HsImportArgs 54 | defaultArgs = HsImportArgs 55 | { moduleName = def 56 | , symbolName = def 57 | , hiding = def 58 | , all = def 59 | , with = def 60 | , qualifiedName = def 61 | , as = def 62 | , inputSrcFile = def 63 | , outputSrcFile = def 64 | } 65 | 66 | 67 | versionInfo :: String 68 | versionInfo = 69 | #ifdef CABAL 70 | "hsimport version " ++ showVersion version 71 | #else 72 | "hsimport version unknown (not built with cabal)" 73 | #endif 74 | -------------------------------------------------------------------------------- /lib/HsImport/ImportPos.hs: -------------------------------------------------------------------------------- 1 | {-# Language CPP #-} 2 | 3 | module HsImport.ImportPos 4 | ( findImportPos 5 | , ImportPos(..) 6 | , matchingImports 7 | , bestMatchingImport 8 | ) where 9 | 10 | import qualified Language.Haskell.Exts as HS 11 | import Data.List.Index (ifoldl') 12 | import Data.List.Split (splitOn) 13 | import HsImport.Types 14 | 15 | #if __GLASGOW_HASKELL__ < 710 16 | import Control.Applicative ((<$>)) 17 | #endif 18 | 19 | -- | Where a new import declaration should be added. 20 | data ImportPos = Before ImportDecl -- ^ before the specified import declaration 21 | | After ImportDecl -- ^ after the specified import declaration 22 | deriving (Show, Eq) 23 | 24 | 25 | -- | Returns the position where the import declaration for the 26 | -- new import should be put into the list of import declarations. 27 | findImportPos :: ImportDecl -> [ImportDecl] -> Maybe ImportPos 28 | findImportPos newImport imports = After <$> bestMatchingImport name imports 29 | where 30 | HS.ModuleName _ name = HS.importModule newImport 31 | 32 | 33 | -- | Returns all import declarations having the same module name. 34 | matchingImports :: ModuleName -> [ImportDecl] -> [ImportDecl] 35 | matchingImports moduleName imports = 36 | [ i 37 | | i@HS.ImportDecl {HS.importModule = HS.ModuleName _ name} <- imports 38 | , moduleName == name 39 | ] 40 | 41 | 42 | -- | Returns the best matching import declaration for the given module name. 43 | -- E.g. if the module name is "Foo.Bar.Boo", then "Foo.Bar" is considered 44 | -- better matching than "Foo". 45 | bestMatchingImport :: ModuleName -> [ImportDecl] -> Maybe ImportDecl 46 | bestMatchingImport _ [] = Nothing 47 | bestMatchingImport moduleName imports = 48 | case ifoldl' computeMatches Nothing splittedMods of 49 | Just (idx, _) -> Just $ imports !! idx 50 | _ -> Nothing 51 | where 52 | computeMatches :: Maybe (Int, Int) -> Int -> [String] -> Maybe (Int, Int) 53 | computeMatches matches idx mod = 54 | let num' = numMatches splittedMod mod 55 | in case matches of 56 | Just (_, num) | num' >= num -> Just (idx, num') 57 | | otherwise -> matches 58 | 59 | Nothing | num' > 0 -> Just (idx, num') 60 | | otherwise -> Nothing 61 | where 62 | numMatches = loop 0 63 | where 64 | loop num (a:as) (b:bs) 65 | | a == b = loop (num + 1) as bs 66 | | otherwise = num 67 | 68 | loop num [] _ = num 69 | loop num _ [] = num 70 | 71 | splittedMod = splitOn "." moduleName 72 | splittedMods = [ splitOn "." name 73 | | HS.ImportDecl {HS.importModule = HS.ModuleName _ name} <- imports 74 | ] 75 | -------------------------------------------------------------------------------- /lib/HsImport/HsImportSpec.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE TemplateHaskell, PatternGuards #-} 2 | 3 | module HsImport.HsImportSpec 4 | ( HsImportSpec(..) 5 | , hsImportSpec 6 | ) where 7 | 8 | import qualified Language.Haskell.Exts as HS 9 | import qualified HsImport.Args as Args 10 | import HsImport.Args (HsImportArgs) 11 | import HsImport.Parse (parseFile) 12 | import HsImport.SymbolImport (SymbolImport(..), Symbol(..)) 13 | import HsImport.ModuleImport 14 | import HsImport.Types 15 | import Data.List (find) 16 | 17 | data HsImportSpec = HsImportSpec 18 | { sourceFile :: FilePath 19 | , parsedSrcFile :: Module 20 | , moduleImport :: ModuleImport 21 | , symbolImport :: Maybe SymbolImport 22 | , saveToFile :: Maybe FilePath 23 | } deriving (Show) 24 | 25 | 26 | hsImportSpec :: HsImportArgs -> IO (Either ErrorMessage HsImportSpec) 27 | hsImportSpec args 28 | | Just error <- checkArgs args = return $ Left error 29 | | otherwise = do 30 | result <- parseFile $ Args.inputSrcFile args 31 | case result of 32 | Right (ParseResult (HS.ParseOk hsModule) _) -> return $ Right $ 33 | HsImportSpec { sourceFile = Args.inputSrcFile args 34 | , parsedSrcFile = hsModule 35 | , moduleImport = module_ 36 | , symbolImport = symbolImport 37 | , saveToFile = saveToFile 38 | } 39 | 40 | Right (ParseResult (HS.ParseFailed srcLoc error) _) -> return $ Left (show srcLoc ++ error) 41 | 42 | Left error -> return $ Left error 43 | 44 | where 45 | module_ = ModuleImport { moduleName = Args.moduleName args 46 | , qualified = not . null $ Args.qualifiedName args 47 | , as = find (/= "") [Args.qualifiedName args, Args.as args] 48 | } 49 | 50 | constructor = if Args.hiding args then Hiding else Import 51 | 52 | symbolImport = 53 | case Args.symbolName args of 54 | "" -> Nothing 55 | 56 | name | Args.all args -> Just $ constructor $ AllOf name 57 | | ws@(_:_) <- Args.with args -> Just $ constructor $ SomeOf name ws 58 | | otherwise -> Just $ constructor $ Only name 59 | 60 | saveToFile = 61 | case Args.outputSrcFile args of 62 | "" -> Nothing 63 | fp -> Just fp 64 | 65 | checkArgs args 66 | | null . Args.inputSrcFile $ args 67 | = Just "Missing source file!" 68 | 69 | | null . Args.moduleName $ args 70 | = Just "Missing module name!" 71 | 72 | | (not . null $ qualifiedName) && (not . null $ asName) 73 | = Just "Invalid usage of options '--qualifiedname' and '--as' at once!" 74 | 75 | | otherwise 76 | = Nothing 77 | where 78 | qualifiedName = Args.qualifiedName args 79 | asName = Args.as args 80 | -------------------------------------------------------------------------------- /hsimport.cabal: -------------------------------------------------------------------------------- 1 | cabal-version: 2.0 2 | name: hsimport 3 | version: 0.11.0 4 | license: BSD3 5 | license-file: LICENSE 6 | maintainer: power.walross@gmail.com 7 | author: Daniel Trstenjak 8 | tested-with: GHC ==8.4.4 || ==8.6.5 || ==8.8.4 || ==8.10.2 9 | synopsis: Extend the import list of a Haskell source file 10 | description: 11 | A command line program for extending the import list of a Haskell source file. 12 | 13 | category: Utils, Development 14 | build-type: Simple 15 | extra-source-files: 16 | CHANGELOG 17 | README.md 18 | tests/goldenFiles/*.hs 19 | tests/inputFiles/*.hs 20 | tests/outputFiles/.gitignore 21 | 22 | source-repository head 23 | type: git 24 | location: https://github.com/fendor/hsimport 25 | 26 | library 27 | exposed-modules: 28 | HsImport 29 | HsImport.Args 30 | HsImport.Config 31 | HsImport.ImportPos 32 | HsImport.Main 33 | 34 | cpp-options: -DCABAL 35 | hs-source-dirs: lib 36 | other-modules: 37 | HsImport.HsImportSpec 38 | HsImport.ImportChange 39 | HsImport.ModuleImport 40 | HsImport.Parse 41 | HsImport.PrettyPrint 42 | HsImport.SymbolImport 43 | HsImport.Types 44 | HsImport.Utils 45 | Paths_hsimport 46 | 47 | default-language: Haskell2010 48 | ghc-options: -W 49 | build-depends: 50 | attoparsec >=0.10.4.0 && <0.15 51 | , base >=3 && <5 52 | , cmdargs ^>=0.10.5 53 | , directory >=1.2.0.1 && <1.4 54 | , dyre ^>=0.9 55 | , haskell-src-exts >=1.18.0 && <1.24 56 | , ilist >=0.1 && <0.5 57 | , microlens ^>=0.4 58 | , mtl >=2.1.2 && <2.3 59 | , split ^>=0.2.2 60 | , text >=0.11.3.1 && <1.3 61 | 62 | library library-internal 63 | exposed-modules: 64 | HsImport 65 | HsImport.Args 66 | HsImport.Config 67 | HsImport.HsImportSpec 68 | HsImport.ImportChange 69 | HsImport.ImportPos 70 | HsImport.Main 71 | HsImport.ModuleImport 72 | HsImport.Parse 73 | HsImport.PrettyPrint 74 | HsImport.SymbolImport 75 | HsImport.Types 76 | HsImport.Utils 77 | Paths_hsimport 78 | 79 | cpp-options: -DCABAL 80 | hs-source-dirs: lib 81 | autogen-modules: Paths_hsimport 82 | default-language: Haskell2010 83 | ghc-options: -W 84 | build-depends: 85 | attoparsec 86 | , base 87 | , cmdargs 88 | , directory 89 | , dyre 90 | , haskell-src-exts 91 | , ilist 92 | , microlens 93 | , mtl 94 | , split 95 | , text 96 | 97 | executable hsimport 98 | main-is: Main.hs 99 | cpp-options: -DCABAL 100 | hs-source-dirs: exe 101 | default-language: Haskell2010 102 | ghc-options: -W 103 | build-depends: 104 | base >=3 && <5 105 | , hsimport 106 | 107 | test-suite tests 108 | type: exitcode-stdio-1.0 109 | main-is: Main.hs 110 | hs-source-dirs: tests 111 | default-language: Haskell2010 112 | ghc-options: -W 113 | build-depends: 114 | base >=3 && <5 115 | , bytestring ^>=0.10.8.2 || ^>=0.11.1 116 | , filepath >=1.3.0.1 && <1.5 117 | , haskell-src-exts 118 | , library-internal 119 | , tasty >=0.9.0.1 && <1.5 120 | , tasty-golden >=2.2.0.1 && <2.4 121 | , utf8-string ^>=1.0.1.1 122 | -------------------------------------------------------------------------------- /lib/HsImport/Main.hs: -------------------------------------------------------------------------------- 1 | {-# Language PatternGuards, CPP #-} 2 | 3 | module HsImport.Main 4 | ( hsimport 5 | , hsimportWithArgs 6 | ) where 7 | 8 | import Control.Monad (when) 9 | import System.Exit (exitFailure, exitSuccess) 10 | import System.IO (hPutStrLn, stderr) 11 | import Data.Maybe (isJust, mapMaybe) 12 | import Data.List (foldl', partition) 13 | import qualified Data.Text as T 14 | import qualified Data.Text.IO as TIO 15 | import qualified Config.Dyre as Dyre 16 | import qualified Language.Haskell.Exts as HS 17 | import HsImport.ImportChange 18 | import HsImport.HsImportSpec 19 | import HsImport.ImportPos (ImportPos(..)) 20 | import qualified HsImport.Args as Args 21 | import HsImport.Config 22 | import HsImport.Utils 23 | import HsImport.Types 24 | 25 | #if __GLASGOW_HASKELL__ < 710 26 | import Control.Applicative ((<$>)) 27 | #endif 28 | 29 | 30 | hsimport :: Config -> IO () 31 | hsimport = Dyre.wrapMain $ 32 | Dyre.newParams 33 | "hsimport" 34 | realMain 35 | (\config err -> config { configError = Just err }) 36 | where 37 | realMain :: Config -> IO () 38 | realMain config = do 39 | case configError config of 40 | Just error -> hPutStrLn stderr ("hsimport: " ++ error) >> exitFailure 41 | _ -> return () 42 | 43 | args <- Args.hsImportArgs 44 | maybeErr <- hsimportWithArgs config args 45 | case maybeErr of 46 | Just err -> hPutStrLn stderr ("hsimport: " ++ err) >> exitFailure 47 | _ -> exitSuccess 48 | 49 | 50 | hsimportWithArgs :: Config -> Args.HsImportArgs -> IO (Maybe ErrorMessage) 51 | hsimportWithArgs config args = do 52 | maybeSpec <- hsImportSpec args 53 | case maybeSpec of 54 | Left error -> return $ Just error 55 | Right spec -> hsimportWithSpec config spec 56 | 57 | 58 | hsimportWithSpec :: Config -> HsImportSpec -> IO (Maybe ErrorMessage) 59 | hsimportWithSpec Config { prettyPrint = prettyPrint, findImportPos = findImportPos } spec = do 60 | let impChanges = importChanges (moduleImport spec) (symbolImport spec) (parsedSrcFile spec) 61 | case partition hasImportError impChanges of 62 | ([], changes) -> do 63 | srcLines <- lines . T.unpack <$> TIO.readFile (sourceFile spec) 64 | let srcLines' = applyChanges srcLines changes 65 | when (srcLines' /= srcLines || isJust (saveToFile spec)) $ 66 | TIO.writeFile (outputFile spec) (T.pack $ unlines srcLines') 67 | return Nothing 68 | 69 | (errors, _) -> 70 | return (Just (unlines $ mapMaybe toErrorMessage errors)) 71 | 72 | where 73 | applyChanges = foldl' applyChange 74 | 75 | applyChange srcLines (ReplaceImportAt srcSpan importDecl) = 76 | let numTakes = max 0 (HS.srcSpanStartLine srcSpan - 1) 77 | numDrops = HS.srcSpanEndLine srcSpan 78 | in take numTakes srcLines ++ [prettyPrint importDecl] ++ drop numDrops srcLines 79 | 80 | applyChange srcLines (AddImportAfter srcLine importDecl) = 81 | let numTakes = srcLine 82 | numDrops = numTakes 83 | in take numTakes srcLines ++ [prettyPrint importDecl] ++ drop numDrops srcLines 84 | 85 | applyChange srcLines (AddImportAtEnd importDecl) = 86 | srcLines ++ [prettyPrint importDecl] 87 | 88 | applyChange srcLines (FindImportPos importDecl) = 89 | case findImportPos importDecl allImportDecls of 90 | Just (After impDecl) -> applyChange srcLines (AddImportAfter (lastSrcLine . HS.ann $ impDecl) 91 | importDecl) 92 | Just (Before impDecl) -> applyChange srcLines (AddImportAfter (max 0 ((firstSrcLine . HS.ann $ impDecl) - 1)) 93 | importDecl) 94 | _ -> applyChange srcLines (AddImportAfter (lastSrcLine . HS.ann . last $ allImportDecls) 95 | importDecl) 96 | 97 | applyChange srcLines NoImportChange = srcLines 98 | 99 | applyChange _ (ImportError _) = error "hsimportWithSpec: unexpected 'ImportError'" 100 | 101 | outputFile spec 102 | | Just file <- saveToFile spec = file 103 | | otherwise = sourceFile spec 104 | 105 | allImportDecls = importDecls $ parsedSrcFile spec 106 | -------------------------------------------------------------------------------- /lib/HsImport/Parse.hs: -------------------------------------------------------------------------------- 1 | {-# Language ScopedTypeVariables, PatternGuards, CPP #-} 2 | 3 | module HsImport.Parse 4 | ( parseFile 5 | , replaceCpp 6 | ) where 7 | 8 | import qualified Data.Text.IO as TIO 9 | import qualified Data.Text as T 10 | import Data.List (isPrefixOf) 11 | import qualified Language.Haskell.Exts as HS 12 | import Control.Exception (catch, SomeException) 13 | 14 | #if __GLASGOW_HASKELL__ < 710 15 | import Control.Applicative ((<$>)) 16 | #endif 17 | 18 | import HsImport.Types 19 | 20 | parseFile :: FilePath -> IO (Either ErrorMessage ParseResult) 21 | parseFile file = do 22 | srcFile <- replaceCpp . T.unpack <$> TIO.readFile file 23 | catch (do let result = parseFileContents srcFile 24 | case result of 25 | HS.ParseOk _ -> return . Right $ ParseResult result Nothing 26 | 27 | HS.ParseFailed srcLoc _ -> do 28 | srcResult <- parseInvalidSource (lines srcFile) (HS.srcLine srcLoc) 29 | return $ case srcResult of 30 | Just srcRes -> Right srcRes 31 | Nothing -> Right $ ParseResult result Nothing) 32 | 33 | (\(e :: SomeException) -> do 34 | let srcLines = lines srcFile 35 | srcResult <- parseInvalidSource srcLines (length srcLines) 36 | return $ maybe (Left $ show e) Right srcResult) 37 | 38 | 39 | -- | replace the complete cpp directive, from #ifdef till #endif, by empty lines 40 | replaceCpp :: String -> String 41 | replaceCpp contents = unlines . reverse $ go (lines contents) [] 0 42 | where 43 | go [] newLines _ = newLines 44 | go lines newLines ifdefLevel = go lines' newLines' ifdefLevel' 45 | where 46 | currLine = head lines 47 | hasCpp = "#" `isPrefixOf` currLine 48 | hasIf = "#if" `isPrefixOf` currLine 49 | hasEndIf = "#endif" `isPrefixOf` currLine 50 | ifdefLevel' = ifdefLevel + (if hasIf then 1 else 0) - (if hasEndIf then 1 else 0) 51 | lines' = tail lines 52 | inCpp = hasCpp || (max ifdefLevel ifdefLevel') > 0 53 | newLines' = (if inCpp then "" else currLine) : newLines 54 | 55 | 56 | type HsParseResult = HS.ParseResult Module 57 | 58 | 59 | -- | tries to find the maximal part of the source file (from the beginning) that contains 60 | -- valid/complete Haskell code 61 | parseInvalidSource :: [String] -> Int -> IO (Maybe ParseResult) 62 | parseInvalidSource srcLines firstInvalidLine = do 63 | parseInvalidSource' 1 firstInvalidLine Nothing 0 64 | where 65 | parseInvalidSource' :: Int -> Int -> Maybe (Int, HsParseResult) -> Int -> IO (Maybe ParseResult) 66 | parseInvalidSource' lastValidLine currLastLine maxParseOk iteration 67 | | null srcLines || lastValidLine >= currLastLine 68 | = return Nothing 69 | 70 | | iteration >= 10 71 | = return $ case maxParseOk of 72 | Just (lastLine, result) -> Just $ ParseResult result (Just lastLine) 73 | Nothing -> Nothing 74 | 75 | | otherwise = do 76 | catch (case parseFileContents source of 77 | result@(HS.ParseOk _) 78 | | nextLine == currLastLine -> return . Just $ ParseResult result (Just lastValidLine) 79 | | otherwise -> parseInvalidSource' nextLine currLastLine (maxParseOk' result) iteration' 80 | 81 | HS.ParseFailed srcLoc _ 82 | | HS.srcLine srcLoc == firstInvalidLine -> 83 | parseInvalidSource' lastValidLine nextLine maxParseOk iteration' 84 | 85 | | otherwise -> 86 | parseInvalidSource' nextLine currLastLine maxParseOk iteration') 87 | 88 | (\(_ :: SomeException) -> parseInvalidSource' lastValidLine nextLine maxParseOk iteration') 89 | where 90 | source = unlines $ take nextLine srcLines 91 | nextLine = lastValidLine + (floor ((realToFrac (currLastLine - lastValidLine) / 2) :: Double) :: Int) 92 | iteration' = iteration + 1 93 | 94 | maxParseOk' nextResult = 95 | case maxParseOk of 96 | Just (maxLine, _) 97 | | nextLine > maxLine -> Just (nextLine, nextResult) 98 | | otherwise -> maxParseOk 99 | 100 | _ -> Just (nextLine, nextResult) 101 | 102 | 103 | parseFileContents :: String -> HsParseResult 104 | parseFileContents contents = 105 | let result = HS.parseFileContentsWithComments parseMode contents 106 | in case result of 107 | HS.ParseOk res -> HS.ParseOk $ HS.associateHaddock res 108 | HS.ParseFailed sloc msg -> HS.ParseFailed sloc msg 109 | 110 | where 111 | parseMode = HS.defaultParseMode { HS.fixities = Just [] } 112 | 113 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | hsimport 2 | ======== 3 | 4 | [![Build Status](https://travis-ci.org/fendor/hsimport.svg?branch=master)](https://travis-ci.org/fendor/hsimport) 5 | [![Hackage](http://img.shields.io/hackage/v/hsimport.svg)](https://hackage.haskell.org/package/hsimport) 6 | 7 | A command line program for extending the import list of a Haskell source file. 8 | 9 | `hsimport` gets the module name and the symbol name to import as arguments, 10 | parses the given source file using the library `haskell-src-exts` and then tries 11 | to only extend the import list if it's necessary. If the symbol is already 12 | imported or if the whole module is already imported, then the given source file 13 | isn't changed. 14 | 15 | Installation 16 | ------------ 17 | 18 | cabal install hsimport 19 | 20 | Examples 21 | -------- 22 | 23 | $> hsimport -m 'Control.Monad' SomeSource.hs 24 | => import Control.Monad 25 | 26 | $> hsimport -m 'Control.Monad' -s 'when' SomeSource.hs 27 | => import Control.Monad (when) 28 | 29 | $> hsimport -m 'Control.Monad' -q 'CM' SomeSource.hs 30 | => import qualified Control.Monad as CM 31 | 32 | $> hsimport -m 'Control.Monad' --as 'CM' SomeSource.hs 33 | => import Control.Monad as CM 34 | 35 | $> hsimport -m 'Data.Maybe' -s 'Maybe' 36 | => import Data.Maybe (Maybe) 37 | 38 | $> hsimport -m 'Data.Maybe' -s 'Maybe' -a 39 | => import Data.Maybe (Maybe(..)) 40 | 41 | $> hsimport -m 'Data.Maybe' -s 'Maybe' -w 'Just' 42 | => import Data.Maybe (Maybe(Just)) 43 | 44 | $> hsimport -m 'Data.Maybe' -s 'Maybe' -w 'Just' -w 'Nothing' 45 | => import Data.Maybe (Maybe(Just, Nothing)) 46 | 47 | Configuration 48 | ------------- 49 | 50 | The easiest way to configure `hsimport` is by creating a `cabal` project. 51 | An example for this is [here](). 52 | 53 | 54 | The other way - which most likely isn't worth the hassle - is by writting a `~/.config/hsimport/hsimport.hs` file: 55 | 56 | -- ~/.config/hsimport/hsimport.hs 57 | import qualified Language.Haskell.Exts as HS 58 | import HsImport 59 | 60 | main :: IO () 61 | main = hsimport $ defaultConfig { prettyPrint = prettyPrint, findImportPos = findImportPos } 62 | where 63 | -- This is a bogus implementation of prettyPrint, because it doesn't handle the 64 | -- qualified import case nor does it considers any explicitely imported or hidden symbols. 65 | prettyPrint :: ImportDecl -> String 66 | prettyPrint (ImportDecl { HS.importModule = HS.ModuleName _ modName }) = 67 | "import " ++ modName 68 | 69 | -- This findImportPos implementation will always add the new import declaration 70 | -- at the end of the current ones. The data type ImportPos has the two constructors 71 | -- After and Before. 72 | findImportPos :: ImportDecl -> [ImportDecl] -> Maybe ImportPos 73 | findImportPos _ [] = Nothing 74 | findImportPos newImport currentImports = Just . After . last $ currentImports 75 | 76 | The position of the configuration file depends on the result of `getUserConfigDir "hsimport"`, 77 | which is a function from the package [xdg-basedir](), 78 | on linux like systems it is `~/.config/hsimport/hsimport.hs`. 79 | 80 | If you've modified the configuration file, then the next call of `hsimport` will ensure a rebuild. 81 | If you've installed `hsimport` with `cabal install`, without using a sandbox, then this should just work. 82 | 83 | If you've build `hsimport` inside of a sandbox, then you most likely have to temporary modify the 84 | `GHC_PACKAGE_PATH` for the next call of `hsimport`, to point `ghc` to the global database and 85 | to the package database of the sandbox. 86 | 87 | # global package database 88 | $> export GLOBAL_PKG_DB=/usr/lib/ghc/package.conf.d/ 89 | 90 | # hsimport sandbox package database 91 | $> export SANDBOX_PKG_DB=/home/you/hsimport-build-dir/.cabal-sandbox/*-packages.conf.d/ 92 | 93 | $> GHC_PACKAGE_PATH=$GLOBAL_PKG_DB:$SANDBOX_PKG_DB hsimport --help 94 | 95 | Text Editor Integration 96 | ----------------------- 97 | 98 | [vim-hsimport]() 99 | 100 | Command Line Usage 101 | ------------------ 102 | 103 | $> hsimport --help 104 | hsimport [OPTIONS] [SOURCEFILE] 105 | A command line program for extending the import list of a Haskell source 106 | file. 107 | 108 | Common flags: 109 | -m --modulename=ITEM The module to import 110 | -s --symbolname=ITEM The symbol to import, if empty, the entire module 111 | is imported 112 | -a --all All constructors or methods of the symbol should 113 | be imported: 'Symbol(..)' 114 | -w --with=ITEM The constructors or methods of the symbol 115 | should be imported: 'Symbol(With)' 116 | -q --qualifiedname=ITEM The name to use for a qualified module import 117 | -o --outputsrcfile=FILE Save modified source file to file, if empty, the 118 | source file is modified inplace 119 | -h --help Display help message 120 | -v --version Print version information 121 | 122 | Issues 123 | ------ 124 | 125 | There is some rudimentarily handling for code using CPP, but the import statements 126 | might be added at the wrong place, because the lines containing CPP directives 127 | are ignored and therefore they aren't considered in the source line count. 128 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # This Travis job script has been generated by a script via 2 | # 3 | # haskell-ci 'hsimport.cabal' 4 | # 5 | # For more information, see https://github.com/haskell-CI/haskell-ci 6 | # 7 | # version: 0.3.20190814 8 | # 9 | language: c 10 | dist: xenial 11 | sudo: required 12 | git: 13 | # whether to recursively clone submodules 14 | submodules: false 15 | cache: 16 | directories: 17 | - $HOME/.cabal/packages 18 | - $HOME/.cabal/store 19 | before_cache: 20 | - rm -fv $CABALHOME/packages/hackage.haskell.org/build-reports.log 21 | # remove files that are regenerated by 'cabal update' 22 | - rm -fv $CABALHOME/packages/hackage.haskell.org/00-index.* 23 | - rm -fv $CABALHOME/packages/hackage.haskell.org/*.json 24 | - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.cache 25 | - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.tar 26 | - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.tar.idx 27 | - rm -rfv $CABALHOME/packages/head.hackage 28 | matrix: 29 | include: 30 | - compiler: ghc-8.6.5 31 | addons: {"apt":{"sources":["hvr-ghc"],"packages":["ghc-8.6.5","cabal-install-2.4"]}} 32 | - compiler: ghc-8.6.3 33 | addons: {"apt":{"sources":["hvr-ghc"],"packages":["ghc-8.6.3","cabal-install-2.4"]}} 34 | - compiler: ghc-8.4.2 35 | addons: {"apt":{"sources":["hvr-ghc"],"packages":["ghc-8.4.2","cabal-install-2.4"]}} 36 | - compiler: ghc-8.2.1 37 | addons: {"apt":{"sources":["hvr-ghc"],"packages":["ghc-8.2.1","cabal-install-2.4"]}} 38 | before_install: 39 | - HC=$(echo "/opt/$CC/bin/ghc" | sed 's/-/\//') 40 | - WITHCOMPILER="-w $HC" 41 | - HCPKG="$HC-pkg" 42 | - unset CC 43 | - CABAL=/opt/ghc/bin/cabal 44 | - CABALHOME=$HOME/.cabal 45 | - export PATH="$CABALHOME/bin:$PATH" 46 | - TOP=$(pwd) 47 | - "HCNUMVER=$(${HC} --numeric-version|perl -ne '/^(\\d+)\\.(\\d+)\\.(\\d+)(\\.(\\d+))?$/; print(10000 * $1 + 100 * $2 + ($3 == 0 ? $5 != 1 : $3))')" 48 | - echo $HCNUMVER 49 | - CABAL="$CABAL -vnormal+nowrap+markoutput" 50 | - set -o pipefail 51 | - | 52 | echo 'function blue(s) { printf "\033[0;34m" s "\033[0m " }' >> .colorful.awk 53 | echo 'BEGIN { state = "output"; }' >> .colorful.awk 54 | echo '/^-----BEGIN CABAL OUTPUT-----$/ { state = "cabal" }' >> .colorful.awk 55 | echo '/^-----END CABAL OUTPUT-----$/ { state = "output" }' >> .colorful.awk 56 | echo '!/^(-----BEGIN CABAL OUTPUT-----|-----END CABAL OUTPUT-----)/ {' >> .colorful.awk 57 | echo ' if (state == "cabal") {' >> .colorful.awk 58 | echo ' print blue($0)' >> .colorful.awk 59 | echo ' } else {' >> .colorful.awk 60 | echo ' print $0' >> .colorful.awk 61 | echo ' }' >> .colorful.awk 62 | echo '}' >> .colorful.awk 63 | - cat .colorful.awk 64 | - | 65 | color_cabal_output () { 66 | awk -f $TOP/.colorful.awk 67 | } 68 | - echo text | color_cabal_output 69 | install: 70 | - ${CABAL} --version 71 | - echo "$(${HC} --version) [$(${HC} --print-project-git-commit-id 2> /dev/null || echo '?')]" 72 | - TEST=--enable-tests 73 | - BENCH=--enable-benchmarks 74 | - HEADHACKAGE=false 75 | - rm -f $CABALHOME/config 76 | - | 77 | echo "verbose: normal +nowrap +markoutput" >> $CABALHOME/config 78 | echo "remote-build-reporting: anonymous" >> $CABALHOME/config 79 | echo "write-ghc-environment-files: always" >> $CABALHOME/config 80 | echo "remote-repo-cache: $CABALHOME/packages" >> $CABALHOME/config 81 | echo "logs-dir: $CABALHOME/logs" >> $CABALHOME/config 82 | echo "world-file: $CABALHOME/world" >> $CABALHOME/config 83 | echo "extra-prog-path: $CABALHOME/bin" >> $CABALHOME/config 84 | echo "symlink-bindir: $CABALHOME/bin" >> $CABALHOME/config 85 | echo "installdir: $CABALHOME/bin" >> $CABALHOME/config 86 | echo "build-summary: $CABALHOME/logs/build.log" >> $CABALHOME/config 87 | echo "store-dir: $CABALHOME/store" >> $CABALHOME/config 88 | echo "install-dirs user" >> $CABALHOME/config 89 | echo " prefix: $CABALHOME" >> $CABALHOME/config 90 | echo "repository hackage.haskell.org" >> $CABALHOME/config 91 | echo " url: http://hackage.haskell.org/" >> $CABALHOME/config 92 | - cat $CABALHOME/config 93 | - rm -fv cabal.project cabal.project.local cabal.project.freeze 94 | - travis_retry ${CABAL} v2-update -v 95 | # Generate cabal.project 96 | - rm -rf cabal.project cabal.project.local cabal.project.freeze 97 | - touch cabal.project 98 | - | 99 | echo "packages: ." >> cabal.project 100 | - | 101 | - "for pkg in $($HCPKG list --simple-output); do echo $pkg | sed 's/-[^-]*$//' | (grep -vE -- '^(hsimport)$' || true) | sed 's/^/constraints: /' | sed 's/$/ installed/' >> cabal.project.local; done" 102 | - cat cabal.project || true 103 | - cat cabal.project.local || true 104 | - if [ -f "./configure.ac" ]; then (cd "." && autoreconf -i); fi 105 | - ${CABAL} v2-freeze $WITHCOMPILER ${TEST} ${BENCH} | color_cabal_output 106 | - "cat cabal.project.freeze | sed -E 's/^(constraints: *| *)//' | sed 's/any.//'" 107 | - rm cabal.project.freeze 108 | - ${CABAL} v2-build $WITHCOMPILER ${TEST} ${BENCH} --dep -j2 all | color_cabal_output 109 | - ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks --dep -j2 all | color_cabal_output 110 | script: 111 | - DISTDIR=$(mktemp -d /tmp/dist-test.XXXX) 112 | # Packaging... 113 | - ${CABAL} v2-sdist all | color_cabal_output 114 | # Unpacking... 115 | - mv dist-newstyle/sdist/*.tar.gz ${DISTDIR}/ 116 | - cd ${DISTDIR} || false 117 | - find . -maxdepth 1 -type f -name '*.tar.gz' -exec tar -xvf '{}' \; 118 | - find . -maxdepth 1 -type f -name '*.tar.gz' -exec rm '{}' \; 119 | - PKGDIR_hsimport="$(find . -maxdepth 1 -type d -regex '.*/hsimport-[0-9.]*')" 120 | # Generate cabal.project 121 | - rm -rf cabal.project cabal.project.local cabal.project.freeze 122 | - touch cabal.project 123 | - | 124 | echo "packages: ${PKGDIR_hsimport}" >> cabal.project 125 | - | 126 | - "for pkg in $($HCPKG list --simple-output); do echo $pkg | sed 's/-[^-]*$//' | (grep -vE -- '^(hsimport)$' || true) | sed 's/^/constraints: /' | sed 's/$/ installed/' >> cabal.project.local; done" 127 | - cat cabal.project || true 128 | - cat cabal.project.local || true 129 | # Building... 130 | # this builds all libraries and executables (without tests/benchmarks) 131 | - ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks all | color_cabal_output 132 | # Building with tests and benchmarks... 133 | # build & run tests, build benchmarks 134 | - ${CABAL} v2-build $WITHCOMPILER ${TEST} ${BENCH} all | color_cabal_output 135 | # Testing... 136 | - ${CABAL} v2-test $WITHCOMPILER ${TEST} ${BENCH} all | color_cabal_output 137 | # cabal check... 138 | - (cd ${PKGDIR_hsimport} && ${CABAL} -vnormal check) 139 | # haddock... 140 | - ${CABAL} v2-haddock $WITHCOMPILER ${TEST} ${BENCH} all | color_cabal_output 141 | # Building without installed constraints for packages in global-db... 142 | - rm -f cabal.project.local 143 | - ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks all | color_cabal_output 144 | 145 | # REGENDATA ["hsimport.cabal"] 146 | # EOF 147 | -------------------------------------------------------------------------------- /tests/Main.hs: -------------------------------------------------------------------------------- 1 | 2 | module Main where 3 | 4 | import Test.Tasty 5 | import Test.Tasty.Golden 6 | import System.FilePath 7 | import System.IO (hPutStrLn, stderr) 8 | import Data.List (intercalate) 9 | import qualified Data.ByteString.Lazy.UTF8 as BS 10 | import qualified Language.Haskell.Exts as HS 11 | import qualified HsImport as HI 12 | import qualified HsImport.Parse as HIP 13 | import HsImport.Types 14 | 15 | main = defaultMain tests 16 | 17 | tests :: TestTree 18 | tests = testGroup "Tests" [moduleTests, symbolTests, replaceCppTests, parseTests] 19 | 20 | moduleTests :: TestTree 21 | moduleTests = testGroup "Module Tests" 22 | [ test "ModuleTest0" $ HI.defaultArgs { HI.moduleName = "Foo.Bar" } 23 | , test "ModuleTest1" $ HI.defaultArgs { HI.moduleName = "Foo.Bar" } 24 | , test "ModuleTest2" $ HI.defaultArgs { HI.moduleName = "Foo.Bar.Blub" } 25 | , test "ModuleTest3" $ HI.defaultArgs { HI.moduleName = "Control.Monad" } 26 | , test "ModuleTest4" $ HI.defaultArgs { HI.moduleName = "Ugah.Argh2" } 27 | , test "ModuleTest5" $ HI.defaultArgs { HI.moduleName = "Control.Monad" } 28 | , test "ModuleTest6" $ HI.defaultArgs { HI.moduleName = "Control.Monad" } 29 | , test "ModuleTest7" $ HI.defaultArgs { HI.moduleName = "Control.Monad" } 30 | , test "ModuleTest8" $ HI.defaultArgs { HI.moduleName = "Control.Monad" } 31 | , test "ModuleTest9" $ HI.defaultArgs { HI.moduleName = "Control.Monad" } 32 | , test "ModuleTest10" $ HI.defaultArgs { HI.moduleName = "Control.Monad" } 33 | , test "ModuleTest11" $ HI.defaultArgs { HI.moduleName = "Control.Monad" } 34 | , test "ModuleTest12" $ HI.defaultArgs { HI.moduleName = "Control.Monad" } 35 | , test "ModuleTest13" $ HI.defaultArgs { HI.moduleName = "Control.Monad" } 36 | , test "ModuleTest14" $ HI.defaultArgs { HI.moduleName = "Control.Monad" } 37 | , test "ModuleTest15" $ HI.defaultArgs { HI.moduleName = "Control.Monad" } 38 | , test "ModuleTest16" $ HI.defaultArgs { HI.moduleName = "Control.Monad" } 39 | , test "ModuleTest17" $ HI.defaultArgs { HI.moduleName = "Control.Monad" } 40 | , test "ModuleTest18" $ HI.defaultArgs { HI.moduleName = "Control.Monad" } 41 | , test "ModuleTest19" $ HI.defaultArgs { HI.moduleName = "Control.Monad" } 42 | , test "ModuleTest20" $ HI.defaultArgs { HI.moduleName = "Control.Monad" } 43 | , test "ModuleTest21" $ HI.defaultArgs { HI.moduleName = "Control.Monad" } 44 | , test "ModuleTest22" $ HI.defaultArgs { HI.moduleName = "Control.Monad" } 45 | , test "ModuleTest23" $ HI.defaultArgs { HI.moduleName = "Control.Monad", HI.qualifiedName = "CM" } 46 | , test "ModuleTest24" $ HI.defaultArgs { HI.moduleName = "Control.Monad", HI.qualifiedName = "CM" } 47 | , test "ModuleTest25" $ HI.defaultArgs { HI.moduleName = "Control.Monad", HI.qualifiedName = "Control.Monad" } 48 | , test "ModuleTest26" $ HI.defaultArgs { HI.moduleName = "Control.Monad" } 49 | , configTest "ModuleTest27" (HI.defaultConfig { HI.findImportPos = importPosBeforeFirst }) (HI.defaultArgs { HI.moduleName = "Control.Monad" }) 50 | , configTest "ModuleTest28" (HI.defaultConfig { HI.findImportPos = importPosAfterFirst }) (HI.defaultArgs { HI.moduleName = "Control.Monad" }) 51 | , configTest "ModuleTest29" (HI.defaultConfig { HI.findImportPos = importPosBeforeLast }) (HI.defaultArgs { HI.moduleName = "Control.Monad" }) 52 | , configTest "ModuleTest30" (HI.defaultConfig { HI.findImportPos = importPosAfterLast }) (HI.defaultArgs { HI.moduleName = "Control.Monad" }) 53 | , test "ModuleTest31" $ HI.defaultArgs { HI.moduleName = "Control.Monad", HI.as = "CM" } 54 | , test "ModuleTest32" $ HI.defaultArgs { HI.moduleName = "Control.Monad" } 55 | , test "ModuleTest33" $ HI.defaultArgs { HI.moduleName = "Control.Monad" } 56 | , test "ModuleTest34" $ HI.defaultArgs { HI.moduleName = "Control.Monad" } 57 | , test "ModuleTest35" $ HI.defaultArgs { HI.moduleName = "Control.Monad" } 58 | , test "ModuleTest36" $ HI.defaultArgs { HI.moduleName = "Control.Monad" } 59 | , test "ModuleTest37" $ HI.defaultArgs { HI.moduleName = "Control.Monad" } 60 | , test "ModuleTest38" $ HI.defaultArgs { HI.moduleName = "Data.Text" } 61 | ] 62 | 63 | 64 | symbolTests :: TestTree 65 | symbolTests = testGroup "Symbol Tests" 66 | [ test "SymbolTest0" $ HI.defaultArgs { HI.moduleName = "Foo.Bar", HI.symbolName = "foo" } 67 | , test "SymbolTest1" $ HI.defaultArgs { HI.moduleName = "Foo.Bar", HI.symbolName = "foo" } 68 | , test "SymbolTest2" $ HI.defaultArgs { HI.moduleName = "Foo.Bar.Blub", HI.symbolName = "foo" } 69 | , test "SymbolTest3" $ HI.defaultArgs { HI.moduleName = "Control.Monad", HI.symbolName = "when" } 70 | , test "SymbolTest4" $ HI.defaultArgs { HI.moduleName = "Ugah.Argh2", HI.symbolName = "argh" } 71 | , test "SymbolTest5" $ HI.defaultArgs { HI.moduleName = "Control.Monad", HI.symbolName = "when" } 72 | , test "SymbolTest6" $ HI.defaultArgs { HI.moduleName = "Control.Monad", HI.symbolName = "unless" } 73 | , test "SymbolTest7" $ HI.defaultArgs { HI.moduleName = "Control.Monad", HI.symbolName = "unless" } 74 | , test "SymbolTest8" $ HI.defaultArgs { HI.moduleName = "Control.Monad", HI.symbolName = "unless" } 75 | , test "SymbolTest9" $ HI.defaultArgs { HI.moduleName = "Control.Monad", HI.symbolName = "unless" } 76 | , test "SymbolTest10" $ HI.defaultArgs { HI.moduleName = "Control.Applicative", HI.symbolName = "<$>" } 77 | , test "SymbolTest11" $ HI.defaultArgs { HI.moduleName = "Control.Applicative", HI.symbolName = "<$>" } 78 | , test "SymbolTest12" $ HI.defaultArgs { HI.moduleName = "Control.Applicative", HI.symbolName = "<$>" } 79 | , test "SymbolTest13" $ HI.defaultArgs { HI.moduleName = "Control.Applicative", HI.symbolName = "<*" } 80 | , test "SymbolTest14" $ HI.defaultArgs { HI.moduleName = "Control.Applicative", HI.symbolName = "<*" } 81 | , test "SymbolTest15" $ HI.defaultArgs { HI.moduleName = "Control.Applicative", HI.symbolName = "*>" } 82 | , test "SymbolTest16" $ HI.defaultArgs { HI.moduleName = "Control.Monad", HI.symbolName = "when", HI.qualifiedName = "CM" } 83 | , test "SymbolTest17" $ HI.defaultArgs { HI.moduleName = "Control.Monad", HI.symbolName = "when", HI.qualifiedName = "CM" } 84 | , test "SymbolTest18" $ HI.defaultArgs { HI.moduleName = "Data.Text", HI.symbolName = "Text" } 85 | , test "SymbolTest19" $ HI.defaultArgs { HI.moduleName = "Data.List", HI.symbolName = "foldl'" } 86 | , test "SymbolTest20" $ HI.defaultArgs { HI.moduleName = "Data.Maybe", HI.symbolName = "Maybe", HI.all = True } 87 | , test "SymbolTest21" $ HI.defaultArgs { HI.moduleName = "Data.Maybe", HI.symbolName = "Maybe", HI.all = True } 88 | , test "SymbolTest22" $ HI.defaultArgs { HI.moduleName = "Data.Maybe", HI.symbolName = "Maybe", HI.with = ["Just"] } 89 | , test "SymbolTest23" $ HI.defaultArgs { HI.moduleName = "Data.Maybe", HI.symbolName = "Maybe", HI.all = True, HI.with = ["Just"] } 90 | , test "SymbolTest24" $ HI.defaultArgs { HI.moduleName = "Data.Maybe", HI.symbolName = "Maybe", HI.with = ["Just"] } 91 | , test "SymbolTest25" $ HI.defaultArgs { HI.moduleName = "Data.Maybe", HI.symbolName = "Maybe", HI.with = ["Nothing", "Just"] } 92 | , test "SymbolTest26" $ HI.defaultArgs { HI.moduleName = "Foo", HI.symbolName = "bar" } 93 | , test "SymbolTest27" $ HI.defaultArgs { HI.moduleName = "Ugah.Blub", HI.symbolName = "g" } 94 | , test "SymbolTest28" $ HI.defaultArgs { HI.moduleName = "Ugah.Blub", HI.symbolName = "d" } 95 | , configTest "SymbolTest29" (HI.defaultConfig { HI.prettyPrint = prettyPrint }) (HI.defaultArgs { HI.moduleName = "X.Y", HI.symbolName = "x" }) 96 | , configTest "SymbolTest30" (HI.defaultConfig { HI.prettyPrint = prettyPrint }) (HI.defaultArgs { HI.moduleName = "X.Y", HI.symbolName = "x" }) 97 | , test "SymbolTest31" $ HI.defaultArgs { HI.moduleName = "Ugah.Blub", HI.symbolName = "d" } 98 | , test "SymbolTest32" $ HI.defaultArgs { HI.moduleName = "Control.Foo", HI.symbolName = "foo" } 99 | , test "SymbolTest33" $ HI.defaultArgs { HI.moduleName = "Control.Monad", HI.symbolName = "mapM_", HI.hiding = True } 100 | , test "SymbolTest34" $ HI.defaultArgs { HI.moduleName = "Data.Text", HI.symbolName = "isPrefixOf", HI.hiding = True } 101 | , test "SymbolTest35" $ HI.defaultArgs { HI.moduleName = "Data.Text", HI.symbolName = "isInfixOf", HI.hiding = True } 102 | , test "SymbolTest36" $ HI.defaultArgs { HI.qualifiedName = "T", HI.moduleName = "Data.Text", HI.symbolName = "isInfixOf", HI.hiding = True } 103 | , test "SymbolTest37" $ HI.defaultArgs { HI.moduleName = "Data.Text", HI.symbolName = "Text", HI.all = True, HI.hiding = True } 104 | , test "SymbolTest38" $ HI.defaultArgs { HI.moduleName = "Data.Text", HI.symbolName = "Text", HI.with = ["A", "B", "C"], HI.hiding = True } 105 | , test "SymbolTest39" $ HI.defaultArgs { HI.moduleName = "Data.Text", HI.symbolName = "Text", HI.all = True, HI.as = "T", HI.hiding = True } 106 | , test "SymbolTest40" $ HI.defaultArgs { HI.moduleName = "Data.Text", HI.symbolName = "Text", HI.with = ["A", "B", "C"], HI.as = "T", HI.hiding = True } 107 | , test "SymbolTest41" $ HI.defaultArgs { HI.moduleName = "Control.Applicative", HI.symbolName = "t", HI.hiding = True } 108 | , test "SymbolTest42" $ HI.defaultArgs { HI.moduleName = "Control.Applicative", HI.symbolName = "z", HI.hiding = True } 109 | , test "SymbolTest43" $ HI.defaultArgs { HI.moduleName = "Data.Text", HI.symbolName = "isInfixOf" } 110 | , test "SymbolTest44" $ HI.defaultArgs { HI.moduleName = "Data.Text", HI.symbolName = "Text", HI.all = True, HI.hiding = True } 111 | , test "SymbolTest45" $ HI.defaultArgs { HI.moduleName = "Data.Text", HI.symbolName = "Text", HI.with = ["A"], HI.hiding = True } 112 | , test "SymbolTest46" $ HI.defaultArgs { HI.moduleName = "Data.Text", HI.symbolName = "Text", HI.with = ["A"], HI.hiding = True } 113 | , test "SymbolTest47" $ HI.defaultArgs { HI.moduleName = "Data.Text", HI.symbolName = "Text", HI.all = True, HI.hiding = True } 114 | , test "SymbolTest48" $ HI.defaultArgs { HI.moduleName = "Data.Text", HI.symbolName = "isInfixOf" } 115 | , test "SymbolTest49" $ HI.defaultArgs { HI.moduleName = "Data.Text", HI.symbolName = "Text", HI.hiding = True } 116 | , test "SymbolTest50" $ HI.defaultArgs { HI.moduleName = "Data.Text", HI.symbolName = "Text", HI.with = ["B", "C"], HI.hiding = True } 117 | , failedTest "SymbolTest51" $ HI.defaultArgs { HI.moduleName = "Data.Text", HI.symbolName = "Text", HI.with = ["A"], HI.hiding = True } 118 | ] 119 | 120 | 121 | replaceCppTests :: TestTree 122 | replaceCppTests = testGroup "ReplaceCpp Tests" 123 | [ replaceCppTest "ReplaceCppTest1" 124 | , replaceCppTest "ReplaceCppTest2" 125 | , replaceCppTest "ReplaceCppTest3" 126 | ] 127 | 128 | 129 | parseTests :: TestTree 130 | parseTests = testGroup "Parse Tests" 131 | [ parseTest "ParseTest1" 132 | , parseTest "ParseTest2" 133 | ] 134 | 135 | 136 | test :: String -> HI.HsImportArgs -> TestTree 137 | test testName args = configTest testName HI.defaultConfig args 138 | 139 | 140 | failedTest :: String -> HI.HsImportArgs -> TestTree 141 | failedTest testName args = 142 | goldenVsStringDiff testName diff goldenFile command 143 | where 144 | command = do 145 | Just message <- HI.hsimportWithArgs HI.defaultConfig (args { HI.inputSrcFile = inputFile, HI.outputSrcFile = outputFile }) 146 | return . BS.fromString $ message 147 | 148 | diff ref new = ["diff", "-u", ref, new] 149 | 150 | goldenFile = "tests" "goldenFiles" testName <.> "hs" 151 | outputFile = "tests" "outputFiles" testName <.> "hs" 152 | inputFile = "tests" "inputFiles" testName <.> "hs" 153 | 154 | 155 | configTest :: String -> HI.Config -> HI.HsImportArgs -> TestTree 156 | configTest testName config args = 157 | goldenVsFileDiff testName diff goldenFile outputFile command 158 | where 159 | command = do 160 | maybeErr <- HI.hsimportWithArgs config (args { HI.inputSrcFile = inputFile, HI.outputSrcFile = outputFile }) 161 | case maybeErr of 162 | Just err -> hPutStrLn stderr ("hsimport: " ++ err) 163 | _ -> return () 164 | 165 | diff ref new = ["diff", "-u", ref, new] 166 | 167 | goldenFile = "tests" "goldenFiles" testName <.> "hs" 168 | outputFile = "tests" "outputFiles" testName <.> "hs" 169 | inputFile = "tests" "inputFiles" testName <.> "hs" 170 | 171 | 172 | replaceCppTest :: String -> TestTree 173 | replaceCppTest testName = 174 | goldenVsFileDiff testName diff goldenFile outputFile command 175 | where 176 | command = do 177 | contents <- readFile inputFile 178 | writeFile outputFile $ HIP.replaceCpp contents 179 | 180 | diff ref new = ["diff", "-u", ref, new] 181 | 182 | goldenFile = "tests" "goldenFiles" testName <.> "hs" 183 | outputFile = "tests" "outputFiles" testName <.> "hs" 184 | inputFile = "tests" "inputFiles" testName <.> "hs" 185 | 186 | 187 | parseTest :: String -> TestTree 188 | parseTest testName = 189 | goldenVsFileDiff testName diff goldenFile outputFile command 190 | where 191 | command = do 192 | Right (ParseResult (HS.ParseOk _) lastValidLine) <- HIP.parseFile inputFile 193 | contents <- readFile inputFile 194 | case lastValidLine of 195 | Just line -> writeFile outputFile $ unlines . take line . lines $ contents 196 | Nothing -> writeFile outputFile contents 197 | 198 | diff ref new = ["diff", "-u", ref, new] 199 | 200 | goldenFile = "tests" "goldenFiles" testName <.> "hs" 201 | outputFile = "tests" "outputFiles" testName <.> "hs" 202 | inputFile = "tests" "inputFiles" testName <.> "hs" 203 | 204 | 205 | prettyPrint :: HI.ImportDecl -> String 206 | prettyPrint HS.ImportDecl { HS.importModule = HS.ModuleName _ modName, HS.importSpecs = Just (HS.ImportSpecList _ False syms) } = 207 | "import " ++ modName ++ " ( " ++ ppSyms ++ " )" 208 | where 209 | ppSyms = intercalate " , " symNames 210 | symNames = map symName syms 211 | 212 | symName (HS.IVar _ (HS.Ident _ name)) = name 213 | symName _ = "" 214 | 215 | prettyPrint _ = "Uupps" 216 | 217 | 218 | importPosAfterLast :: HI.ImportDecl -> [HI.ImportDecl] -> Maybe HI.ImportPos 219 | importPosAfterLast _ [] = Nothing 220 | importPosAfterLast _ imports = Just . HI.After . last $ imports 221 | 222 | 223 | importPosBeforeLast :: HI.ImportDecl -> [HI.ImportDecl] -> Maybe HI.ImportPos 224 | importPosBeforeLast _ [] = Nothing 225 | importPosBeforeLast _ imports = Just . HI.Before . last $ imports 226 | 227 | 228 | importPosAfterFirst :: HI.ImportDecl -> [HI.ImportDecl] -> Maybe HI.ImportPos 229 | importPosAfterFirst _ [] = Nothing 230 | importPosAfterFirst _ imports = Just . HI.After . head $ imports 231 | 232 | 233 | importPosBeforeFirst :: HI.ImportDecl -> [HI.ImportDecl] -> Maybe HI.ImportPos 234 | importPosBeforeFirst _ [] = Nothing 235 | importPosBeforeFirst _ imports = Just . HI.Before . head $ imports 236 | -------------------------------------------------------------------------------- /lib/HsImport/ImportChange.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE ScopedTypeVariables #-} 2 | {-# LANGUAGE PatternGuards #-} 3 | 4 | module HsImport.ImportChange 5 | ( ImportChange(..) 6 | , importChanges 7 | , hasImportError 8 | , toErrorMessage 9 | ) where 10 | 11 | import Data.Maybe 12 | import Data.List (find, (\\)) 13 | import Lens.Micro 14 | import qualified Language.Haskell.Exts as HS 15 | import qualified Data.Attoparsec.Text as A 16 | import HsImport.SymbolImport (SymbolImport(..), Symbol(..), symbol, isHiding, toggleHiding) 17 | import HsImport.ModuleImport (ModuleImport(..)) 18 | import HsImport.ImportPos (matchingImports) 19 | import HsImport.Utils 20 | import HsImport.Types 21 | 22 | -- | How the import declarations should be changed 23 | data ImportChange 24 | = ReplaceImportAt SrcSpan ImportDecl -- ^ replace the import declaration at SrcSpan 25 | | AddImportAfter SrcLine ImportDecl -- ^ add import declaration after SrcLine 26 | | AddImportAtEnd ImportDecl -- ^ add import declaration at end of source file 27 | | FindImportPos ImportDecl -- ^ search for an insert position for the import declaration 28 | | NoImportChange -- ^ no changes of the import declarations 29 | | ImportError ErrorMessage -- ^ import error 30 | deriving (Show) 31 | 32 | hasImportError :: ImportChange -> Bool 33 | hasImportError (ImportError _) = True 34 | hasImportError _ = False 35 | 36 | toErrorMessage :: ImportChange -> Maybe ErrorMessage 37 | toErrorMessage (ImportError err) = Just err 38 | toErrorMessage _ = Nothing 39 | 40 | importChanges :: ModuleImport -> Maybe SymbolImport -> Module -> [ImportChange] 41 | importChanges (ModuleImport moduleName False Nothing) Nothing hsModule = 42 | [ importModule moduleName hsModule ] 43 | 44 | importChanges (ModuleImport moduleName False Nothing) (Just symbolImport) hsModule = 45 | [ importModuleWithSymbol moduleName symbolImport hsModule ] 46 | 47 | importChanges (ModuleImport moduleName qualified as) symbolImport hsModule = 48 | [ maybe NoImportChange 49 | (\sym -> importModuleWithSymbol moduleName sym hsModule) 50 | symbolImport 51 | , if qualified 52 | then importQualifiedModule moduleName (fromMaybe moduleName as) hsModule 53 | else maybe NoImportChange 54 | (\asName -> importModuleAs moduleName asName hsModule) 55 | as 56 | ] 57 | 58 | -- | Checks whether the given import declaration is unqualified and 59 | -- contains an import spec list. 60 | -- Useful to replace an existing import declaration that has imports, 61 | -- with a more general import. 62 | isUnqualifiedWithSpecList :: ImportDecl -> Bool 63 | isUnqualifiedWithSpecList decl 64 | | Just (HS.ImportSpecList _ False _) <- HS.importSpecs decl 65 | , not (HS.importQualified decl) 66 | = True 67 | 68 | | otherwise 69 | = False 70 | 71 | importModule :: String -> Module -> ImportChange 72 | importModule moduleName module_ 73 | | matching@(_:_) <- matchingImports moduleName (importDecls module_) = 74 | if any hasEntireModuleImported matching 75 | then NoImportChange 76 | else case find isUnqualifiedWithSpecList matching of 77 | Just impDecl -> ReplaceImportAt (srcSpan . HS.ann $ impDecl) 78 | impDecl { HS.importSpecs = Nothing } 79 | 80 | Nothing -> FindImportPos $ importDecl moduleName 81 | 82 | | not $ null (importDecls module_) = 83 | FindImportPos $ importDecl moduleName 84 | 85 | | otherwise = 86 | case srcLineForNewImport module_ of 87 | Just srcLine -> AddImportAfter srcLine (importDecl moduleName) 88 | Nothing -> AddImportAtEnd (importDecl moduleName) 89 | 90 | 91 | existingMatching :: [ImportDecl] -> String -> SymbolImport -> ImportChange 92 | existingMatching matching moduleName symbolImport 93 | -- There is a module import 94 | | Just impDecl <- find hasEntireModuleImported matching 95 | = if isHiding symbolImport 96 | -- We add a hiding clause, since we only want to hide a very specific symbol. 97 | then ReplaceImportAt (srcSpan . HS.ann $ impDecl) 98 | (setSymbol impDecl symbolImport) 99 | 100 | -- If we want to import a symbol, we dont have to, since it is already imported. 101 | else NoImportChange 102 | 103 | -- The symbol we want to import/hide is already imported/hidden. 104 | | any (hasSymbols symbolImport) matching 105 | = NoImportChange 106 | 107 | | otherwise 108 | = case find (hasAnySymbols $ isHiding symbolImport) matching of 109 | -- There is a fitting import declaration to which we can add the symbol to. 110 | Just impDecl -> ReplaceImportAt (srcSpan . HS.ann $ impDecl) 111 | (addSymbol impDecl symbolImport) 112 | 113 | -- The symbol is either not imported/hidden or another import 114 | -- hides/imports it. 115 | -- If something explictly imports the symbol, we remove it from the import list. 116 | -- If something explictly hides the symbol, we remove it from the hiding list. 117 | Nothing -> case find (hasSymbolsOverlap (toggleHiding symbolImport)) matching of 118 | -- There is a import declaration that imports/hides the symbol we want to hide/import. 119 | Just impDecl -> case removeSymbol impDecl symbolImport of 120 | Left err -> ImportError err 121 | Right symbolList -> ReplaceImportAt (srcSpan . HS.ann $ impDecl) 122 | symbolList 123 | 124 | -- Symbol is not mentioned at all. 125 | Nothing -> FindImportPos $ importDeclWithSymbol moduleName symbolImport 126 | 127 | importModuleWithSymbol :: String -> SymbolImport -> Module -> ImportChange 128 | importModuleWithSymbol moduleName symbolImport module_ 129 | -- There is already a matching import line 130 | | matching@(_:_) <- matchingImports moduleName (importDecls module_) = 131 | existingMatching matching moduleName symbolImport 132 | 133 | | not $ null (importDecls module_) = 134 | FindImportPos $ importDeclWithSymbol moduleName symbolImport 135 | 136 | | otherwise = 137 | case srcLineForNewImport module_ of 138 | Just srcLine -> AddImportAfter srcLine (importDeclWithSymbol moduleName symbolImport) 139 | Nothing -> AddImportAtEnd (importDeclWithSymbol moduleName symbolImport) 140 | 141 | -- | Extend the spec list with the given symbol. 142 | -- Might result in duplciates. 143 | extendSpecList :: SymbolImport -> ImportSpecList -> ImportSpecList 144 | extendSpecList symbolImport (HS.ImportSpecList annotation hid specs) = 145 | HS.ImportSpecList annotation hid (specs ++ [importSpec $ symbol symbolImport]) 146 | 147 | -- | Remove an element from the import list if it matches the symbol. 148 | -- If the resulting spec list is empty afterwards, Nothing is returned to remove 149 | -- the import list. 150 | -- Removes duplicate imports. 151 | removeSpecList 152 | :: SymbolImport 153 | -> ImportSpecList 154 | -> Either ErrorMessage (Maybe (ImportSpecList)) 155 | removeSpecList symbolImport (HS.ImportSpecList annotation hid specs) = 156 | let specListRemovedSymbol = traverse (removeSymbols (symbol symbolImport)) specs 157 | in specListRemovedSymbol >>= \specList -> 158 | if null (catMaybes specList) 159 | then Right Nothing -- Remove the spec list if it is empty now 160 | else Right $ Just $ HS.ImportSpecList annotation hid (catMaybes specList) 161 | 162 | where 163 | removeSymbols :: Symbol -> ImportSpec -> Either ErrorMessage (Maybe ImportSpec) 164 | removeSymbols (SomeOf symName _) t@(HS.IThingAll _ name) = 165 | if symName == nameString name 166 | then Left $ unlines 167 | [ "Tried to remove Constructors from a Type that exposed all Constructors." 168 | , "This does not work because other Constructors are not available for HsImport." 169 | , "Thus, this operation can not be performed." 170 | , "" 171 | , "Example:" 172 | , "import Foo.Bar (Baz(..))" 173 | , "" 174 | , "> hsimport --hiding -m Foo.Bar -s Baz -w A" 175 | , "" 176 | , "The correct solution would be, assuming Constructors are A, B and C, to change the import to:" 177 | , "import Foo.Bar (Baz(B,C))" 178 | , "" 179 | , "However, this is not possible for this program, thus, we abort the program execution." 180 | ] 181 | else Right $ Just t 182 | 183 | removeSymbols (SomeOf symName names) t@(HS.IThingWith a hsSymName hsNames) = 184 | if symName == nameString hsSymName 185 | then Right $ Just (HS.IThingWith a hsSymName (removeFromList names hsNames)) 186 | else Right $ Just t 187 | 188 | removeSymbols (AllOf symName) t@(HS.IThingWith a hsSymName _) = 189 | if symName == nameString hsSymName 190 | -- Remove all used constructors 191 | then Right $ Just (HS.IThingWith a hsSymName []) 192 | else Right $ Just t 193 | 194 | removeSymbols sym spec = 195 | if imports sym spec 196 | then Right $ Nothing 197 | else Right $ Just spec 198 | 199 | removeFromList :: [String] -> [CName] -> [CName] 200 | removeFromList names = filter ((`notElem` names) . nameString . toName) 201 | 202 | 203 | -- | Set the spec list to the given symbol. 204 | setSpecList :: SymbolImport -> Annotation -> ImportSpecList 205 | setSpecList symbolImport annotation = 206 | HS.ImportSpecList annotation (isHiding symbolImport) [importSpec $ symbol symbolImport] 207 | 208 | -- | Add a symbol to the given spec list. May result in duplicates. 209 | addSymbol :: ImportDecl -> SymbolImport -> ImportDecl 210 | addSymbol id@HS.ImportDecl {HS.importSpecs = specs} symbolImport = 211 | id {HS.importSpecs = specs & _Just %~ extendSpecList symbolImport} 212 | 213 | -- | Set a symbol to be exported from the current import declaration. 214 | -- Does not care whether the import declaration already has a spec list. 215 | setSymbol :: ImportDecl -> SymbolImport -> ImportDecl 216 | setSymbol id@HS.ImportDecl {HS.importAnn = importAnn } symbolImport = 217 | id {HS.importSpecs = Just (setSpecList symbolImport importAnn) } 218 | 219 | -- | Remove a symbol from the import declaration. 220 | -- May remove the whole spec list if the list is empty after removal. 221 | removeSymbol :: ImportDecl -> SymbolImport -> Either ErrorMessage ImportDecl 222 | removeSymbol id@HS.ImportDecl {HS.importSpecs = specs} symbolImport = 223 | case specs & _Just %~ removeSpecList symbolImport of 224 | Nothing -> Right id {HS.importSpecs = Nothing } 225 | Just xs -> xs >>= \newSpecList -> Right id {HS.importSpecs = newSpecList} 226 | 227 | 228 | importQualifiedModule :: String -> String -> Module -> ImportChange 229 | importQualifiedModule moduleName qualifiedName module_ 230 | | matching@(_:_) <- matchingImports moduleName (importDecls module_) = 231 | if any (hasQualifiedImport qualifiedName) matching 232 | then NoImportChange 233 | else FindImportPos $ qualifiedImportDecl moduleName qualifiedName 234 | 235 | | not $ null (importDecls module_) = 236 | FindImportPos $ qualifiedImportDecl moduleName qualifiedName 237 | 238 | | otherwise = 239 | case srcLineForNewImport module_ of 240 | Just srcLine -> AddImportAfter srcLine (qualifiedImportDecl moduleName qualifiedName) 241 | Nothing -> AddImportAtEnd (qualifiedImportDecl moduleName qualifiedName) 242 | 243 | 244 | importModuleAs :: String -> String -> Module -> ImportChange 245 | importModuleAs moduleName asName module_ 246 | | matching@(_:_) <- matchingImports moduleName (importDecls module_) = 247 | if any (hasAsImport asName) matching 248 | then NoImportChange 249 | else FindImportPos $ asImportDecl moduleName asName 250 | 251 | | not $ null (importDecls module_) = 252 | FindImportPos $ asImportDecl moduleName asName 253 | 254 | | otherwise = 255 | case srcLineForNewImport module_ of 256 | Just srcLine -> AddImportAfter srcLine (asImportDecl moduleName asName) 257 | Nothing -> AddImportAtEnd (asImportDecl moduleName asName) 258 | 259 | 260 | hasEntireModuleImported :: ImportDecl -> Bool 261 | hasEntireModuleImported import_ = 262 | not (HS.importQualified import_) && isNothing (HS.importSpecs import_) 263 | 264 | 265 | hasQualifiedImport :: String -> ImportDecl -> Bool 266 | hasQualifiedImport qualifiedName import_ 267 | | HS.importQualified import_ 268 | , Just (HS.ModuleName _ importAs) <- HS.importAs import_ 269 | , importAs == qualifiedName 270 | = True 271 | 272 | | otherwise = False 273 | 274 | 275 | hasAsImport :: String -> ImportDecl -> Bool 276 | hasAsImport asName import_ 277 | | not $ HS.importQualified import_ 278 | , Just (HS.ModuleName _ importAs) <- HS.importAs import_ 279 | , importAs == asName 280 | = True 281 | 282 | | otherwise 283 | = False 284 | 285 | -- | Checks whether the given symbol is somehow mentioned in the import spec. 286 | -- Mainly used to check for constructor overlaps. 287 | hasSymbolsOverlap :: SymbolImport -> ImportDecl -> Bool 288 | hasSymbolsOverlap symbolImport import_ 289 | | Just (HS.ImportSpecList _ hidden hsSymbols) <- HS.importSpecs import_ 290 | , hidden == isHiding symbolImport 291 | , any (importsOverlap $ symbol symbolImport) hsSymbols 292 | = True 293 | 294 | | otherwise 295 | = False 296 | 297 | -- | Checks whether the given SymbolImport is already covered by the current ImportDecl. 298 | hasSymbols :: SymbolImport -> ImportDecl -> Bool 299 | hasSymbols symbolImport import_ 300 | | Just (HS.ImportSpecList _ hidden hsSymbols) <- HS.importSpecs import_ 301 | , hidden == isHiding symbolImport 302 | , any (imports $ symbol symbolImport) hsSymbols 303 | = True 304 | 305 | | otherwise 306 | = False 307 | 308 | -- | Checks whether the given symbol is somehow mentioned in the import spec. 309 | -- Mainly used to check for constructor overlaps. 310 | importsOverlap :: Symbol -> ImportSpec -> Bool 311 | importsOverlap (AllOf symName) (HS.IThingWith _ name _) = symName == nameString name 312 | importsOverlap (SomeOf symName _) (HS.IThingAll _ name) = symName == nameString name 313 | importsOverlap (SomeOf symName _) (HS.IThingWith _ name _) = symName == nameString name 314 | importsOverlap sym spec = imports sym spec 315 | 316 | -- | Checks whether the given symbol is completely covered by the import spec. 317 | imports :: Symbol -> ImportSpec -> Bool 318 | imports = imports_ 319 | where 320 | imports_ :: Symbol -> ImportSpec -> Bool 321 | imports_ (Only symName) (HS.IVar _ name) = symName == nameString name 322 | imports_ (Only symName) (HS.IAbs _ _ name) = symName == nameString name 323 | imports_ (Only symName) (HS.IThingAll _ name) = symName == nameString name 324 | imports_ (Only symName) (HS.IThingWith _ name _) = symName == nameString name 325 | imports_ (AllOf symName) (HS.IThingAll _ name) = symName == nameString name 326 | imports_ (SomeOf symName _ ) (HS.IThingAll _ name) = symName == nameString name 327 | imports_ (SomeOf symName names) (HS.IThingWith _ hsSymName hsNames) = 328 | symName == nameString hsSymName && null (names \\ (map (nameString . toName) hsNames)) 329 | 330 | imports_ _ _ = False 331 | 332 | nameString :: Name -> String 333 | nameString (HS.Ident _ id) = id 334 | nameString (HS.Symbol _ sym) = sym 335 | 336 | toName :: CName -> Name 337 | toName (HS.VarName _ name) = name 338 | toName (HS.ConName _ name) = name 339 | 340 | 341 | hasAnySymbols :: Bool -> ImportDecl -> Bool 342 | hasAnySymbols hiding import_ 343 | | Just (HS.ImportSpecList _ hid (_:_)) <- HS.importSpecs import_ 344 | , hid == hiding 345 | = True 346 | 347 | | otherwise 348 | = False 349 | 350 | 351 | importDecl :: String -> ImportDecl 352 | importDecl moduleName = HS.ImportDecl 353 | { HS.importAnn = noAnnotation 354 | , HS.importModule = HS.ModuleName noAnnotation moduleName 355 | , HS.importQualified = False 356 | , HS.importSrc = False 357 | , HS.importSafe = False 358 | , HS.importPkg = Nothing 359 | , HS.importAs = Nothing 360 | , HS.importSpecs = Nothing 361 | } 362 | 363 | 364 | importDeclWithSymbol :: String -> SymbolImport -> ImportDecl 365 | importDeclWithSymbol moduleName symbolImport = 366 | case symbolImport of 367 | Hiding s -> makeImportDecl True s 368 | Import s -> makeImportDecl False s 369 | where 370 | makeImportDecl :: Bool -> Symbol -> ImportDecl 371 | makeImportDecl hiding symbols = 372 | (importDecl moduleName) 373 | { HS.importSpecs = Just (HS.ImportSpecList noAnnotation 374 | hiding 375 | [importSpec symbols]) 376 | } 377 | 378 | 379 | qualifiedImportDecl :: String -> String -> ImportDecl 380 | qualifiedImportDecl moduleName qualifiedName = 381 | (importDecl moduleName) { HS.importQualified = True 382 | , HS.importAs = if moduleName /= qualifiedName 383 | then Just $ HS.ModuleName noAnnotation qualifiedName 384 | else Nothing 385 | } 386 | 387 | 388 | asImportDecl :: String -> String -> ImportDecl 389 | asImportDecl moduleName asName = 390 | (importDecl moduleName) { HS.importQualified = False 391 | , HS.importAs = Just $ HS.ModuleName noAnnotation asName 392 | } 393 | 394 | 395 | importSpec :: Symbol -> ImportSpec 396 | importSpec (Only symName) = HS.IVar noAnnotation (hsName symName) 397 | importSpec (AllOf symName) = HS.IThingAll noAnnotation (hsName symName) 398 | importSpec (SomeOf symName names) = HS.IThingWith noAnnotation 399 | (hsName symName) 400 | (map (HS.VarName noAnnotation . hsName) names) 401 | 402 | hsName :: String -> Name 403 | hsName symbolName 404 | | isSymbol = HS.Symbol noAnnotation symbolName 405 | | otherwise = HS.Ident noAnnotation symbolName 406 | where 407 | isSymbol = any (A.notInClass "a-zA-Z0-9_'") symbolName 408 | 409 | 410 | srcLineForNewImport :: Module -> Maybe SrcLine 411 | srcLineForNewImport module_ = 412 | case module_ of 413 | HS.Module ann _ _ imports decls -> newSrcLine ann imports decls 414 | HS.XmlPage _ _ _ _ _ _ _ -> Nothing 415 | HS.XmlHybrid ann _ _ imports decls _ _ _ _ -> newSrcLine ann imports decls 416 | where 417 | newSrcLine :: Annotation -> [ImportDecl] -> [Decl] -> Maybe SrcLine 418 | newSrcLine ann imports decls 419 | | not $ null imports 420 | = Just (firstSrcLine . HS.ann $ last imports) 421 | 422 | | (decl:_) <- decls 423 | , sLoc <- declSrcLoc decl 424 | , HS.srcLine sLoc >= firstSrcLine ann 425 | = Just $ max 0 (HS.srcLine sLoc - 1) 426 | 427 | | otherwise 428 | = Nothing 429 | --------------------------------------------------------------------------------