module Pencil.App
( PencilApp
, run
) where
import Pencil.App.Internal
import Pencil.Content
import Pencil.Config
import Control.Monad.Except
import Control.Monad.Reader
import qualified Data.List as L
import qualified Data.Text as T
import qualified Text.EditDistance as EditDistance
run :: PencilApp a -> Config -> IO ()
run app config = do
e <- runExceptT $ runReaderT app config
case e of
Left (FileNotFound (Just fp)) -> do
e2 <- runExceptT $ runReaderT (mostSimilarFiles fp) config
case e2 of
Right closestFiles ->
if not (null closestFiles)
then do
putStrLn ("File " ++ fp ++ " not found. Maybe you meant: ")
printAsList (take 3 closestFiles)
else putStrLn ("File " ++ fp ++ " not found.")
_ -> return ()
Left (CollectionNotLastInStructure name) ->
putStrLn ("Collections must be last in a Structure. But the collection named " ++
T.unpack name ++ " was not the last in the Structure.")
Left (CollectionFirstInStructure name) ->
putStrLn ("Collections cannot be first in a Structure. But the collection named " ++
T.unpack name ++ " first in the Structure.")
Left (NotTextFile fp) ->
putStrLn ("Tried to load " ++ maybe "UNKNOWNFILE" id fp ++ " as text file, but either it's not a text file or the file is corrupted.")
_ -> return ()
case e of
Left _ -> fail "Exception when running program!"
_ -> return ()
mostSimilarFiles :: FilePath -> PencilApp [FilePath]
mostSimilarFiles fp = do
sitePrefix <- asks getSourceDir
fps <- listDir True ""
let fps' = map (sitePrefix ++) fps
let costs = map (\f -> (f, EditDistance.levenshteinDistance EditDistance.defaultEditCosts fp f)) fps'
let sorted = L.sortBy (\(_, d1) (_, d2) -> compare d1 d2) costs
return $ map fst sorted