packages feed

zwirn-0.2.3.1: app/zwirnmill/Editor/File.hs

module Editor.File where

import Brick hiding (on)
import Brick.BChan (writeBChan)
import Control.Concurrent (forkIO)
import Control.Monad (void)
import Control.Monad.IO.Class (liftIO)
import qualified Data.Base64.Types as B64
import qualified Data.ByteString as B
import qualified Data.ByteString.Base64 as B64
import Data.Text (Text)
import qualified Data.Text as T
import qualified Data.Text.Encoding as TE
import qualified Data.Text.Zipper as Z
import Editor.Core
import Editor.Selection
import Editor.Util
import Graphics.UI.TinyFileDialogs (openFileDialog, saveFileDialog)
import qualified Graphics.Vty as V
import Lens.Micro
import Lens.Micro.Extras
import UI.Core

saveEvent :: EventM Name EditorEventEnv ()
saveEvent = do
  result <- gets (view envEditorState) >>= liftIO . saveFile
  case result of
    Right es' -> modify $ envEditorState .~ es'
    Left msg -> modify $ envEditorState %~ setMessage msg

openEvent :: EventM Name EditorEventEnv ()
openEvent = do
  chan <- gets (view envBChan)
  void $ liftIO $ forkIO $ do
    mPath <- openFile
    writeBChan chan (FileSelected mPath)

copyEvent :: EventM Name EditorEventEnv ()
copyEvent = do
  es <- gets (view envEditorState)
  vtyOut <- gets (view envVtyOut)
  case selectedText es of
    Nothing -> return ()
    Just t -> case vtyOut of
      Nothing -> return ()
      Just out -> do
        liftIO (copyToClipboard out t)
        modify $ envEditorState %~ setMessage "Copied."

loadEvent :: FilePath -> EventM Name EditorEventEnv ()
loadEvent path = do
  contents <- liftIO (readFile path)
  modify $ envEditorState .~ loadFile path (T.pack contents)

saveFile :: EditorState -> IO (Either String EditorState)
saveFile es =
  case es ^. esFilePath of
    Nothing -> do
      mpath <- saveFileDialog "save file" "untitled.zwirn" ["*.zwirn"] "zwirn files"
      case mpath of
        Nothing -> return $ Left "Failed to get path"
        Just path -> do
          writeFile (T.unpack path) (T.unpack content)
          return $
            Right $
              es
                & esUnsaved .~ False
                & esMessage ?~ "Saved."
                & esFilePath ?~ T.unpack path
    Just path -> do
      writeFile path (T.unpack content)
      return $ Right $ es & esUnsaved .~ False & esMessage ?~ "Saved."
  where
    content = getContent es

loadFile :: FilePath -> Text -> EditorState
loadFile path contents =
  let ls = T.lines contents
   in newEditor
        & esZipper .~ Z.textZipper ls Nothing
        & esFilePath ?~ path
        & esUnsaved .~ False

openFile :: IO (Maybe FilePath)
openFile = fmap T.unpack . safeHead <$> openFileDialog "choose a zwirn file" "untitled.zwirn" ["*.zwirn"] "zwirn files" False
  where
    safeHead (Just (x : _)) = Just x
    safeHead _ = Nothing

copyToClipboard :: V.Output -> Text -> IO ()
copyToClipboard output text = V.outputByteBuffer output osc52
  where
    textBytes = TE.encodeUtf8 text
    b64Bytes = B64.extractBase64 $ B64.encodeBase64' textBytes
    osc52 = B.concat ["\ESC]52;c;", b64Bytes, "\BEL"]