content: {-# language
     OverloadedStrings
  #-}
  
  module Rasa.Ext.Files
    ( files
    , save
    ) where
  
  import qualified Data.Text.IO as TIO
  import System.Environment
  
  import Data.Typeable
  import Data.Default
  import Data.Maybe
  
  import Control.Monad
  import Control.Monad.Trans
  import qualified Yi.Rope as Y
  
  import Rasa.Ext
  import Rasa.Ext.Views
  import Rasa.Ext.Cmd
  
  -- | Stores filename
  data FileInfo =
    FileInfo (Maybe String)
    deriving (Typeable, Show, Eq)
  
  instance Default FileInfo where
    def = FileInfo Nothing
  
  type Filename = String
  
  -- | Stores File status; Clean means all changes are saved
  data FileStatus =
    Dirty
    | Clean
    deriving Show
  
  instance Default FileStatus where
    def = Clean
  
  -- | Returns 'FileStatus' of current buffer
  getFileStatus :: BufAction FileStatus
  getFileStatus = getBufExt
  
  -- | Sets 'FileStatus' of current buffer
  setFileStatus :: FileStatus -> BufAction ()
  setFileStatus = setBufExt
  
  -- | Gets filename of current buffer
  getFilename :: BufAction (Maybe Filename)
  getFilename = do
    FileInfo filename <- getBufExt
    return filename
  
  -- | Main export, use this in your Rasa config
  files :: App ()
  files = do
    onEveryNewBuffer_ $ do
      void . onBufTextChanged $ bufferChanged
      void . addTopStatus $ fileStatus
      void . addTopStatus $ (fmap Y.fromString <$> getFilename)
  
    afterInit $ do
      loadFiles
      addCmd "save" $ focusDo_ . saveAs
  
  -- | Renders the current file status
  fileStatus :: BufAction (Maybe RenderInfo)
  fileStatus = do
    hasFilename <- isJust <$> getFilename
    status <- getFileStatus
    if hasFilename
      then return . Just $
         case status of
           Dirty -> styleText "✘" $ fg Red
           Clean -> styleText "✓" $ fg Green
      else return Nothing
  
  -- | Keeps track of buffer status
  bufferChanged :: BufTextChanged -> BufAction ()
  bufferChanged _ = setFileStatus Dirty
  
  saveAs :: String -> BufAction ()
  saveAs fName = getText >>= liftIO . TIO.writeFile fName . Y.toText
  
  -- | Save the buffer if we have a filename
  save :: BufAction ()
  save = do
    FileInfo mName <- getBufExt
    case mName of
      Just fName -> saveAs fName
      Nothing -> return ()
    setFileStatus Clean
  
  -- | Set the filename
  setFilename :: String -> BufAction ()
  setFilename fname = setBufExt $ FileInfo (Just fname)
  
  -- | Add a buffer for a file
  addFile :: String -> Y.YiString -> App ()
  addFile fname txt = do
    newBuf <- addBuffer txt
    bufDo_ newBuf (setFilename fname)
  
  -- | Load files from command line
  loadFiles :: App ()
  loadFiles = do
    fileNames <- liftIO getArgs
    fileTexts <- liftIO $ traverse TIO.readFile fileNames
    mapM_ (uncurry addFile) $ zip fileNames (Y.fromText <$> fileTexts)
  