Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F2896379
ArcanistTextLinter.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Advanced/Developer...
View Handle
View Hovercard
Size
7 KB
Referenced Files
None
Subscribers
None
ArcanistTextLinter.php
View Options
<?php
/**
* Enforces basic text file rules.
*/
final
class
ArcanistTextLinter
extends
ArcanistLinter
{
const
LINT_DOS_NEWLINE
=
1
;
const
LINT_TAB_LITERAL
=
2
;
const
LINT_LINE_WRAP
=
3
;
const
LINT_EOF_NEWLINE
=
4
;
const
LINT_BAD_CHARSET
=
5
;
const
LINT_TRAILING_WHITESPACE
=
6
;
const
LINT_BOF_WHITESPACE
=
8
;
const
LINT_EOF_WHITESPACE
=
9
;
const
LINT_EMPTY_FILE
=
10
;
private
$maxLineLength
=
80
;
public
function
getInfoName
(
)
{
return
pht
(
'Basic Text Linter'
)
;
}
public
function
getInfoDescription
(
)
{
return
pht
(
'Enforces basic text rules like line length, character encoding, '
.
'and trailing whitespace.'
)
;
}
public
function
getLinterPriority
(
)
{
return
0.5
;
}
public
function
getLinterConfigurationOptions
(
)
{
$options
=
array
(
'text.max-line-length'
=>
array
(
'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.'
)
,
)
,
)
;
return
$options
+
parent
::
getLinterConfigurationOptions
(
)
;
}
public
function
setMaxLineLength
(
$new_length
)
{
$this
->
maxLineLength
=
$new_length
;
return
$this
;
}
public
function
setLinterConfigurationValue
(
$key
,
$value
)
{
switch
(
$key
)
{
case
'text.max-line-length'
:
$this
->
setMaxLineLength
(
$value
)
;
return
;
}
return
parent
::
setLinterConfigurationValue
(
$key
,
$value
)
;
}
public
function
getLinterName
(
)
{
return
'TXT'
;
}
public
function
getLinterConfigurationName
(
)
{
return
'text'
;
}
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
,
)
;
}
public
function
getLintNameMap
(
)
{
return
array
(
self
::
LINT_DOS_NEWLINE
=>
pht
(
'DOS Newlines'
)
,
self
::
LINT_TAB_LITERAL
=>
pht
(
'Tab Literal'
)
,
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_TRAILING_WHITESPACE
=>
pht
(
'Trailing Whitespace'
)
,
self
::
LINT_BOF_WHITESPACE
=>
pht
(
'Leading Whitespace at BOF'
)
,
self
::
LINT_EOF_WHITESPACE
=>
pht
(
'Trailing Whitespace at EOF'
)
,
self
::
LINT_EMPTY_FILE
=>
pht
(
'Empty File'
)
,
)
;
}
public
function
lintPath
(
$path
)
{
$this
->
lintEmptyFile
(
$path
)
;
if
(
!
strlen
(
$this
->
getData
(
$path
)
)
)
{
// If the file is empty, don't bother; particularly, don't require
// the user to add a newline.
return
;
}
if
(
$this
->
didStopAllLinters
(
)
)
{
return
;
}
$this
->
lintNewlines
(
$path
)
;
$this
->
lintTabs
(
$path
)
;
if
(
$this
->
didStopAllLinters
(
)
)
{
return
;
}
$this
->
lintCharset
(
$path
)
;
if
(
$this
->
didStopAllLinters
(
)
)
{
return
;
}
$this
->
lintLineLength
(
$path
)
;
$this
->
lintEOFNewline
(
$path
)
;
$this
->
lintTrailingWhitespace
(
$path
)
;
$this
->
lintBOFWhitespace
(
$path
)
;
$this
->
lintEOFWhitespace
(
$path
)
;
}
protected
function
lintEmptyFile
(
$path
)
{
$data
=
$this
->
getData
(
$path
)
;
// It is reasonable for certain file types to be completely empty,
// so they are excluded here.
switch
(
$filename
=
basename
(
$this
->
getActivePath
(
)
)
)
{
case
'__init__.py'
:
return
;
default
:
if
(
strlen
(
$filename
)
&&
$filename
[
0
]
==
'.'
)
{
return
;
}
}
if
(
preg_match
(
'/^\s*$/'
,
$data
)
)
{
$this
->
raiseLintAtPath
(
self
::
LINT_EMPTY_FILE
,
pht
(
"Empty files usually don't serve any useful purpose."
)
)
;
$this
->
stopAllLinters
(
)
;
}
}
protected
function
lintNewlines
(
$path
)
{
$data
=
$this
->
getData
(
$path
)
;
$pos
=
strpos
(
$this
->
getData
(
$path
)
,
"\r"
)
;
if
(
$pos
!==
false
)
{
$this
->
raiseLintAtOffset
(
0
,
self
::
LINT_DOS_NEWLINE
,
pht
(
'You must use ONLY Unix linebreaks ("%s") in source code.'
,
'\n'
)
,
$data
,
str_replace
(
"\r\n"
,
"\n"
,
$data
)
)
;
if
(
$this
->
isMessageEnabled
(
self
::
LINT_DOS_NEWLINE
)
)
{
$this
->
stopAllLinters
(
)
;
}
}
}
protected
function
lintTabs
(
$path
)
{
$pos
=
strpos
(
$this
->
getData
(
$path
)
,
"\t"
)
;
if
(
$pos
!==
false
)
{
$this
->
raiseLintAtOffset
(
$pos
,
self
::
LINT_TAB_LITERAL
,
pht
(
'Configure your editor to use spaces for indentation.'
)
,
"\t"
)
;
}
}
protected
function
lintLineLength
(
$path
)
{
$lines
=
explode
(
"\n"
,
$this
->
getData
(
$path
)
)
;
$width
=
$this
->
maxLineLength
;
foreach
(
$lines
as
$line_idx
=>
$line
)
{
if
(
strlen
(
$line
)
>
$width
)
{
$this
->
raiseLintAtLine
(
$line_idx
+
1
,
1
,
self
::
LINT_LINE_WRAP
,
pht
(
'This line is %s characters long, but the '
.
'convention is %s characters.'
,
new
PhutilNumber
(
strlen
(
$line
)
)
,
$width
)
,
$line
)
;
}
}
}
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"
)
;
}
}
protected
function
lintCharset
(
$path
)
{
$data
=
$this
->
getData
(
$path
)
;
$matches
=
null
;
$bad
=
'[^\x09\x0A\x20-\x7E]'
;
$preg
=
preg_match_all
(
"/{$bad}(.*{$bad})?/"
,
$data
,
$matches
,
PREG_OFFSET_CAPTURE
)
;
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
)
;
}
if
(
$this
->
isMessageEnabled
(
self
::
LINT_BAD_CHARSET
)
)
{
$this
->
stopAllLinters
(
)
;
}
}
protected
function
lintTrailingWhitespace
(
$path
)
{
$data
=
$this
->
getData
(
$path
)
;
$matches
=
null
;
$preg
=
preg_match_all
(
'/[[:blank:]]+$/m'
,
$data
,
$matches
,
PREG_OFFSET_CAPTURE
)
;
if
(
!
$preg
)
{
return
;
}
foreach
(
$matches
[
0
]
as
$match
)
{
list
(
$string
,
$offset
)
=
$match
;
$this
->
raiseLintAtOffset
(
$offset
,
self
::
LINT_TRAILING_WHITESPACE
,
pht
(
'This line contains trailing whitespace. Consider setting '
.
'up your editor to automatically remove trailing whitespace.'
)
,
$string
,
''
)
;
}
}
protected
function
lintBOFWhitespace
(
$path
)
{
$data
=
$this
->
getData
(
$path
)
;
$matches
=
null
;
$preg
=
preg_match
(
'/^\s*\n/'
,
$data
,
$matches
,
PREG_OFFSET_CAPTURE
)
;
if
(
!
$preg
)
{
return
;
}
list
(
$string
,
$offset
)
=
$matches
[
0
]
;
$this
->
raiseLintAtOffset
(
$offset
,
self
::
LINT_BOF_WHITESPACE
,
pht
(
'This file contains leading whitespace at the beginning of the file. '
.
'This is unnecessary and should be avoided when possible.'
)
,
$string
,
''
)
;
}
protected
function
lintEOFWhitespace
(
$path
)
{
$data
=
$this
->
getData
(
$path
)
;
$matches
=
null
;
$preg
=
preg_match
(
'/(?<=\n)\s+$/'
,
$data
,
$matches
,
PREG_OFFSET_CAPTURE
)
;
if
(
!
$preg
)
{
return
;
}
list
(
$string
,
$offset
)
=
$matches
[
0
]
;
$this
->
raiseLintAtOffset
(
$offset
,
self
::
LINT_EOF_WHITESPACE
,
pht
(
'This file contains unnecessary trailing whitespace.'
)
,
$string
,
''
)
;
}
}
File Metadata
Details
Attached
Mime Type
text/x-php
Expires
Jan 19 2025, 23:00 (6 w, 3 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1114004
Default Alt Text
ArcanistTextLinter.php (7 KB)
Attached To
Mode
rARC Arcanist
Attached
Detach File
Event Timeline
Log In to Comment