Skip to content

Commit c260ed9

Browse files
Merge pull request #2 from siddhartha-gadgil/cleanup
feat: general cleanup
2 parents 1709ad5 + 934e87e commit c260ed9

File tree

9 files changed

+112
-81
lines changed

9 files changed

+112
-81
lines changed

LeanSearchClient/Basic.lean

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import Lean
1+
import Lean.Data.Options
22

33
register_option leansearch.queries : Nat :=
44
{ defValue := 6

LeanSearchClient/Examples.lean

-17
This file was deleted.

LeanSearchClient/Syntax.lean

+63-48
Original file line numberDiff line numberDiff line change
@@ -3,29 +3,37 @@ Copyright (c) 2024 Siddhartha Gadgil. All rights reserved.
33
Released under Apache 2.0 license as described in the file LICENSE.
44
Authors: Siddhartha Gadgil
55
-/
6-
import Lean
6+
import Lean.Elab.Tactic.Meta
7+
import Lean.Meta.Tactic.TryThis
78
import LeanSearchClient.Basic
89

910
/-!
1011
# LeanSearchClient
1112
12-
In this file, we provide syntax for search using the [leansearch API](https://leansearch.net/) from within Lean. It allows you to search for Lean tactics and theorems using natural language.
13+
In this file, we provide syntax for search using the [leansearch API](https://leansearch.net/)
14+
from within Lean. It allows you to search for Lean tactics and theorems using natural language.
1315
14-
We provide syntax to make a query and generate `TryThis` options to click or use a code action to use the results. The queries are of three forms:
16+
We provide syntax to make a query and generate `TryThis` options to click or
17+
use a code action to use the results.
18+
19+
The queries are of three forms:
1520
1621
* `Command` syntax: `#leansearch "search query"` as a command.
1722
* `Term` syntax: `#leansearch "search query"` as a term.
1823
* `Tactic` syntax: `#leansearch "search query"` as a tactic.
1924
20-
In all cases results are displayed in the Lean Infoview and clicking these replaces the query text. In the cases of a query for tactics only valid tactics are displayed.
25+
In all cases results are displayed in the Lean Infoview and clicking these replaces the query text.
26+
In the cases of a query for tactics only valid tactics are displayed.
2127
-/
2228

29+
namespace LeanSearchClient
30+
2331
open Lean Meta Elab Tactic Parser Term
2432

25-
def getQueryJson (s: String)(num_results : Nat := 6) : IO <| Array Json := do
33+
def getQueryJson (s : String) (num_results : Nat := 6) : IO <| Array Json := do
2634
let apiUrl := "https://leansearch.net/api/search"
2735
let s' := s.replace " " "%20"
28-
let q := apiUrl++ s!"?query={s'}&num_results={num_results}"
36+
let q := apiUrl ++ s!"?query={s'}&num_results={num_results}"
2937
let s ← IO.Process.output {cmd := "curl", args := #["-X", "GET", q]}
3038
let js := Json.parse s.stdout |>.toOption |>.get!
3139
return js.getArr? |>.toOption |>.get!
@@ -42,8 +50,7 @@ def queryNum : CoreM Nat := do
4250

4351
namespace SearchResult
4452

45-
46-
def ofJson? (js: Json) : Option SearchResult :=
53+
def ofJson? (js : Json) : Option SearchResult :=
4754
match js.getObjValAs? String "formal_name" with
4855
| Except.ok name =>
4956
let type? := js.getObjValAs? String "formal_type" |>.toOption
@@ -54,7 +61,7 @@ def ofJson? (js: Json) : Option SearchResult :=
5461
some {name := name, type? := type?, docString? := doc?, doc_url? := docurl?, kind? := kind?}
5562
| _ => none
5663

57-
def query (s: String)(num_results : Nat) :
64+
def query (s : String) (num_results : Nat) :
5865
IO <| Array SearchResult := do
5966
let jsArr ← getQueryJson s num_results
6067
return jsArr.filterMap ofJson?
@@ -65,12 +72,12 @@ def toCommandSuggestion (sr : SearchResult) : TryThis.Suggestion :=
6572
| none => ""
6673
{suggestion := s!"#check {sr.name}", postInfo? := sr.type?.map fun s => s!" -- {s}" ++ s!"\n{data}"}
6774

68-
def toTermSuggestion (sr: SearchResult) : TryThis.Suggestion :=
75+
def toTermSuggestion (sr : SearchResult) : TryThis.Suggestion :=
6976
match sr.type? with
7077
| some type => {suggestion := sr.name, postInfo? := some s!" (type: {type})"}
7178
| none => {suggestion := sr.name}
7279

73-
def toTacticSuggestions (sr: SearchResult) : Array TryThis.Suggestion :=
80+
def toTacticSuggestions (sr : SearchResult) : Array TryThis.Suggestion :=
7481
match sr.type? with
7582
| some type => #[{suggestion := s!"apply {sr.name}"},
7683
{suggestion := s!"have : {type} := {sr.name}"},
@@ -80,24 +87,24 @@ def toTacticSuggestions (sr: SearchResult) : Array TryThis.Suggestion :=
8087

8188
end SearchResult
8289

83-
def getQueryCommandSuggestions (s: String)(num_results : Nat) :
84-
IO <| Array TryThis.Suggestion := do
85-
let searchResults ← SearchResult.query s num_results
86-
return searchResults.map SearchResult.toCommandSuggestion
87-
88-
def getQueryTermSuggestions (s: String)(num_results : Nat) :
89-
IO <| Array TryThis.Suggestion := do
90-
let searchResults ← SearchResult.query s num_results
91-
return searchResults.map SearchResult.toTermSuggestion
92-
93-
def getQueryTacticSuggestionGroups (s: String)(num_results : Nat) :
94-
IO <| Array (String × Array TryThis.Suggestion) := do
95-
let searchResults ← SearchResult.query s num_results
96-
return searchResults.map fun sr =>
97-
let fullName := match sr.type? with
98-
| some type => s!"{sr.name} (type: {type})"
99-
| none => sr.name
100-
(fullName, sr.toTacticSuggestions)
90+
def getQueryCommandSuggestions (s : String) (num_results : Nat) :
91+
IO <| Array TryThis.Suggestion := do
92+
let searchResults ← SearchResult.query s num_results
93+
return searchResults.map SearchResult.toCommandSuggestion
94+
95+
def getQueryTermSuggestions (s : String) (num_results : Nat) :
96+
IO <| Array TryThis.Suggestion := do
97+
let searchResults ← SearchResult.query s num_results
98+
return searchResults.map SearchResult.toTermSuggestion
99+
100+
def getQueryTacticSuggestionGroups (s : String) (num_results : Nat) :
101+
IO <| Array (String × Array TryThis.Suggestion) := do
102+
let searchResults ← SearchResult.query s num_results
103+
return searchResults.map fun sr =>
104+
let fullName := match sr.type? with
105+
| some type => s!"{sr.name} (type: {type})"
106+
| none => sr.name
107+
(fullName, sr.toTacticSuggestions)
101108

102109
def defaultTerm (expectedType? : Option Expr) : MetaM Expr := do
103110
match expectedType? with
@@ -108,48 +115,56 @@ def defaultTerm (expectedType? : Option Expr) : MetaM Expr := do
108115
return mkConst ``True.intro
109116
| none => return mkConst ``True.intro
110117

111-
def checkTactic (target: Expr)(tac: Syntax):
112-
TermElabM (Option Nat) :=
113-
withoutModifyingState do
114-
try
115-
let goal ← mkFreshExprMVar target
116-
let (goals, _) ←
117-
withoutErrToSorry do
118-
Elab.runTactic goal.mvarId! tac
119-
(← read) (← get)
120-
return some goals.length
121-
catch _ =>
122-
return none
118+
def checkTactic (target : Expr) (tac : Syntax) :
119+
TermElabM (Option Nat) :=
120+
withoutModifyingState do
121+
try
122+
let goal ← mkFreshExprMVar target
123+
let (goals, _) ←
124+
withoutErrToSorry do
125+
Elab.runTactic goal.mvarId! tac
126+
(← read) (← get)
127+
return some goals.length
128+
catch _ =>
129+
return none
130+
131+
def incompleteQuery : String :=
132+
"#leansearch query should end with a `.` or `?`.\n\
133+
Note this command sends your query to an external service at https://leansearch.net/."
123134

124135
open Command
136+
125137
syntax (name := leansearch_cmd) "#leansearch" str : command
126-
@[command_elab leansearch_cmd] def leanSearchImpl : CommandElab :=
138+
139+
@[command_elab leansearch_cmd] def leanSearchCommandImpl : CommandElab :=
127140
fun stx => Command.liftTermElabM do
128141
match stx with
129142
| `(command| #leansearch $s) =>
130143
let s := s.getString
131144
if s.endsWith "." || s.endsWith "?" then
132145
let suggestions ← getQueryCommandSuggestions s (← queryNum)
133-
TryThis.addSuggestions stx suggestions (header:= "Lean Search Results")
146+
TryThis.addSuggestions stx suggestions (header := "Lean Search Results")
134147
else
135-
logWarning "Lean search query should end with a full stop (period) or a question mark. Note this command sends your query to an external service at https://leansearch.net/."
148+
logWarning incompleteQuery
136149
| _ => throwUnsupportedSyntax
137150

138151
syntax (name := leansearch_term) "#leansearch" str : term
152+
139153
@[term_elab leansearch_term] def leanSearchTermImpl : TermElab :=
140154
fun stx expectedType? => do
141155
match stx with
142156
| `(#leansearch $s) =>
143157
let s := s.getString
144158
if s.endsWith "." || s.endsWith "?" then
145159
let suggestions ← getQueryTermSuggestions s (← queryNum)
146-
TryThis.addSuggestions stx suggestions (header:= "Lean Search Results")
160+
TryThis.addSuggestions stx suggestions (header := "Lean Search Results")
147161
else
148-
logWarning "Lean search query should end with a full stop (period) or a question mark. Note this command sends your query to an external service at https://leansearch.net/."
162+
logWarning incompleteQuery
149163
defaultTerm expectedType?
150164
| _ => throwUnsupportedSyntax
151165

152166
syntax (name := leansearch_tactic) "#leansearch" str : tactic
167+
153168
@[tactic leansearch_tactic] def leanSearchTacticImpl : Tactic :=
154169
fun stx => withMainContext do
155170
match stx with
@@ -173,7 +188,7 @@ syntax (name := leansearch_tactic) "#leansearch" str : tactic
173188
pure false
174189
| _ => pure false
175190
unless sg.isEmpty do
176-
TryThis.addSuggestions stx sg (header:= s!"From: {name}")
191+
TryThis.addSuggestions stx sg (header := s!"From: {name}")
177192
else
178-
logWarning "Lean search query should end with a full stop (period) or a question mark. Note this command sends your query to an external service at https://leansearch.net/."
193+
logWarning incompleteQuery
179194
| _ => throwUnsupportedSyntax

LeanSearchClientTest.lean

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
import LeanSearchClientTest.Examples

LeanSearchClientTest/Examples.lean

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import LeanSearchClient.Syntax
2+
3+
/-!
4+
# Lean Search Examples
5+
6+
Examples of using the leansearch API. The search is triggered when the sentence ends with a full stop (period) or a question mark.
7+
-/
8+
9+
/--
10+
warning: #leansearch query should end with a `.` or `?`.
11+
Note this command sends your query to an external service at https://leansearch.net/.
12+
-/
13+
#guard_msgs in
14+
#leansearch "If a natural number n is less than m, then the successor of n is less than the successor of m"
15+
16+
/--
17+
warning: #leansearch query should end with a `.` or `?`.
18+
Note this command sends your query to an external service at https://leansearch.net/.
19+
-/
20+
#guard_msgs in
21+
example := #leansearch "If a natural number n is less than m, then the successor of n is less than the successor of m"
22+
23+
set_option leansearch.queries 1
24+
25+
/--
26+
info: From: Nat.succ_lt_succ (type: ∀ {n m : Nat}, n < m → Nat.succ n < Nat.succ m)
27+
• apply Nat.succ_lt_succ
28+
• have : ∀ {n m : Nat}, n < m → Nat.succ n < Nat.succ m := Nat.succ_lt_succ
29+
---
30+
warning: declaration uses 'sorry'
31+
-/
32+
#guard_msgs in
33+
example : 35 := by
34+
#leansearch "If a natural number n is less than m, then the successor of n is less than the successor of m."
35+
sorry

Main.lean

-4
This file was deleted.

README.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,13 @@ The following are examples of using the leansearch API. The search is triggered
1717
### Query Command
1818

1919
```lean
20-
#leansearch "If a natural number n is less than m, then the successor of n is less than the successor of m"
20+
#leansearch "If a natural number n is less than m, then the successor of n is less than the successor of m."
2121
```
2222

2323
### Query Term
2424

2525
```lean
26-
example := #leansearch "If a natural number n is less than m, then the successor of n is less than the successor of m"
26+
example := #leansearch "If a natural number n is less than m, then the successor of n is less than the successor of m."
2727
```
2828

2929
### Query Tactic
@@ -32,6 +32,6 @@ Note that only valid tactics are displayed.
3232

3333
```lean
3434
example : 3 ≤ 5 := by
35-
#leansearch "If a natural number n is less than m, then the successor of n is less than the successor of m"
35+
#leansearch "If a natural number n is less than m, then the successor of n is less than the successor of m."
3636
sorry
3737
```

lakefile.lean

-8
This file was deleted.

lakefile.toml

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
name = "LeanSearchClient"
2+
testDriver = "LeanSearchClientTest"
3+
defaultTargets = ["LeanSearchClient"]
4+
5+
[[lean_lib]]
6+
name = "LeanSearchClient"
7+
8+
[[lean_lib]]
9+
name = "LeanSearchClientTest"

0 commit comments

Comments
 (0)