leksah-0.4.4.1: src/IDE/Package.hs
{-# LANGUAGE CPP, ForeignFunctionInterface #-}
{-# OPTIONS_GHC -XScopedTypeVariables #-}
-----------------------------------------------------------------------------
--
-- Module : IDE.Package
-- Copyright : (c) Juergen Nicklisch-Franken, Hamish Mackenzie
-- License : GNU-GPL
--
-- Maintainer : <maintainer at leksah.org>
-- Stability : provisional
-- Portability : portable
--
--
-- | The packages methods of ide.
--
---------------------------------------------------------------------------------
module IDE.Package (
packageOpen
, packageOpenThis
, packageNew
, packageConfig
, packageBuild
, packageDoc
, packageClean
, packageCopy
, packageRun
, nextError
, previousError
, activatePackage
, deactivatePackage
, getActivePackage
, packageInstall
, packageRegister
, packageUnregister
, packageTest
, packageSdist
, packageOpenDoc
, getPackageDescriptionAndPath
, getModuleTemplate
, addModuleToPackageDescr
, backgroundBuildToggled
, backgroundLinkToggled
) where
import Graphics.UI.Gtk
import Control.Monad.Reader
import Distribution.Package hiding (depends,packageId)
import Distribution.PackageDescription
import Distribution.PackageDescription.Parse
import Distribution.PackageDescription.Configuration
import Distribution.Verbosity
import System.FilePath
import Control.Concurrent
import System.Directory
(doesFileExist, setCurrentDirectory, canonicalizePath)
import System.IO (Handle(..), hClose, hGetLine, hSetBuffering)
import Prelude hiding (catch)
import Text.ParserCombinators.Parsec.Language
import qualified Text.ParserCombinators.Parsec.Token as P
import Text.ParserCombinators.Parsec hiding(Parser)
import Data.Maybe (isJust, fromJust)
import Control.Exception (SomeException(..), catch)
import IDE.Pane.Log
import Control.Event
import IDE.Core.State
import IDE.Pane.PackageEditor
import IDE.Pane.SourceBuffer
import IDE.Pane.PackageFlags
import IDE.Metainfo.Provider
import Distribution.Text (display)
import IDE.FileUtils (getConfigFilePathForLoad)
import MyMissing (replace)
import Distribution.ModuleName (ModuleName(..))
import Data.List (isPrefixOf, foldl')
import qualified System.IO.UTF8 as UTF8 (readFile)
#if defined(mingw32_HOST_OS) || defined(__MINGW32__)
import System.Process (getProcessExitCode, ProcessHandle(..))
import Data.Maybe (isNothing)
import GHC.ConsoleHandler (Handler(..), installHandler)
import System.Win32
(th32SnapEnumProcesses,
DWORD(..),
cTRL_BREAK_EVENT,
generateConsoleCtrlEvent,
tH32CS_SNAPPROCESS,
withTh32Snap)
import System.Process.Internals
(withProcessHandle, ProcessHandle__(..))
#else
import System.Posix
(getGroupProcessStatus,
sigINT,
installHandler,
signalProcessGroup,
getProcessGroupID)
import System.Posix.Signals (Handler(..))
import Foreign.C (Errno(..), getErrno)
#endif
import GHC.IOBase (BufferMode(..))
#if defined(mingw32_HOST_OS) || defined(__MINGW32__)
foreign import stdcall unsafe "winbase.h GetCurrentProcessId"
c_GetCurrentProcessId :: IO DWORD
foreign import stdcall unsafe "winbase.h GetProcessId"
c_GetProcessId :: DWORD -> IO DWORD
#endif
packageNew :: IDEAction
packageNew = packageNew' (\fp -> activatePackage fp >> return ())
packageOpen :: IDEAction
packageOpen = packageOpenThis Nothing
packageOpenThis :: Maybe FilePath -> IDEAction
packageOpenThis mbFilePath = do
active <- readIDE activePack
case active of
Just p -> deactivatePackage
Nothing -> return ()
selectActivePackage mbFilePath
return ()
getActivePackage :: IDEM (Maybe IDEPackage)
getActivePackage = do
active <- readIDE activePack
case active of
Just p -> return (Just p)
Nothing -> selectActivePackage Nothing
selectActivePackage :: Maybe FilePath -> IDEM (Maybe IDEPackage)
selectActivePackage mbFilePath' = do
ideR <- ask
window <- readIDE window
mbFilePath <- case mbFilePath' of
Nothing -> liftIO $ choosePackageFile window
Just fp -> return (Just fp)
case mbFilePath of
Nothing -> return Nothing
Just filePath -> do
let ppath = dropFileName filePath
exists <- liftIO $ doesFileExist (ppath </> "IDE.session")
wantToLoadSession <-
if exists
then liftIO $ do
md <- messageDialogNew Nothing [] MessageQuestion ButtonsYesNo
$ "Load the session settings stored with this project?"
rid <- dialogRun md
widgetDestroy md
case rid of
ResponseYes -> return True
otherwise -> return False
else return False
if wantToLoadSession
then do
triggerEvent ideR (LoadSession (ppath </> "IDE.session"))
readIDE activePack
else activatePackage filePath
activatePackage :: FilePath -> IDEM (Maybe IDEPackage)
activatePackage filePath = do
ideR <- ask
let ppath = dropFileName filePath
liftIO $ setCurrentDirectory ppath
mbPackageD <- reifyIDE (\ideR -> catch (do
pd <- readPackageDescription normal filePath
return (Just (flattenPackageDescription pd)))
(\(e :: SomeException) -> do
reflectIDE (ideMessage Normal ("Can't activate package " ++(show e))) ideR
return Nothing))
case mbPackageD of
Nothing -> return (Nothing)
Just packageD -> do
let packp = IDEPackage (package packageD) filePath (buildDepends packageD) [] [] [] [] [] [] [] []
pack <- (do
flagFileExists <- liftIO $ doesFileExist (ppath </> "IDE.flags")
if flagFileExists
then liftIO $ readFlags (ppath </> "IDE.flags") packp
else return packp)
modifyIDE_ (\ide -> return (ide{activePack = (Just pack)}))
ide <- getIDE
triggerEvent ideR ActivePack
triggerEvent ideR (Sensitivity [(SensitivityProjectActive,True)])
sb <- getSBActivePackage
liftIO $ statusbarPop sb 1
liftIO $ statusbarPush sb 1 (display $ packageId pack)
removeRecentlyUsedPackage filePath
return (Just pack)
deactivatePackage :: IDEAction
deactivatePackage = do
ideR <- ask
oldActivePack <- readIDE activePack
when (isJust oldActivePack) $ do
triggerEvent ideR (SaveSession
((dropFileName . cabalFile . fromJust) oldActivePack </> "IDE.session"))
addRecentlyUsedPackage ((cabalFile . fromJust) oldActivePack)
return ()
modifyIDE_ (\ide -> return (ide{activePack = Nothing}))
ideR <- ask
triggerEvent ideR ActivePack
when (isJust oldActivePack) $ do
triggerEvent ideR (Sensitivity [(SensitivityProjectActive,False)])
return ()
sb <- getSBActivePackage
liftIO $ statusbarPop sb 1
liftIO $ statusbarPush sb 1 ""
return ()
packageConfig :: IDEAction
packageConfig = catchIDE (do
mbPackage <- getActivePackage
log <- getLog
case mbPackage of
Nothing -> return ()
Just package -> do
mbPackageD <- reifyIDE (\ideR -> catch (do
(inp,out,err,pid) <- runExternal "runhaskell" (["Setup","configure"]
++ (configFlags package))
oid <- forkIO(readOut log out)
eid <- forkIO (readErr log err)
pd <- readPackageDescription normal (cabalFile package)
return (Just (flattenPackageDescription pd)))
(\(e :: SomeException) -> do
reflectIDE (ideMessage Normal (show e)) ideR
return Nothing))
case mbPackageD of
Just packageD -> do
modifyIDE_ (\ide -> return (ide{activePack =
Just package{depends=buildDepends packageD}}))
ask >>= \ideR -> triggerEvent ideR ActivePack
return ()
Nothing -> return ())
(\(e :: SomeException) -> putStrLn (show e))
packageBuild :: Bool -> IDEAction
packageBuild backgroundBuild = catchIDE (do
mbPackage <- if backgroundBuild then readIDE activePack else getActivePackage
log <- getLog
ideR <- ask
prefs <- readIDE prefs
case mbPackage of
Nothing -> return ()
Just package -> do
modified <- if (saveAllBeforeBuild prefs) then fileCheckAll else return False
when ((not backgroundBuild) || modified) $ do
alreadyRunning <- isRunning
if alreadyRunning
then do
interruptBuild
when (not backgroundBuild) $ liftIO $ do
timeoutAddFull (do
reflectIDE (do packageBuild False; return False) ideR
return False) priorityDefaultIdle 100
return ()
else do
when (saveAllBeforeBuild prefs) (do fileSaveAll; return ())
sb <- getSBErrors
liftIO $statusbarPop sb 1
liftIO $statusbarPush sb 1 "Building"
reifyIDE (\ideR -> forkIO $ do
let args = (["Setup","build"] ++
if ((not backgroundBuild) || (backgroundLink prefs))
then []
else ["--ghc-options=-c", "--with-ar=true", "--with-ld=true"]
++ buildFlags package)
(inp,out,err,pid) <- runExternal "runhaskell" args
oid <- forkIO (readOut log out)
hSetBuffering err NoBuffering
eid <- forkIO (reflectIDE (readErrForBuild backgroundBuild log err) ideR)
reflectIDE (modifyIDE_ (\ide -> return ide{buildProcess = Just pid})) ideR
when ((not backgroundBuild) && (collectAfterBuild prefs)) $ reflectIDE (mayRebuildInBackground (Just pid)) ideR
return ())
return ())
(\(e :: SomeException) -> putStrLn (show e))
packageDoc :: IDEAction
packageDoc = catchIDE (do
mbPackage <- getActivePackage
log <- getLog
case mbPackage of
Nothing -> return ()
Just package -> liftIO $do
(inp,out,err,pid) <- runExternal "runhaskell" (["Setup","haddock"]
++ (haddockFlags package))
oid <- forkIO (readOut log out)
eid <- forkIO (readErr log err)
return ())
(\(e :: SomeException) -> putStrLn (show e))
packageClean :: IDEAction
packageClean = do
mbPackage <- getActivePackage
log <- getLog
case mbPackage of
Nothing -> return ()
Just package -> liftIO $do
(inp,out,err,pid) <- runExternal "runhaskell" ["Setup","clean"]
oid <- forkIO (readOut log out)
eid <- forkIO (readErr log err)
return ()
packageCopy :: IDEAction
packageCopy = catchIDE (do
mbPackage <- getActivePackage
log <- getLog
mbDir <- chooseDir "Select the target directory"
case mbDir of
Nothing -> return ()
Just fp ->
case mbPackage of
Nothing -> return ()
Just package -> liftIO $ do
(inp,out,err,pid) <- runExternal "runhaskell" (["Setup","copy"]
++ ["--destdir=" ++ fp])
oid <- forkIO (readOut log out)
eid <- forkIO (readErr log err)
return ())
(\(e :: SomeException) -> putStrLn (show e))
packageRun :: IDEAction
packageRun = catchIDE (do
mbPackage <- getActivePackage
log <- getLog
case mbPackage of
Nothing -> return ()
Just package -> liftIO $do
pd <- readPackageDescription normal (cabalFile package) >>= return . flattenPackageDescription
case executables pd of
[(Executable name _ _)] -> do
let path = "dist/build" </> name </> name
(inp,out,err,pid) <- runExternal path (exeFlags package)
oid <- forkIO (readOut log out)
eid <- forkIO (readErr log err)
return ()
otherwise -> do
sysMessage Normal "no single executable in selected package"
return ())
(\(e :: SomeException) -> putStrLn (show e))
packageInstall :: IDEAction
packageInstall = catchIDE (do
mbPackage <- getActivePackage
log <- getLog
case mbPackage of
Nothing -> return ()
Just package -> liftIO $ do
(inp,out,err,pid) <- runExternal "runhaskell" (["Setup","install"]
++ (installFlags package))
oid <- forkIO (readOut log out)
eid <- forkIO (readErr log err)
return ())
(\(e :: SomeException) -> putStrLn (show e))
packageRegister :: IDEAction
packageRegister = catchIDE (do
mbPackage <- getActivePackage
log <- getLog
case mbPackage of
Nothing -> return ()
Just package -> liftIO $do
(inp,out,err,pid) <- runExternal "runhaskell" (["Setup","register"]
++ (registerFlags package))
oid <- forkIO (readOut log out)
eid <- forkIO (readErr log err)
return ())
(\(e :: SomeException) -> putStrLn (show e))
packageUnregister :: IDEAction
packageUnregister = catchIDE (do
mbPackage <- getActivePackage
log <- getLog
case mbPackage of
Nothing -> return ()
Just package -> liftIO $do
(inp,out,err,pid) <- runExternal "runhaskell" (["Setup","unregister"]
++ (unregisterFlags package))
oid <- forkIO (readOut log out)
eid <- forkIO (readErr log err)
return ())
(\(e :: SomeException) -> putStrLn (show e))
packageTest :: IDEAction
packageTest = catchIDE (do
mbPackage <- getActivePackage
log <- getLog
case mbPackage of
Nothing -> return ()
Just package -> liftIO $do
(inp,out,err,pid) <- runExternal "runhaskell" (["Setup","test"])
oid <- forkIO (readOut log out)
eid <- forkIO (readErr log err)
return ())
(\(e :: SomeException) -> putStrLn (show e))
packageSdist :: IDEAction
packageSdist = catchIDE (do
mbPackage <- getActivePackage
log <- getLog
case mbPackage of
Nothing -> return ()
Just package -> liftIO $do
(inp,out,err,pid) <- runExternal "runhaskell" (["Setup","sdist"]
++ (sdistFlags package))
oid <- forkIO (readOut log out)
eid <- forkIO (readErr log err)
return ())
(\(e :: SomeException) -> putStrLn (show e))
packageOpenDoc :: IDEAction
packageOpenDoc = catchIDE (do
mbPackage <- getActivePackage
prefs <- readIDE prefs
log <- getLog
case mbPackage of
Nothing -> return ()
Just package ->
let path = dropFileName (cabalFile package)
</> "dist/doc/html"
</> display (pkgName (packageId package))
</> display (pkgName (packageId package))
</> "index.html"
in liftIO $do
(inp,out,err,pid) <- runExternal (browser prefs) [path]
oid <- forkIO (readOut log out)
eid <- forkIO (readErr log err)
return ())
(\(e :: SomeException) -> putStrLn (show e))
chooseDir :: String -> IDEM (Maybe FilePath)
chooseDir str = do
win <- readIDE window
liftIO $do
dialog <- fileChooserDialogNew
(Just $ str)
(Just win)
FileChooserActionSelectFolder
[("gtk-cancel"
,ResponseCancel)
,("gtk-open"
,ResponseAccept)]
widgetShow dialog
response <- dialogRun dialog
case response of
ResponseAccept -> do
fn <- fileChooserGetFilename dialog
widgetDestroy dialog
return fn
ResponseCancel -> do
widgetDestroy dialog
return Nothing
ResponseDeleteEvent -> do
widgetDestroy dialog
return Nothing
_ -> return Nothing
-- ---------------------------------------------------------------------
-- | Handling of Compiler errors
--
isRunning :: IDEM Bool
#if defined(mingw32_HOST_OS) || defined(__MINGW32__)
isRunning = do
maybeProcess <- readIDE buildProcess
liftIO $ do
case maybeProcess of
Just process -> do
maybeExitCode <- getProcessExitCode process
return $ isNothing maybeExitCode
Nothing -> return False
-- Once we can interupt the build on windows, then something like this might be needed
-- alreadyRunning <- liftIO $ do
-- withTh32Snap tH32CS_SNAPPROCESS Nothing (\h -> do
-- all <- th32SnapEnumProcesses h
-- currentId <- c_GetCurrentProcessId
-- return $ not $ null $ filter (\(_, _, parentId, _, _) -> parentId == currentId) all)
#else
isRunning = do
ideR <- ask
liftIO $ (do
group <- getProcessGroupID
status <- getGroupProcessStatus False False group
putStrLn $ "Status " ++ show status
case status of
Just _ -> reflectIDE isRunning ideR
Nothing -> return True)
`catch` (\(e :: IOError) -> do
Errno errno <- liftIO $ getErrno
putStrLn $ "Error " ++ show errno
return $ errno /= 10)
#endif
interruptBuild :: IDEAction
#if defined(mingw32_HOST_OS) || defined(__MINGW32__)
interruptBuild = do
-- I can't get this to work
--maybeProcess <- readIDE buildProcess
--liftIO $ do
-- processGroupId <- case maybeProcess of
-- Just h -> do
-- withProcessHandle h (\h2 -> do
-- case h2 of
-- OpenHandle oh -> do
-- pid <- c_GetProcessId oh
-- return (h2, pid)
-- _ -> return (h2, 0))
-- _ -> return 0
-- old <- installHandler Ignore
-- putStrLn $ show processGroupId
-- generateConsoleCtrlEvent cTRL_BREAK_EVENT processGroupId
-- installHandler old
return ()
#else
interruptBuild = liftIO $ do
group <- getProcessGroupID
old_int <- installHandler sigINT Ignore Nothing
signalProcessGroup sigINT group
installHandler sigINT old_int Nothing
return ()
#endif
readErrForBuild :: Bool -> IDELog -> Handle -> IDEAction
readErrForBuild backgroundBuild log hndl = do
ideRef <- ask
errs <- liftIO $readAndShow ideRef False []
unmarkErrors
modifyIDE_ (\ide -> return (ide{errors = reverse errs, currentErr = Nothing}))
markErrors
triggerEvent ideRef (Sensitivity [(SensitivityError,not (null errs))])
sb <- getSBErrors
let errorNum = length (filter isError errs)
let warnNum = length errs - errorNum
liftIO $statusbarPop sb 1
liftIO $statusbarPush sb 1 $show errorNum ++ " Errors, " ++ show warnNum ++ " Warnings"
when ((not backgroundBuild) && (not (null errs))) nextError
where
readAndShow :: IDERef -> Bool -> [ErrorSpec] -> IO [ErrorSpec]
readAndShow ideR inError errs = catch (do
line <- hGetLine hndl
tag <- case line of
'[' : _ -> return LogTag
_ | "Linking " `isPrefixOf` line || "ar:" `isPrefixOf` line || "ld:" `isPrefixOf` line -> do
-- when backgroundBuild $ reflectIDE interruptProcess ideR
postGUISync $ reflectIDE (do
unmarkErrors
modifyIDE_ (\ide -> return (ide{errors = reverse errs, currentErr = Nothing}))
markErrors
) ideR
return LogTag
_ -> return ErrorTag
let parsed = parse buildLineParser "" line
lineNr <- appendLog log (line ++ "\n") tag
case (parsed, errs) of
(Left e,_) -> do
sysMessage Normal (show e)
readAndShow ideR False errs
(Right ne@(ErrorLine fp l c str),_) ->
readAndShow ideR True ((ErrorSpec fp l c str (lineNr,lineNr) True):errs)
(Right (OtherLine str1),(ErrorSpec fp i1 i2 str (l1,l2) isError):tl) ->
if inError
then readAndShow ideR True ((ErrorSpec fp i1 i2
(if null str
then line
else str ++ "\n" ++ line)
(l1,lineNr) isError) : tl)
else readAndShow ideR False errs
(Right (WarningLine str1),(ErrorSpec fp i1 i2 str (l1,l2) isError):tl) ->
if inError
then readAndShow ideR True ((ErrorSpec fp i1 i2
(if null str
then line
else str ++ "\n" ++ line)
(l1,lineNr) False) : tl)
else readAndShow ideR False errs
otherwise -> readAndShow ideR False errs)
(\ (_ :: SomeException) -> do
hClose hndl
let errorNum = length (filter isError errs)
let warnNum = length errs - errorNum
case errs of
[] -> appendLog log "Finished.\n" LogTag
_ -> appendLog log ("Finished. " ++ show errorNum ++ " errors - "
++ show warnNum ++ " warnings.") LogTag
return errs)
selectErr :: Int -> IDEAction
selectErr index = do
errors <- readIDE errors
if length errors < index + 1
then return ()
else do
let thisErr = errors !! index
mbBuf <- selectSourceBuf (filePath thisErr)
case mbBuf of
Just buf -> markErrorInSourceBuf index buf (line thisErr) (column thisErr)
(errDescription thisErr) True
Nothing -> return ()
log :: IDELog <- getLog
liftIO $ markErrorInLog log (logLines thisErr)
forOpenErrors :: (Int -> ErrorSpec -> IDEBuffer -> IDEAction) -> IDEAction
forOpenErrors f = do
errors <- readIDE errors
allBufs <- allBuffers
forM_ [0 .. ((length errors)-1)] (\index -> do
let error = errors !! index
fpc <- liftIO $ canonicalizePath $ filePath error
forM_ (filter (\buf -> case (fileName buf) of
Just fn -> equalFilePath fpc fn
Nothing -> False) allBufs) (f index error))
markErrors :: IDEAction
markErrors = do
forOpenErrors (\index error buf -> do
markErrorInSourceBuf index buf (line error) (column error)
(errDescription error) False
return())
unmarkErrors :: IDEAction
unmarkErrors = do
forOpenErrors (\index error buf -> liftIO $ do
gtkbuf <- textViewGetBuffer (sourceView buf)
i1 <- textBufferGetStartIter gtkbuf
i2 <- textBufferGetEndIter gtkbuf
textBufferRemoveTagByName gtkbuf ("Err" ++ show index) i1 i2)
nextError :: IDEAction
nextError = do
errs <- readIDE errors
currentErr <- readIDE currentErr
if null errs
then return ()
else do
case currentErr of
Nothing -> do
modifyIDE_ (\ide -> return (ide{currentErr = Just 0}))
selectErr 0
Just n | (n + 1) < length errs -> do
modifyIDE_ (\ide -> return (ide{currentErr = Just (n + 1)}))
selectErr (n + 1)
Just n -> selectErr n
previousError :: IDEAction
previousError = do
errs <- readIDE errors
currentErr <- readIDE currentErr
if null errs
then return ()
else do
case currentErr of
Nothing -> do
modifyIDE_ (\ide -> return (ide{currentErr = Just (length errs - 1)}))
selectErr (length errs - 1)
Just n | n > 0 -> do
modifyIDE_ (\ide -> return (ide{currentErr = Just (n - 1)}))
selectErr (n - 1)
otherwise -> selectErr 0
data BuildError = BuildLine
| EmptyLine
| ErrorLine FilePath Int Int String
| WarningLine String
| OtherLine String
buildLineParser :: CharParser () BuildError
buildLineParser = try (do
char '['
integer
symbol "of"
integer
char '['
many (anyChar)
return BuildLine)
<|> try (do
filePath <- many (noneOf ":")
char ':'
line <- integer
char ':'
column <- integer
char ':'
whiteSpace
text <- many anyChar
return (ErrorLine filePath (fromIntegral line) (fromIntegral column) text))
<|> try (do
whiteSpace
eof
return EmptyLine)
<|> try (do
whiteSpace
symbol "Warning:"
text <- many anyChar
return (WarningLine ("Warning:" ++ text)))
<|> try (do
text <- many anyChar
eof
return (OtherLine text))
<?> "buildLineParser"
lexer = P.makeTokenParser emptyDef
lexeme = P.lexeme lexer
whiteSpace = P.whiteSpace lexer
hexadecimal = P.hexadecimal lexer
symbol = P.symbol lexer
identifier = P.identifier lexer
colon = P.colon lexer
integer = P.integer lexer
-- ---------------------------------------------------------------------
-- | * Utility functions/procedures, that have to do with packages
--
getPackageDescriptionAndPath :: IDEM (Maybe (PackageDescription,FilePath))
getPackageDescriptionAndPath = do
active <- readIDE activePack
case active of
Nothing -> do
ideMessage Normal "No active packjage"
return Nothing
Just p -> do
ideR <- ask
reifyIDE (\ideR -> catch (do
pd <- readPackageDescription normal (cabalFile p)
return (Just (flattenPackageDescription pd,cabalFile p)))
(\(e :: SomeException) -> do
reflectIDE (ideMessage Normal ("Can't load package " ++(show e))) ideR
return Nothing))
getModuleTemplate :: PackageDescription -> String -> IO String
getModuleTemplate pd modName = do
filePath <- getConfigFilePathForLoad "Module.template"
template <- UTF8.readFile filePath
return (foldl' (\ a (from, to) -> replace from to a) template
[("@License@", (show . license) pd), ("@Maintainer@", maintainer pd),
("@Stability@",stability pd), ("@Portability@",""),
("@Copyright@", copyright pd),("@ModuleName@", modName)])
addModuleToPackageDescr :: ModuleName -> Bool -> IDEM ()
addModuleToPackageDescr moduleName isExposed = do
active <- readIDE activePack
case active of
Nothing -> do
ideMessage Normal "No active packjage"
return ()
Just p -> do
ideR <- ask
reifyIDE (\ideR -> catch (do
gpd <- readPackageDescription normal (cabalFile p)
if hasConfigs gpd
then do
reflectIDE (ideMessage High
"Cabal File with configurations can't be automatically updated") ideR
else
let pd = flattenPackageDescription gpd
npd = if isExposed && isJust (library pd)
then pd{library = Just ((fromJust (library pd)){exposedModules =
moduleName : exposedModules (fromJust $ library pd)})}
else let npd1 = case library pd of
Nothing -> pd
Just lib -> pd{library = Just (lib{libBuildInfo =
addModToBuildInfo (libBuildInfo lib) moduleName})}
in npd1{executables = map
(\exe -> exe{buildInfo = addModToBuildInfo (buildInfo exe) moduleName})
(executables npd1)}
in writePackageDescription (cabalFile p) npd)
(\(e :: SomeException) -> do
reflectIDE (ideMessage Normal ("Can't upade package " ++ show e)) ideR
return ()))
where
addModToBuildInfo :: BuildInfo -> ModuleName -> BuildInfo
addModToBuildInfo bi mn = bi {otherModules = mn : otherModules bi}
addRecentlyUsedPackage :: FilePath -> IDEAction
addRecentlyUsedPackage fp = do
state <- readIDE currentState
when (not $ isStartingOrClosing state) $ do
recentPackages' <- readIDE recentPackages
unless (elem fp recentPackages') $
modifyIDE_ (\ide -> return ide{recentPackages = take 12 (fp : recentPackages')})
ask >>= \ideR -> triggerEvent ideR UpdateRecent
return ()
removeRecentlyUsedPackage :: FilePath -> IDEAction
removeRecentlyUsedPackage fp = do
state <- readIDE currentState
when (not $ isStartingOrClosing state) $ do
recentPackages' <- readIDE recentPackages
when (elem fp recentPackages') $
modifyIDE_ (\ide -> return ide{recentPackages = filter (\e -> e /= fp) recentPackages'})
ask >>= \ideR -> triggerEvent ideR UpdateRecent
return ()
backgroundBuildToggled :: IDEAction
backgroundBuildToggled = do
toggled <- getBackgroundBuildToggled
modifyIDE_ (\ide -> return (ide{prefs = (prefs ide){backgroundBuild= toggled}}))
backgroundLinkToggled :: IDEAction
backgroundLinkToggled = do
toggled <- getBackgroundLinkToggled
modifyIDE_ (\ide -> return (ide{prefs = (prefs ide){backgroundLink= toggled}}))