~ubuntu-branches/ubuntu/wily/phabricator/wily

« back to all changes in this revision

Viewing changes to src/lint/renderer/ArcanistConsoleLintRenderer.php

  • Committer: Package Import Robot
  • Author(s): Richard Sellam
  • Date: 2014-11-01 23:20:06 UTC
  • mto: This revision was merged to the branch mainline in revision 4.
  • Revision ID: package-import@ubuntu.com-20141101232006-mvlnp0cil67tsboe
Tags: upstream-0~git20141101/arcanist
Import upstream version 0~git20141101, component arcanist

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
<?php
 
2
 
 
3
/**
 
4
 * Shows lint messages to the user.
 
5
 */
 
6
final class ArcanistConsoleLintRenderer extends ArcanistLintRenderer {
 
7
 
 
8
  private $showAutofixPatches = false;
 
9
 
 
10
  public function setShowAutofixPatches($show_autofix_patches) {
 
11
    $this->showAutofixPatches = $show_autofix_patches;
 
12
    return $this;
 
13
  }
 
14
 
 
15
  public function renderLintResult(ArcanistLintResult $result) {
 
16
    $messages = $result->getMessages();
 
17
    $path = $result->getPath();
 
18
 
 
19
    $lines = explode("\n", $result->getData());
 
20
 
 
21
    $text = array();
 
22
 
 
23
    foreach ($messages as $message) {
 
24
      if (!$this->showAutofixPatches && $message->isAutofix()) {
 
25
        continue;
 
26
      }
 
27
 
 
28
      if ($message->isError()) {
 
29
        $color = 'red';
 
30
      } else {
 
31
        $color = 'yellow';
 
32
      }
 
33
 
 
34
      $severity = ArcanistLintSeverity::getStringForSeverity(
 
35
        $message->getSeverity());
 
36
      $code = $message->getCode();
 
37
      $name = $message->getName();
 
38
      $description = $message->getDescription();
 
39
 
 
40
      if ($message->getOtherLocations()) {
 
41
        $locations = array();
 
42
        foreach ($message->getOtherLocations() as $location) {
 
43
          $locations[] =
 
44
            idx($location, 'path', $path).
 
45
            (!empty($location['line']) ? ":{$location['line']}" : '');
 
46
        }
 
47
        $description .= "\nOther locations: ".implode(', ', $locations);
 
48
      }
 
49
 
 
50
      $text[] = phutil_console_format(
 
51
        "  **<bg:{$color}> %s </bg>** (%s) __%s__\n%s\n",
 
52
        $severity,
 
53
        $code,
 
54
        $name,
 
55
        phutil_console_wrap($description, 4));
 
56
 
 
57
      if ($message->hasFileContext()) {
 
58
        $text[] = $this->renderContext($message, $lines);
 
59
      }
 
60
    }
 
61
 
 
62
    if ($text) {
 
63
      $prefix = phutil_console_format("**>>>** Lint for __%s__:\n\n\n", $path);
 
64
      return $prefix.implode("\n", $text);
 
65
    } else {
 
66
      return null;
 
67
    }
 
68
  }
 
69
 
 
70
  protected function renderContext(
 
71
    ArcanistLintMessage $message,
 
72
    array $line_data) {
 
73
 
 
74
    $lines_of_context = 3;
 
75
    $out = array();
 
76
 
 
77
    $num_lines = count($line_data);
 
78
     // make line numbers line up with array indexes
 
79
    array_unshift($line_data, '');
 
80
 
 
81
    $line_num = min($message->getLine(), $num_lines);
 
82
    $line_num = max(1, $line_num);
 
83
 
 
84
    // Print out preceding context before the impacted region.
 
85
    $cursor = max(1, $line_num - $lines_of_context);
 
86
    for (; $cursor < $line_num; $cursor++) {
 
87
      $out[] = $this->renderLine($cursor, $line_data[$cursor]);
 
88
    }
 
89
 
 
90
    $text = $message->getOriginalText();
 
91
    $start = $message->getChar() - 1;
 
92
    $patch = '';
 
93
    // Refine original and replacement text to eliminate start and end in common
 
94
    if ($message->isPatchable()) {
 
95
      $patch = $message->getReplacementText();
 
96
      $text_strlen = strlen($text);
 
97
      $patch_strlen = strlen($patch);
 
98
      $min_length = min($text_strlen, $patch_strlen);
 
99
 
 
100
      $same_at_front = 0;
 
101
      for ($ii = 0; $ii < $min_length; $ii++) {
 
102
        if ($text[$ii] !== $patch[$ii]) {
 
103
          break;
 
104
        }
 
105
        $same_at_front++;
 
106
        $start++;
 
107
        if ($text[$ii] == "\n") {
 
108
          $out[] = $this->renderLine($cursor, $line_data[$cursor]);
 
109
          $cursor++;
 
110
          $start = 0;
 
111
          $line_num++;
 
112
        }
 
113
      }
 
114
      // deal with shorter string '     ' longer string '     a     '
 
115
      $min_length -= $same_at_front;
 
116
 
 
117
      // And check the end of the string
 
118
      $same_at_end = 0;
 
119
      for ($ii = 1; $ii <= $min_length; $ii++) {
 
120
        if ($text[$text_strlen - $ii] !== $patch[$patch_strlen - $ii]) {
 
121
          break;
 
122
        }
 
123
        $same_at_end++;
 
124
      }
 
125
 
 
126
      $text = substr(
 
127
        $text,
 
128
        $same_at_front,
 
129
        $text_strlen - $same_at_end - $same_at_front);
 
130
      $patch = substr(
 
131
        $patch,
 
132
        $same_at_front,
 
133
        $patch_strlen - $same_at_end - $same_at_front);
 
134
    }
 
135
    // Print out the impacted region itself.
 
136
    $diff = $message->isPatchable() ? '-' : null;
 
137
 
 
138
    $text_lines = explode("\n", $text);
 
139
    $text_length = count($text_lines);
 
140
 
 
141
    $intraline = ($text != '' || $start || !preg_match('/\n$/', $patch));
 
142
 
 
143
    if ($intraline) {
 
144
      for (; $cursor < $line_num + $text_length; $cursor++) {
 
145
        $chevron = ($cursor == $line_num);
 
146
        // We may not have any data if, e.g., the old file does not exist.
 
147
        $data = idx($line_data, $cursor, null);
 
148
 
 
149
        // Highlight the problem substring.
 
150
        $text_line = $text_lines[$cursor - $line_num];
 
151
        if (strlen($text_line)) {
 
152
          $data = substr_replace(
 
153
            $data,
 
154
            phutil_console_format('##%s##', $text_line),
 
155
            ($cursor == $line_num ? $start : 0),
 
156
            strlen($text_line));
 
157
        }
 
158
 
 
159
        $out[] = $this->renderLine($cursor, $data, $chevron, $diff);
 
160
      }
 
161
    }
 
162
 
 
163
    // Print out replacement text.
 
164
    if ($message->isPatchable()) {
 
165
      // Strip trailing newlines, since "explode" will create an extra patch
 
166
      // line for these.
 
167
      if (strlen($patch) && ($patch[strlen($patch) - 1] === "\n")) {
 
168
        $patch = substr($patch, 0, -1);
 
169
      }
 
170
      $patch_lines = explode("\n", $patch);
 
171
      $patch_length = count($patch_lines);
 
172
 
 
173
      $patch_line = $patch_lines[0];
 
174
 
 
175
      $len = isset($text_lines[0]) ? strlen($text_lines[0]) : 0;
 
176
 
 
177
      $patched = phutil_console_format('##%s##', $patch_line);
 
178
 
 
179
      if ($intraline) {
 
180
        $patched = substr_replace(
 
181
          $line_data[$line_num],
 
182
          $patched,
 
183
          $start,
 
184
          $len);
 
185
      }
 
186
 
 
187
      $out[] = $this->renderLine(null, $patched, false, '+');
 
188
 
 
189
      foreach (array_slice($patch_lines, 1) as $patch_line) {
 
190
        $out[] = $this->renderLine(
 
191
          null,
 
192
          phutil_console_format('##%s##', $patch_line), false, '+');
 
193
      }
 
194
    }
 
195
 
 
196
    $end = min($num_lines, $cursor + $lines_of_context);
 
197
    for (; $cursor < $end; $cursor++) {
 
198
      // If there is no original text, we didn't print out a chevron or any
 
199
      // highlighted text above, so print it out here. This allows messages
 
200
      // which don't have any original/replacement information to still
 
201
      // render with indicator chevrons.
 
202
      if ($text || $message->isPatchable()) {
 
203
        $chevron = false;
 
204
      } else {
 
205
        $chevron = ($cursor == $line_num);
 
206
      }
 
207
      $out[] = $this->renderLine($cursor, $line_data[$cursor], $chevron);
 
208
 
 
209
      // With original text, we'll render the text highlighted above. If the
 
210
      // lint message only has a line/char offset there's nothing to
 
211
      // highlight, so print out a caret on the next line instead.
 
212
      if ($chevron && $message->getChar()) {
 
213
        $out[] = $this->renderCaret($message->getChar());
 
214
      }
 
215
    }
 
216
    $out[] = null;
 
217
 
 
218
    return implode("\n", $out);
 
219
  }
 
220
 
 
221
  private function renderCaret($pos) {
 
222
    return str_repeat(' ', 16 + $pos).'^';
 
223
  }
 
224
 
 
225
  protected function renderLine($line, $data, $chevron = false, $diff = null) {
 
226
    $chevron = $chevron ? '>>>' : '';
 
227
    return sprintf(
 
228
      '    %3s %1s %6s %s',
 
229
      $chevron,
 
230
      $diff,
 
231
      $line,
 
232
      $data);
 
233
  }
 
234
 
 
235
  public function renderOkayResult() {
 
236
    return phutil_console_format(
 
237
      "<bg:green>** OKAY **</bg> No lint warnings.\n");
 
238
  }
 
239
 
 
240
}