@@ -32,7 +32,7 @@ or for downstream projects to allow a gradual adoption of this linter.
32
32
An executable running all these linters is defined in `scripts/lint-style.lean`.
33
33
-/
34
34
35
- open System
35
+ open Lean.Linter System
36
36
37
37
namespace Mathlib.Linter.TextBased
38
38
@@ -195,23 +195,33 @@ return an array of all style errors with line numbers. If possible,
195
195
also return the collection of all lines, changed as needed to fix the linter errors.
196
196
(Such automatic fixes are only possible for some kinds of `StyleError`s.)
197
197
-/
198
- abbrev TextbasedLinter := Array String → Array (StyleError × ℕ) × (Option (Array String))
198
+ abbrev TextbasedLinter := Lean.Options → Array String →
199
+ Array (StyleError × ℕ) × (Option (Array String))
199
200
200
201
/-! Definitions of the actual text-based linters. -/
201
202
section
202
203
203
204
/-- Lint on any occurrences of the string "Adaptation note:" or variants thereof. -/
204
- def adaptationNoteLinter : TextbasedLinter := fun lines ↦ Id.run do
205
+ register_option linter.adaptationNote : Bool := { defValue := true }
206
+
207
+ @[inherit_doc linter.adaptationNote]
208
+ def adaptationNoteLinter : TextbasedLinter := fun opts lines ↦ Id.run do
209
+ unless getLinterValue linter.adaptationNote opts do return (#[], none)
210
+
205
211
let mut errors := Array.mkEmpty 0
206
212
for h : idx in [:lines.size] do
207
213
-- We make this shorter to catch "Adaptation note", "adaptation note" and a missing colon.
208
214
if lines[idx].containsSubstr "daptation note" then
209
215
errors := errors.push (StyleError.adaptationNote, idx + 1 )
210
216
return (errors, none)
211
217
212
-
213
218
/-- Lint a collection of input strings if one of them contains trailing whitespace. -/
214
- def trailingWhitespaceLinter : TextbasedLinter := fun lines ↦ Id.run do
219
+ register_option linter.trailingWhitespace : Bool := { defValue := true }
220
+
221
+ @[inherit_doc linter.trailingWhitespace]
222
+ def trailingWhitespaceLinter : TextbasedLinter := fun opts lines ↦ Id.run do
223
+ unless getLinterValue linter.trailingWhitespace opts do return (#[], none)
224
+
215
225
let mut errors := Array.mkEmpty 0
216
226
let mut fixedLines : Vector String lines.size := lines.toVector
217
227
for h : idx in [:lines.size] do
@@ -221,9 +231,13 @@ def trailingWhitespaceLinter : TextbasedLinter := fun lines ↦ Id.run do
221
231
fixedLines := fixedLines.set idx line.trimRight
222
232
return (errors, if errors.size > 0 then some fixedLines.toArray else none)
223
233
224
-
225
234
/-- Lint a collection of input strings for a semicolon preceded by a space. -/
226
- def semicolonLinter : TextbasedLinter := fun lines ↦ Id.run do
235
+ register_option linter.whitespaceBeforeSemicolon : Bool := { defValue := true }
236
+
237
+ @[inherit_doc linter.whitespaceBeforeSemicolon]
238
+ def semicolonLinter : TextbasedLinter := fun opts lines ↦ Id.run do
239
+ unless getLinterValue linter.whitespaceBeforeSemicolon opts do return (#[], none)
240
+
227
241
let mut errors := Array.mkEmpty 0
228
242
let mut fixedLines := lines
229
243
for h : idx in [:lines.size] do
@@ -256,7 +270,7 @@ def allLinters : Array TextbasedLinter := #[
256
270
Return a list of all unexpected errors, and, if some errors could be fixed automatically,
257
271
the collection of all lines with every automatic fix applied.
258
272
`exceptions` are any pre-existing style exceptions for this file. -/
259
- def lintFile (path : FilePath) (exceptions : Array ErrorContext) :
273
+ def lintFile (opts : Lean.Options) ( path : FilePath) (exceptions : Array ErrorContext) :
260
274
IO (Array ErrorContext × Option (Array String)) := do
261
275
let mut errors := #[]
262
276
-- Whether any changes were made by auto-fixes.
@@ -280,7 +294,7 @@ def lintFile (path : FilePath) (exceptions : Array ErrorContext) :
280
294
let mut changed := lines
281
295
282
296
for lint in allLinters do
283
- let (err, changes) := lint changed
297
+ let (err, changes) := lint opts changed
284
298
allOutput := allOutput.append (Array.map (fun (e, n) ↦ #[(ErrorContext.mk e n path)]) err)
285
299
-- TODO: auto-fixes do not take style exceptions into account
286
300
if let some c := changes then
@@ -291,52 +305,65 @@ def lintFile (path : FilePath) (exceptions : Array ErrorContext) :
291
305
(allOutput.flatten.filter (fun e ↦ (e.find?_comparable exceptions).isNone))
292
306
return (errors, if changes_made then some changed else none)
293
307
308
+ /-- Enables the old Python-based style linters. -/
309
+ register_option linter.pythonStyle : Bool := { defValue := true }
310
+
294
311
/-- Lint a collection of modules for style violations.
295
312
Print formatted errors for all unexpected style violations to standard output;
296
313
correct automatically fixable style errors if configured so.
297
314
Return the number of files which had new style errors.
315
+ `opts` contains the options defined in the Lakefile, determining which linters to enable.
298
316
`nolints` is a list of style exceptions to take into account.
299
317
`moduleNames` are the names of all the modules to lint,
300
318
`mode` specifies what kind of output this script should produce,
301
319
`fix` configures whether fixable errors should be corrected in-place. -/
302
- def lintModules (nolints : Array String) (moduleNames : Array Lean.Name) (style : ErrorFormat )
303
- (fix : Bool) : IO UInt32 := do
320
+ def lintModules (opts : Lean.Options) ( nolints : Array String) (moduleNames : Array Lean.Name)
321
+ (style : ErrorFormat) ( fix : Bool) : IO UInt32 := do
304
322
let styleExceptions := parseStyleExceptions nolints
305
323
let mut numberErrorFiles : UInt32 := 0
306
324
let mut allUnexpectedErrors := #[]
307
325
for module in moduleNames do
308
326
-- Convert the module name to a file name, then lint that file.
309
327
let path := mkFilePath (module.components.map toString)|>.addExtension "lean"
310
328
311
- let (errors, changed) := ← lintFile path styleExceptions
329
+ let (errors, changed) := ← lintFile opts path styleExceptions
312
330
if let some c := changed then
313
331
if fix then
314
332
let _ := ← IO.FS.writeFile path ("\n " .intercalate c.toList)
315
333
if errors.size > 0 then
316
334
allUnexpectedErrors := allUnexpectedErrors.append errors
317
335
numberErrorFiles := numberErrorFiles + 1
318
336
319
- -- Run the remaining python linters. It is easier to just run on all files.
320
- -- If this poses an issue, I can either filter the output
321
- -- or wait until lint-style.py is fully rewritten in Lean.
322
- let args := if fix then #["--fix" ] else #[]
323
- let output ← IO.Process.output { cmd := "./scripts/print-style-errors.sh" , args := args }
324
- if output.exitCode != 0 then
325
- numberErrorFiles := numberErrorFiles + 1
326
- IO.eprintln s! "error: `print-style-error.sh` exited with code { output.exitCode} "
327
- IO.eprint output.stderr
328
- else if output.stdout != "" then
329
- numberErrorFiles := numberErrorFiles + 1
330
- IO.eprint output.stdout
337
+ -- Passing Lean options to Python files seems like a lot of work for something we want to
338
+ -- run entirely inside of Lean in the end anyway.
339
+ -- So for now, we enable/disable all of them with a single switch.
340
+ if getLinterValue linter.pythonStyle opts then
341
+ -- Run the remaining python linters. It is easier to just run on all files.
342
+ -- If this poses an issue, I can either filter the output
343
+ -- or wait until lint-style.py is fully rewritten in Lean.
344
+ let args := if fix then #["--fix" ] else #[]
345
+ let output ← IO.Process.output { cmd := "./scripts/print-style-errors.sh" , args := args }
346
+ if output.exitCode != 0 then
347
+ numberErrorFiles := numberErrorFiles + 1
348
+ IO.eprintln s! "error: `print-style-error.sh` exited with code { output.exitCode} "
349
+ IO.eprint output.stderr
350
+ else if output.stdout != "" then
351
+ numberErrorFiles := numberErrorFiles + 1
352
+ IO.eprint output.stdout
331
353
formatErrors allUnexpectedErrors style
332
354
if allUnexpectedErrors.size > 0 then
333
355
IO.eprintln s! "error: found { allUnexpectedErrors.size} new style error(s)"
334
356
return numberErrorFiles
335
357
358
+ /-- Verify that all modules are named in `UpperCamelCase` -/
359
+ register_option linter.modulesUpperCamelCase : Bool := { defValue := true }
360
+
336
361
/-- Verifies that all modules in `modules` are named in `UpperCamelCase`
337
362
(except for explicitly discussed exceptions, which are hard-coded here).
338
363
Return the number of modules violating this. -/
339
- def modulesNotUpperCamelCase (modules : Array Lean.Name) : IO Nat := do
364
+ def modulesNotUpperCamelCase (opts : Lean.Options) (modules : Array Lean.Name) : IO Nat := do
365
+ unless getLinterValue linter.modulesUpperCamelCase opts do return 0
366
+
340
367
-- Exceptions to this list should be discussed on zulip!
341
368
let exceptions := [
342
369
`Mathlib.Analysis.CStarAlgebra.lpSpace,
0 commit comments