1{-# LANGUAGE PatternGuards #-}
3module Idris.Interactive(caseSplitAt, addClauseFrom, addProofClauseFrom,
4 addMissing, makeWith, doProofSearch,
7{- Bits and pieces for editing source files interactively, called from
11import Idris.Core.Evaluate
16import Idris.Delaborate
18import Idris.IdeSlave hiding (IdeSlaveCommand(..))
24import System.Directory
27import Data.Maybe (fromMaybe)
30caseSplitAt :: Handle -> FilePath -> Bool -> Int -> Name -> Idris ()
31caseSplitAt h fn updatefile l n
32 = do src <- runIO $ readFile fn
33 res <- splitOnLine l n fn
34 iLOG (showSep "\n" (map show res))
35 let (before, (ap : later)) = splitAt (l-1) (lines src)
36 res' <- replaceSplits ap res
39 then do let fb = fn ++ "~" -- make a backup!
40 runIO $ writeFile fb (unlines before ++ new ++ unlines later)
41 runIO $ copyFile fb fn
42 else -- do ihputStrLn h (show res)
45addClauseFrom :: Handle -> FilePath -> Bool -> Int -> Name -> Idris ()
46addClauseFrom h fn updatefile l n
47 = do src <- runIO $ readFile fn
48 let (before, tyline : later) = splitAt (l-1) (lines src)
49 let indent = getIndent 0 (show n) tyline
50 cl <- getClause l n fn
51 -- add clause before first blank line in 'later'
52 let (nonblank, rest) = span (not . all isSpace) (tyline:later)
54 then do let fb = fn ++ "~"
55 runIO $ writeFile fb (unlines (before ++ nonblank) ++
56 replicate indent ' ' ++
59 runIO $ copyFile fb fn
60 else ihPrintResult h cl
63 getIndent i n xs | take 9 xs == "instance " = i
64 getIndent i n xs | take (length n) xs == n = i
65 getIndent i n (x : xs) = getIndent (i + 1) n xs
67addProofClauseFrom :: Handle -> FilePath -> Bool -> Int -> Name -> Idris ()
68addProofClauseFrom h fn updatefile l n
69 = do src <- runIO $ readFile fn
70 let (before, tyline : later) = splitAt (l-1) (lines src)
71 let indent = getIndent 0 (show n) tyline
72 cl <- getProofClause l n fn
73 -- add clause before first blank line in 'later'
74 let (nonblank, rest) = span (not . all isSpace) (tyline:later)
76 then do let fb = fn ++ "~"
77 runIO $ writeFile fb (unlines (before ++ nonblank) ++
78 replicate indent ' ' ++
81 runIO $ copyFile fb fn
82 else ihPrintResult h cl
85 getIndent i n xs | take (length n) xs == n = i
86 getIndent i n (x : xs) = getIndent (i + 1) n xs
88addMissing :: Handle -> FilePath -> Bool -> Int -> Name -> Idris ()
89addMissing h fn updatefile l n
90 = do src <- runIO $ readFile fn
91 let (before, tyline : later) = splitAt (l-1) (lines src)
92 let indent = getIndent 0 (show n) tyline
94 cl <- getInternalApp fn l
95 let n' = getAppName cl
97 extras <- case lookupCtxt n' (idris_patdefs i) of
99 [(_, tms)] -> do tms' <- nameMissing tms
100 showNew (show n ++ "_rhs") 1 indent tms'
101 let (nonblank, rest) = span (not . all isSpace) (tyline:later)
103 then do let fb = fn ++ "~"
104 runIO $ writeFile fb (unlines (before ++ nonblank)
105 ++ extras ++ unlines rest)
106 runIO $ copyFile fb fn
107 else ihPrintResult h extras
108 where showPat = show . stripNS
109 stripNS tm = mapPT dens tm where
110 dens (PRef fc n) = PRef fc (nsroot n)
113 nsroot (NS n _) = nsroot n
114 nsroot (SN (WhereN _ _ n)) = nsroot n
117 getAppName (PApp _ r _) = getAppName r
118 getAppName (PRef _ r) = r
121 showNew nm i ind (tm : tms)
122 = do (nm', i') <- getUniq nm i
123 rest <- showNew nm i' ind tms
124 return (replicate ind ' ' ++
125 showPat tm ++ " = ?" ++ nm' ++
127 showNew nm i _ [] = return ""
130 getIndent i n xs | take (length n) xs == n = i
131 getIndent i n (x : xs) = getIndent (i + 1) n xs
134makeWith :: Handle -> FilePath -> Bool -> Int -> Name -> Idris ()
135makeWith h fn updatefile l n
136 = do src <- runIO $ readFile fn
137 let (before, tyline : later) = splitAt (l-1) (lines src)
138 let ind = getIndent tyline
139 let with = mkWith tyline n
140 -- add clause before first blank line in 'later',
141 -- or (TODO) before first line with same indentation as tyline
142 let (nonblank, rest) = span (\x -> not (all isSpace x) &&
143 not (ind == getIndent x)) later
145 do let fb = fn ++ "~"
146 runIO $ writeFile fb (unlines (before ++ nonblank)
149 runIO $ copyFile fb fn
150 else ihPrintResult h with
151 where getIndent s = length (takeWhile isSpace s)
154doProofSearch :: Handle -> FilePath -> Bool -> Bool ->
155 Int -> Name -> [Name] -> Idris ()
156doProofSearch h fn updatefile rec l n hints
157 = do src <- runIO $ readFile fn
158 let (before, tyline : later) = splitAt (l-1) (lines src)
160 mn <- case lookupNames n ctxt of
163 ns -> ierror (CantResolveAlts (map show ns))
165 let (top, envlen, _) = case lookup mn (idris_metavars i) of
166 Just (t, e, False) -> (t, e, False)
167 _ -> (Nothing, 0, True)
169 let body t = PProof [Try (TSeq Intros (ProofSearch rec False t hints))
170 (ProofSearch rec False t hints)]
171 let def = PClause fc mn (PRef fc mn) [] (body top) []
173 (do elabDecl' EAll toplevel (PClauses fc [] mn [def])
174 (tm, ty) <- elabVal toplevel False (PRef fc mn)
177 return . flip displayS "" . renderPretty 1.0 80 $
178 pprintPTerm defaultPPOption [] [] (idris_infixes i)
181 (delab i (specialise ctxt [] [(mn, 1)] tm)))))
182 (\e -> return ("?" ++ show n))
184 do let fb = fn ++ "~"
185 runIO $ writeFile fb (unlines before ++
186 updateMeta False tyline (show n) newmv ++ "\n"
188 runIO $ copyFile fb fn
189 else ihPrintResult h newmv
190 where dropCtxt 0 sc = sc
191 dropCtxt i (PPi _ _ _ sc) = dropCtxt (i - 1) sc
192 dropCtxt i (PLet _ _ _ sc) = dropCtxt (i - 1) sc
193 dropCtxt i (PLam _ _ sc) = dropCtxt (i - 1) sc
196 stripNS tm = mapPT dens tm where
197 dens (PRef fc n) = PRef fc (nsroot n)
200 nsroot (NS n _) = nsroot n
201 nsroot (SN (WhereN _ _ n)) = nsroot n
204updateMeta brack ('?':cs) n new
205 | length cs >= length n
206 = case splitAt (length n) cs of
208 if ((isSpace c || c == ')' || c == '}') && mv == n)
209 then addBracket brack new ++ (c : cs)
210 else '?' : mv ++ c : updateMeta True cs n new
211 (mv, []) -> if (mv == n) then addBracket brack new else '?' : mv
212updateMeta brack ('=':cs) n new = '=':updateMeta False cs n new
213updateMeta brack (c:cs) n new
214 = c : updateMeta (brack || not (isSpace c)) cs n new
215updateMeta brack [] n new = ""
217checkProv line n = isProv' False line n
219 isProv' p cs n | take (length n) cs == n = p
220 isProv' _ ('?':cs) n = isProv' False cs n
221 isProv' _ ('{':cs) n = isProv' True cs n
222 isProv' _ ('}':cs) n = isProv' True cs n
223 isProv' p (_:cs) n = isProv' p cs n
224 isProv' _ [] n = False
226addBracket False new = new
227addBracket True new@('(':xs) | last xs == ')' = new
228addBracket True new | any isSpace new = '(' : new ++ ")"
232makeLemma :: Handle -> FilePath -> Bool -> Int -> Name -> Idris ()
233makeLemma h fn updatefile l n
234 = do src <- runIO $ readFile fn
235 let (before, tyline : later) = splitAt (l-1) (lines src)
237 -- if the name is in braces, rather than preceded by a ?, treat it
238 -- as a lemma in a provisional definition
240 let isProv = checkProv tyline (show n)
243 mty <- case lookupTy n ctxt of
245 [] -> ierror (NoSuchVariable n)
246 ns -> ierror (CantResolveAlts (map show ns))
249 if (not isProv) then do
250 let skip = guessImps (tt_ctxt i) mty
252 let lem = show n ++ " : " ++ show (stripMNBind skip (delab i mty))
253 let lem_app = show n ++ appArgs skip mty
256 do let fb = fn ++ "~"
257 runIO $ writeFile fb (addLem before tyline lem lem_app later)
258 runIO $ copyFile fb fn
259 else case idris_outputmode i of
260 RawOutput -> ihPrintResult h $ lem ++ "\n" ++ lem_app
262 let good = SexpList [SymbolAtom "ok",
263 SexpList [SymbolAtom "metavariable-lemma",
264 SexpList [SymbolAtom "replace-metavariable",
266 SexpList [SymbolAtom "definition-type",
268 in runIO . hPutStrLn h $ convSExp "return" good n
270 else do -- provisional definition
271 let lem_app = show n ++ appArgs [] mty ++
272 " = ?" ++ show n ++ "_rhs"
274 do let fb = fn ++ "~"
275 runIO $ writeFile fb (addProv before tyline lem_app later)
276 runIO $ copyFile fb fn
277 else case idris_outputmode i of
278 RawOutput -> ihPrintResult h $ lem_app
280 let good = SexpList [SymbolAtom "ok",
281 SexpList [SymbolAtom "provisional-definition-lemma",
282 SexpList [SymbolAtom "definition-clause",
283 StringAtom lem_app]]]
284 in runIO . hPutStrLn h $ convSExp "return" good n
286 where getIndent s = length (takeWhile isSpace s)
288 appArgs skip (Bind n@(UN c) (Pi _) sc)
289 | thead c /= '_' && n `notElem` skip
290 = " " ++ show n ++ appArgs skip sc
291 appArgs skip (Bind _ (Pi _) sc) = appArgs skip sc
294 stripMNBind skip (PPi b n@(UN c) ty sc)
296 n `notElem` skip = PPi b n ty (stripMNBind skip sc)
297 stripMNBind skip (PPi b _ ty sc) = stripMNBind skip sc
298 stripMNBind skip t = t
300 -- Guess which binders should be implicits in the generated lemma.
301 -- Make them implicit if they appear guarded by a top level constructor,
302 -- or at the top level themselves.
303 guessImps :: Context -> Term -> [Name]
304 guessImps ctxt (Bind n (Pi _) sc)
305 | guarded ctxt n (substV (P Bound n Erased) sc)
306 = n : guessImps ctxt sc
307 | otherwise = guessImps ctxt sc
308 guessImps ctxt _ = []
310 guarded ctxt n (P _ n' _) | n == n' = True
311 guarded ctxt n ap@(App _ _)
312 | (P _ f _, args) <- unApply ap,
313 isConName f ctxt = any (guarded ctxt n) args
314-- guarded ctxt n (Bind (UN cn) (Pi t) sc) -- ignore shadows
315-- | thead cn /= '_' = guarded ctxt n t || guarded ctxt n sc
316 guarded ctxt n (Bind _ (Pi t) sc)
317 = guarded ctxt n t || guarded ctxt n sc
318 guarded ctxt n _ = False
322 addLem before tyline lem lem_app later
323 = let (bef_end, blankline : bef_start)
324 = case span (not . blank) (reverse before) of
325 (bef, []) -> (bef, "" : [])
327 mvline = updateMeta False tyline (show n) lem_app in
328 unlines $ reverse bef_start ++
329 [blankline, lem, blankline] ++
330 reverse bef_end ++ mvline : later
332 addProv before tyline lem_app later
333 = let (later_bef, blankline : later_end)
334 = case span (not . blank) later of
335 (bef, []) -> (bef, "" : [])
337 unlines $ before ++ tyline :
338 (later_bef ++ [blankline, lem_app, blankline] ++
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list