default.ex (4120B)
1 defmodule Credo.CLI.Command.List.Output.Default do 2 @moduledoc false 3 4 alias Credo.CLI.Filename 5 alias Credo.CLI.Output 6 alias Credo.CLI.Output.Summary 7 alias Credo.CLI.Output.UI 8 alias Credo.Code.Scope 9 alias Credo.Issue 10 alias Credo.SourceFile 11 12 @indent 8 13 14 @doc "Called before the analysis is run." 15 def print_before_info(source_files, exec) do 16 UI.puts("") 17 18 case Enum.count(source_files) do 19 0 -> UI.puts("No files found!") 20 1 -> UI.puts("Checking 1 source file ...") 21 count -> UI.puts("Checking #{count} source files ...") 22 end 23 24 Output.print_skipped_checks(exec) 25 end 26 27 @doc "Called after the analysis has run." 28 def print_after_info(source_files, exec, time_load, time_run) do 29 term_width = Output.term_columns() 30 31 source_files 32 |> Enum.sort_by(& &1.filename) 33 |> Enum.each(&print_issues(&1, exec, term_width)) 34 35 source_files 36 |> Summary.print(exec, time_load, time_run) 37 end 38 39 defp print_issues( 40 %SourceFile{filename: filename} = source_file, 41 exec, 42 term_width 43 ) do 44 issues = Credo.Execution.get_issues(exec, filename) 45 46 issues 47 |> print_issues(filename, source_file, exec, term_width) 48 end 49 50 defp print_issues(issues, _filename, source_file, _exec, term_width) do 51 if issues |> Enum.any?() do 52 first_issue = issues |> List.first() 53 scope_name = Scope.mod_name(first_issue.scope) 54 color = Output.check_color(first_issue) 55 56 UI.puts() 57 58 [ 59 :bright, 60 "#{color}_background" |> String.to_atom(), 61 color, 62 " ", 63 Output.foreground_color(color), 64 :normal, 65 " #{scope_name}" |> String.pad_trailing(term_width - 1) 66 ] 67 |> UI.puts() 68 69 color 70 |> UI.edge() 71 |> UI.puts() 72 73 issues 74 |> Enum.sort_by(& &1.line_no) 75 |> Enum.each(&print_issue(&1, source_file, term_width)) 76 end 77 end 78 79 defp print_issue( 80 %Issue{ 81 check: check, 82 message: message, 83 filename: filename, 84 priority: priority 85 } = issue, 86 source_file, 87 term_width 88 ) do 89 outer_color = Output.check_color(issue) 90 inner_color = Output.issue_color(issue) 91 message_color = inner_color 92 filename_color = :default_color 93 94 tag_style = 95 if outer_color == inner_color do 96 :faint 97 else 98 :bright 99 end 100 101 [ 102 UI.edge(outer_color), 103 inner_color, 104 tag_style, 105 Output.check_tag(check.category), 106 " ", 107 priority |> Output.priority_arrow(), 108 :normal, 109 message_color, 110 " ", 111 message 112 ] 113 |> UI.puts() 114 115 [ 116 UI.edge(outer_color, @indent), 117 filename_color, 118 :faint, 119 filename |> to_string, 120 :default_color, 121 :faint, 122 Filename.pos_suffix(issue.line_no, issue.column), 123 :faint, 124 " (#{issue.scope})" 125 ] 126 |> UI.puts() 127 128 if issue.line_no do 129 print_issue_line_no(source_file, term_width, issue, outer_color, inner_color) 130 end 131 132 UI.puts_edge([outer_color, :faint], @indent) 133 end 134 135 defp print_issue_column(raw_line, line, issue, outer_color, inner_color) do 136 offset = String.length(raw_line) - String.length(line) 137 # column is one-based 138 x = max(issue.column - offset - 1, 0) 139 140 w = 141 if is_nil(issue.trigger) do 142 1 143 else 144 issue.trigger 145 |> to_string() 146 |> String.length() 147 end 148 149 [ 150 UI.edge([outer_color, :faint], @indent), 151 inner_color, 152 String.duplicate(" ", x), 153 :faint, 154 String.duplicate("^", w) 155 ] 156 |> UI.puts() 157 end 158 159 defp print_issue_line_no(source_file, term_width, issue, outer_color, inner_color) do 160 raw_line = SourceFile.line_at(source_file, issue.line_no) 161 line = String.trim(raw_line) 162 163 UI.puts_edge([outer_color, :faint]) 164 165 [ 166 UI.edge([outer_color, :faint]), 167 :cyan, 168 :faint, 169 String.duplicate(" ", @indent - 2), 170 UI.truncate(line, term_width - @indent) 171 ] 172 |> UI.puts() 173 174 if issue.column, do: print_issue_column(raw_line, line, issue, outer_color, inner_color) 175 end 176 end