Page MenuHomePhabricator

D11458.diff
No OneTemporary

D11458.diff

diff --git a/src/lint/linter/ArcanistTextLinter.php b/src/lint/linter/ArcanistTextLinter.php
--- a/src/lint/linter/ArcanistTextLinter.php
+++ b/src/lint/linter/ArcanistTextLinter.php
@@ -5,15 +5,16 @@
*/
final class ArcanistTextLinter extends ArcanistLinter {
- const LINT_DOS_NEWLINE = 1;
- const LINT_TAB_LITERAL = 2;
+ const LINT_END_OF_LINE = 1;
+ const LINT_INDENT_STYLE = 2;
const LINT_LINE_WRAP = 3;
const LINT_EOF_NEWLINE = 4;
- const LINT_BAD_CHARSET = 5;
+ const LINT_CHARSET = 5;
const LINT_TRAILING_WHITESPACE = 6;
const LINT_BOF_WHITESPACE = 8;
const LINT_EOF_WHITESPACE = 9;
+ private $editorconfig;
private $maxLineLength = 80;
public function getInfoName() {
@@ -23,7 +24,7 @@
public function getInfoDescription() {
return pht(
'Enforces basic text rules like line length, character encoding, '.
- 'and trailing whitespace.');
+ 'and trailing whitespace. Supports EditorConfig configuration.');
}
public function getLinterPriority() {
@@ -36,7 +37,9 @@
'type' => 'optional int',
'help' => pht(
'Adjust the maximum line length before a warning is raised. By '.
- 'default, a warning is raised on lines exceeding 80 characters.'),
+ 'default, a warning is raised on lines exceeding 80 characters. '.
+ 'This is deprecated and you should use an EditorConfig file to '.
+ 'configure this value.'),
),
);
@@ -51,6 +54,9 @@
public function setLinterConfigurationValue($key, $value) {
switch ($key) {
case 'text.max-line-length':
+ phutil_deprecated(
+ $key,
+ 'You should specify this configuration in an EditorConfig file.');
$this->setMaxLineLength($value);
return;
}
@@ -69,25 +75,30 @@
public function getLintSeverityMap() {
return array(
self::LINT_LINE_WRAP => ArcanistLintSeverity::SEVERITY_WARNING,
- self::LINT_TRAILING_WHITESPACE => ArcanistLintSeverity::SEVERITY_AUTOFIX,
- self::LINT_BOF_WHITESPACE => ArcanistLintSeverity::SEVERITY_AUTOFIX,
- self::LINT_EOF_WHITESPACE => ArcanistLintSeverity::SEVERITY_AUTOFIX,
+ self::LINT_TRAILING_WHITESPACE => ArcanistLintSeverity::SEVERITY_ADVICE,
+ self::LINT_BOF_WHITESPACE => ArcanistLintSeverity::SEVERITY_ADVICE,
+ self::LINT_EOF_WHITESPACE => ArcanistLintSeverity::SEVERITY_ADVICE,
);
}
public function getLintNameMap() {
return array(
- self::LINT_DOS_NEWLINE => pht('DOS Newlines'),
- self::LINT_TAB_LITERAL => pht('Tab Literal'),
+ self::LINT_END_OF_LINE => pht('End Of Line'),
+ self::LINT_INDENT_STYLE => pht('Indent Style'),
self::LINT_LINE_WRAP => pht('Line Too Long'),
self::LINT_EOF_NEWLINE => pht('File Does Not End in Newline'),
- self::LINT_BAD_CHARSET => pht('Bad Charset'),
+ self::LINT_CHARSET => pht('Bad Charset'),
self::LINT_TRAILING_WHITESPACE => pht('Trailing Whitespace'),
self::LINT_BOF_WHITESPACE => pht('Leading Whitespace at BOF'),
self::LINT_EOF_WHITESPACE => pht('Trailing Whitespace at EOF'),
);
}
+ public function willLintPaths(array $paths) {
+ $root = $this->getEngine()->getWorkingCopy()->getProjectRoot();
+ $this->editorconfig = new PhutilEditorConfig($root);
+ }
+
public function lintPath($path) {
if (!strlen($this->getData($path))) {
// If the file is empty, don't bother; particularly, don't require
@@ -95,8 +106,8 @@
return;
}
- $this->lintNewlines($path);
- $this->lintTabs($path);
+ $this->lintEndOfLine($path);
+ $this->lintIndentStyle($path);
if ($this->didStopAllLinters()) {
return;
@@ -116,39 +127,123 @@
$this->lintEOFWhitespace($path);
}
- protected function lintNewlines($path) {
+ private function lintEndOfLine($path) {
+ switch ($this->getEditorConfig($path, PhutilEditorConfig::END_OF_LINE)) {
+ case 'lf':
+ $search = "\r";
+ $replace = array(
+ "\r\n" => "\n",
+ );
+ break;
+
+ case 'cr':
+ $search = "\n";
+ $replace = array(
+ "\r\n" => "\r",
+ );
+ break;
+
+ case 'lfcr':
+ $search = "\n";
+ $replace = array(
+ "\r\n" => "\n\r",
+ );
+ break;
+
+ default:
+ return;
+ }
+
$data = $this->getData($path);
- $pos = strpos($this->getData($path), "\r");
+ $pos = strpos($this->getData($path), $search);
if ($pos !== false) {
$this->raiseLintAtOffset(
0,
- self::LINT_DOS_NEWLINE,
- pht('You must use ONLY Unix linebreaks ("%s") in source code.', '\n'),
+ self::LINT_END_OF_LINE,
+ pht('Invalid end-of-line character(s).'),
$data,
- str_replace("\r\n", "\n", $data));
+ str_replace(array_keys($replace), array_values($replace), $data));
- if ($this->isMessageEnabled(self::LINT_DOS_NEWLINE)) {
+ if ($this->isMessageEnabled(self::LINT_END_OF_LINE)) {
$this->stopAllLinters();
}
}
}
- protected function lintTabs($path) {
+ private function lintIndentStyle($path) {
+ switch ($this->getEditorConfig($path, PhutilEditorConfig::INDENT_STYLE)) {
+ case 'space':
+ break;
+
+ case 'tab':
+ // TODO: Can we do anything here?
+ return;
+
+ default:
+ return;
+ }
+
$pos = strpos($this->getData($path), "\t");
if ($pos !== false) {
$this->raiseLintAtOffset(
$pos,
- self::LINT_TAB_LITERAL,
+ self::LINT_INDENT_STYLE,
pht('Configure your editor to use spaces for indentation.'),
"\t");
}
}
- protected function lintLineLength($path) {
- $lines = explode("\n", $this->getData($path));
+ private function lintCharset($path) {
+ switch ($this->getEditorConfig($path, PhutilEditorConfig::CHARSET)) {
+ case 'latin1':
+ $charset = 'ISO-8859-1';
+ break;
+
+ case 'utf-8':
+ case 'utf-8-bom':
+ // TODO: Do we really care about the BOM?
+ $charset = 'UTF-8';
+ break;
+
+ case 'utf-16be':
+ $charset = 'UTF-16BE';
+ break;
+
+ case 'utf-16le':
+ $charset = 'UTF-16LE';
+ break;
+
+ default:
+ return;
+ }
+
+ $data = $this->getData($path);
+
+ if (mb_check_encoding($data, $charset)) {
+ return;
+ }
+
+ $this->raiseLintAtPath(
+ self::LINT_CHARSET,
+ pht('Invalid characters in charset.'));
+
+ if ($this->isMessageEnabled(self::LINT_BAD_CHARSET)) {
+ $this->stopAllLinters();
+ }
+ }
+
+ private function lintLineLength($path) {
+ $lines = phutil_split_lines($this->getData($path), false);
+ $width = $this->getEditorConfig(
+ $path,
+ PhutilEditorConfig::LINE_LENGTH,
+ $this->maxLineLength);
+
+ if (!$width) {
+ return;
+ }
- $width = $this->maxLineLength;
foreach ($lines as $line_idx => $line) {
if (strlen($line) > $width) {
$this->raiseLintAtLine(
@@ -165,53 +260,47 @@
}
}
- protected function lintEOFNewline($path) {
- $data = $this->getData($path);
- if (!strlen($data) || $data[strlen($data) - 1] != "\n") {
- $this->raiseLintAtOffset(
- strlen($data),
- self::LINT_EOF_NEWLINE,
- pht('Files must end in a newline.'),
- '',
- "\n");
+ private function lintEOFNewline($path) {
+ $config = $this->getEditorConfig(
+ $path,
+ PhutilEditorConfig::FINAL_NEWLINE,
+ false);
+
+ if (!$config) {
+ return;
}
- }
- protected function lintCharset($path) {
$data = $this->getData($path);
-
$matches = null;
- $bad = '[^\x09\x0A\x20-\x7E]';
- $preg = preg_match_all(
- "/{$bad}(.*{$bad})?/",
+ $preg = preg_match(
+ '/(\n|\r|\r\n)$/',
$data,
$matches,
PREG_OFFSET_CAPTURE);
- if (!$preg) {
+ if ($preg) {
return;
}
- foreach ($matches[0] as $match) {
- list($string, $offset) = $match;
- $this->raiseLintAtOffset(
- $offset,
- self::LINT_BAD_CHARSET,
- pht(
- 'Source code should contain only ASCII bytes with ordinal '.
- 'decimal values between 32 and 126 inclusive, plus linefeed. '.
- 'Do not use UTF-8 or other multibyte charsets.'),
- $string);
- }
+ $this->raiseLintAtOffset(
+ strlen($data),
+ self::LINT_EOF_NEWLINE,
+ pht('Files must end in a newline.'),
+ '',
+ $this->getEndOfLineCharacters($path));
+ }
- if ($this->isMessageEnabled(self::LINT_BAD_CHARSET)) {
- $this->stopAllLinters();
+ private function lintTrailingWhitespace($path) {
+ $config = $this->getEditorConfig(
+ $path,
+ PhutilEditorConfig::TRAILING_WHITESPACE,
+ false);
+
+ if (!$config) {
+ return;
}
- }
- protected function lintTrailingWhitespace($path) {
$data = $this->getData($path);
-
$matches = null;
$preg = preg_match_all(
'/ +$/m',
@@ -237,9 +326,17 @@
}
}
- protected function lintBOFWhitespace($path) {
- $data = $this->getData($path);
+ private function lintBOFWhitespace($path) {
+ $config = $this->getEditorConfig(
+ $path,
+ PhutilEditorConfig::TRAILING_WHITESPACE,
+ false);
+ if (!$config) {
+ return;
+ }
+
+ $data = $this->getData($path);
$matches = null;
$preg = preg_match(
'/^\s*\n/',
@@ -262,9 +359,17 @@
'');
}
- protected function lintEOFWhitespace($path) {
- $data = $this->getData($path);
+ private function lintEOFWhitespace($path) {
+ $config = $this->getEditorConfig(
+ $path,
+ PhutilEditorConfig::TRAILING_WHITESPACE,
+ false);
+
+ if (!$config) {
+ return;
+ }
+ $data = $this->getData($path);
$matches = null;
$preg = preg_match(
'/(?<=\n)\s+$/',
@@ -287,4 +392,45 @@
'');
}
+ /**
+ * Retrieve a value from the EditorConfig files.
+ *
+ * This function delegates handling of the EditorConfig file(s) to
+ * @{class:PhutilEditorConfigParser}.
+ *
+ * @param string The path of the file.
+ * @param string The name of the EditorConfig property.
+ * @param mixed Default value.
+ * @return mixed
+ */
+ protected function getEditorConfig($path, $property, $default = null) {
+ if (!$this->editorconfig) {
+ throw new PhutilInvalidStateException('willLintPaths');
+ }
+
+ $path = $this->getEngine()->getFilePathOnDisk($path);
+ $value = $this->editorconfig->getProperty($path, $property);
+
+ return coalesce($value, $default);
+ }
+
+ /**
+ * Return the end-of-line character(s) for a given path.
+ *
+ * @param string The path to the file.
+ * @return string|null
+ */
+ protected function getEndOfLineCharacters($path) {
+ switch ($this->getEditorConfig($path, PhutilEditorConfig::END_OF_LINE)) {
+ case 'lf':
+ return "\n";
+
+ case 'cr':
+ return "\r";
+
+ case 'lfcr':
+ return "\r\n";
+ }
+ }
+
}

File Metadata

Mime Type
text/plain
Expires
Thu, May 9, 8:01 PM (3 w, 1 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6276264
Default Alt Text
D11458.diff (11 KB)

Event Timeline