leksah-0.4.2: src/IDE/Pane/References.hs
{-# OPTIONS_GHC -XDeriveDataTypeable -XMultiParamTypeClasses -XTypeSynonymInstances #-}
-----------------------------------------------------------------------------
--
-- Module : IDE.Pane.References
-- Copyright : (c) Juergen Nicklisch-Franken (aka Jutaro)
-- License : GNU-GPL
--
-- Maintainer : Juergen Nicklisch-Franken <info at leksah.org>
-- Stability : experimental
-- Portability : portable
--
-- | The pane of the ide where references to an identifier are presented
--
-------------------------------------------------------------------------------
module IDE.Pane.References (
IDE(..)
, ReferencesState
, referencedFrom
, showReferences
) where
import Graphics.UI.Gtk hiding (get)
import IDE.Find (focusFindEntry,showFindbar,setFindState,entryStr, getFindState, editFind)
import IDE.Pane.SourceBuffer (selectSourceBuf)
import Graphics.UI.Gtk.Gdk.Events
import Data.IORef (newIORef,writeIORef,readIORef,IORef(..))
import Data.Maybe
import Control.Monad.Reader
import qualified Data.Map as Map
import qualified Data.Set as Set
import Data.List
import Data.Typeable
import Distribution.ModuleName(ModuleName)
import Distribution.Text
import Text.PrettyPrint (render)
import IDE.Core.State
-- | A References pane description
--
data IDEReferences = IDEReferences {
scrolledView :: ScrolledWindow
, treeViewC :: TreeView
, referencesDescr :: IORef (Maybe Descr)
, referencesStore :: ListStore (ModuleDescr,Symbol)
, refScopeRef :: IORef Scope
, referencesEntry :: Entry
, topBox :: VBox
} deriving Typeable
data ReferencesState = ReferencesState {
refTo :: Maybe Descr
, refScope :: Scope}
deriving(Eq,Ord,Read,Show,Typeable)
instance IDEObject IDEReferences
instance Pane IDEReferences IDEM
where
primPaneName _ = "References"
getAddedIndex _ = 0
getTopWidget = castToWidget . topBox
paneId b = "*References"
makeActive p = activatePane p []
close = closePane
-- | We don't recover this pane
instance RecoverablePane IDEReferences ReferencesState IDEM where
saveState p = do
mbDescr <- liftIO $ readIORef (referencesDescr p)
scope <- liftIO $ readIORef (refScopeRef p)
return (Just (ReferencesState mbDescr scope))
recoverState pp (ReferencesState mbDescr scope) = do
nb <- getNotebook pp
initReferences pp nb (Just scope)
when (isJust mbDescr) (referencedFrom (fromJust mbDescr))
showReferences :: IDEAction
showReferences = do
m <- getReferences
liftIO $ bringPaneToFront m
liftIO $ widgetGrabFocus (treeViewC m)
-- | Open a pane with the references of this identifier
referencedFrom :: Descr -> IDEAction
referencedFrom idDescr = do
references <- getReferences
scope <- liftIO $ getScope references
mbCurrentInfo <- readIDE currentInfo
mbAccessibleInfo <- readIDE accessibleInfo
packages <- case scope of
System -> case mbAccessibleInfo of
Nothing -> return []
Just scope -> return ((Map.elems . fst) scope)
Package -> case mbCurrentInfo of
Nothing -> return []
Just currentInfo -> return ((Map.elems . fst . fst) currentInfo
++ (Map.elems . fst . snd) currentInfo)
Local -> case mbCurrentInfo of
Nothing -> return []
Just currentInfo -> return ((Map.elems . fst . fst) currentInfo)
let modulesList = modulesForCallerFromPackages packages (descrName idDescr, modu $ descrModu idDescr)
liftIO $ do
writeIORef (referencesDescr references) (Just idDescr)
listStoreClear (referencesStore references)
mapM_ (listStoreAppend (referencesStore references))
$ sort $ zip modulesList (repeat (descrName idDescr))
entrySetText (referencesEntry references)
$ descrName idDescr ++
" << " ++ showPackModule (descrModu idDescr)
bringPaneToFront references
modulesForCallerFromPackages :: [PackageDescr] -> (Symbol,ModuleName) -> [ModuleDescr]
modulesForCallerFromPackages [] _ = []
modulesForCallerFromPackages (p :rest) (sym,mod) =
(filter (\ md -> case mod `Map.lookup` (referencesMD md) of
Nothing -> False
Just syms -> sym `Set.member` syms) (exposedModulesPD p))
++ modulesForCallerFromPackages rest (sym,mod)
getReferences :: IDEM IDEReferences
getReferences = do
mbMod <- getPane
case mbMod of
Nothing -> do
prefs <- readIDE prefs
layout <- readIDE layout
let pp = getStandardPanePath (logPanePath prefs) layout
nb <- getNotebook pp
initReferences pp nb Nothing
mbMod <- getPane
case mbMod of
Nothing -> throwIDE "Can't init references"
Just m -> return m
Just m -> return m
scopeSelection :: Scope -> IDEAction
scopeSelection scope = do
refs <- getReferences
liftIO $ writeIORef (refScopeRef refs) scope
mbDescr <- liftIO $ readIORef (referencesDescr refs)
case mbDescr of
Nothing -> return ()
Just descr -> referencedFrom descr
getScope :: IDEReferences -> IO Scope
getScope refs = readIORef (refScopeRef refs)
initReferences :: PanePath -> Notebook -> Maybe Scope -> IDEAction
initReferences panePath nb mbScope = do
let scope = case mbScope of
Just s -> s
Nothing -> Package
prefs <- readIDE prefs
currentInfo <- readIDE currentInfo
(buf,cids) <- reifyIDE $ \ideR -> do
scopebox <- hBoxNew True 2
rb1 <- radioButtonNewWithLabel "Local"
rb2 <- radioButtonNewWithLabelFromWidget rb1 "Package"
rb3 <- radioButtonNewWithLabelFromWidget rb1 "System"
toggleButtonSetActive
(case scope of
Local -> rb1
Package -> rb2
System -> rb3) True
boxPackStart scopebox rb1 PackNatural 2
boxPackStart scopebox rb2 PackNatural 2
boxPackEnd scopebox rb3 PackNatural 2
listStore <- listStoreNew []
treeView <- treeViewNew
treeViewSetModel treeView listStore
renderer0 <- cellRendererPixbufNew
set renderer0 [ cellPixbufStockId := stockYes ]
renderer <- cellRendererTextNew
col <- treeViewColumnNew
treeViewColumnSetTitle col "Modules"
treeViewColumnSetSizing col TreeViewColumnAutosize
treeViewColumnSetResizable col True
treeViewColumnSetReorderable col True
treeViewAppendColumn treeView col
cellLayoutPackStart col renderer0 False
cellLayoutPackStart col renderer True
cellLayoutSetAttributes col renderer listStore
$ \row -> [ cellText := render $ disp $ modu $ moduleIdMD $ fst row]
cellLayoutSetAttributes col renderer0 listStore
$ \row -> [cellPixbufStockId :=
if isJust (mbSourcePathMD $ fst row)
then stockJumpTo
else stockYes]
renderer2 <- cellRendererTextNew
col2 <- treeViewColumnNew
treeViewColumnSetTitle col2 "Packages"
treeViewColumnSetSizing col2 TreeViewColumnAutosize
treeViewColumnSetResizable col True
treeViewColumnSetReorderable col2 True
treeViewAppendColumn treeView col2
cellLayoutPackStart col2 renderer2 True
cellLayoutSetAttributes col2 renderer2 listStore
$ \row -> [ cellText := render $ disp $ pack $ moduleIdMD $ fst row]
treeViewSetHeadersVisible treeView True
sel <- treeViewGetSelection treeView
treeSelectionSetMode sel SelectionSingle
sw <- scrolledWindowNew Nothing Nothing
containerAdd sw treeView
scrolledWindowSetPolicy sw PolicyAutomatic PolicyAutomatic
entry <- entryNew
set entry [ entryEditable := False ]
box <- vBoxNew False 2
boxPackStart box scopebox PackNatural 0
boxPackStart box entry PackNatural 0
boxPackEnd box sw PackGrow 0
referencesDescr' <- newIORef Nothing
scope <- newIORef (case mbScope of
Just s -> s
Nothing -> Package)
let references = IDEReferences sw treeView referencesDescr' listStore scope entry box
notebookInsertOrdered nb box (paneName references) Nothing
widgetShowAll box
cid1 <- treeView `afterFocusIn`
(\_ -> do reflectIDE (makeActive references) ideR ; return True)
treeView `onButtonPress` (treeViewPopup ideR references)
rb1 `onToggled` (reflectIDE (scopeSelection Local) ideR )
rb2 `onToggled` (reflectIDE (scopeSelection Package) ideR )
rb3 `onToggled` (reflectIDE (scopeSelection System) ideR )
return (references,[ConnectC cid1])
addPaneAdmin buf cids panePath
liftIO $widgetGrabFocus (scrolledView buf)
getSelectionTree :: TreeView
-> ListStore (ModuleDescr,Symbol)
-> IO (Maybe (ModuleDescr,Symbol))
getSelectionTree treeView listStore = do
treeSelection <- treeViewGetSelection treeView
rows <- treeSelectionGetSelectedRows treeSelection
case rows of
[[n]] -> do
val <- listStoreGetValue listStore n
return (Just val)
_ -> return Nothing
treeViewPopup :: IDERef
-> IDEReferences
-> Event
-> IO (Bool)
treeViewPopup ideR references (Button _ click _ _ _ _ button _ _) = do
if button == RightButton
then do
theMenu <- menuNew
item1 <- menuItemNewWithLabel "Edit"
item1 `onActivateLeaf` do
sel <- getSelectionTree (treeViewC references) (referencesStore references)
case sel of
Just (m,_) -> case mbSourcePathMD m of
Nothing -> return ()
Just fp -> do
text <- entryGetText (referencesEntry references)
case words text of
(hd : tl) -> do
reflectIDE (selectText fp hd) ideR
return ()
_ -> return ()
otherwise -> return ()
menuShellAppend theMenu item1
menuPopup theMenu Nothing
widgetShowAll theMenu
return True
else if button == LeftButton && click == DoubleClick
then do sel <- getSelectionTree (treeViewC references)
(referencesStore references)
case sel of
Just (m,_)
-> case mbSourcePathMD m of
Nothing -> return False
Just fp -> do
text <- entryGetText (referencesEntry references)
case words text of
(hd : tl) -> do
reflectIDE (selectText fp hd) ideR
return True
_ -> return False
otherwise -> return False
else return False
treeViewPopup _ _ _ = throwIDE "treeViewPopup wrong event type"
selectText :: FilePath -> String -> IDEM Bool
selectText fp text = do
res <- selectSourceBuf fp
fs <- getFindState
case res of
Nothing -> return False
Just _ -> do
setFindState fs {entryStr = text}
showFindbar
focusFindEntry
reifyIDE $ \ideR -> do
idleAdd (do
reflectIDE (editFind True True True text "" Forward) ideR
return False)
priorityDefaultIdle
return True