tabloid 0.3 → 0.44
raw patch · 14 files changed
+363/−169 lines, 14 filesdep +hintdep +paralleldep ~base
Dependencies added: hint, parallel
Dependency ranges changed: base
Files
- DataProcController.hs +43/−8
- DataProcView.hs +35/−12
- HaskellCmdInputController.hs +121/−0
- Main.hs +1/−1
- MultiWidgetContainerController.hs +24/−13
- PerformanceTuning.hs +0/−41
- ShellCmdInputController.hs +6/−6
- ShellCmdInputView.hs +9/−48
- TableController.hs +28/−37
- TextInputView.hs +63/−0
- examples/example.hs +3/−0
- examples/example.submatches.regex +1/−0
- examples/example_shell_cmd.sh +1/−0
- tabloid.cabal +28/−3
DataProcController.hs view
@@ -1,4 +1,10 @@-module DataProcController where+module DataProcController + ( new+ , view+ , Controller+ , onUpdate+ , Haskell.Env+ ) where import Graphics.UI.Gtk import Control.Monad@@ -6,12 +12,14 @@ import qualified DataProcView as View import qualified ShellCmdInputController as Shell+import qualified HaskellCmdInputController as Haskell import qualified LineSplitterController as RxDef import qualified TableController as Table+import qualified Data.Map as M import qualified Data.ByteString.Lazy.Char8 as L import SimpleRegex- +import Data.Maybe import WindowedApp import Component @@ -19,28 +27,54 @@ view = View.mainWidget . gui -new :: IO Controller-new = do+new :: IO Haskell.Env -> IO Controller+new env = do s <- Shell.new r <- RxDef.new t <- Table.new+ h <- Haskell.new env sv <- (s.>Shell.view) rv <- (r.>RxDef.view) tv <- (t.>Table.view)- g <- View.new sv rv tv - this <- newRef $ C g s r t RxDef.defaultFilter+ hv <- (h.>Haskell.view)+ g@(View.V _ _ _ _ useShellRB useHaskellRB) <- View.new sv rv tv hv+ toggleButtonSetActive useShellRB True+ toggleButtonSetActive useHaskellRB False+ this <- newRef $ C g s r t RxDef.defaultFilter Nothing+ onToggled useHaskellRB (this .<< switchViews) s .< Shell.onUpdate (Just (\lines -> this .>> showData lines)) r .< RxDef.onUpdate (Just (\filt -> do this .< (\stat -> stat {filterFun = filt}) postGUIAsync $ s .<< Shell.runText))+ h .< Haskell.onUpdate (Just (\lines ->+ Table.push t ((map L.pack) <$> lines))) return this +onUpdate :: (Maybe ([[String]] -> IO ())) -> C -> C+onUpdate f state = state {updateCB = f}+ -- internal +switchViews :: C -> IO C+switchViews state = do+ useHaskell <- toggleButtonGetActive $ View.useShellRB (gui state)+ let cont = View.shellOrHaskellContainer (gui state)+ let hs = View.shellView (gui state)+ let sh = View.haskellView (gui state)+ [c] <- containerGetChildren cont+ containerRemove cont c+ boxPackStart cont (if useHaskell then hs else sh) PackGrow 2+ widgetShowAll cont+ return state+ showData :: L.ByteString -> C -> IO ()-showData x state = (filterFun state x) >>= Table.push (table state) +showData x state = do+ content <- (filterFun state x) + when (isJust (updateCB state)) + ((fromJust (updateCB state)) (((map L.unpack) <$>) content))+ Table.push (table state) content data C = C { gui :: View.ViewState@@ -48,9 +82,10 @@ , rxdef :: RxDef.Controller , table :: Table.Controller , filterFun :: RxDef.Filter+ , updateCB :: Maybe ([[String]] -> IO ()) } -- tests test = windowedApp "DataProcController test" $ do- t <- new :: IO Controller+ t <- new (return M.empty) :: IO Controller t .> view
DataProcView.hs view
@@ -6,25 +6,48 @@ data ViewState = V { mainWidget :: Widget+ , shellView :: Widget+ , haskellView :: Widget+ , shellOrHaskellContainer :: VBox+ , useShellRB :: RadioButton + , useHaskellRB :: RadioButton } -new :: Widget -> Widget -> Widget -> IO ViewState-new w1 w2 w3 = do- vbox <- vBoxNew False 2- vbox2 <- vBoxNew False 0+new :: Widget -> Widget -> Widget -> Widget -> IO ViewState+new sv rv tv haskellView = do + useShellRB <- radioButtonNewWithLabel "Input From Shell"+ useHaskellRB <- radioButtonNewWithLabelFromWidget useShellRB "Haskell Code"+ vbox <- vBoxNew False 0++ radioButtonHBox <- hBoxNew False 0+ boxPackStart radioButtonHBox useShellRB PackNatural 2+ boxPackStart radioButtonHBox useHaskellRB PackNatural 2+ boxPackStart vbox radioButtonHBox PackNatural 2+ + shellOrHaskellContainer <- vBoxNew False 0+ boxPackStart vbox shellOrHaskellContainer PackNatural 2++ shellView <- vBoxNew False 2+ vbox2 <- vBoxNew False 0 w1ex <- expanderNew "Shell Command" expanderSetExpanded w1ex True- containerAdd w1ex w1-+ containerAdd w1ex sv w2ex <- expanderNew "Splitter Regex" expanderSetExpanded w2ex False- containerAdd w2ex w2-+ containerAdd w2ex rv boxPackStart vbox2 w1ex PackNatural 2 boxPackEnd vbox2 w2ex PackNatural 2-- boxPackStart vbox vbox2 PackNatural 2- boxPackStart vbox w3 PackGrow 2- return (V (toWidget vbox))+ boxPackStart shellView vbox2 PackNatural 2+ boxPackStart shellOrHaskellContainer shellView PackNatural 2+ + boxPackEnd vbox tv PackGrow 2+ + return (V + (toWidget vbox) + (toWidget shellView) + (toWidget haskellView) + shellOrHaskellContainer + useShellRB + useHaskellRB)
+ HaskellCmdInputController.hs view
@@ -0,0 +1,121 @@+{-# LANGUAGE OverloadedStrings #-}+module HaskellCmdInputController+ (+ Controller+ , new+ , onUpdate+ , view+ , OnUpdate+ , runText+ , Env+ ) where++import qualified Graphics.UI.Gtk.ModelView as MV +import qualified TextInputView as View+import Graphics.UI.Gtk+import WindowedApp+import Component+import qualified Data.ByteString.Lazy.Char8 as L+import Control.Concurrent.MVar+import qualified LoadSaveController as LSC+import Language.Haskell.Interpreter+import GHC.Exts( IsString(..) )+import Control.Concurrent+import Control.Applicative+import qualified Data.Map as M+import qualified Control.Exception as Exc+import Control.Parallel.Strategies+import Data.List++type Controller = Ref C++view = View.mainWidget . gui++new env = do+ buf <- textBufferNew Nothing+ lsc <- LSC.new (Just "hs")+ lscv <- (lsc .> LSC.view)+ v@(View.V _ runB _ _ _) <- View.new buf lscv+ lock <- newEmptyMVar+ this <- newRef (C v "" Nothing buf lock env)+ runB `onClicked` (this .<< runText)+ lsc .< (LSC.onLoad (Just (\cont -> textBufferSetText buf (L.unpack cont))))+ lsc .< (LSC.onSave (Just (Just <$> L.pack <$> getBufferText buf))) + onBufferChanged buf (lsc .>> LSC.clearLabel)+ return this++type OnUpdate = [[String]] -> IO ()+type Env = M.Map String [[String]]++onUpdate :: Maybe OnUpdate -> C -> C+onUpdate cb state = state {executeCB = cb}+-- internal functions +data C = C + { + gui :: View.ViewState+ , currentCmd :: String+ , executeCB :: Maybe OnUpdate+ , buffer :: TextBuffer+ , execLock :: MVar Bool+ , env :: IO Env+ }++getBufferText buf = do+ s <- textBufferGetStartIter buf+ e <- textBufferGetEndIter buf+ textBufferGetText buf s e True+ +runText :: C -> IO C+runText state = do+ locked <- tryPutMVar (execLock state) True+ if locked then+ case executeCB state of+ Just execCB -> + do+ text <- getBufferText (buffer state)+ forkOS $ executeCmd text execCB state+ return $ state+ Nothing -> + return state+ else return state++executeCmd text execCB state = do+ e <- env state+ postGUISync $ widgetSetSensitivity (View.cancelB $ gui state) False+ postGUISync $ widgetSetSensitivity (View.executeB $ gui state) False+ postGUISync $ widgetSetSensitivity (View.textView $ gui state) False+ postGUISync $ labelSetText (View.exitCodeL $ gui state) $ "Executing..."+ let haskellCode = "(" ++ text ++ ") :: (Map String [[String]] -> [[String]])"+ res <- runInterpreter (evalText haskellCode)+ case res of + Right func -> do + let ex_handler :: (Show e) => e -> IO [[String]]+ ex_handler exc = postGUISync (labelSetText (View.exitCodeL $ gui state) ("Error: " ++ show exc)) >> return []+ lines <- Exc.catch (let res' = func e+ in (res' `using` rnf) `seq` return res')+ ex_handler+ postGUISync (execCB lines)+ postGUISync $ labelSetText (View.exitCodeL $ gui state) ("Procuced " ++ show (length lines) ++ " rows")++ Left errs -> + postGUISync $ labelSetText (View.exitCodeL $ gui state) ("Error: " ++ show errs)++ postGUISync $ widgetSetSensitivity (View.cancelB $ gui state) False+ postGUISync $ widgetSetSensitivity (View.textView $ gui state) True+ postGUISync $ widgetSetSensitivity (View.executeB $ gui state) True+ takeMVar (execLock state)+ return ()+ where + evalText :: String -> Interpreter (Env -> [[String]]) + evalText source = do+ setImports ["Data.Map", "Prelude", "Data.List", "Data.Char"]+ interpret source (undefined ::(Env -> [[String]]))+ +-- tests+main = windowedApp "HaskellCmdInputController test" $ do+ t <- new (return M.empty) :: IO Controller+ t .< onUpdate (Just ((mapM_ (putStrLn . show)) + . (take 100)))+ t .> view+ +
Main.hs view
@@ -2,4 +2,4 @@ import qualified MultiWidgetContainerController as MainC -main = MainC.test+main = MainC.main
MultiWidgetContainerController.hs view
@@ -3,7 +3,7 @@ module MultiWidgetContainerController ( new- , test+ , main , view , Controller ) where@@ -23,30 +23,41 @@ new :: IO Controller new = do v@(View.V _ _ _ ab) <- View.new - this <- newRef (C v M.empty)- onClicked ab (this .<< addComponent) + this <- newRef (C v M.empty M.empty)+ onClicked ab (addComponent this) return this removeComponent :: String -> C -> C removeComponent name state = state { components = (M.delete name (components state)) } -addComponent :: C -> IO C-addComponent (C g cs) = do- name <- entryGetText (View.nameE g)- putStrLn $ "add comp " ++ name- dpc <- DP.new- (dpc .> DP.view) >>= View.add g name- let cs' = M.insert name dpc cs- return (C g cs')+addComponent :: Controller -> IO ()+addComponent this = this .<< + \(C g cs env) -> do+ name <- entryGetText (View.nameE g)+ putStrLn $ "add comp " ++ name+ dpc <- DP.new (this .>> getEnv)+ (dpc .> DP.view) >>= View.add g name+ let cs' = M.insert name dpc cs+ dpc .< DP.onUpdate (Just (\ls -> this .<< dpcUpdated name ls))+ return (C g cs' env) -- internal ++getEnv :: C -> IO DP.Env+getEnv = return . contents ++dpcUpdated :: String -> [[String]] -> C -> IO C+dpcUpdated name content state = do + return (state {contents = M.insert name content (contents state)})+ data C = C { gui :: View.ViewState , components :: M.Map String DP.Controller+ , contents :: DP.Env } -test = windowedApp "RegexDefinitionController test" $ do- clut <- new+main = windowedApp "tabloid" $ do+ clut <- new mw <- View.mainWidget <$> (clut .> gui) return mw
− PerformanceTuning.hs
@@ -1,41 +0,0 @@-module Main where --import qualified System.Process as P-import System.IO-import qualified Data.ByteString.Lazy.Char8 as L-import SimpleRegex-import Control.Concurrent--main = do- lines <- L.readFile "testdata"- res <- testAction lines- putStrLn $ show res- return ()---interactive_test = do- let text = "cat testdata"- (hin, hout, _, ph) <- P.runInteractiveProcess "/bin/bash" [] Nothing Nothing- hPutStr hin text- lines <- L.hGetContents hout- res <- testAction lines- putStrLn $ show res- ec <- P.waitForProcess ph - return ()--test_rx = "([0-9]{4}-[0-9]{2}-[0-9]{2} ..:..:..),....+[[][0-9]+[]] ([^ ]+) +(incoming|outgoing) c[Aa]ll #([0-9]+)/R:(.+)/C:(.+)/L:([0-9-]+) BCH#(.+)/DCH#(.+):(.+)/BRD#(.+) .+ CRN ([0-9A-Za-z]+) @([-0-9]+) (from|local) (.+) (to|remote) (.+) [[][^ ]+ *(.*)$"--testAction c = do- rx <- compile "(incoming)"- return $ map (submatches rx) (L.lines c)--testAction2 c = do--- rx <- compile "([0-9]{4}-[0-9]{2}-[0-9]{2} ..:..:..),....+[[][0-9]+[]] ([^ ]+) +(incoming|outgoing) c[Aa]ll #([0-9]+)/R:(.+)/C:(.+)/L:([0-9-]+) BCH#(.+)/DCH#(.+):(.+)/BRD#(.+) .+ CRN ([0-9A-Za-z]+) @([-0-9]+) local (.+) remote (.+) [[][^ ]+ *(.*)$"- rx <- compile "(incoming)"- let sms = catSubmatches rx $ L.lines c- return $ map (\ (ss, s) -> - case ss of- [] -> [s]- _ -> ss) sms--
ShellCmdInputController.hs view
@@ -1,7 +1,6 @@ module ShellCmdInputController ( Controller- , test , new , onUpdate , view@@ -32,7 +31,7 @@ buf <- textBufferNew Nothing lsc <- LSC.new (Just "sh") lscv <- (lsc .> LSC.view)- v@(View.V _ runB _ _ _ _) <- View.new buf lscv+ v@(View.V _ runB _ _ _ _ _) <- View.new buf lscv lock <- newEmptyMVar this <- newRef (C v "" Nothing buf lock) runB `onClicked` (this .<< runText)@@ -68,7 +67,7 @@ Just execCB -> do text <- getBufferText (buffer state)- theshell <- entryGetText (View.shellE (gui state))+ theshell <- entryGetText (View.shellE (gui state)) forkOS $ executeCmd text execCB state (words theshell) return $ state Nothing -> @@ -80,6 +79,7 @@ postGUISync $ widgetSetSensitivity (View.executeB $ gui state) False postGUISync $ widgetSetSensitivity (View.textView $ gui state) False postGUISync $ labelSetText (View.exitCodeL $ gui state) $ "Executing..."+ (hin, hout, _, ph) <- P.runInteractiveProcess theshell theargs Nothing Nothing postGUISync $ (View.cancelB $ gui state) `onClicked` (do P.terminateProcess ph@@ -88,19 +88,19 @@ hPutStr hin text lines <- L.hGetContents hout postGUISync $ execCB lines-+ ec <- P.waitForProcess ph + postGUISync $ labelSetText (View.exitCodeL $ gui state) $ "Exit Code: " ++ show ec postGUISync $ (View.cancelB $ gui state) `onClicked` (return ()) postGUISync $ widgetSetSensitivity (View.cancelB $ gui state) False postGUISync $ widgetSetSensitivity (View.textView $ gui state) True postGUISync $ widgetSetSensitivity (View.executeB $ gui state) True- postGUISync $ labelSetText (View.exitCodeL $ gui state) $ "Exit Code: " ++ show ec takeMVar (execLock state) return () -- tests-test = windowedApp "ShellCmdInputController test" $ do+main = windowedApp "ShellCmdInputController test" $ do t <- new :: IO Controller t .< onUpdate (Just ((mapM_ putStrLn) . (take 100)
ShellCmdInputView.hs view
@@ -2,6 +2,7 @@ import Graphics.UI.Gtk import Graphics.UI.Gtk.ModelView as MV+import qualified TextInputView as TV data ViewState = V {@@ -11,58 +12,18 @@ , textView :: TextView , cancelB :: Button , shellE :: Entry+ , tvv :: TV.ViewState } -new buf fileButtons = do - cmdE <- textViewNewWithBuffer buf-- let stateTypes = [StateNormal, StateActive, StatePrelight, StateSelected, StateInsensitive]- fgCols = [Color 65535 49152 0, Color 65535 49152 0, Color 65535 49152 0, Color 65535 49152 0]- bgCols = [Color 255 192 0, Color 0 0 0, Color 0 0 0, Color 32535 32535 0]-- mapM_ (uncurry (widgetModifyText cmdE)) $- stateTypes `zip` fgCols-- mapM_ (uncurry (widgetModifyBase cmdE)) $- stateTypes `zip` bgCols-- scrollWin <- scrolledWindowNew Nothing Nothing- set scrollWin - [ containerBorderWidth := 5- , scrolledWindowShadowType := ShadowIn- , scrolledWindowVscrollbarPolicy := PolicyAutomatic- , scrolledWindowHscrollbarPolicy := PolicyAutomatic- ]- containerAdd scrollWin cmdE-- cmdBHbox <- hBoxNew False 2- cmdRunB <- buttonNewFromStock stockExecute- boxPackEnd cmdBHbox cmdRunB PackNatural 2- - cancB <- buttonNewFromStock stockCancel- widgetSetSensitivity cancB False- boxPackEnd cmdBHbox cancB PackNatural 2- - boxPackStart cmdBHbox fileButtons PackNatural 2-- exitL <- labelNew Nothing- boxPackStart cmdBHbox exitL PackGrow 2-+new buf fileButtons = do shellH <- hBoxNew False 2- shellL <- labelNew $ Just "Shell: " shellE <- entryNew entrySetText shellE "/bin/bash"+ shellL <- labelNew $ Just "shell: " boxPackStart shellH shellL PackNatural 2 boxPackStart shellH shellE PackGrow 2-- centerHB <- hBoxNew False 2- - cmdVbox <- vBoxNew False 2- boxPackStart cmdVbox shellH PackNatural 2- boxPackStart cmdVbox scrollWin PackGrow 2- boxPackStart cmdVbox cmdBHbox PackNatural 2 -- vbox <- vBoxNew False 2- boxPackStart vbox cmdVbox PackGrow 2-- return $ V (toWidget vbox) cmdRunB exitL cmdE cancB shellE+ tvv@(TV.V mainW execB exitL cmdE cancB) <- TV.new buf fileButtons+ vbox <- vBoxNew False 2 + boxPackStart vbox shellH PackGrow 2+ boxPackStart vbox mainW PackGrow 2+ return $ V (toWidget vbox) execB exitL cmdE cancB shellE tvv
TableController.hs view
@@ -106,46 +106,37 @@ ((fst_sel:_):_) -> fst_sel _ -> 0 -{--toCsv :: StringList -> IO L.ByteString -toCsv liststore = do- cont <- MV.listStoreToList liststore- return (L.unlines (lineToCsv <$> cont))+toCsv liststore = withRows liststore (formatLine + [('"', L.pack "\"\"")] + (L.pack "\"") + (L.pack ";"))++toJira liststore = withRows liststore + (((pipeSym `L.append`) . + (`L.append` pipeSym)) .+ (formatLine [] L.empty pipeSym)) where- lineToCsv :: [L.ByteString] -> L.ByteString- lineToCsv ls = - let els = doQuotes <$> ls- in L.concat (intersperse (L.pack ";") els)- doQuotes :: L.ByteString -> L.ByteString- doQuotes cont = - let escaped = L.foldl' (\s c -> - s `L.append` - (if c == '"' - then L.pack ['\\', c] - else L.pack [c])) - L.empty- cont- in (L.pack "\"") `L.append` escaped `L.append` (L.pack "\"")--}-toJira :: StringList -> IO L.ByteString -toJira liststore = do+ pipeSym = L.pack "|"++withRows :: StringList -> ([L.ByteString] -> L.ByteString) -> IO L.ByteString+withRows liststore action = do cont <- MV.listStoreToList liststore- return (L.unlines (lineToCsv <$> cont))- where- lineToCsv :: [L.ByteString] -> L.ByteString- lineToCsv ls = - let els = escape <$> ls- in (L.pack "| ") `L.append` - L.concat (intersperse (L.pack " | ") els) `L.append` (L.pack " |")- escape :: L.ByteString -> L.ByteString- escape cont = L.foldl' (\s c -> - s `L.append` - (if c == '|' - then L.pack ['\\', c] - else L.pack [c])) - L.empty- cont+ return (L.unlines (action <$> cont)) +formatLine repl quot sep = (intercal sep) . (map $ embedString quot) . (map $ replaceChars repl) ++embedString :: L.ByteString -> L.ByteString -> L.ByteString+embedString es = (es `L.append`) . (`L.append` es)++intercal :: L.ByteString -> [L.ByteString] -> L.ByteString +intercal = (L.concat .) . intersperse++replaceChars :: [(Char,L.ByteString)] -> L.ByteString -> L.ByteString+replaceChars tab = L.foldl'+ (\s c -> + s `L.append` fromJust (lookup c tab `mplus` Just (L.pack [c])))+ L.empty+ pushRaw :: [[L.ByteString]] -> C -> IO C pushRaw rows c@(C g listM mc groupCol) = let
+ TextInputView.hs view
@@ -0,0 +1,63 @@+module TextInputView where++import Graphics.UI.Gtk+import Graphics.UI.Gtk.ModelView as MV++data ViewState = V + {+ mainWidget :: Widget+ , executeB :: Button+ , exitCodeL :: Label+ , textView :: TextView+ , cancelB :: Button+ }++new buf fileButtons = do + cmdE <- textViewNewWithBuffer buf++ let stateTypes = [StateNormal, StateActive, StatePrelight, StateSelected, StateInsensitive]+ fgCols = [Color 65535 49152 0, Color 65535 49152 0, Color 65535 49152 0, Color 65535 49152 0]+ bgCols = [Color 255 192 0, Color 0 0 0, Color 0 0 0, Color 32535 32535 0]++ mapM_ (uncurry (widgetModifyText cmdE)) $+ stateTypes `zip` fgCols++ mapM_ (uncurry (widgetModifyBase cmdE)) $+ stateTypes `zip` bgCols++ scrollWin <- scrolledWindowNew Nothing Nothing+ set scrollWin + [ containerBorderWidth := 5+ , scrolledWindowShadowType := ShadowIn+ , scrolledWindowVscrollbarPolicy := PolicyAutomatic+ , scrolledWindowHscrollbarPolicy := PolicyAutomatic+ ]+ containerAdd scrollWin cmdE+ ++ cmdBHbox <- hBoxNew False 2+ cmdRunB <- buttonNewFromStock stockExecute+ boxPackEnd cmdBHbox cmdRunB PackNatural 2+ + cancB <- buttonNewFromStock stockCancel+ widgetSetSensitivity cancB False+ boxPackEnd cmdBHbox cancB PackNatural 2+ + boxPackStart cmdBHbox fileButtons PackNatural 2++ exitL <- labelNew Nothing+ boxPackStart cmdBHbox exitL PackGrow 2++ centerHB <- hBoxNew False 2+ + cmdVbox <- vBoxNew False 2+ boxPackStart cmdVbox scrollWin PackGrow 2+ boxPackStart cmdVbox cmdBHbox PackNatural 2 ++ vbox <- vBoxNew False 2+ boxPackStart vbox cmdVbox PackGrow 2++ return $ V (toWidget vbox) cmdRunB exitL cmdE cancB+++-- some Utility functions for working with a text View
+ examples/example.hs view
@@ -0,0 +1,3 @@+\env ->+ [ r | r <- env ! "a", + "ext" `isInfixOf` (fmap toLower (r !! 3)) ]
+ examples/example.submatches.regex view
@@ -0,0 +1,1 @@+([^ ]+ [^ ]+ [^ ]+:[^ ]+:[^ ]+) ([^ ]+) ([^ ]+): (.+)
+ examples/example_shell_cmd.sh view
@@ -0,0 +1,1 @@+sudo cat /var/log/messages.log
tabloid.cabal view
@@ -1,5 +1,5 @@ Name: tabloid-Version: 0.3+Version: 0.44 Description: GUI for shell commands and log analysis Category: System Synopsis: View the output of shell commands in a table@@ -9,8 +9,33 @@ Maintainer: sven.heyll@gmail.com Build-Type: Simple Cabal-Version: >=1.2+extra-source-files: README,+ Component.hs,+ DataProcController.hs,+ DataProcView.hs,+ DataSourceView.hs,+ FileChooser.hs,+ HaskellCmdInputController.hs,+ LineSplitterController.hs,+ LineSplitterView.hs,+ LoadSaveController.hs,+ LoadSaveView.hs,+ MultiWidgetContainerController.hs,+ MultiWidgetContainerView.hs,+ RegexDefinitionController.hs,+ RegexDefinitionView.hs,+ ShellCmdInputController.hs,+ ShellCmdInputView.hs,+ SimpleRegex.hs,+ TableController.hs,+ TableView.hs,+ TextInputView.hs,+ WindowedApp.hs,+ examples/example.hs,+ examples/example.submatches.regex,+ examples/example_shell_cmd.sh Executable tabloid Main-is: Main.hs- Build-Depends: base, gtk, regex-base, regex-posix>=0.93, bytestring, process, containers- ghc-options: -O9 -fforce-recomp -funbox-strict-fields -Wall -threaded+ Build-Depends: base >= 3.0 && < 4.0, gtk, regex-base, regex-posix>=0.93, bytestring, process, containers, hint, parallel+ ghc-options: -O9 -fforce-recomp -funbox-strict-fields -threaded