{-# LANGUAGE StandaloneDeriving , DeriveGeneric , LambdaCase , ScopedTypeVariables , BangPatterns , MultiWayIf , FlexibleContexts , TypeFamilies , TupleSections , TemplateHaskell , ViewPatterns #-} -- | Defines common utilities for using refactorings. Provides an interface for both demo, command line and integrated tools. module Language.Haskell.Tools.Refactor.Perform where import Data.List.Split import Language.Haskell.Tools.AST as AST import Language.Haskell.Tools.Refactor.Predefined.ExtractBinding import Language.Haskell.Tools.Refactor.Predefined.FloatOut import Language.Haskell.Tools.Refactor.Predefined.GenerateExports import Language.Haskell.Tools.Refactor.Predefined.GenerateTypeSignature import Language.Haskell.Tools.Refactor.Predefined.InlineBinding import Language.Haskell.Tools.Refactor.Predefined.OrganizeImports import Language.Haskell.Tools.Refactor.Predefined.RenameDefinition import Language.Haskell.Tools.Refactor.Prepare import Language.Haskell.Tools.Refactor.RefactorBase import GHC -- | Executes a given command on the selected module and given other modules performCommand :: (HasModuleInfo dom, DomGenerateExports dom, OrganizeImportsDomain dom, DomainRenameDefinition dom, ExtractBindingDomain dom, GenerateSignatureDomain dom) => RefactorCommand -> ModuleDom dom -- ^ The module in which the refactoring is performed -> [ModuleDom dom] -- ^ Other modules -> Ghc (Either String [RefactorChange dom]) performCommand rf mod mods = runRefactor mod mods $ selectCommand rf where selectCommand NoRefactor = localRefactoring return selectCommand OrganizeImports = localRefactoring organizeImports selectCommand ProjectOrganizeImports = projectOrganizeImports selectCommand GenerateExports = localRefactoring generateExports selectCommand (GenerateSignature sp) = localRefactoring $ generateTypeSignature' (correctRefactorSpan (snd mod) sp) selectCommand (RenameDefinition sp str) = renameDefinition' (correctRefactorSpan (snd mod) sp) str selectCommand (ExtractBinding sp str) = localRefactoring $ extractBinding' (correctRefactorSpan (snd mod) sp) str selectCommand (InlineBinding sp) = inlineBinding (correctRefactorSpan (snd mod) sp) selectCommand (FloatOut sp) = localRefactoring $ floatOut (correctRefactorSpan (snd mod) sp) -- | A refactoring command data RefactorCommand = NoRefactor | OrganizeImports | ProjectOrganizeImports | GenerateExports | GenerateSignature RealSrcSpan | RenameDefinition RealSrcSpan String | ExtractBinding RealSrcSpan String | InlineBinding RealSrcSpan | FloatOut RealSrcSpan deriving Show -- | Recognize a command from its textual representation readCommand :: String -> Either String RefactorCommand readCommand (splitOn " " -> refact:args) = analyzeCommand refact args readCommand _ = error "panic: splitOn resulted empty" -- | Check the parts and return the command analyzeCommand :: String -> [String] -> Either String RefactorCommand analyzeCommand "" _ = Right NoRefactor analyzeCommand "CheckSource" _ = Right NoRefactor analyzeCommand "OrganizeImports" _ = Right OrganizeImports analyzeCommand "ProjectOrganizeImports" _ = Right ProjectOrganizeImports analyzeCommand "GenerateExports" _ = Right GenerateExports analyzeCommand "GenerateSignature" [sp] = Right $ GenerateSignature (readSrcSpan sp) analyzeCommand "GenerateSignature" _ = Left $ "GenerateSignature needs one argument: the source range of the definition" analyzeCommand "RenameDefinition" [sp, newName] = Right $ RenameDefinition (readSrcSpan sp) newName analyzeCommand "RenameDefinition" _ = Left $ "RenameDefinition needs two arguments: the source range of the name and the new name" analyzeCommand "ExtractBinding" [sp, newName] = Right $ ExtractBinding (readSrcSpan sp) newName analyzeCommand "ExtractBinding" _ = Left $ "RenameDefinition needs two arguments: the source range of the expression and the new name" analyzeCommand "InlineBinding" [sp] = Right $ InlineBinding (readSrcSpan sp) analyzeCommand "InlineBinding" _ = Left $ "InlineBinding needs one argument: the source range of the definition" analyzeCommand "FloatOut" [sp] = Right $ FloatOut (readSrcSpan sp) analyzeCommand "FloatOut" _ = Left $ "FloatOut needs one argument: the source range of the definition" analyzeCommand ref _ = Left $ "Unknown command: " ++ ref refactorCommands :: [String] refactorCommands = [ "CheckSource", "OrganizeImports", "ProjectOrganizeImports", "GenerateExports" , "GenerateSignature", "RenameDefinition", "ExtractBinding", "InlineBinding" , "FloatOut" ]