-
Notifications
You must be signed in to change notification settings - Fork 0
/
j.hs
142 lines (114 loc) · 4.61 KB
/
j.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
{-# LANGUAGE GADTs #-}
import Options.Applicative
import Control.Applicative
import Control.Monad
import Control.Monad.Trans.Except
import Control.Monad.IO.Class
import Data.Binary (decodeFileOrFail, encodeFile)
import Data.Bifunctor (second)
import System.Directory
import System.IO (hPutStrLn, stderr)
import System.IO.Error
import System.Exit
import System.FilePath ((</>))
import Text.Megaparsec (parse, errorBundlePretty)
import Jass.Parser
import Jass.Ast
import Jassbot.Signature (pretty)
import Jassbot.Search (search)
import Jassbot.Typeof (typeof)
import Jassbot.DB (buildDatabase, DB)
exceptT :: Either e a -> ExceptT e IO a
exceptT = ExceptT . return
data Command = TypeOf String (Maybe String)
| Search String Int Double (Maybe String)
| MkDatabase [FilePath] (Maybe FilePath)
parseOptions = customExecParser (prefs showHelpOnEmpty) opts
where
opts = info (pCommand <**> helper)
( fullDesc
<> header "j - cli jass utility"
)
pCommand = hsubparser
( command "type" (info typeOfOptions (progDesc "Returns the type of the function"))
<> command "search" (info searchOptions (progDesc "Fuzzy searches functions"))
<> command "init" (info mkDatabaseOptions (progDesc "Initialized the database used"))
)
typeOfOptions =
TypeOf <$> argument str (help "The functions name" <> metavar "needle")
<*> optional (option str $ long "data-dir")
searchOptions =
Search <$> argument str (help "The search string" <> metavar "needle")
<*> option auto ( showDefault
<> value 3
<> long "results"
<> short 'n'
<> help "Display at most N results. Use 0 to disable the limit."
<> metavar "N"
)
<*> option auto ( showDefault
<> value 0.4
<> long "threshold"
<> short 't'
<> help "Minimum score for a function to be displayed"
<> metavar "T"
)
<*> optional (option str $ long "data-dir")
mkDatabaseOptions =
MkDatabase <$> some (argument str (help "path to jass files to idnex" <> metavar "[JASSFILES]"))
<*> optional (option str $ long "data-dir")
main = do
options <- parseOptions
case options of
TypeOf needle p -> readDb p >>= typeOfx needle
Search _ _ _ p -> readDb p >>= searchx options
MkDatabase jassFiles databasePath -> mkDatabasex jassFiles databasePath
typeOfx needle db = do
let x = typeof db needle
case x of
Nothing -> putStrLn $ unwords ["Unknown function:", needle]
Just s -> putStrLn $ pretty s
searchx (Search needle numresults threshold _) db = do
let numresults' = if numresults <= 0 then maxBound else numresults
forM_ (take numresults' $ search db needle threshold) $
putStrLn . pretty . snd
getDbPath :: Maybe String -> IO String
getDbPath x =
case x of
Just datadir -> return datadir
Nothing -> getXdgDirectory XdgData "jassbot"
readDb :: Maybe String -> IO DB
readDb p = do
datadir <- getDbPath p
x <- tryIOError (decodeFileOrFail $ datadir </> "jassbot.db")
case x of
Left ex -> do
hPutStrLn stderr $ unwords ["Could not open database. Have you run init yet?", show ex]
exitWith $ ExitFailure 1
Right x' ->
case x' of
Right x' -> return x'
Left (_, msg) -> do
hPutStrLn stderr $ unwords ["Could not open database. Have you run init yet?", msg]
exitWith $ ExitFailure 1
writeDb :: Maybe String -> DB -> IO ()
writeDb p db = do
datadir <- getDbPath p
createDirectoryIfMissing True datadir
encodeFile (datadir </> "jassbot.db") db
mkDatabasex :: [FilePath] -> Maybe FilePath -> IO ()
mkDatabasex jassFiles databasePath = do
x <- runExceptT $ forM jassFiles $ \path -> do
src <- liftIO $ readFile path
exceptT $ parse programm path src
case x of
Left err -> do
hPutStrLn stderr $ errorBundlePretty err
exitWith $ ExitFailure 2
Right progs -> do
writeDb databasePath . buildDatabase $ concatPrograms progs
where
getToplevel :: Ast x Programm -> [Ast x Toplevel]
getToplevel (Programm xs) = xs
concatPrograms :: [Ast x Programm] -> Ast x Programm
concatPrograms = Programm . concatMap getToplevel