|
| 1 | +%%============================================================================== |
| 2 | +%% Compiler diagnostics |
| 3 | +%%============================================================================== |
| 4 | + |
| 5 | +-module(els_sheldon_diagnostics). |
| 6 | + |
| 7 | +%%============================================================================== |
| 8 | +%% Behaviours |
| 9 | +%%============================================================================== |
| 10 | + |
| 11 | +-behaviour(els_diagnostics). |
| 12 | + |
| 13 | +%%============================================================================== |
| 14 | +%% Exports |
| 15 | +%%============================================================================== |
| 16 | + |
| 17 | +-export([ is_default/0 |
| 18 | + , run/1 |
| 19 | + , source/0 |
| 20 | + ]). |
| 21 | + |
| 22 | +%%============================================================================== |
| 23 | +%% Includes |
| 24 | +%%============================================================================== |
| 25 | + |
| 26 | +-include("els_lsp.hrl"). |
| 27 | +-include_lib("kernel/include/logger.hrl"). |
| 28 | + |
| 29 | +%%============================================================================== |
| 30 | +%% Callback Functions |
| 31 | +%%============================================================================== |
| 32 | + |
| 33 | +-spec is_default() -> boolean(). |
| 34 | +is_default() -> |
| 35 | + false. |
| 36 | + |
| 37 | +-spec run(uri()) -> [els_diagnostics:diagnostic()]. |
| 38 | +run(Uri) -> |
| 39 | + case els_utils:project_relative(Uri) of |
| 40 | + {error, not_relative} -> []; |
| 41 | + RelFile -> |
| 42 | + try |
| 43 | + RegEx = "[_@./#&+-=*]", |
| 44 | + Mod = rebar3_sheldon_ast, |
| 45 | + Mod:spellcheck([RelFile], RegEx) |
| 46 | + of |
| 47 | + [] -> []; |
| 48 | + Problems -> format_diagnostics(Problems) |
| 49 | + catch _:Err -> |
| 50 | + ?LOG_WARNING("Sheldon error.[Err=~p] ", [Err]), |
| 51 | + [] |
| 52 | + end |
| 53 | + end. |
| 54 | + |
| 55 | +-spec source() -> binary(). |
| 56 | +source() -> |
| 57 | + <<"Sheldon">>. |
| 58 | + |
| 59 | +%%============================================================================== |
| 60 | +%% Internal Functions |
| 61 | +%%============================================================================== |
| 62 | + |
| 63 | +-spec format_diagnostics(any()) -> [map()]. |
| 64 | +format_diagnostics(Data) -> |
| 65 | + R = format_rules(Data), |
| 66 | + lists:flatten(R). |
| 67 | + |
| 68 | +-spec format_rules([any()]) -> [[map()]]. |
| 69 | +format_rules([]) -> |
| 70 | + []; |
| 71 | +format_rules([#{reason := #{misspelled_words := Miss}} = Data | EItems]) -> |
| 72 | + ItemDiags = format_item(Miss, Data), |
| 73 | + [lists:flatten(ItemDiags) | format_rules(EItems)]. |
| 74 | + |
| 75 | +-spec format_item([any()], map()) -> [[map()]]. |
| 76 | +format_item([#{candidates := [], word := Word} | Items], Data) -> |
| 77 | + #{line := Line, type := Type} = Data, |
| 78 | + Msg = format_text("The word ~p in ~p is unknown.", [Word, Type]), |
| 79 | + Diagnostic = diagnostic(Msg, Line, ?DIAGNOSTIC_WARNING), |
| 80 | + [Diagnostic | format_item(Items, Data)]; |
| 81 | +format_item([#{candidates := Candidates, word := Word} | Items], Data) -> |
| 82 | + #{line := Line, type := Type} = Data, |
| 83 | + FormatCandidates = format_sheldon_candidates(Candidates, []), |
| 84 | + Text = "The word ~p in ~p is unknown. Maybe you wanted to use ~ts?", |
| 85 | + Msg = format_text(Text, [Word, Type, FormatCandidates]), |
| 86 | + Diagnostic = diagnostic(Msg, Line, ?DIAGNOSTIC_WARNING), |
| 87 | + [Diagnostic | format_item(Items, Data)]; |
| 88 | +format_item([], _) -> |
| 89 | + []. |
| 90 | + |
| 91 | +-spec diagnostic( any(), integer(), els_diagnostics:severity()) -> [map()]. |
| 92 | +diagnostic(Msg, Ln, Severity) -> |
| 93 | + Range = els_protocol:range(#{from => {Ln, 1}, to => {Ln + 1, 1}}), |
| 94 | + Message = els_utils:to_binary(Msg), |
| 95 | + [#{ range => Range |
| 96 | + , severity => Severity |
| 97 | + , code => spellcheck |
| 98 | + , source => source() |
| 99 | + , message => Message |
| 100 | + , relatedInformation => [] |
| 101 | + }]. |
| 102 | + |
| 103 | +-spec format_sheldon_candidates([any()], [[[any()] | char()]]) -> list(). |
| 104 | +format_sheldon_candidates([], Acc) -> |
| 105 | + Acc; |
| 106 | +format_sheldon_candidates([Candidate], Acc) -> |
| 107 | + [Acc, format_text("~p", [Candidate])]; |
| 108 | +format_sheldon_candidates([Candidate | T], Acc) -> |
| 109 | + format_sheldon_candidates(T, [Acc, format_text("~p or ", [Candidate])]). |
| 110 | + |
| 111 | +-spec format_text(string(), list()) -> string(). |
| 112 | +format_text(Text, Args) -> |
| 113 | + Formatted = io_lib:format(Text, Args), |
| 114 | + unicode:characters_to_list(Formatted). |
0 commit comments