Skip to content

Commit 82d0204

Browse files
committed
feat(Linter): combinators for linter option boilerplate (leanprover-community#31133)
Provides simple combinators `whenLinterOption` and `whenNotLinterOption` to parallel `whenPPOption` and `whenNotPPOption`, and bundles `withSetOptionIn` and `whenLinterOption` into `whenLinterActivated`. Currently, a typical linter action uses ```lean run := withSetOptionIn fun stx => do unless getLinterValue linter.foo (← getLinterOptions) do return ... ``` This allows us to simply write ```lean run := whenLinterActivated linter.foo fun stx => do ... ``` Using these combinators in Mathlib's linters is left to a subsequent PR (leanprover-community#31134). Since this is a utility used in basic linters, including the header linter, we exclude it from `lint-style`. Co-authored-by: thorimur <thomasmurrills@gmail.com>
1 parent e1d6e8b commit 82d0204

3 files changed

Lines changed: 75 additions & 0 deletions

File tree

Mathlib.lean

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4459,6 +4459,7 @@ public import Mathlib.Lean.Expr.Rat
44594459
public import Mathlib.Lean.Expr.ReplaceRec
44604460
public import Mathlib.Lean.GoalsLocation
44614461
public import Mathlib.Lean.Json
4462+
public import Mathlib.Lean.Linter
44624463
public import Mathlib.Lean.LocalContext
44634464
public import Mathlib.Lean.Message
44644465
public import Mathlib.Lean.Meta

Mathlib/Init.lean

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ module -- shake: keep-all, shake: keep-downstream
22

33
public import Lean.Linter.Sets -- for the definition of linter sets
44
public import Lean.LibrarySuggestions.Default -- for `+suggestions` modes in tactics
5+
public import Mathlib.Lean.Linter -- linter utilities; will be transitively imported in #31134
56
public import Mathlib.Tactic.Linter.DeprecatedSyntaxLinter
67
public import Mathlib.Tactic.Linter.DirectoryDependency
78
public import Mathlib.Tactic.Linter.DocPrime

Mathlib/Lean/Linter.lean

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/-
2+
Copyright (c) 2025 Thomas R. Murrills. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: Thomas R. Murrills
5+
-/
6+
module
7+
8+
public meta import Lean.Elab.Command
9+
public meta import Lean.Linter.Basic
10+
-- Import this linter explicitly to ensure that
11+
-- this file has a valid copyright header and module docstring.
12+
import Mathlib.Tactic.Linter.Header
13+
14+
/-!
15+
# Additional utilities and boilerplate for the `Linter` API
16+
-/
17+
18+
public meta section
19+
20+
open Lean Elab Command Linter
21+
22+
namespace Lean.Linter
23+
24+
variable {m : TypeType} [Monad m] [MonadOptions m] [MonadEnv m]
25+
26+
/--
27+
Runs a `CommandElabM` action when the provided linter option is `true`.
28+
29+
This function assumes you have already called `withSetOptionIn`; use `whenLinterActivated`
30+
to do so automatically. At the start of linter code, `whenLinterActivated` should be preferred when
31+
possible.
32+
33+
Note: this definition is marked as `@[macro_inline]`, so it is okay to supply it with a linter
34+
option which has been registered in the same module.
35+
-/
36+
@[expose, macro_inline]
37+
def whenLinterOption (opt : Lean.Option Bool) (x : m Unit) : m Unit := do
38+
if getLinterValue opt (← getLinterOptions) then x
39+
40+
/--
41+
Runs a `CommandElabM` action when the provided linter option is `false`.
42+
43+
Note: this definition is marked as `@[macro_inline]`, so it is okay to supply it with a linter
44+
option which has been registered in the same module.
45+
-/
46+
@[expose, macro_inline]
47+
def whenNotLinterOption (opt : Lean.Option Bool) (x : m Unit) : m Unit := do
48+
unless getLinterValue opt (← getLinterOptions) do x
49+
50+
/--
51+
Processes `set_option ... in`s that wrap the input `stx`, then acts on the inner syntax with
52+
`x` after checking that the provided linter option is `true`.
53+
54+
If `breakOnError` is `true` (the default), avoids running the linter when errors are present.
55+
56+
This is typically used to start off linter code:
57+
```
58+
def myLinter : Linter where
59+
run := whenLinterActivated linter.myLinter fun stx ↦ do
60+
...
61+
```
62+
63+
Note: this definition is marked as `@[macro_inline]`, so it is okay to supply it with a linter
64+
option which has been registered in the same module.
65+
-/
66+
@[expose, macro_inline]
67+
def whenLinterActivated (opt : Lean.Option Bool) (x : CommandElab) (breakOnError := true) :
68+
CommandElab :=
69+
withSetOptionIn fun stx => whenLinterOption opt do
70+
unless ← pure breakOnError <&&> MonadLog.hasErrors do
71+
x stx
72+
73+
end Lean.Linter

0 commit comments

Comments
 (0)