yi-0.5.2: Yi/IReader.hs
module Yi.IReader where
import Control.Monad.State
import Data.List
import System.Directory (getHomeDirectory)
import Yi.Keymap
import Yi.Prelude
import Yi.Buffer.Misc
import Yi.Buffer.Region
import Yi.Buffer.Normal
import Yi.Buffer.HighLevel
import qualified System.IO as IO
type Article = String
type ArticleDB = [String]
-- | Get the first article in the list. We use the list to express relative priority;
-- the first is the most, the last least. We then just cycle through - everybody gets equal time.
getLatestArticle :: ArticleDB -> Article
getLatestArticle [] = ""
getLatestArticle adb = head adb
-- | We remove the old first article, and we stick it on the end of the
-- list using the presumably modified version.
updateSetLast :: ArticleDB -> Article -> ArticleDB
updateSetLast [] a = [a]
updateSetLast (_:bs) a = bs ++ [a]
-- | Insert a new article with top priority (that is, at the front of the list).
insertArticle :: ArticleDB -> Article -> ArticleDB
insertArticle = flip (:)
-- | Delete the first
deleteArticle :: ArticleDB -> Article -> ArticleDB
deleteArticle = flip delete
writeDB :: ArticleDB -> YiM ()
writeDB adb = io $ join $ liftM (flip writeFile $ show adb) $ dbLocation
readDB :: YiM ArticleDB
readDB = io $ rddb `catch` (\_ -> return (return []))
where rddb = do db <- liftM readfile $ dbLocation
liftM read db
-- We need these for strict IO
readfile :: FilePath -> IO String
readfile f = IO.openFile f IO.ReadMode >>= hGetContents
hGetContents :: IO.Handle -> IO.IO String
hGetContents h = IO.hGetContents h >>= \s -> length s `seq` return s
dbLocation :: IO FilePath
dbLocation = getHomeDirectory >>= \home -> return (home ++ "/.yi/articles.db")
-- | Returns the database as it exists on the disk, and the current Yi buffer contents.
oldDbNewArticle :: YiM (ArticleDB, Article)
oldDbNewArticle = do olddb <- readDB
newarticle <- withBuffer getBufferContents
return (olddb, newarticle)
getBufferContents :: BufferM String
getBufferContents = readRegionB =<< regionOfB Document
-- | Given an 'ArticleDB', dump the scheduled article into the buffer (replacing previous contents).
setDisplayedArticle :: ArticleDB -> YiM ()
setDisplayedArticle newdb = do let nextarticle = getLatestArticle newdb
withBuffer (replaceBufferContent nextarticle)
withBuffer topB -- replaceBufferContents moves us
-- to bottom?
-- | Go to next one. This ignores the buffer, but it doesn't remove anything from the database.
-- The ordering does change, however.
nextArticle :: YiM ()
nextArticle = do (oldb,_) <- oldDbNewArticle
-- Ignore buffer, just set the first article last
let newdb = updateSetLast oldb (getLatestArticle oldb)
setDisplayedArticle newdb
writeDB newdb
-- | Delete current article (the article as in the database), and go to next one.
deleteAndNextArticle :: YiM ()
deleteAndNextArticle = do ((_:ndb),_) <- oldDbNewArticle -- throw away changes, drop head
setDisplayedArticle ndb
writeDB ndb
-- | The main action. We fetch the old database, we fetch the modified article from the buffer,
-- then we call the function 'updateSetLast' which removes the first article and pushes our modified article
-- to the end of the list.
saveAndNextArticle :: YiM ()
saveAndNextArticle = do (oldb,newa) <- oldDbNewArticle
let newdb = updateSetLast oldb newa
setDisplayedArticle newdb
writeDB newdb
-- | Assume the buffer is an entirely new article just imported this second, and save it.
-- We don't want to use 'updateSetLast' since that will erase an article.
saveAsNewArticle :: YiM ()
saveAsNewArticle = do (oldb,newa) <- oldDbNewArticle
let newdb = insertArticle oldb newa
writeDB newdb