{-# LANGUAGE GADTs #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MultiWayIf #-}
{-# LANGUAGE BinaryLiterals #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE DeriveDataTypeable #-}
module Phoityne.IO.GUI.Control (
createMainWindow
, DebugCommandData(..)
) where
-- モジュール
import Phoityne.Constant
import Phoityne.Utility
import Phoityne.IO.Utility
import qualified Phoityne.IO.GUI.GTK.Interface as IF
-- システム
import System.Exit
import System.FilePath
import System.Directory
import System.Log.Logger
import Control.Monad
import Control.Concurrent
import Data.Maybe
import Data.String.Utils
import Data.Char
import Data.Functor.Identity
import Text.Parsec
import qualified Data.Map as Map
import qualified Data.List as L
import qualified Data.Tree as T
import qualified Data.Text as TE
import qualified Data.Text.Encoding as TE
import qualified Text.StringTemplate as TPL
-- |
--
--
type NoteMap = Map.Map IF.NodeData IF.TextEditorData
-- |
--
--
data UndoRedoData =
DeleteRangeUndoRedoData {
filePathDeleteRangeUndoRedoData :: FilePath
, startLineNoDeleteRangeUndoRedoData :: Int
, startColNoDeleteRangeUndoRedoData :: Int
, endLineNoDeleteRangeUndoRedoData :: Int
, endColNoDeleteRangeUndoRedoData :: Int
, textDeleteRangeUndoRedoData :: String
} |
InsertTextUndoRedoData {
filePathInsertTextUndoRedoData :: FilePath
, startLineNoInsertTextUndoRedoData :: Int
, startColNoInsertTextUndoRedoData :: Int
, textInsertTextUndoRedoData :: String
}
deriving (Show, Read, Eq, Ord)
-- |
--
--
data MVarGUIData =
MVarGUIData {
widgetStoreMVarGUIData :: IF.WidgetStore
, breakPointListMVarGUIData :: IF.BreakPointListStore
, codeNoteMapMVarGUIData :: NoteMap
, folderTreeMVarGUIData :: IF.FolderTreeStore
, bindingListStoreMVarGUIData :: IF.BindingListStore
, traceListStoreMVarGUIData :: IF.TraceDataListStore
, searchResultListStoreMVarGUIData :: IF.SearchResultListStore
, traceIdMVarGUIData :: Int
, undoBufferMVarGUIData :: [UndoRedoData]
, redoBufferMVarGUIData :: [UndoRedoData]
, unDoReDoFlagMVarGUIData :: Bool
, buildMsgMVarGUIData :: [String]
, searchFilesMVarGUIData :: [FilePath]
, startupNodeDataMVarGUIData :: Maybe IF.NodeData
}
-- |
--
--
data DebugCommandData =
DebugCommandData {
startDebugCommandData :: IO ()
, stopDebugCommandData :: IO ExitCode
, readDebugCommandData :: IO String
, readLinesDebugCommandData :: ([String] -> IO Bool) -> IO [String]
, promptDebugCommandData :: IO String
, breakDebugCommandData :: ModuleName -> Int -> IO String
, bindingsDebugCommandData :: IO String
, runDebugCommandData :: Bool -> IO String
, continueDebugCommandData :: Bool -> IO String
, stepDebugCommandData :: IO String
, stepOverDebugCommandData :: IO String
, printEvldDebugCommandData :: IO String
, deleteBreakDebugCommandData :: Int -> IO String
, traceHistDebugCommandData :: IO String
, traceBackDebugCommandData :: IO String
, traceForwardDebugCommandData :: IO String
, forceDebugCommandData :: String -> IO String
, execCommandData :: String -> IO String
, quitDebugCommandData :: IO String
, buildStartDebugCommandData :: IO ()
, cleanStartDebugCommandData :: IO ()
, loadFileDebugCommandData :: FilePath -> IO String
, readWhileDebugCommandData :: (String -> Bool) -> IO String
}
-- |
--
--
data HighlightTextRangeData = HighlightTextRangeData {
filePathHighlightTextRangeData :: FilePath
, startLineNoHighlightTextRangeData :: Int
, startColNoHighlightTextRangeData :: Int
, endLineNoHighlightTextRangeData :: Int
, endColNoHighlightTextRangeData :: Int
} deriving (Show, Read, Eq, Ord)
-- |
--
--
getKeyOfHighlightTextRangeData :: HighlightTextRangeData -> IF.BreakPointDataKey
getKeyOfHighlightTextRangeData (HighlightTextRangeData file line _ _ _) = (file, line)
-- |
--
--
defaultMVarGUIData :: IF.WidgetStore
-> IF.BreakPointListStore
-> IF.FolderTreeStore
-> IF.BindingListStore
-> IF.TraceDataListStore
-> IF.SearchResultListStore
-> MVarGUIData
defaultMVarGUIData widgets breaks folder bindings trace search =
MVarGUIData {
widgetStoreMVarGUIData = widgets
, breakPointListMVarGUIData = breaks
, codeNoteMapMVarGUIData = Map.fromList []
, folderTreeMVarGUIData = folder
, bindingListStoreMVarGUIData = bindings
, traceListStoreMVarGUIData = trace
, searchResultListStoreMVarGUIData = search
, traceIdMVarGUIData = 0
, undoBufferMVarGUIData = []
, redoBufferMVarGUIData = []
, unDoReDoFlagMVarGUIData = False
, buildMsgMVarGUIData = []
, searchFilesMVarGUIData = []
, startupNodeDataMVarGUIData = Nothing
}
-- |
--
--
createMainWindow :: DebugCommandData -> [FilePath] -> IO ()
createMainWindow cmdData paths = do
-- Storeの作成
builder <- IF.getBuilder
breakStore <- IF.createBreakPointListStore
bindingStore <- IF.createBindingListStore
traceStore <- IF.createTraceDataListStore
searchResultStore <- IF.createSearchResultListStore
treeStore <- loadFolderForest _PROJECT_ROOT_MODULE_NAME paths >>= IF.createTreeStore
-- GUI共有データの作成
mvarGUI <- newMVar $ defaultMVarGUIData builder breakStore treeStore bindingStore traceStore searchResultStore
-- イベントハンドラの登録
IF.setupMainWindow builder
(mainWindowCloseEventHanlder)
(mainWindowKeyPressEventHandler mvarGUI cmdData)
IF.setupToolButton builder
(toolBTdebugStartHandler mvarGUI cmdData)
(toolBTdebugStopHandler mvarGUI cmdData)
(toolBTstepOverHandler mvarGUI cmdData)
(toolBTstepInHandler mvarGUI cmdData)
(toolBTcontinueHandler mvarGUI cmdData)
(toolBTbuildHandler mvarGUI cmdData)
(toolBTdeleteHandler mvarGUI cmdData)
(toolBTsaveHandler mvarGUI cmdData)
(toolBTindentHandler mvarGUI)
(toolBTunIndentHandler mvarGUI)
(toolBTcommentHandler mvarGUI)
(toolBTunCommentHandler mvarGUI)
IF.setupFolderTree builder treeStore
(folderTreeDoubleClickedHandler mvarGUI cmdData)
(folderTreePopupHandler mvarGUI)
(folderTreeCreateFolderAction mvarGUI)
(folderTreeCreateFileAction mvarGUI cmdData)
(folderTreeRenameAction mvarGUI)
(folderTreeDeleteAction mvarGUI)
(folderTreeSearchAction mvarGUI)
(folderTreeReplaceAction mvarGUI cmdData)
(folderTreeKeyPressEventHandler mvarGUI cmdData)
(folderTreeStartupAction mvarGUI cmdData)
IF.setupConsoleView builder
(consoleDoubleClickedHandler mvarGUI cmdData)
IF.setupBreakPointTable builder breakStore
(breakPointTableDoubleClickedHandler mvarGUI cmdData)
IF.setupBindingTable builder bindingStore
(bindingTableDoubleClickedHandler mvarGUI cmdData)
IF.setupTraceTable builder traceStore
(traceTableDoubleClickedHandler mvarGUI cmdData)
IF.setupSearchResultTable builder searchResultStore
(searchResultTableDoubleClickedHandler mvarGUI cmdData)
-- 開始
IF.start builder
-- |=====================================================================
-- MainWindowのイベントハンドラ
--
-- |
--
--
mainWindowCloseEventHanlder :: IF.MainWindowCloseEventHandler
mainWindowCloseEventHanlder = infoM _LOG_NAME "See you again."
-- |
--
--
mainWindowKeyPressEventHandler :: MVar MVarGUIData -> DebugCommandData -> IF.MainWindowKeyPressEventHandler
mainWindowKeyPressEventHandler mvarGUI cmdDat "F5" isShift _ = do
guiData <- readMVar mvarGUI
let builder = widgetStoreMVarGUIData guiData
isStart <- IF.isDebugStart builder
withStart isStart isShift
return True
where
withStart True True = toolBTdebugStopHandler mvarGUI cmdDat
withStart True False = toolBTcontinueHandler mvarGUI cmdDat
withStart False False = toolBTdebugStartHandler mvarGUI cmdDat
withStart _ _ = return ()
mainWindowKeyPressEventHandler mvarGUI cmdDat "F7" True _ = do
guiData <- readMVar mvarGUI
let builder = widgetStoreMVarGUIData guiData
isStart <- IF.isBuildStart builder
when (False == isStart) $ do
runClean
toolBTbuildHandler mvarGUI cmdDat
return True
where
runClean = do
guiData <- readMVar mvarGUI
let builder = widgetStoreMVarGUIData guiData
cleanCmd = cleanStartDebugCommandData cmdDat
readLine = readLinesDebugCommandData cmdDat
exitCmd = stopDebugCommandData cmdDat
IF.clearConsole builder
IF.putStrConsole builder $ "start stack clean.\n"
cleanCmd
readLine $ cleanResultHandler mvarGUI
code <- exitCmd
IF.putStrLnConsole builder $ show code
cleanResultHandler :: MVar MVarGUIData -> [String] -> IO Bool
cleanResultHandler _ [] = return False
cleanResultHandler mvarGUI strs = do
guiData <- takeMVar mvarGUI
let builder = widgetStoreMVarGUIData guiData
IF.putStrLnConsole builder $ last strs
return True
mainWindowKeyPressEventHandler mvarGUI cmdDat "F7" _ _ = do
guiData <- readMVar mvarGUI
let builder = widgetStoreMVarGUIData guiData
isStart <- IF.isBuildStart builder
when (False == isStart) $ do
IF.clearConsole builder
toolBTbuildHandler mvarGUI cmdDat
return True
mainWindowKeyPressEventHandler mvarGUI cmdDat "F10" _ _ = do
guiData <- takeMVar mvarGUI
let builder = widgetStoreMVarGUIData guiData
isStart <- IF.isDebugStart builder
putMVar mvarGUI guiData
if isStart then toolBTstepOverHandler mvarGUI cmdDat
else return ()
return True
mainWindowKeyPressEventHandler mvarGUI cmdDat "F11" _ _ = do
guiData <- takeMVar mvarGUI
let builder = widgetStoreMVarGUIData guiData
isStart <- IF.isDebugStart builder
putMVar mvarGUI guiData
if isStart then toolBTstepInHandler mvarGUI cmdDat
else return ()
return True
mainWindowKeyPressEventHandler mvarGUI cmdDat "s" _ True = do
saveAll mvarGUI cmdDat -- Ctr+s
return True
mainWindowKeyPressEventHandler mvarGUI cmdDat "f" _ True = findCurrentTextEditor mvarGUI >>= \case
Nothing -> errorM _LOG_NAME "[mainWindowKeyPressEventHandler] invalid text editor." >> return True
Just a -> withEditor a
where
withEditor (nodeData, editor) = do
guiData <- readMVar mvarGUI
let builder = widgetStoreMVarGUIData guiData
defaultStr <- IF.getSelectedText editor
IF.getSearchKeyBySearchDialog builder defaultStr >>= \case
Nothing -> return True
Just key -> do
clearSearchResultTable mvarGUI
activateSearchResultTab mvarGUI
setSearchFiles mvarGUI [nodeData]
keywordLineSearch [nodeData] key (searchResultHandler mvarGUI)
(lineNo, _) <- IF.getCodeTextLineNumber editor
activateTextEditorWithSearchResult mvarGUI cmdDat $ Just (IF.getPathFromNodeData nodeData, lineNo+1)
return True
mainWindowKeyPressEventHandler mvarGUI cmdDat "r" _ True =findCurrentTextEditor mvarGUI >>= \case
Nothing -> errorM _LOG_NAME "[mainWindowKeyPressEventHandler] invalid text editor." >> return True
Just a -> withEditor a
where
withEditor (nodeData, editor) = do
guiData <- readMVar mvarGUI
let builder = widgetStoreMVarGUIData guiData
nodeDatas = [nodeData]
IF.getReplaceByReplaceDialog builder >>= \case
Nothing -> return True
Just (key, rep) -> do
saveAll mvarGUI cmdDat
replaceFiles nodeDatas key rep
reloadAll mvarGUI
-- search
clearSearchResultTable mvarGUI
activateSearchResultTab mvarGUI
setSearchFiles mvarGUI nodeDatas
keywordLineSearch nodeDatas rep (searchResultHandler mvarGUI)
(lineNo, _) <- IF.getCodeTextLineNumber editor
activateTextEditorWithSearchResult mvarGUI cmdDat $ Just (IF.getPathFromNodeData nodeData, lineNo+1)
return True
mainWindowKeyPressEventHandler mvarGUI cmdDat "F3" False _ = do
activateTextEditorWithSearchResult mvarGUI cmdDat Nothing
return True
mainWindowKeyPressEventHandler _ _ _ _ _ = return False
-- |=====================================================================
-- ToolButtonのイベントハンドラ
--
-- |
-- Event Handler
--
toolBTdebugStartHandler :: MVar MVarGUIData -> DebugCommandData -> IF.DebugStartBTClickedEventHandler
toolBTdebugStartHandler mvarGUI cmdData = do
runGHCi >>= \case
False -> do
warningM _LOG_NAME "run ghci fail."
True -> loadHsFile >>= \case
False -> do
warningM _LOG_NAME "run ghci fail."
True -> setupDebug >> startDebug
where
runGHCi = do
guiData <- readMVar mvarGUI
let builder = widgetStoreMVarGUIData guiData
startCmd = startDebugCommandData cmdData
readLines = readLinesDebugCommandData cmdData
readWhile = readWhileDebugCommandData cmdData
IF.clearConsole builder
IF.putStrConsole builder $ "start stack ghci.\n"
startCmd
cont <- readLines (debugStartResultHandler builder)
if | null cont -> return False
| startswith "Ok," (last cont) -> do
res <- readWhile $ not . endswith "> "
IF.putStrConsole builder res
return True
| otherwise -> return False
loadHsFile = do
guiData <- readMVar mvarGUI
loadHsFileMay $ startupNodeDataMVarGUIData guiData
loadHsFileMay Nothing = return True
loadHsFileMay (Just nodeDat) = do
guiData <- readMVar mvarGUI
let builder = widgetStoreMVarGUIData guiData
loadFile = loadFileDebugCommandData cmdData
readLines = readLinesDebugCommandData cmdData
readWhile = readWhileDebugCommandData cmdData
cmdStr <- loadFile $ IF.getPathFromNodeData nodeDat
IF.putStrLnConsole builder cmdStr
cont <- readLines (debugStartResultHandler builder)
if | null cont -> return False
| startswith "Ok," (last cont) -> do
res <- readWhile $ not . endswith "> "
IF.putStrConsole builder res
return True
| otherwise -> return False
setupDebug = do
guiData <- readMVar mvarGUI
let builder = widgetStoreMVarGUIData guiData
breakStore = breakPointListMVarGUIData guiData
setPrompt = promptDebugCommandData cmdData
getResult = readDebugCommandData cmdData
printEvld = printEvldDebugCommandData cmdData
promptStr <- setPrompt
IF.putStrLnConsole builder promptStr
cmdStr <- getResult
IF.putStrConsole builder cmdStr
cmdStr <- printEvld
IF.putStrLnConsole builder cmdStr
cmdStr <- getResult
IF.putStrConsole builder cmdStr
IF.setupDebugButtonOn builder
breakList <- IF.getBreakPointList breakStore
mapM_ (addBreakPointOnCUI mvarGUI cmdData) breakList
startDebug = do
guiData <- readMVar mvarGUI
let builder = widgetStoreMVarGUIData guiData
getResult = readDebugCommandData cmdData
runDebug = runDebugCommandData cmdData
cmdStr <- runDebug True
IF.putStrLnConsole builder cmdStr
cmdStr <- getResult
IF.putStrConsole builder cmdStr
let breakPos = getStoppedTextRangeData cmdStr
continueWithHighlightTextRangeData mvarGUI cmdData breakPos
-- |
--
--
debugStartResultHandler :: IF.WidgetStore -> [String] -> IO Bool
debugStartResultHandler builder acc = IF.putStrLnConsole builder curStr >> if
| L.isPrefixOf "Ok," curStr -> return False
| L.isPrefixOf "Failed," curStr -> return False
| otherwise -> return True
where
curStr | null acc = ""
| otherwise = last acc
-- |
-- Event Handler
--
toolBTdebugStopHandler :: MVar MVarGUIData -> DebugCommandData -> IF.DebugStopBTClickedEventHandler
toolBTdebugStopHandler mvarGUI cmdData = do
guiData <- takeMVar mvarGUI
let builder = widgetStoreMVarGUIData guiData
codeNoteMap = codeNoteMapMVarGUIData guiData
exitCmd = stopDebugCommandData cmdData
quitCmd = quitDebugCommandData cmdData
-- readLines = readLinesDebugCommandData cmdData
readWhile = readWhileDebugCommandData cmdData
putMVar mvarGUI guiData
cmdStr <- quitCmd
IF.putStrLnConsole builder cmdStr
str <- readWhile $ const True
IF.putStrConsole builder str
IF.putStrLnConsole builder ""
code <- exitCmd
IF.putStrLnConsole builder $ show code
IF.setupDebugButtonOff builder
mapM_ IF.offLightBreakPoint $ Map.elems codeNoteMap
return ()
-- |
-- Event Handler
--
toolBTstepOverHandler :: MVar MVarGUIData -> DebugCommandData -> IF.StepOverBTClickedEventHandler
toolBTstepOverHandler mvarGUI cmdData = do
guiData <- readMVar mvarGUI
let builder = widgetStoreMVarGUIData guiData
bindStore = bindingListStoreMVarGUIData guiData
stepOver = stepOverDebugCommandData cmdData
getResult = readDebugCommandData cmdData
bindings = bindingsDebugCommandData cmdData
cmdStr <- stepOver
IF.putStrLnConsole builder cmdStr
cmdStr <- getResult
IF.putStrConsole builder cmdStr
let breakPos = getStoppedTextRangeData cmdStr
_ <- bindings
bindStr <- getResult
case getBindingDataList bindStr of
Left err -> warningM _LOG_NAME $ show err
Right dats -> IF.updateBindingTable bindStore dats
case breakPos of
Left err -> warningM _LOG_NAME $ show err
Right pos -> activateTextEditor mvarGUI cmdData pos
return ()
-- |
-- Event Handler
--
toolBTstepInHandler :: MVar MVarGUIData -> DebugCommandData -> IF.StepInBTClickedEventHandler
toolBTstepInHandler mvarGUI cmdData = do
guiData <- takeMVar mvarGUI
let builder = widgetStoreMVarGUIData guiData
bindStore = bindingListStoreMVarGUIData guiData
step = stepDebugCommandData cmdData
getResult = readDebugCommandData cmdData
bindings = bindingsDebugCommandData cmdData
putMVar mvarGUI guiData
cmdStr <- step
IF.putStrLnConsole builder cmdStr
cmdStr <- getResult
IF.putStrConsole builder cmdStr
let breakPos = getStoppedTextRangeData cmdStr
_ <- bindings
bindStr <- getResult
case getBindingDataList bindStr of
Left err -> warningM _LOG_NAME $ show err
Right dats -> IF.updateBindingTable bindStore dats
case breakPos of
Left err -> warningM _LOG_NAME $ show err
Right pos -> activateTextEditor mvarGUI cmdData pos
return ()
-- |
-- Event Handler
--
toolBTcontinueHandler :: MVar MVarGUIData -> DebugCommandData -> IF.StepInBTClickedEventHandler
toolBTcontinueHandler mvarGUI cmdData = do
guiData <- takeMVar mvarGUI
let builder = widgetStoreMVarGUIData guiData
continue = continueDebugCommandData cmdData
getResult = readDebugCommandData cmdData
putMVar mvarGUI guiData
cmdStr <- continue True
IF.putStrLnConsole builder cmdStr
cmdStr <- getResult
IF.putStrConsole builder cmdStr
let breakPos = getStoppedTextRangeData cmdStr
continueWithHighlightTextRangeData mvarGUI cmdData breakPos
-- |
-- Event Handler
--
toolBTbuildHandler :: MVar MVarGUIData -> DebugCommandData -> IF.BuildBTClickedEventHandler
toolBTbuildHandler mvarGUI cmdData = do
saveAll mvarGUI cmdData
_ <- forkIO $ do
hid <- IF.addCallback $ buildCallbackHandler mvarGUI True
guiData <- takeMVar mvarGUI
let builder = widgetStoreMVarGUIData guiData
buildStart = buildStartDebugCommandData cmdData
readLine = readLinesDebugCommandData cmdData
exitCmd = stopDebugCommandData cmdData
putMVar mvarGUI guiData{buildMsgMVarGUIData = []}
IF.setupBuildButtonOff builder
--IF.clearConsole builder
appendBuildMsg mvarGUI "start stack build.\n"
buildStart
readLine (buildStartResultHandler mvarGUI)
IF.delCallback hid
code <- exitCmd
appendBuildMsg mvarGUI $ "\n" ++ show code ++ "\n"
_ <- IF.addCallback $ buildCallbackHandler mvarGUI False
IF.setupBuildButtonOn builder
return ()
where
-- |
-- Event Handler
--
buildCallbackHandler :: MVar MVarGUIData -> Bool -> IO Bool
buildCallbackHandler mvarGUI doNotDelHandle = do
guiData <- takeMVar mvarGUI
let builder = widgetStoreMVarGUIData guiData
curMsg = buildMsgMVarGUIData guiData
putMVar mvarGUI guiData{ buildMsgMVarGUIData = [] }
mapM_ (IF.putStrConsole builder) curMsg
return doNotDelHandle
-- |
--
--
buildStartResultHandler :: MVar MVarGUIData -> [String] -> IO Bool
buildStartResultHandler _ [] = return False
buildStartResultHandler mvarGUI strs = do
appendBuildMsg mvarGUI $ last strs
return True
-- |
--
--
appendBuildMsg :: MVar MVarGUIData -> String -> IO ()
appendBuildMsg mvarGUI msg = do
guiData <- takeMVar mvarGUI
let curMsg = buildMsgMVarGUIData guiData
putMVar mvarGUI guiData{ buildMsgMVarGUIData = curMsg ++ [msg] }
-- |
-- Event Handler
--
toolBTdeleteHandler :: MVar MVarGUIData -> DebugCommandData -> IF.DeleteAllBreakBTClickedEventHandler
toolBTdeleteHandler mvarGUI cmdData = do
guiData <- takeMVar mvarGUI
let bpList = breakPointListMVarGUIData guiData
noteMap = codeNoteMapMVarGUIData guiData
mapM_ IF.offLightBreakPoint $ Map.elems noteMap
putMVar mvarGUI guiData
IF.getBreakPointList bpList >>= mapM_ go
where
go (IF.BreakPointData _ path lineNo _ _) = do
let bpKey = (path, lineNo)
deleteBreakPointOnCUI mvarGUI cmdData bpKey
deleteBreakPointOnBPTable mvarGUI bpKey
deleteBreakPointTag mvarGUI bpKey
-- |
-- Event Handler
--
toolBTsaveHandler :: MVar MVarGUIData -> DebugCommandData -> IF.SaveBTClickedEventHandler
toolBTsaveHandler = saveAll
-- |
-- Event Handler
--
toolBTindentHandler :: MVar MVarGUIData -> IF.IndentBTClickedEventHandler
toolBTindentHandler mvarGUI = findCurrentTextEditor mvarGUI >>= \case
Nothing -> return()
Just (_, editor) -> IF.blockIndentTextEditor editor
-- |
-- Event Handler
--
toolBTunIndentHandler :: MVar MVarGUIData -> IF.UnIndentBTClickedEventHandler
toolBTunIndentHandler mvarGUI = findCurrentTextEditor mvarGUI >>= \case
Nothing -> return()
Just (_, editor) -> IF.blockUnIndentTextEditor editor
-- |
-- Event Handler
--
toolBTcommentHandler :: MVar MVarGUIData -> IF.CommentBTClickedEventHandler
toolBTcommentHandler mvarGUI = findCurrentTextEditor mvarGUI >>= \case
Nothing -> return()
Just (_, editor) -> IF.blockCommentTextEditor editor
-- |
-- Event Handler
--
toolBTunCommentHandler :: MVar MVarGUIData -> IF.UnCommentBTClickedEventHandler
toolBTunCommentHandler mvarGUI = findCurrentTextEditor mvarGUI >>= \case
Nothing -> return()
Just (_, editor) -> IF.blockUnCommentTextEditor editor
-- |
--
--
continueWithHighlightTextRangeData :: MVar MVarGUIData -> DebugCommandData -> Either ParseError HighlightTextRangeData -> IO ()
continueWithHighlightTextRangeData mvarGUI cmdData (Left err) = do
warningM _LOG_NAME $ "[continueWithHighlightTextRangeData]" ++ show err
updateBindingTable mvarGUI cmdData
updateTraceTable mvarGUI cmdData
continueWithHighlightTextRangeData mvarGUI cmdData (Right pos) = do
guiData <- takeMVar mvarGUI
let breakStore = breakPointListMVarGUIData guiData
condCmd <- IF.getBreakCondition breakStore $ getKeyOfHighlightTextRangeData pos
putMVar mvarGUI guiData
continueWithCondCmd mvarGUI cmdData pos condCmd
where
continueWithCondCmd mvarGUI cmdData pos condCmd
| null condCmd = continueWithCondResult mvarGUI cmdData pos True
| otherwise = do
guiData <- takeMVar mvarGUI
let builder = widgetStoreMVarGUIData guiData
condition = execCommandData cmdData
getResult = readDebugCommandData cmdData
putMVar mvarGUI guiData
_ <- condition condCmd
IF.putStrLnConsole builder condCmd
cmdStr <- getResult
IF.putStrConsole builder cmdStr
condRes <- getConditionResult cmdStr
continueWithCondResult mvarGUI cmdData pos condRes
continueWithCondResult mvarGUI cmdData _ False = toolBTcontinueHandler mvarGUI cmdData
continueWithCondResult mvarGUI cmdData pos True = do
updateBindingTable mvarGUI cmdData
updateTraceTable mvarGUI cmdData
activateTextEditor mvarGUI cmdData pos
getConditionResult res
| L.isPrefixOf "True" res = return True
| L.isPrefixOf "False" res = return False
| otherwise = warningM _LOG_NAME ("invalid condition result. " ++ res) >> return True
-- |
-- continueWithHighlightTextRangeDataで使用している
--
updateBindingTable :: MVar MVarGUIData -> DebugCommandData -> IO ()
updateBindingTable mvarGUI cmdData = do
guiData <- readMVar mvarGUI
let bindStore = bindingListStoreMVarGUIData guiData
bindings = bindingsDebugCommandData cmdData
getResult = readDebugCommandData cmdData
_ <- bindings
bindStr <- getResult
case getBindingDataList bindStr of
Left err -> errorM _LOG_NAME $ show err
Right dats -> IF.updateBindingTable bindStore dats
-- |
-- continueWithHighlightTextRangeDataで使用している
--
updateTraceTable :: MVar MVarGUIData -> DebugCommandData -> IO ()
updateTraceTable mvarGUI cmdData = do
guiData <- takeMVar mvarGUI
let traceStore = traceListStoreMVarGUIData guiData
getResult = readDebugCommandData cmdData
history = traceHistDebugCommandData cmdData
_ <- history
traceStr <- getResult
case getTraceDataList traceStr of
Left err -> errorM _LOG_NAME $ show err
Right dats -> IF.updateTraceTable traceStore dats
putMVar mvarGUI guiData {traceIdMVarGUIData = 0}
-- |=====================================================================
-- FolderTreeのイベントハンドラ
--
-- |
-- Event Handler
-- フォルダーツリーでファイルがダブルクリックされた場合に
-- コードノートを表示する。
--
folderTreeDoubleClickedHandler :: MVar MVarGUIData -> DebugCommandData -> IF.FolderTreeDoubleClickedHandler
folderTreeDoubleClickedHandler mvarGUI cmdDat = do
guiData <- readMVar mvarGUI
let builder = widgetStoreMVarGUIData guiData
treeStore = folderTreeMVarGUIData guiData
IF.getSelectedFolderTreeNodeData builder treeStore >>= withNodeData
where
withNodeData (Just (IF.FileNodeData _ _ path)) = do
editorMay <- findTextEditorByPath mvarGUI path
activateWithEditor mvarGUI cmdDat editorMay path 1
withNodeData _ = return ()
-- |
-- Event Handler
--
folderTreePopupHandler :: MVar MVarGUIData -> IF.FolderTreePopupHandler
folderTreePopupHandler mvarGUI = do
guiData <- takeMVar mvarGUI
let builder = widgetStoreMVarGUIData guiData
treeStore = folderTreeMVarGUIData guiData
nodeData <- IF.getSelectedFolderTreeNodeData builder treeStore
IF.folderTreeMenuPopup builder nodeData
putMVar mvarGUI guiData
-- |
-- Event Handler
--
folderTreeCreateFolderAction :: MVar MVarGUIData -> IF.FolderTreeCreateFolderAction
folderTreeCreateFolderAction mvarGUI = do
guiData <- takeMVar mvarGUI
let builder = widgetStoreMVarGUIData guiData
treeStore = folderTreeMVarGUIData guiData
nodeData <- IF.getSelectedFolderTreeNodeData builder treeStore
nameMay <- IF.getNameByFolderTreeDialog builder "Create Folder" "Input folder name." "" True
case getFolderTreeNodeData nodeData nameMay of
Nothing -> return () -- canceled.
Just (IF.FileNodeData _ _ _) -> return ()
Just child@(IF.FolderNodeData _ _ path) -> do
createDirectory path
IF.addNode2TreeStore treeStore (fromJust nodeData) child
putMVar mvarGUI guiData{folderTreeMVarGUIData = treeStore}
where
getFolderTreeNodeData :: Maybe IF.NodeData -> Maybe String -> Maybe IF.NodeData
getFolderTreeNodeData (Just (IF.FolderNodeData modName _ path)) (Just name) =
Just $ IF.FolderNodeData (getModName modName name) name (path > name)
getFolderTreeNodeData _ _ = Nothing
getModName :: String -> String -> String
getModName parent child
| null parent = child
| otherwise = parent ++ "." ++ child
-- |
-- Event Handler
--
folderTreeCreateFileAction :: MVar MVarGUIData -> DebugCommandData -> IF.FolderTreeCreateFileAction
folderTreeCreateFileAction mvarGUI cmdDat = do
guiData <- takeMVar mvarGUI
let builder = widgetStoreMVarGUIData guiData
treeStore = folderTreeMVarGUIData guiData
nodeData <- IF.getSelectedFolderTreeNodeData builder treeStore
nameMay <- IF.getNameByFolderTreeDialog builder "Create File" "Input file name." "" True
case getFileTreeNodeData nodeData nameMay of
Nothing -> putMVar mvarGUI guiData
Just (IF.FolderNodeData _ _ _) -> return ()
Just child@(IF.FileNodeData modName _ path) -> do
saveFileLBS path $ str2lbs $ code modName
IF.addNode2TreeStore treeStore (fromJust nodeData) child
putMVar mvarGUI guiData{folderTreeMVarGUIData = treeStore}
activateWithEditor mvarGUI cmdDat Nothing (IF.getPathFromNodeData child) 1
where
getFileTreeNodeData :: Maybe IF.NodeData -> Maybe String -> Maybe IF.NodeData
getFileTreeNodeData (Just (IF.FolderNodeData modName _ path)) (Just name) =
Just $ IF.FileNodeData (getModName modName (snd (normName name))) (fst (normName name)) (path > (fst (normName name)))
getFileTreeNodeData _ _ = Nothing
normName name
| L.isSuffixOf _HS_FILE_EXT name = (name, takeBaseName name)
| otherwise = (name++_HS_FILE_EXT, name)
getModName :: String -> String -> String
getModName parent child
| null parent = child
| otherwise = parent ++ "." ++ child
tpl = ["{-# LANGUAGE GADTs #-}"
,"{-# LANGUAGE LambdaCase #-}"
,"{-# LANGUAGE MultiWayIf #-}"
,"{-# LANGUAGE BinaryLiterals #-}"
,"{-# LANGUAGE TemplateHaskell #-}"
,"{-# LANGUAGE OverloadedStrings #-}"
,"{-# LANGUAGE ScopedTypeVariables #-}"
,"{-# LANGUAGE DeriveDataTypeable #-}"
,""
,"module $MODULE$ where"
,""
]
code modName =
TPL.toString
$ TPL.setManyAttrib [("MODULE", modName)]
$ TPL.newSTMP $ unlines tpl
-- |
-- Event Handler
--
folderTreeRenameAction :: MVar MVarGUIData -> IF.FolderTreeRenameAction
folderTreeRenameAction mvarGUI = do
guiData <- readMVar mvarGUI
let builder = widgetStoreMVarGUIData guiData
treeStore = folderTreeMVarGUIData guiData
_ <- IF.getSelectedFolderTreeNodeData builder treeStore
nameMay <- IF.getNameByFolderTreeDialog builder "Rename" "Input name." "" True
infoM _LOG_NAME $ "[folderTreeRenameAction] not yet implemented. " ++ show nameMay
-- |
-- Event Handler
--
folderTreeDeleteAction :: MVar MVarGUIData -> IF.FolderTreeDeleteAction
folderTreeDeleteAction mvarGUI = do
guiData <- readMVar mvarGUI
let builder = widgetStoreMVarGUIData guiData
treeStore = folderTreeMVarGUIData guiData
IF.getSelectedFolderTreeNodeData builder treeStore >>= \case
Nothing -> errorM _LOG_NAME $ "invalid node data."
Just nodeDat -> do
let name = IF.getNameFromNodeData nodeDat
nameMay <- IF.getNameByFolderTreeDialog builder "Delete" ("Delete " ++ name) name False
infoM _LOG_NAME $ "[folderTreeDeleteAction] not yet implemented. " ++ show nameMay
-- |
-- Event Handler
--
folderTreeSearchAction :: MVar MVarGUIData -> IF.FolderTreeSearchAction
folderTreeSearchAction mvarGUI = do
guiData <- readMVar mvarGUI
let builder = widgetStoreMVarGUIData guiData
treeStore = folderTreeMVarGUIData guiData
IF.getSelectedFolderTreeAllNodeData builder treeStore >>= withNodeDatas builder
where
withNodeDatas _ [] = errorM _LOG_NAME "invalid node data."
withNodeDatas builder nodeDatas = do
keyMay <- IF.getSearchKeyBySearchDialog builder ""
when (isJust keyMay) $ do
clearSearchResultTable mvarGUI
activateSearchResultTab mvarGUI
setSearchFiles mvarGUI nodeDatas
keywordLineSearch nodeDatas (fromJust keyMay) (searchResultHandler mvarGUI)
-- |
-- Event Handler
--
folderTreeReplaceAction :: MVar MVarGUIData -> DebugCommandData -> IF.FolderTreeReplaceAction
folderTreeReplaceAction mvarGUI cmdDat = do
guiData <- readMVar mvarGUI
let builder = widgetStoreMVarGUIData guiData
treeStore = folderTreeMVarGUIData guiData
IF.getSelectedFolderTreeAllNodeData builder treeStore >>= withNodeDatas builder
where
withNodeDatas _ [] = errorM _LOG_NAME "invalid node data."
withNodeDatas builder nodeDatas = do
IF.getReplaceByReplaceDialog builder >>= \case
Nothing -> return ()
Just (key, rep) -> do
saveAll mvarGUI cmdDat
replaceFiles nodeDatas key rep
reloadAll mvarGUI
-- search
clearSearchResultTable mvarGUI
activateSearchResultTab mvarGUI
setSearchFiles mvarGUI nodeDatas
keywordLineSearch nodeDatas rep (searchResultHandler mvarGUI)
-- |
-- イベントハンドラ
--
folderTreeKeyPressEventHandler :: MVar MVarGUIData -> DebugCommandData -> IF.FolderTreeKeyPressEventHandler
folderTreeKeyPressEventHandler mvarGUI _ "Right" _ _ = do
guiData <- takeMVar mvarGUI
let builder = widgetStoreMVarGUIData guiData
store = folderTreeMVarGUIData guiData
IF.expandFolderTree builder store
putMVar mvarGUI guiData
return True
folderTreeKeyPressEventHandler mvarGUI _ "Left" _ _ = do
guiData <- takeMVar mvarGUI
let builder = widgetStoreMVarGUIData guiData
store = folderTreeMVarGUIData guiData
IF.collapseFolderTree builder store
putMVar mvarGUI guiData
return True
folderTreeKeyPressEventHandler mvarGUI cmdDat "Return" _ _ = do
guiData <- takeMVar mvarGUI
let builder = widgetStoreMVarGUIData guiData
store = folderTreeMVarGUIData guiData
nodeMay <- IF.getSelectedFolderTreeNodeData builder store
putMVar mvarGUI guiData
case nodeMay of
Just (IF.FolderNodeData _ _ _) -> do
guiData <- takeMVar mvarGUI
let builder = widgetStoreMVarGUIData guiData
store = folderTreeMVarGUIData guiData
IF.expandCollapseFolderTree builder store
putMVar mvarGUI guiData
Just (IF.FileNodeData _ _ path) -> do
editorMay <- findTextEditorByPath mvarGUI path
activateWithEditor mvarGUI cmdDat editorMay path 1
Nothing -> errorM _LOG_NAME $ "invalid tree node"
return True
folderTreeKeyPressEventHandler _ _ _ _ _ = return False
-- |
-- Event Handler
--
folderTreeStartupAction :: MVar MVarGUIData -> DebugCommandData -> IF.FolderTreeStartupAction
folderTreeStartupAction mvarGUI _ = do
guiData <- readMVar mvarGUI
let builder = widgetStoreMVarGUIData guiData
store = folderTreeMVarGUIData guiData
curStartupDat = startupNodeDataMVarGUIData guiData
IF.getSelectedFolderTreeNodeData builder store >>= \case
Nothing -> errorM _LOG_NAME "[folderTreeStartupAction]invalid node data."
Just nodeDat -> do
when (isJust curStartupDat) $ IF.updateTreeNode store (fromJust curStartupDat) $ IF.changeNameColorOfNodeData (fromJust curStartupDat) _STARTUP_MODULE_COLOR_BLUE _STARTUP_MODULE_COLOR_BLACK
let newDat = IF.changeNameColorOfNodeData nodeDat _STARTUP_MODULE_COLOR_BLACK _STARTUP_MODULE_COLOR_BLUE
IF.updateTreeNode store nodeDat newDat
guiData <- takeMVar mvarGUI
putMVar mvarGUI guiData {startupNodeDataMVarGUIData = Just newDat}
-- |=====================================================================
-- ConsoleViewのイベントハンドラ
--
-- |
--
--
consoleDoubleClickedHandler :: MVar MVarGUIData -> DebugCommandData -> IF.ConsoleDoubleClickedHandler
consoleDoubleClickedHandler mvarGUI cmdData str = do
case getActivatePosFromLine str of
Nothing -> infoM _LOG_NAME $ "code highlight rage not found." ++ str
Just pos -> activateTextEditor mvarGUI cmdData pos
-- |=====================================================================
-- BreakPointTableのイベントハンドラ
--
-- |
--
--
breakPointTableDoubleClickedHandler :: MVar MVarGUIData -> DebugCommandData -> IF.BreakPointTableDoubleClickedHandler
breakPointTableDoubleClickedHandler mvarGUI cmdDat (IF.BreakPointData _ path lineNo _ _) = do
editorMay <- findTextEditorByPath mvarGUI path
activateWithEditor mvarGUI cmdDat editorMay path lineNo
-- |=====================================================================
-- BindingTableのイベントハンドラ
--
-- |
--
--
bindingTableDoubleClickedHandler :: MVar MVarGUIData -> DebugCommandData -> IF.BindingTableDoubleClickedHandler
bindingTableDoubleClickedHandler mvarGUI cmdData (IF.BindingData argName _ _) = do
guiData <- takeMVar mvarGUI
let builder = widgetStoreMVarGUIData guiData
bindStore = bindingListStoreMVarGUIData guiData
forceVar = forceDebugCommandData cmdData
bindings = bindingsDebugCommandData cmdData
getResult = readDebugCommandData cmdData
putMVar mvarGUI guiData
cmdStr <- forceVar argName
IF.putStrLnConsole builder cmdStr
cmdStr <- getResult
IF.putStrConsole builder cmdStr
_ <- bindings
bindStr <- getResult
case getBindingDataList bindStr of
Left err -> errorM _LOG_NAME $ show err
Right dats -> IF.updateBindingTable bindStore dats
-- |=====================================================================
-- TraceTableのイベントハンドラ
--
-- |
--
--
traceTableDoubleClickedHandler :: MVar MVarGUIData -> DebugCommandData -> IF.TraceTableDoubleClickedHandler
traceTableDoubleClickedHandler mvarGUI cmdData (IF.TraceData traceIdStr _ filePath) = do
guiData <- takeMVar mvarGUI
let builder = widgetStoreMVarGUIData guiData
bindings = bindingsDebugCommandData cmdData
curTraceId = traceIdMVarGUIData guiData
traceId = (read traceIdStr) :: Int
moveCount = curTraceId - traceId
getResult = readDebugCommandData cmdData
bindStore = bindingListStoreMVarGUIData guiData
traceCmd = if 0 > moveCount then traceForwardDebugCommandData cmdData
else traceBackDebugCommandData cmdData
putMVar mvarGUI guiData {traceIdMVarGUIData = traceId}
res <- foldM (go builder traceCmd getResult) (""::String) [1..(abs moveCount)]
let path = strip $ replace "Logged breakpoint at " "" $ head $ lines res
when (filePath /= path) $ warningM _LOG_NAME $ "move trace failed." ++ res
_ <- bindings
bindStr <- getResult
case getBindingDataList bindStr of
Left err -> errorM _LOG_NAME $ show err
Right dats -> IF.updateBindingTable bindStore dats
case getHighlightTextRangeData filePath of
Left err -> errorM _LOG_NAME $ show err
Right pos -> activateTextEditor mvarGUI cmdData pos
where
go builder traceCmd getResult _ _ = do
cmdStr <- traceCmd
IF.putStrLnConsole builder cmdStr
cmdStr <- getResult
IF.putStrConsole builder cmdStr
return cmdStr
-- |=====================================================================
-- SearchResultTableのイベントハンドラ
--
-- |
--
--
searchResultTableDoubleClickedHandler :: MVar MVarGUIData -> DebugCommandData -> IF.SearchResultTableDoubleClickedHandler
searchResultTableDoubleClickedHandler mvarGUI cmdData (IF.SearchResultData filePath lineNo startCol endCol _) = do
let pos = HighlightTextRangeData {
filePathHighlightTextRangeData = filePath
, startLineNoHighlightTextRangeData = lineNo
, startColNoHighlightTextRangeData = startCol
, endLineNoHighlightTextRangeData = lineNo
, endColNoHighlightTextRangeData = endCol
}
activateTextEditor mvarGUI cmdData pos
-- |=====================================================================
-- activateWithEditorで登録するイベントハンドラ
--
-- |
-- Event Handler
--
codeNoteCloseEventHanlder :: MVar MVarGUIData -> IF.CodeNoteCloseEventHandler
codeNoteCloseEventHanlder mvarGUI textEditor = do
guiData <- takeMVar mvarGUI
let noteMap = codeNoteMapMVarGUIData guiData
let delKeys = Map.foldWithKey (\k v acc -> if textEditor == v then k:acc else acc) [] noteMap
let newMap = foldr Map.delete noteMap delKeys
putMVar mvarGUI $ guiData {codeNoteMapMVarGUIData = newMap}
-- |
-- Event Handler
--
lineTextDoubleClickedHandler :: MVar MVarGUIData -> DebugCommandData -> IF.LineTextDoubleClickedHandler
lineTextDoubleClickedHandler mvarGUI cmdData False lineNo = findCurrentTextEditor mvarGUI >>= \case
Nothing -> errorM _LOG_NAME "[lineTextDoubleClickedHandler] invalid text editor."
Just a -> withEditor a
where
withEditor (nodeDat, editor) = do
IF.updateBreakPointTag editor False lineNo
let bpDat = IF.BreakPointData (IF.getModNameFromNodeData nodeDat) (IF.getPathFromNodeData nodeDat) (lineNo+1) Nothing ""
addBreakPointOnBPTable mvarGUI bpDat
addBreakPointOnCUI mvarGUI cmdData bpDat
lineTextDoubleClickedHandler mvarGUI cmdData True lineNo = findCurrentTextEditor mvarGUI >>= \case
Nothing -> errorM _LOG_NAME "[lineTextDoubleClickedHandler] invalid text editor."
Just a -> withEditor a
where
withEditor (nodeDat, editor) = do
IF.updateBreakPointTag editor True lineNo
let bpKey = (IF.getPathFromNodeData nodeDat, lineNo+1)
deleteBreakPointOnCUI mvarGUI cmdData bpKey
deleteBreakPointOnBPTable mvarGUI bpKey
-- |
--
--
codeTextKeyPressEventHandler :: MVar MVarGUIData -> DebugCommandData -> IF.CodeTextKeyPressEventHandler
codeTextKeyPressEventHandler mvarGUI cmdData "F9" False False True lineNo = findCurrentTextEditor mvarGUI >>= \case
Nothing -> errorM _LOG_NAME "[codeTextKeyPressEventHandler] invalid text editor" >> return True
Just a -> withEditor a
where
withEditor (nodeDat, editor) = do
IF.updateBreakPointTag editor True lineNo
let bpKey = (IF.getPathFromNodeData nodeDat, lineNo+1)
deleteBreakPointOnCUI mvarGUI cmdData bpKey
deleteBreakPointOnBPTable mvarGUI bpKey
return True
codeTextKeyPressEventHandler mvarGUI cmdData "F9" False False False lineNo = findCurrentTextEditor mvarGUI >>= \case
Nothing -> errorM _LOG_NAME "[codeTextKeyPressEventHandler] invalid text editor" >> return True
Just a -> withEditor a
where
withEditor (nodeDat, editor) = do
IF.updateBreakPointTag editor False lineNo
let bpDat = IF.BreakPointData (IF.getModNameFromNodeData nodeDat) (IF.getPathFromNodeData nodeDat) (lineNo+1) Nothing ""
addBreakPointOnBPTable mvarGUI bpDat
addBreakPointOnCUI mvarGUI cmdData bpDat
return True
codeTextKeyPressEventHandler mvarGUI _ "Right" False True _ _ = do
toolBTindentHandler mvarGUI
return True
codeTextKeyPressEventHandler mvarGUI _ "Left" False True _ _ = do
toolBTunIndentHandler mvarGUI
return True
codeTextKeyPressEventHandler _ _ "g" False True _ _ = do
infoM _LOG_NAME "ctrl g called. not yet implemented."
return True
codeTextKeyPressEventHandler mvarGUI cmdDat "z" False True _ _ = do
guiData <- takeMVar mvarGUI
let buf = undoBufferMVarGUIData guiData
itemMay <- case buf of
[] -> putMVar mvarGUI guiData >> return Nothing
x:xs -> do
putMVar mvarGUI guiData{ undoBufferMVarGUIData = xs
, redoBufferMVarGUIData = x:redoBufferMVarGUIData guiData
, unDoReDoFlagMVarGUIData = True}
return $ Just x
unDo mvarGUI cmdDat itemMay
guiData <- takeMVar mvarGUI
putMVar mvarGUI guiData{unDoReDoFlagMVarGUIData = False}
return True
where
unDo :: MVar MVarGUIData -> DebugCommandData -> Maybe UndoRedoData -> IO ()
unDo _ _ Nothing = return ()
unDo mvarGUI cmdDat (Just (DeleteRangeUndoRedoData path startLineNo startColNo _ _ str)) = do
editorMay <- findTextEditorByPath mvarGUI path
activateWithEditor mvarGUI cmdDat editorMay path startLineNo
findTextEditorByPath mvarGUI path >>= \case
Nothing -> errorM _LOG_NAME $ "invalie note."
Just editor -> do
IF.insertText2TextEditor editor startLineNo startColNo str
IF.setCursorOnTextEditor editor startLineNo startColNo
unDo mvarGUI cmdDat (Just (InsertTextUndoRedoData path startLineNo startColNo str)) = do
editorMay <- findTextEditorByPath mvarGUI path
activateWithEditor mvarGUI cmdDat editorMay path startLineNo
findTextEditorByPath mvarGUI path >>= \case
Nothing -> errorM _LOG_NAME $ "invalie note."
Just editor -> do
(endLineNo, endColNo) <- IF.searchEndIter editor startLineNo startColNo str
IF.deleteRangeOnTextEditor editor startLineNo startColNo endLineNo endColNo
IF.setCursorOnTextEditor editor startLineNo startColNo
codeTextKeyPressEventHandler mvarGUI cmdDat "y" False True _ _ = do
guiData <- takeMVar mvarGUI
let buf = redoBufferMVarGUIData guiData
itemMay <- case buf of
[] -> putMVar mvarGUI guiData >> return Nothing
x:xs -> do
putMVar mvarGUI guiData{ redoBufferMVarGUIData = xs
, unDoReDoFlagMVarGUIData = True}
return $ Just x
reDo mvarGUI cmdDat itemMay
guiData <- takeMVar mvarGUI
putMVar mvarGUI guiData{unDoReDoFlagMVarGUIData = False}
return True
where
reDo :: MVar MVarGUIData -> DebugCommandData -> Maybe UndoRedoData -> IO ()
reDo _ _ Nothing = return ()
reDo mvarGUI cmdDat (Just (DeleteRangeUndoRedoData path startLineNo startColNo _ _ str)) = do
editorMay <- findTextEditorByPath mvarGUI path
activateWithEditor mvarGUI cmdDat editorMay path startLineNo
findTextEditorByPath mvarGUI path >>= \case
Nothing -> errorM _LOG_NAME $ "[reDo]invalie note."
Just editor -> do
(endLineNo, endColNo) <- IF.searchEndIter editor startLineNo startColNo str
IF.deleteRangeOnTextEditor editor startLineNo startColNo endLineNo endColNo
IF.setCursorOnTextEditor editor startLineNo startColNo
return ()
reDo mvarGUI cmdDat (Just (InsertTextUndoRedoData path startLineNo startColNo str)) = do
editorMay <- findTextEditorByPath mvarGUI path
activateWithEditor mvarGUI cmdDat editorMay path startLineNo
findTextEditorByPath mvarGUI path >>= \case
Nothing -> errorM _LOG_NAME $ "[reDo] invalie note."
Just editor -> do
IF.insertText2TextEditor editor startLineNo startColNo str
(endLineNo, endColNo) <- IF.searchEndIter editor startLineNo startColNo str
IF.setCursorOnTextEditor editor endLineNo endColNo
return ()
codeTextKeyPressEventHandler _ _ _ _ _ _ _ = return False
-- |
-- イベントハンドラ
--
codeBufferChangedEventHandler :: MVar MVarGUIData -> IO ()
codeBufferChangedEventHandler _ = return ()
-- |
-- イベントハンドラ
--
codeBufferDeleteRangeEventHandler :: MVar MVarGUIData -> (Int, Int) -> (Int, Int) -> String -> IO ()
codeBufferDeleteRangeEventHandler mvarGUI (siLineNo, siColNo) (eiLineNo, eiColNo) str = findCurrentTextEditor mvarGUI >>= \case
Nothing -> errorM _LOG_NAME "[codeBufferDeleteRangeEventHandler] invalid text editor."
Just a -> withEditor a
where
withEditor (nodeDat, _) = do
guiData <- takeMVar mvarGUI
let unDoBuf = undoBufferMVarGUIData guiData
reDoBuf = redoBufferMVarGUIData guiData
doing = unDoReDoFlagMVarGUIData guiData
let delDat = DeleteRangeUndoRedoData {
filePathDeleteRangeUndoRedoData = IF.getPathFromNodeData nodeDat
, startLineNoDeleteRangeUndoRedoData = siLineNo
, startColNoDeleteRangeUndoRedoData = siColNo
, endLineNoDeleteRangeUndoRedoData = eiLineNo
, endColNoDeleteRangeUndoRedoData = eiColNo
, textDeleteRangeUndoRedoData = str
}
let newUndoBuf = if doing then unDoBuf
else pushWithLimit unDoBuf delDat _UNDO_BUFFER_MAX_SIZE
let newRedoBuf = if doing then reDoBuf else []
putMVar mvarGUI guiData{ undoBufferMVarGUIData = newUndoBuf
, redoBufferMVarGUIData = newRedoBuf}
-- |
-- イベントハンドラ
--
codeBufferInsertTextEventHandler :: MVar MVarGUIData -> (Int, Int) -> String -> IO ()
codeBufferInsertTextEventHandler mvarGUI (siLineNo, siColNo) str = findCurrentTextEditor mvarGUI >>= \case
Nothing -> errorM _LOG_NAME "[codeBufferInsertTextEventHandler] invalid text editor."
Just a -> withEditor a
where
withEditor (nodeDat, _) = do
guiData <- takeMVar mvarGUI
let unDoBuf = undoBufferMVarGUIData guiData
reDoBuf = redoBufferMVarGUIData guiData
doing = unDoReDoFlagMVarGUIData guiData
let insertDat = InsertTextUndoRedoData {
filePathInsertTextUndoRedoData = IF.getPathFromNodeData nodeDat
, startLineNoInsertTextUndoRedoData = siLineNo
, startColNoInsertTextUndoRedoData = siColNo
, textInsertTextUndoRedoData = str
}
let newUndoBuf = if doing then unDoBuf
else pushWithLimit unDoBuf insertDat _UNDO_BUFFER_MAX_SIZE
let newRedoBuf = if doing then reDoBuf else []
putMVar mvarGUI guiData{ undoBufferMVarGUIData = newUndoBuf
, redoBufferMVarGUIData = newRedoBuf}
-- |=====================================================================
-- Utility
-- パーサ
-- |
-- コンソールに表示される文字列において、コードハイライトが可能な位置を
-- 抽出するパーサ
--
getActivatePosFromLine :: String -> Maybe HighlightTextRangeData
getActivatePosFromLine res = go $ split " " res
where
go [] = Nothing
go (x:xs) = case parse parseHighlightTextRange "getActivatePosFromLine" x of
Left _ -> go xs
Right bp -> Just bp
-- |
--
--
getHighlightTextRangeData :: String -> Either ParseError HighlightTextRangeData
getHighlightTextRangeData = parse parseHighlightTextRange "getHighlightTextRangeData"
-- |
--
--
getStoppedTextRangeData :: String -> Either ParseError HighlightTextRangeData
getStoppedTextRangeData = parse parser "getStoppedTextRangeData"
where
parser = do
_ <- manyTill anyChar (string "Stopped at ")
parseHighlightTextRange
-- |
-- parser of
-- A) src\Phoityne\IO\Main.hs:31:11-14
-- B) src\Main.hs:(17,3)-(19,35)
-- C) src\Phoityne\IO\Main.hs:31:11
--
parseHighlightTextRange :: forall u. ParsecT String u Identity HighlightTextRangeData
parseHighlightTextRange = do
path <- manyTill anyChar (string (_HS_FILE_EXT ++ ":"))
(sl, sn, el, en) <- try parseA <|> try parseB <|> try parseC
return $ HighlightTextRangeData (path ++ _HS_FILE_EXT) sl sn el en
where
parseA = do
ln <- manyTill digit (char ':')
sn <- manyTill digit (char '-')
en <- try (manyTill digit endOfLine) <|> try (manyTill digit eof)
return ((read ln), (read sn), (read ln), (read en))
parseB = do
_ <- char '('
sl <- manyTill digit (char ',')
sn <- manyTill digit (char ')')
_ <- string "-("
el <- manyTill digit (char ',')
en <- manyTill digit (char ')')
return ((read sl), (read sn), (read el), (read en))
parseC = do
ln <- manyTill digit (char ':')
sn <- manyTill digit (char ':')
return ((read ln), (read sn), (read ln), (read sn))
-- |
-- バインディング値のパーサ
--
-- parser of
-- args :: Project.Argument.ArgData = _
-- _result :: IO Data.ConfigFile.Types.ConfigParser = _
--
getBindingDataList :: String -> Either ParseError [IF.BindingData]
getBindingDataList res = parse parser "getBindingDataList" res
where
parser = manyTill parser1 (string _PHOITYNE_GHCI_PROMPT)
parser1 = do
varName <- manyTill anyChar (string "::")
modName <- manyTill anyChar (try (string "="))
valStr <- manyTill anyChar lineSep <|> manyTill anyChar eof
return $ IF.BindingData (strip varName) (strip modName) valStr
lineSep = try $ endOfLine >> notFollowedBy space
-- |
-- トレース情報のパーサ
--
-- parser of
-- Phoityne>>= :history
-- -1 : config:confB (src\Project\Argument.hs:85:17-28)
-- -2 : config:confB (src\Project\Argument.hs:87:17-36)
-- src\Project\IO\Main.hs:(70,9)-(71,65)
--
getTraceDataList :: String -> Either ParseError [IF.TraceData]
getTraceDataList res = go [] $ reverse $ filter (L.isPrefixOf "-") $ lines res
where
go acc [] = Right acc
go acc (x:xs) = case parse parser "getTraceDataList" x of
Left err -> Left err
Right dat -> go (dat:acc) xs
parser = do
traceId <- manyTill anyChar (many1 space >> char ':' >> space)
funcName <- manyTill anyChar (space >> char '(')
filePath <- manyTill anyChar eof
return $ IF.TraceData (strip traceId) funcName (init (strip filePath))
-- |=====================================================================
-- Utility
-- 検索
--
-- |
-- 検索対象となったファイル群を共有データに保存する。
--
setSearchFiles :: MVar MVarGUIData -> [IF.NodeData] -> IO ()
setSearchFiles mvarGUI datas = do
let paths = foldr (\d acc->IF.getPathFromNodeData d : acc) [] datas
guiData <- takeMVar mvarGUI
putMVar mvarGUI guiData { searchFilesMVarGUIData = paths }
-- |
-- 検索結果の削除
--
clearSearchResultTable :: MVar MVarGUIData -> IO ()
clearSearchResultTable mvarGUI = do
guiData <- takeMVar mvarGUI
let store = searchResultListStoreMVarGUIData guiData
IF.clearSearchResultTable store
putMVar mvarGUI guiData{searchResultListStoreMVarGUIData = store}
-- |
-- 検索結果テーブルにフォーカスをあてる。
--
activateSearchResultTab :: MVar MVarGUIData -> IO ()
activateSearchResultTab mvarGUI = do
guiData <- readMVar mvarGUI
let builder = widgetStoreMVarGUIData guiData
IF.activateSearchResultTab builder
-- |
-- 複数ファイルにおいて、行単位のキーワード検索を行う
--
keywordLineSearch :: [IF.NodeData] -> String -> (FilePath -> Int -> Int -> Int -> String -> IO ()) -> IO ()
keywordLineSearch [] _ _ = return ()
keywordLineSearch ((IF.FolderNodeData _ _ _):xs) key hdl = keywordLineSearch xs key hdl
keywordLineSearch ((IF.FileNodeData _ _ path):xs) key hdl = searchFile path key hdl >> keywordLineSearch xs key hdl
where
-- |
--
--
searchFile :: FilePath -> String -> (FilePath -> Int -> Int -> Int -> String -> IO ()) -> IO ()
searchFile path key hdl = do
bs <- loadFile path
searchLine (TE.pack key) (hdl path) 1 $ TE.lines $ TE.decodeUtf8 bs
-- |
--
--
searchLine :: TE.Text -> (Int -> Int -> Int -> String -> IO ()) -> Int -> [TE.Text] -> IO ()
searchLine _ _ _ [] = return ()
searchLine key hdl lineNo (line:lines) = do
mapM_ go $ TE.breakOnAll key line
searchLine key hdl (lineNo+1) lines
where
go (prior, _) = hdl lineNo (colIdx prior) (colIdx prior + TE.length key - 1) (TE.unpack line)
colIdx txt = (TE.length txt) + 1
-- |
-- 検索中にヒットした情報をストアに保存するハンドラ
--
searchResultHandler :: MVar MVarGUIData -> FilePath -> Int -> Int -> Int -> String -> IO ()
searchResultHandler mvarGUI filePath lineNo startColNo endColNo line = do
guiData <- takeMVar mvarGUI
let store = searchResultListStoreMVarGUIData guiData
IF.addSearchReslutTable store $ IF.SearchResultData filePath lineNo startColNo endColNo (strip line)
putMVar mvarGUI guiData{searchResultListStoreMVarGUIData = store}
-- |
-- 行単位の置換を行う
--
replaceFiles :: [IF.NodeData] -> String -> String -> IO ()
replaceFiles [] _ _ = return ()
replaceFiles ((IF.FolderNodeData _ _ _):xs) key rep = replaceFiles xs key rep
replaceFiles ((IF.FileNodeData _ _ path):xs) key rep = replaceFile path key rep >> replaceFiles xs key rep
where
replaceFile :: FilePath -> String -> String -> IO ()
replaceFile path key rep = do
bs <- loadFile path
let res = TE.replace (TE.pack key) (TE.pack rep) $ TE.decodeUtf8 bs
saveFile path $ TE.encodeUtf8 res
-- |=====================================================================
-- Utility
-- デバッグ
--
-- |
-- ブレークポイントテーブルからブレークポイントを削除する
--
deleteBreakPointOnBPTable :: MVar MVarGUIData -> IF.BreakPointDataKey -> IO ()
deleteBreakPointOnBPTable mvarGUI bpKey = do
guiData <- readMVar mvarGUI
let bpList = breakPointListMVarGUIData guiData
IF.deleteFromBreakPointListStore bpList bpKey
-- |
-- ブレークポイントをGHCi上でdeleteする
--
deleteBreakPointOnCUI :: MVar MVarGUIData -> DebugCommandData -> IF.BreakPointDataKey -> IO ()
deleteBreakPointOnCUI mvarGUI cmdData bpKey@(path, lineNo) = do
guiData <- readMVar mvarGUI
let builder = widgetStoreMVarGUIData guiData
isDebug <- IF.isDebugStart builder
when isDebug deleteBreakPointOnCUIInternal
where
deleteBreakPointOnCUIInternal = do
guiData <- readMVar mvarGUI
let bpList = breakPointListMVarGUIData guiData
IF.findBreakPointData bpList bpKey >>= deleteBreakPointByBPData
deleteBreakPointByBPData (Just (IF.BreakPointData _ _ _ (Just breakNo) _)) = do
guiData <- readMVar mvarGUI
let builder = widgetStoreMVarGUIData guiData
deleteBreak = deleteBreakDebugCommandData cmdData
getResult = readDebugCommandData cmdData
cmdStr <- deleteBreak breakNo
IF.putStrLnConsole builder cmdStr
cmdStr <- getResult
IF.putStrConsole builder cmdStr
deleteBreakPointByBPData _ = errorM _LOG_NAME $ "invalid delete break point." ++ path ++ ":" ++ show lineNo
-- |
-- ブレークポイントテーブルにブレークポイントを追加する
--
addBreakPointOnBPTable :: MVar MVarGUIData -> IF.BreakPointData -> IO ()
addBreakPointOnBPTable mvarGUI bpDat = do
guiData <- readMVar mvarGUI
let bpList = breakPointListMVarGUIData guiData
IF.addBreakPoint2Table bpList bpDat
-- |
-- GHCi上でブレークポイントを追加する
--
addBreakPointOnCUI :: MVar MVarGUIData -> DebugCommandData -> IF.BreakPointData -> IO ()
addBreakPointOnCUI mvarGUI cmdData breakData@(IF.BreakPointData modName path lineNo _ _) = do
guiData <- readMVar mvarGUI
let builder = widgetStoreMVarGUIData guiData
IF.isDebugStart builder >>= \case
False -> return ()
True -> addBreakPointInternl
where
addBreakPointInternl = do
guiData <- readMVar mvarGUI
let builder = widgetStoreMVarGUIData guiData
setBreak = breakDebugCommandData cmdData
getResult = readDebugCommandData cmdData
cmdStr <- setBreak modName lineNo
IF.putStrLnConsole builder cmdStr
cmdStr <- getResult
IF.putStrConsole builder cmdStr
case getBreakPointNo cmdStr of
Left err -> if L.isPrefixOf _NO_BREAK_POINT_LOCATION cmdStr then deleteBreakPoint
else errorM _LOG_NAME $ "unexpected break set result. " ++ show err ++ cmdStr
Right no -> updateBreakPointNo no
deleteBreakPoint = do
guiData <- readMVar mvarGUI
let breakStore = breakPointListMVarGUIData guiData
codeNoteMap = codeNoteMapMVarGUIData guiData
treeStore = folderTreeMVarGUIData guiData
nodeMay <- IF.findTreeNode treeStore
(\node -> L.isSuffixOf path (IF.getPathFromNodeData node))
case nodeMay of
Nothing -> errorM _LOG_NAME $ "node data not found." ++ show breakData
Just node -> do
IF.deleteFromBreakPointListStore breakStore (path, lineNo)
case Map.lookup node codeNoteMap of
Nothing -> return ()
Just editor -> IF.deleteBreakPointTag editor (IF.lineNoBreakPointData breakData)
updateBreakPointNo no = do
guiData <- readMVar mvarGUI
let bpList = breakPointListMVarGUIData guiData
key = (path, lineNo)
IF.updateBreakPointTable bpList key breakData{ IF.breakNoBreakPointData = Just no }
-- |
-- parser of
-- Breakpoint 0 activated at src\Main.hs:(21,3)-(23,35)
--
getBreakPointNo :: String -> Either ParseError Int
getBreakPointNo res = parse parser "getBreakPointNo" res
where
parser = do
_ <- manyTill anyChar (string "Breakpoint ")
no <- manyTill digit (string " activated at")
return $ read no
-- |
--
--
deleteBreakPointTag :: MVar MVarGUIData -> IF.BreakPointDataKey -> IO ()
deleteBreakPointTag mvarGUI (path, lineNo) = findTextEditorByPath mvarGUI path >>= withEditor
where
withEditor Nothing = return ()
withEditor (Just (IF.TextEditorData lineView _ _ _)) = IF.deleteBreakPointTagAtLine lineView (lineNo - 1)
-- |=====================================================================
-- Utility
-- テキストエディッタ
--
-- |
--
--
activateTextEditor :: MVar MVarGUIData -> DebugCommandData -> HighlightTextRangeData -> IO ()
activateTextEditor mvarGUI cmdDat pos = do
let path = filePathHighlightTextRangeData pos
lineNo = startLineNoHighlightTextRangeData pos
editorMay <- findTextEditorByPath mvarGUI path
activateWithEditor mvarGUI cmdDat editorMay path lineNo
editorMay <- findTextEditorByPath mvarGUI path
highLightBreakPoint mvarGUI pos editorMay
guiData <- readMVar mvarGUI
let builder = widgetStoreMVarGUIData guiData
breakStore = breakPointListMVarGUIData guiData
IF.highLightBreakPointTableRow builder breakStore ((filePathHighlightTextRangeData pos), (startLineNoHighlightTextRangeData pos))
where
highLightBreakPoint _ _ Nothing = errorM _LOG_NAME $ "[highLightBreakPoint]invalid node map."
highLightBreakPoint mvarGUI pos (Just textEditor) = do
guiData <- readMVar mvarGUI
let codeNoteMap = codeNoteMapMVarGUIData guiData
mapM_ IF.offLightBreakPoint $ Map.elems codeNoteMap
IF.highLightBreakPoint textEditor
(startLineNoHighlightTextRangeData pos)
(startColNoHighlightTextRangeData pos)
(endLineNoHighlightTextRangeData pos)
(endColNoHighlightTextRangeData pos)
-- |
--
--
activateWithEditor :: MVar MVarGUIData -> DebugCommandData -> Maybe IF.TextEditorData -> FilePath -> Int -> IO ()
activateWithEditor mvarGUI _ (Just editor) _ lineNo = do
guiData <- takeMVar mvarGUI
let builder = widgetStoreMVarGUIData guiData
putMVar mvarGUI guiData
IF.activateCodeNote builder editor lineNo
activateWithEditor mvarGUI cmdDat Nothing filePath lineNo = do
createCodeNode mvarGUI filePath lineNo
setupBreakPointTags mvarGUI filePath
where
setupBreakPointTags mvarGUI path = findTextEditorByPath mvarGUI path >>= \case
Nothing -> errorM _LOG_NAME $ "[setupBreakPointTags]invalid node map."
Just (IF.TextEditorData lineView _ _ _) -> do
guiData <- takeMVar mvarGUI
let listStore = breakPointListMVarGUIData guiData
breaks <- IF.getBreakPointList listStore
mapM_ (addBreakPointTag lineView) $ filter (\(IF.BreakPointData _ filePath _ _ _)->L.isSuffixOf path filePath) breaks
putMVar mvarGUI guiData
addBreakPointTag lineView (IF.BreakPointData _ _ lineNo _ _) =
IF.addBreakPointTagAtLine lineView (lineNo-1)
createCodeNode mvarGUI path lineNo = do
guiData <- takeMVar mvarGUI
let treeStore = folderTreeMVarGUIData guiData
nodeMay <- IF.findTreeNode treeStore (\node -> L.isSuffixOf path (IF.getPathFromNodeData node))
putMVar mvarGUI guiData
createCodeNodeWithNodeMay mvarGUI lineNo nodeMay
createCodeNodeWithNodeMay _ _ Nothing = errorM _LOG_NAME $ "[createCodeNodeWithNodeMay]unexpected error."
createCodeNodeWithNodeMay mvarGUI lineNo (Just node) = createCodeNodeWithNode mvarGUI lineNo node
createCodeNodeWithNode _ _ (IF.FolderNodeData _ _ _) = errorM _LOG_NAME $ "[createCodeNodeWithNode]unexpected error."
createCodeNodeWithNode mvarGUI lineNo node@(IF.FileNodeData _ _ path) = do
guiData <- takeMVar mvarGUI
let builder = widgetStoreMVarGUIData guiData
codeNoteMap = codeNoteMapMVarGUIData guiData
code <- loadFile path
wid <- IF.setupCodeNote builder (takeFileName path) path code
(codeNoteCloseEventHanlder mvarGUI)
(lineTextDoubleClickedHandler mvarGUI cmdDat)
(Just lineNo)
(codeTextKeyPressEventHandler mvarGUI cmdDat)
(codeBufferChangedEventHandler mvarGUI)
(codeBufferDeleteRangeEventHandler mvarGUI)
(codeBufferInsertTextEventHandler mvarGUI)
let newMap = Map.insert node wid codeNoteMap
putMVar mvarGUI $ guiData { codeNoteMapMVarGUIData = newMap}
IF.activateCodeNote builder wid lineNo
-- |
--
--
activateTextEditorWithSearchResult :: MVar MVarGUIData -> DebugCommandData -> Maybe IF.SearchResultOffset -> IO ()
activateTextEditorWithSearchResult mvarGUI cmdDat offset = findCurrentTextEditor mvarGUI >>= \case
Nothing -> errorM _LOG_NAME "[activateTextEditorWithSearchResult] invalid text editor"
Just a -> withEditor a
where
withEditor curEditor@(nodeDat, _) = do
guiData <- readMVar mvarGUI
let files = searchFilesMVarGUIData guiData
hasSearched curEditor $ L.elem (IF.getPathFromNodeData nodeDat) files
hasSearched _ True = do
guiData <- readMVar mvarGUI
let builder = widgetStoreMVarGUIData guiData
store = searchResultListStoreMVarGUIData guiData
IF.nextCurrentSearchResult builder store offset
activateTextEditorWithCurrentSearchResult mvarGUI cmdDat
hasSearched curEditor False = do
guiData <- readMVar mvarGUI
let builder = widgetStoreMVarGUIData guiData
key <- IF.getSearchKeyFromSearchDialog builder
isSearchKey curEditor key
isSearchKey (nodeData, editor) key
| null key = mainWindowKeyPressEventHandler mvarGUI cmdDat "f" False True >> return ()
| otherwise = do
clearSearchResultTable mvarGUI
activateSearchResultTab mvarGUI
setSearchFiles mvarGUI [nodeData]
keywordLineSearch [nodeData] key (searchResultHandler mvarGUI)
(lineNo, _) <- IF.getCodeTextLineNumber editor
activateTextEditorWithSearchResult mvarGUI cmdDat $ Just (IF.getPathFromNodeData nodeData, lineNo+1)
activateTextEditorWithCurrentSearchResult :: MVar MVarGUIData -> DebugCommandData -> IO ()
activateTextEditorWithCurrentSearchResult mvarGUI cmdData = do
guiData <- readMVar mvarGUI
let builder = widgetStoreMVarGUIData guiData
store = searchResultListStoreMVarGUIData guiData
IF.getCurrentSearchResult builder store >>= \case
Nothing -> return ()
Just (IF.SearchResultData filePath lineNo startCol endCol _) -> do
activateTextEditor mvarGUI cmdData $ HighlightTextRangeData filePath lineNo startCol lineNo endCol
-- |
--
--
findTextEditorByPath :: MVar MVarGUIData -> FilePath -> IO (Maybe IF.TextEditorData)
findTextEditorByPath mvarGUI path = do
guiData <- readMVar mvarGUI
let codeNoteMap = codeNoteMapMVarGUIData guiData
nodeMay = L.find (\node->L.isSuffixOf path (IF.getPathFromNodeData node)) $ Map.keys codeNoteMap
case nodeMay of
Just node -> return . Just $ codeNoteMap Map.! node
Nothing -> return Nothing
-- |
--
--
findCurrentTextEditor :: MVar MVarGUIData -> IO (Maybe (IF.NodeData, IF.TextEditorData))
findCurrentTextEditor mvarGUI = do
guiData <- readMVar mvarGUI
let builder = widgetStoreMVarGUIData guiData
noteMap = codeNoteMapMVarGUIData guiData
findCurrent builder $ Map.toList noteMap
where
findCurrent _ [] = return Nothing
findCurrent builder ((n, e):xs) = do
IF.isCurrentTextEditor builder e >>= \case
True -> return $ Just (n, e)
False -> findCurrent builder xs
-- |=====================================================================
-- Utility
--
--
-- |
-- すべての変更ファイルを保存する
--
saveAll :: MVar MVarGUIData -> DebugCommandData -> IO ()
saveAll mvarGUI _ = do
guiData <- readMVar mvarGUI
let noteMap = codeNoteMapMVarGUIData guiData
mapM_ go $ Map.toList noteMap
where
go (nodeDat, editor) = do
isModified <- IF.isTextEditorModified editor
when isModified $ do
content <- IF.getCodeViewContent editor
saveFile (IF.getPathFromNodeData nodeDat) content
IF.setTextEditorModified editor False
-- |
-- すべての開いているテキストエディッタのコンテンツを再読み込みする。
--
reloadAll :: MVar MVarGUIData -> IO ()
reloadAll mvarGUI = do
guiData <- readMVar mvarGUI
let noteMap = codeNoteMapMVarGUIData guiData
mapM_ go $ Map.toList noteMap
where
go (nodeDat, editor) = do
let path = IF.getPathFromNodeData nodeDat
bs <- loadFile path
(lineNo, colNo) <- IF.getCodeTextLineNumber editor
guiData <- takeMVar mvarGUI
putMVar mvarGUI guiData{unDoReDoFlagMVarGUIData = True}
IF.setContent2TextEditor editor bs
guiData <- takeMVar mvarGUI
putMVar mvarGUI guiData{unDoReDoFlagMVarGUIData = False}
IF.setCursorOnTextEditor editor lineNo colNo
-- |
-- フォルダツリー全体の読み込み
--
loadFolderForest :: String -> [FilePath] -> IO (T.Tree IF.NodeData)
loadFolderForest _ paths = do
topNodes <- foldM go [] $ reverse paths
return $ head topNodes
-- return $ T.Node (IF.FolderNodeData forestName forestName "") topNodes
where
go acc path = do
tree <- loadFolderTree "" path
return $ tree:acc
-- |
-- フォルダツリーの読み込み
--
loadFolderTree :: ModuleName -> FilePath -> IO (T.Tree IF.NodeData)
loadFolderTree modName path = doesDirectoryExist path >>= withDir
where
withDir False = do
errorM _LOG_NAME $ "invalid dirctory:" ++ path
return $ T.Node (IF.FolderNodeData modName ("invalid directory") path) []
withDir True = do
let dirName = takeFileName path
node = T.Node (IF.FolderNodeData modName (""++dirName++"") path) []
items <- getDirectoryContents path
foldM setFolderItem node $ normalizeList items
normalizeList :: [FilePath] -> [FilePath]
normalizeList fs = files ++ dirs
where
items = filter (\s->'.' /= head s) fs
dirs = filter (\s-> all ((/=) '.') s) items
files = filter (\s-> any ((==) '.') s) items
setFolderItem :: T.Tree IF.NodeData -> FilePath -> IO (T.Tree IF.NodeData)
setFolderItem node item = do
let fullPath = path > item
let baseName = takeBaseName item
let nzModName = getNzModName modName baseName -- if True == null modName then baseName else modName <.> baseName
isDir <- doesDirectoryExist fullPath
setFolderItem_ node nzModName fullPath isDir
getNzModName modName baseName
| null modName = getNzModNameWithNullModName baseName
| otherwise = modName <.> baseName
getNzModNameWithNullModName baseName
| null baseName = ""
| isUpper (head baseName) = baseName
| otherwise = ""
setFolderItem_ :: T.Tree IF.NodeData -> ModuleName -> FilePath -> Bool -> IO (T.Tree IF.NodeData)
setFolderItem_ node nzModName fullPath isDir
| True == isDir = do
child <- loadFolderTree nzModName fullPath
return $ addChildTree node child
| otherwise = do
let fileExt = takeExtension fullPath
setHsItem node nzModName fullPath fileExt
setHsItem :: T.Tree IF.NodeData -> ModuleName -> FilePath -> String -> IO (T.Tree IF.NodeData)
setHsItem node nzModName fullPath fileExt
| elem fileExt _AVAILABLE_FILE_EXT = do
let fileName = takeFileName fullPath
let child = T.Node (IF.FileNodeData nzModName (""++fileName++"") fullPath) []
return $ addChildTree node child
| otherwise = return node