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
23import System.Directory
28caseSplitAt :: Handle -> FilePath -> Bool -> Int -> Name -> Idris ()
29caseSplitAt h fn updatefile l n
30 = do src <- runIO $ readFile fn
31 res <- splitOnLine l n fn
32 iLOG (showSep "\n" (map show res))
33 let (before, (ap : later)) = splitAt (l-1) (lines src)
34 res' <- replaceSplits ap res
37 then do let fb = fn ++ "~" -- make a backup!
38 runIO $ writeFile fb (unlines before ++ new ++ unlines later)
39 runIO $ copyFile fb fn
40 else -- do ihputStrLn h (show res)
43addClauseFrom :: Handle -> FilePath -> Bool -> Int -> Name -> Idris ()
44addClauseFrom h fn updatefile l n
45 = do src <- runIO $ readFile fn
46 let (before, tyline : later) = splitAt (l-1) (lines src)
47 let indent = getIndent 0 (show n) tyline
48 cl <- getClause l n fn
49 -- add clause before first blank line in 'later'
50 let (nonblank, rest) = span (not . all isSpace) (tyline:later)
52 then do let fb = fn ++ "~"
53 runIO $ writeFile fb (unlines (before ++ nonblank) ++
54 replicate indent ' ' ++
57 runIO $ copyFile fb fn
58 else ihPrintResult h cl
61 getIndent i n xs | take 9 xs == "instance " = i
62 getIndent i n xs | take (length n) xs == n = i
63 getIndent i n (x : xs) = getIndent (i + 1) n xs
65addProofClauseFrom :: Handle -> FilePath -> Bool -> Int -> Name -> Idris ()
66addProofClauseFrom h fn updatefile l n
67 = do src <- runIO $ readFile fn
68 let (before, tyline : later) = splitAt (l-1) (lines src)
69 let indent = getIndent 0 (show n) tyline
70 cl <- getProofClause l n fn
71 -- add clause before first blank line in 'later'
72 let (nonblank, rest) = span (not . all isSpace) (tyline:later)
74 then do let fb = fn ++ "~"
75 runIO $ writeFile fb (unlines (before ++ nonblank) ++
76 replicate indent ' ' ++
79 runIO $ copyFile fb fn
80 else ihPrintResult h cl
83 getIndent i n xs | take (length n) xs == n = i
84 getIndent i n (x : xs) = getIndent (i + 1) n xs
86addMissing :: Handle -> FilePath -> Bool -> Int -> Name -> Idris ()
87addMissing h fn updatefile l n
88 = do src <- runIO $ readFile fn
89 let (before, tyline : later) = splitAt (l-1) (lines src)
90 let indent = getIndent 0 (show n) tyline
92 cl <- getInternalApp fn l
93 let n' = getAppName cl
95 extras <- case lookupCtxt n' (idris_patdefs i) of
97 [(_, tms)] -> do tms' <- nameMissing tms
98 showNew (show n ++ "_rhs") 1 indent tms'
99 let (nonblank, rest) = span (not . all isSpace) (tyline:later)
101 then do let fb = fn ++ "~"
102 runIO $ writeFile fb (unlines (before ++ nonblank)
103 ++ extras ++ unlines rest)
104 runIO $ copyFile fb fn
105 else ihPrintResult h extras
106 where showPat = show . stripNS
107 stripNS tm = mapPT dens tm where
108 dens (PRef fc n) = PRef fc (nsroot n)
111 nsroot (NS n _) = nsroot n
112 nsroot (SN (WhereN _ _ n)) = nsroot n
115 getAppName (PApp _ r _) = getAppName r
116 getAppName (PRef _ r) = r
119 showNew nm i ind (tm : tms)
120 = do (nm', i') <- getUniq nm i
121 rest <- showNew nm i' ind tms
122 return (replicate ind ' ' ++
123 showPat tm ++ " = ?" ++ nm' ++
125 showNew nm i _ [] = return ""
128 getIndent i n xs | take (length n) xs == n = i
129 getIndent i n (x : xs) = getIndent (i + 1) n xs
132makeWith :: Handle -> FilePath -> Bool -> Int -> Name -> Idris ()
133makeWith h fn updatefile l n
134 = do src <- runIO $ readFile fn
135 let (before, tyline : later) = splitAt (l-1) (lines src)
136 let ind = getIndent tyline
137 let with = mkWith tyline n
138 -- add clause before first blank line in 'later',
139 -- or (TODO) before first line with same indentation as tyline
140 let (nonblank, rest) = span (\x -> not (all isSpace x) &&
141 not (ind == getIndent x)) later
143 do let fb = fn ++ "~"
144 runIO $ writeFile fb (unlines (before ++ nonblank)
147 runIO $ copyFile fb fn
148 else ihPrintResult h with
149 where getIndent s = length (takeWhile isSpace s)
152doProofSearch :: Handle -> FilePath -> Bool -> Bool ->
153 Int -> Name -> [Name] -> Idris ()
154doProofSearch h fn updatefile rec l n hints
155 = do src <- runIO $ readFile fn
156 let (before, tyline : later) = splitAt (l-1) (lines src)
158 mn <- case lookupNames n ctxt of
161 ns -> ierror (CantResolveAlts (map show ns))
163 let (top, envlen, _) = case lookup mn (idris_metavars i) of
164 Just (t, e, False) -> (t, e, False)
165 _ -> (Nothing, 0, True)
167 let body t = PProof [Try (TSeq Intros (ProofSearch rec False t hints))
168 (ProofSearch rec False t hints)]
169 let def = PClause fc mn (PRef fc mn) [] (body top) []
171 (do elabDecl' EAll toplevel (PClauses fc [] mn [def])
172 (tm, ty) <- elabVal toplevel False (PRef fc mn)
175 return . flip displayS "" . renderPretty 1.0 80 $
176 pprintPTerm defaultPPOption [] [] (idris_infixes i)
179 (delab i (specialise ctxt [] [(mn, 1)] tm)))))
180 (\e -> return ("?" ++ show n))
182 do let fb = fn ++ "~"
183 runIO $ writeFile fb (unlines before ++
184 updateMeta False tyline (show n) newmv ++ "\n"
186 runIO $ copyFile fb fn
187 else ihPrintResult h newmv
188 where dropCtxt 0 sc = sc
189 dropCtxt i (PPi _ _ _ sc) = dropCtxt (i - 1) sc
190 dropCtxt i (PLet _ _ _ sc) = dropCtxt (i - 1) sc
191 dropCtxt i (PLam _ _ sc) = dropCtxt (i - 1) sc
194 stripNS tm = mapPT dens tm where
195 dens (PRef fc n) = PRef fc (nsroot n)
198 nsroot (NS n _) = nsroot n
199 nsroot (SN (WhereN _ _ n)) = nsroot n
202updateMeta brack ('?':cs) n new
203 | length cs >= length n
204 = case splitAt (length n) cs of
206 if ((isSpace c || c == ')' || c == '}') && mv == n)
207 then addBracket brack new ++ (c : cs)
208 else '?' : mv ++ c : updateMeta True cs n new
209 (mv, []) -> if (mv == n) then addBracket brack new else '?' : mv
210updateMeta brack ('=':cs) n new = '=':updateMeta False cs n new
211updateMeta brack (c:cs) n new
212 = c : updateMeta (brack || not (isSpace c)) cs n new
213updateMeta brack [] n new = ""
215addBracket False new = new
216addBracket True new@('(':xs) | last xs == ')' = new
217addBracket True new | any isSpace new = '(' : new ++ ")"
221makeLemma :: Handle -> FilePath -> Bool -> Int -> Name -> Idris ()
222makeLemma h fn updatefile l n
223 = do src <- runIO $ readFile fn
224 let (before, tyline : later) = splitAt (l-1) (lines src)
227 mty <- case lookupTy n ctxt of
229 [] -> ierror (NoSuchVariable n)
230 ns -> ierror (CantResolveAlts (map show ns))
233 let skip = guessImps (tt_ctxt i) mty
235 let lem = show n ++ " : " ++ show (stripMNBind skip (delab i mty))
236 let lem_app = show n ++ appArgs skip mty
239 do let fb = fn ++ "~"
240 runIO $ writeFile fb (addLem before tyline lem lem_app later)
241 runIO $ copyFile fb fn
242 else ihPrintResult h $ lem ++ "\n" ++ lem_app
244 where getIndent s = length (takeWhile isSpace s)
246 appArgs skip (Bind n@(UN c) (Pi _) sc)
247 | thead c /= '_' && n `notElem` skip
248 = " " ++ show n ++ appArgs skip sc
249 appArgs skip (Bind _ (Pi _) sc) = appArgs skip sc
252 stripMNBind skip (PPi b n@(UN c) ty sc)
254 n `notElem` skip = PPi b n ty (stripMNBind skip sc)
255 stripMNBind skip (PPi b _ ty sc) = stripMNBind skip sc
256 stripMNBind skip t = t
258 -- Guess which binders should be implicits in the generated lemma.
259 -- Make them implicit if they appear guarded by a top level constructor,
260 -- or at the top level themselves.
261 guessImps :: Context -> Term -> [Name]
262 guessImps ctxt (Bind n (Pi _) sc)
263 | guarded ctxt n (substV (P Bound n Erased) sc)
264 = n : guessImps ctxt sc
265 | otherwise = guessImps ctxt sc
266 guessImps ctxt _ = []
268 guarded ctxt n (P _ n' _) | n == n' = True
269 guarded ctxt n ap@(App _ _)
270 | (P _ f _, args) <- unApply ap,
271 isConName f ctxt = any (guarded ctxt n) args
272-- guarded ctxt n (Bind (UN cn) (Pi t) sc) -- ignore shadows
273-- | thead cn /= '_' = guarded ctxt n t || guarded ctxt n sc
274 guarded ctxt n (Bind _ (Pi t) sc)
275 = guarded ctxt n t || guarded ctxt n sc
276 guarded ctxt n _ = False
280 addLem before tyline lem lem_app later
281 = let (bef_end, blankline : bef_start)
282 = span (not . blank) (reverse before)
283 mvline = updateMeta False tyline (show n) lem_app in
284 unlines $ reverse bef_start ++
285 [blankline, lem, blankline] ++
286 reverse bef_end ++ mvline : later
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