Skip to content

Commit cf98018

Browse files
committed
chore: move all util functions into Cli namespace to resolve name clashes & bump toolchain
1 parent b88b0ab commit cf98018

File tree

3 files changed

+55
-52
lines changed

3 files changed

+55
-52
lines changed

Cli/Basic.lean

Lines changed: 44 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import Lean.Data.RBTree
22

3+
namespace Cli
4+
35
section Utils
46
/--
57
Matches the lengths of lists `a` and `b` by filling the shorter one with
@@ -20,7 +22,7 @@ section Utils
2022
return r
2123

2224
def flatMap (f : α → Array β) (xs : Array α) : Array β :=
23-
xs.map f |>.join
25+
join (xs.map f)
2426
end Array
2527

2628
namespace String
@@ -52,7 +54,7 @@ section Utils
5254
Panics if `maxWidth = 0`.
5355
-/
5456
def wrapAt! (s : String) (maxWidth : Nat) : String :=
55-
s.wrapAt? maxWidth |>.get!
57+
wrapAt? s maxWidth |>.get!
5658

5759
/--
5860
Deletes all trailing spaces at the end of every line, as seperated by `\n`.
@@ -88,7 +90,7 @@ section Utils
8890
continue
8991
-- if `w` is the first proper word, this will insert a `\n` before the text, which we remove later.
9092
-- `w.wrapAt! maxWidth` ensures that our new line is not already too large.
91-
let wordOnNewLine := "\n" ++ w.wrapAt! maxWidth
93+
let wordOnNewLine := "\n" ++ wrapAt! w maxWidth
9294
result := result.push wordOnNewLine
9395
let wrappedLines : Array String := wordOnNewLine.splitOn "\n" |>.toArray
9496
currentLineWidth := wrappedLines[wrappedLines.size - 1]!.length + 1
@@ -111,7 +113,7 @@ section Utils
111113
Panics if `maxWidth = 0`.
112114
-/
113115
def wrapWordsAt! (s : String) (maxWidth : Nat) : String :=
114-
s.wrapWordsAt? maxWidth |>.get!
116+
wrapWordsAt? s maxWidth |>.get!
115117

116118
/--
117119
Inserts `n` spaces before each line as seperated by `\n` in `s`.
@@ -146,16 +148,16 @@ section Utils
146148
if maxWidth - margin - minRightColumnWidth < 1 then
147149
return none
148150
let rows : Array (List String × String) := rows.map fun (left, right) =>
149-
(maxWidth - margin - minRightColumnWidth |> left.wrapWordsAt! |>.splitOn "\n", right)
151+
(maxWidth - margin - minRightColumnWidth |> String.wrapWordsAt! left |>.splitOn "\n", right)
150152
let leftColumnWidth :=
151-
rows.flatMap (·.1.map (·.length) |>.toArray)
153+
flatMap (·.1.map (·.length) |>.toArray) rows
152154
|>.getMax? (· < ·)
153155
|>.get!
154156
let leftColumnWidth := leftColumnWidth + margin
155157
let rows : Array (List String × List String) := rows.map fun (left, right) =>
156-
(left, maxWidth - leftColumnWidth |> right.wrapWordsAt! |>.splitOn "\n")
157-
let rows : Array (String × String) := rows.flatMap fun (left, right) =>
158-
let (left, right) : List String × List String := left.matchLength right ""
158+
(left, maxWidth - leftColumnWidth |> String.wrapWordsAt! right |>.splitOn "\n")
159+
let rows : Array (String × String) := flatMap (xs := rows) fun (left, right) =>
160+
let (left, right) : List String × List String := List.matchLength left right ""
159161
left.zip right |>.toArray
160162
let rows : Array String := rows.map fun (left, right) =>
161163
if right = "" then
@@ -174,7 +176,7 @@ section Utils
174176
-/
175177
def renderTable! (rows : Array (String × String)) (maxWidth : Nat) (margin : Nat := 2)
176178
: String :=
177-
rows.renderTable? maxWidth margin |>.get!
179+
renderTable? rows maxWidth margin |>.get!
178180
end Array
179181

180182
namespace Option
@@ -190,8 +192,6 @@ section Utils
190192
end Option
191193
end Utils
192194

193-
namespace Cli
194-
195195
section Configuration
196196
/--
197197
Represents a type that can be parsed to a string and the corresponding name of the type.
@@ -457,9 +457,9 @@ section Configuration
457457
/-- Checks whether `m` has a flag with the corresponding `shortName`. -/
458458
def hasFlagByShortName (m : Meta) (name : String) : Bool := m.flagByShortName? name |>.isSome
459459

460-
/--
460+
/--
461461
Adds help (`-h, --help`) and version (`--version`) flags to `m`. Does not add
462-
a version flag if `m` does not designate a version.
462+
a version flag if `m` does not designate a version.
463463
-/
464464
def addHelpAndVersionFlags (m : Meta) : Meta := Id.run do
465465
let helpFlag := .paramless
@@ -475,7 +475,7 @@ section Configuration
475475
{ m with flags := fixedFlags ++ m.flags }
476476
end Cmd.Meta
477477

478-
/--
478+
/--
479479
Represents a recursive variant of `Cmd.Meta` that is used in `Parsed`
480480
to replicate the recursive subcommand structure of a command
481481
without referring to the command itself.
@@ -679,7 +679,7 @@ section Configuration
679679
(subCmds : Array ExtendableCmd := #[])
680680
: ExtendableCmd :=
681681
.mk'
682-
⟨name, parent.meta.parentNames.push parent.meta.name, version?, description, furtherInformation?,
682+
⟨name, parent.meta.parentNames.push parent.meta.name, version?, description, furtherInformation?,
683683
flags, positionalArgs, variableArg?⟩
684684
run subCmds
685685

@@ -710,7 +710,7 @@ section Configuration
710710
(subCmds : Array ExtendableCmd := #[])
711711
: ExtendableCmd :=
712712
.mkWithHelpAndVersionFlags'
713-
⟨name, parent.meta.parentNames.push parent.meta.name, version?, description, furtherInformation?,
713+
⟨name, parent.meta.parentNames.push parent.meta.name, version?, description, furtherInformation?,
714714
flags, positionalArgs, variableArg?⟩
715715
run subCmds
716716

@@ -783,18 +783,18 @@ section Configuration
783783
- The output of the parser can be postprocessed and validated.
784784
-/
785785
structure Extension where
786-
/--
786+
/--
787787
Priority that dictates how early an extension is applied.
788788
The lower the priority, the later it is applied.
789789
-/
790790
priority : Nat := 1024
791-
/--
791+
/--
792792
Extends a command to adjust the displayed help.
793793
The recursive subcommand structure may be mutated.
794794
-/
795795
extend : ExtendableCmd → ExtendableCmd := id
796-
/--
797-
Processes and validates the output of the parser for the given `ExtendableCmd`.
796+
/--
797+
Processes and validates the output of the parser for the given `ExtendableCmd`.
798798
Takes the `ExtendableCmd` that results from all extensions being applied.
799799
If postprocessing mutates the subcommand structure in `Parsed.cmd`, care must be taken to update
800800
`Parsed.parent?` accordingly as well.
@@ -852,7 +852,7 @@ section Configuration
852852
let subCmdParentNames := parentNames.push c.meta.name
853853
let subCmds := c.subCmds.map (loop · subCmdParentNames)
854854
.init { c.meta with parentNames := parentNames } c.run subCmds c.extension?
855-
855+
856856
/--
857857
Creates a new command. Adds a `-h, --help` and a `--version` flag if `meta` designates a version.
858858
Updates the `parentNames` of all subcommands.
@@ -947,7 +947,7 @@ section Configuration
947947
for ⟨fullName, extension?⟩ in extensions do
948948
extensionIndex := extensionIndex.insert fullName extension?
949949
let rec loop (c : ExtendableCmd) : Cli.Cmd :=
950-
let extension? := do extensionIndex.find? (← c.originalFullName?) |>.join
950+
let extension? := do extensionIndex.find? (← c.originalFullName?) |> Option.join
951951
let subCmds := c.subCmds.map loop
952952
.init c.meta c.run subCmds extension?
953953
loop c |>.updateParentNames |> prependOriginalParentNames
@@ -1052,24 +1052,27 @@ section Macro
10521052
(description := $description)
10531053
(flags := $(quote (← flags.getD #[] |>.mapM expandFlag)))
10541054
(positionalArgs := $(quote (← positionalArgs.getD #[] |>.mapM expandPositionalArg)))
1055-
(variableArg? := $(quote (← variableArg.join.mapM expandVariableArg)))
1055+
(variableArg? := $(quote (← (Option.join variableArg).mapM expandVariableArg)))
10561056
(run := $(← expandRunFun run))
10571057
(subCmds := $(quote (subCommands.getD ⟨#[]⟩).getElems))
10581058
(extension? := some <| Array.foldl Extension.then { : Extension } <| Array.qsort
10591059
$(quote (extensions.getD ⟨#[]⟩).getElems) (·.priority > ·.priority)))
10601060
end Macro
10611061

10621062
section Info
1063+
open Cli.String
1064+
open Cli.Option
1065+
10631066
/-- Maximum width within which all formatted text should fit. -/
10641067
def maxWidth : Nat := 80
10651068
/-- Amount of spaces with which section content is indented. -/
10661069
def indentation : Nat := 4
10671070
/-- Maximum width within which all formatted text should fit, after indentation. -/
10681071
def maxIndentedWidth : Nat := maxWidth - indentation
10691072
/-- Formats `xs` by `String.optJoin`ing the components with a single space. -/
1070-
def line (xs : Array String) : String := " ".optJoin xs
1073+
def line (xs : Array String) : String := optJoin xs " "
10711074
/-- Formats `xs` by `String.optJoin`ing the components with a newline `\n`. -/
1072-
def lines (xs : Array String) : String := "\n".optJoin xs
1075+
def lines (xs : Array String) : String := optJoin xs "\n"
10731076

10741077
/--
10751078
Renders a help section with the designated `title` and `content`.
@@ -1088,43 +1091,43 @@ section Info
10881091
else
10891092
return s!"{title}:"
10901093
lines #[
1091-
titleLine?.optStr,
1092-
content |>.wrapWordsAt! maxIndentedWidth |>.indent indentation
1094+
optStr titleLine?,
1095+
wrapWordsAt! content maxIndentedWidth |> indent (n := indentation)
10931096
]
10941097

10951098
/--
1096-
Renders a table using `Array.renderTable!` and then renders a section with
1099+
Renders a table using `Cli.Array.renderTable!` and then renders a section with
10971100
the designated `title` and the rendered table as content.
10981101
-/
10991102
def renderTable
11001103
(title : String)
11011104
(columns : Array (String × String))
11021105
(emptyTablePlaceholder? : Option String := none)
11031106
: String :=
1104-
let table := columns.renderTable! (maxWidth := maxIndentedWidth)
1107+
let table := Array.renderTable! columns (maxWidth := maxIndentedWidth)
11051108
renderSection title table emptyTablePlaceholder?
11061109

11071110
namespace Cmd
11081111
private def metaDataInfo (c : Cmd) : String :=
11091112
let version? : Option String := do return s!"[{← c.meta.version?}]"
11101113
lines #[
1111-
line #[c.meta.fullName, version?.optStr] |>.wrapWordsAt! maxWidth,
1112-
c.meta.description.wrapWordsAt! maxWidth
1114+
line #[c.meta.fullName, optStr version?] |> wrapWordsAt! (maxWidth := maxWidth),
1115+
wrapWordsAt! c.meta.description maxWidth
11131116
]
11141117

11151118
private def usageInfo (c : Cmd) : String :=
11161119
let subCmdTitle? : Option String := if ¬c.subCmds.isEmpty then "[SUBCOMMAND]" else none
11171120
let posArgNames : String := line <| c.meta.positionalArgs.map (s!"<{·.name}>")
11181121
let varArgName? : Option String := do return s!"<{(← c.meta.variableArg?).name}>..."
1119-
let info := line #[c.meta.fullName, subCmdTitle?.optStr, "[FLAGS]", posArgNames, varArgName?.optStr]
1122+
let info := line #[c.meta.fullName, optStr subCmdTitle?, "[FLAGS]", posArgNames, optStr varArgName?]
11201123
renderSection "USAGE" info
11211124

11221125
private def flagInfo (c : Cmd) : String :=
11231126
let columns : Array (String × String) := c.meta.flags.map fun flag =>
11241127
let shortName? : Option String := do return s!"-{← flag.shortName?}"
1125-
let names : String := ", ".optJoin #[shortName?.optStr, s!"--{flag.longName}"]
1128+
let names : String := optJoin #[optStr shortName?, s!"--{flag.longName}"] ", "
11261129
let type? : Option String := if ¬ flag.isParamless then s!": {flag.type.name}" else none
1127-
(line #[names, type?.optStr], flag.description)
1130+
(line #[names, optStr type?], flag.description)
11281131
renderTable "FLAGS" columns (emptyTablePlaceholder? := "None")
11291132

11301133
private def positionalArgInfo (c : Cmd) : String :=
@@ -1148,14 +1151,14 @@ section Info
11481151
"\n" ++ c.flagInfo,
11491152
(if ¬c.meta.positionalArgs.isEmpty ∨ c.meta.hasVariableArg then "\n" else "") ++ c.positionalArgInfo,
11501153
(if ¬c.subCmds.isEmpty then "\n" else "") ++ c.subCommandInfo,
1151-
(if c.meta.hasFurtherInformation then "\n" else "") ++ c.meta.furtherInformation?.optStr
1154+
(if c.meta.hasFurtherInformation then "\n" else "") ++ optStr c.meta.furtherInformation?
11521155
]
11531156

11541157
/-- Renders an error for `c` with the designated message `msg`. -/
11551158
def error (c : Cmd) (msg : String) : String :=
11561159
lines #[
1157-
msg.wrapWordsAt! maxWidth,
1158-
s!"Run `{c.meta.fullName} -h` for further information.".wrapWordsAt! maxWidth
1160+
wrapWordsAt! msg maxWidth,
1161+
wrapWordsAt! s!"Run `{c.meta.fullName} -h` for further information." maxWidth
11591162
]
11601163

11611164
/-- Prints the help for `c`. -/
@@ -1216,7 +1219,7 @@ section Parsing
12161219
return s!" (`--{flag.longName}`)"
12171220
else
12181221
return s!" (`-{← flag.shortName?}`)"
1219-
s!"Duplicate flag `{inputFlag}`{complementaryName?.optStr}.")
1222+
s!"Duplicate flag `{inputFlag}`{Option.optStr complementaryName?}.")
12201223
| redundantFlagArg
12211224
(flag : Flag)
12221225
(inputFlag : InputFlag)
@@ -1538,12 +1541,12 @@ section Parsing
15381541
partial def applyExtensions (c : Cmd) : Cmd := Id.run do
15391542
let subCmds := c.subCmds.map applyExtensions
15401543
let c := c.update (subCmds := subCmds)
1541-
let some extension := c.extension?
1544+
let some extension := c.extension?
15421545
| return c
15431546
extension.extend (.ofFullCmd c) |>.toFullCmd c
15441547

15451548
/--
1546-
Processes `args` by applying all extensions in `c`, `Cmd.parse?`ing the input according to `c`
1549+
Processes `args` by applying all extensions in `c`, `Cmd.parse?`ing the input according to `c`
15471550
and then applying the postprocessing extension of the respective (sub)command that was called.
15481551
Note that `args` designates the list `<foo>` in `somebinary <foo>`.
15491552
Returns either the (sub)command that an error occured in and the corresponding error message or

Cli/Extensions.lean

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import Cli.Basic
22

3+
namespace Cli
4+
35
section Utils
46
namespace Array
57
/--
@@ -36,8 +38,6 @@ section Utils
3638
end Array
3739
end Utils
3840

39-
namespace Cli
40-
4141
section Extensions
4242
/-- Prepends an author name to the description of the command. -/
4343
def author (author : String) : Extension := {
@@ -47,8 +47,8 @@ section Extensions
4747
/-- Appends a longer description to the end of the help. -/
4848
def longDescription (description : String) : Extension := {
4949
extend := fun cmd => cmd.update (furtherInformation? :=
50-
some <| cmd.furtherInformation?.optStr ++ lines #[
51-
cmd.furtherInformation?.optStr,
50+
some <| Option.optStr cmd.furtherInformation? ++ lines #[
51+
Option.optStr cmd.furtherInformation?,
5252
(if cmd.hasFurtherInformation then "\n" else "") ++ renderSection "DESCRIPTION" description
5353
]
5454
)
@@ -58,7 +58,7 @@ section Extensions
5858
def helpSubCommand : Extension := {
5959
priority := 0
6060
extend := fun cmd =>
61-
let helpCmd := .mk
61+
let helpCmd := .mk
6262
(parent := cmd)
6363
(name := "help")
6464
(version? := none)
@@ -67,7 +67,7 @@ section Extensions
6767
-- adding it once without a command handler ensures that the help will include
6868
-- the help subcommand itself
6969
let cmd := cmd.update (subCmds := cmd.subCmds.push helpCmd)
70-
let helpCmd := helpCmd.update (run := fun _ => do
70+
let helpCmd := helpCmd.update (run := fun _ => do
7171
cmd.toFullCmdWithoutExtensions.printHelp
7272
return 0)
7373
let subCmds := cmd.subCmds.set! (cmd.subCmds.size - 1) helpCmd
@@ -80,12 +80,12 @@ section Extensions
8080
if cmd.version?.isNone then
8181
panic! "Cli.versionSubCommand!: Cannot add `version` subcommand to command without a version."
8282
else
83-
let helpCmd := .mk
83+
let helpCmd := .mk
8484
(parent := cmd)
8585
(name := "version")
8686
(version? := none)
8787
(description := "Prints the version.")
88-
(run := fun _ => do
88+
(run := fun _ => do
8989
cmd.toFullCmdWithoutExtensions.printVersion!
9090
return 0)
9191
cmd.update (subCmds := cmd.subCmds.push helpCmd)
@@ -111,7 +111,7 @@ section Extensions
111111
cmd.update (flags := newMetaFlags)
112112
postprocess := fun cmd parsed =>
113113
let defaultFlags := findDefaultFlags cmd
114-
return { parsed with flags := parsed.flags.leftUnionBy (·.flag.longName) defaultFlags }
114+
return { parsed with flags := Array.leftUnionBy (·.flag.longName) parsed.flags defaultFlags }
115115
}
116116

117117
/--
@@ -134,7 +134,7 @@ section Extensions
134134
if parsed.hasFlag "help" ∨ parsed.hasFlag "version" then
135135
return parsed
136136
let requiredFlags := findRequiredFlags cmd
137-
let missingFlags := requiredFlags.diffBy (·.longName) <| parsed.flags.map (·.flag.longName)
137+
let missingFlags := Array.diffBy (·.longName) requiredFlags <| parsed.flags.map (·.flag.longName)
138138
if let some missingFlag ← pure <| missingFlags.get? 0 then
139139
throw s!"Missing required flag `--{missingFlag.longName}`."
140140
return parsed

lean-toolchain

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
leanprover/lean4:nightly-2022-10-20
1+
leanprover/lean4:nightly-2022-10-31

0 commit comments

Comments
 (0)