lib/linguist/strategy/modeline.rb in github-linguist-7.13.0 vs lib/linguist/strategy/modeline.rb in github-linguist-7.14.0
- old
+ new
@@ -1,97 +1,129 @@
module Linguist
module Strategy
class Modeline
- EMACS_MODELINE = /
+ EMACS_MODELINE = %r[
+ (?-m)
+
+ # Opening delimiter
-\*-
+
(?:
# Short form: `-*- ruby -*-`
- \s* (?= [^:;\s]+ \s* -\*-)
+ [ \t]*
+ (?=
+ [^:;\s]+ # Name of mode
+ [ \t]* # Optional whitespace
+ -\*- # Closing delimiter
+ )
|
+
# Longer form: `-*- foo:bar; mode: ruby; -*-`
(?:
- .*? # Preceding variables: `-*- foo:bar bar:baz;`
- [;\s] # Which are delimited by spaces or semicolons
+ .*?[ \t;] # Preceding variables: `-*- foo:bar bar:baz;`
|
(?<=-\*-) # Not preceded by anything: `-*-mode:ruby-*-`
)
- mode # Major mode indicator
- \s*:\s* # Allow whitespace around colon: `mode : ruby`
+
+ # Explicitly-named variable: `mode: ruby` or `mode : ruby`
+ [ \t]* mode [ \t]* : [ \t]*
)
- ([^:;\s]+) # Name of mode
- # Ensure the mode is terminated correctly
+ # Name of major-mode, which corresponds to syntax or filetype
+ ([^:;\s]+)
+
+ # Ensure the name is terminated correctly
(?=
# Followed by semicolon or whitespace
- [\s;]
+ [ \t;]
|
# Touching the ending sequence: `ruby-*-`
(?<![-*]) # Don't allow stuff like `ruby--*-` to match; it'll invalidate the mode
-\*- # Emacs has no problems reading `ruby --*-`, however.
)
- .*? # Anything between a cleanly-terminated mode and the ending -*-
+
+ # If we've gotten this far, it means the modeline is valid.
+ # We gleefully skip past everything up until reaching "-*-"
+ .*?
+
+ # Closing delimiter
-\*-
- /xi
+ ]xi
- VIM_MODELINE = /
+ VIM_MODELINE = %r[
+ (?-m)
- # Start modeline. Could be `vim:`, `vi:` or `ex:`
+ # Start of modeline (syntax documented in E520)
(?:
- (?:[ \t]|^)
- vi
- (?:m[<=>]?\d+|m)? # Version-specific modeline
+ # `vi:`, `vim:` or `Vim:`
+ (?:^|[ \t]) (?:vi|Vi(?=m))
+
+ # Check if specific Vim version(s) are requested (won't work in vi/ex)
+ (?:
+ # Versioned modeline. `vim<700:` targets Vim versions older than 7.0
+ m
+ [<=>]? # If comparison operator is omitted, *only* this version is targeted
+ [0-9]+ # Version argument = (MINOR_VERSION_NUMBER * 100) + MINOR_VERSION_NUMBER
+ |
+
+ # Unversioned modeline. `vim:` targets any version of Vim.
+ m
+ )?
|
- [\t\x20] # `ex:` requires whitespace, because "ex:" might be short for "example:"
- ex
+
+ # `ex:`, which requires leading whitespace to avoid matching stuff like "lex:"
+ [ \t] ex
)
# If the option-list begins with `set ` or `se `, it indicates an alternative
# modeline syntax partly-compatible with older versions of Vi. Here, the colon
# serves as a terminator for an option sequence, delimited by whitespace.
(?=
# So we have to ensure the modeline ends with a colon
- : (?=[ \t]* set? [ \t] [^\n:]+ :) |
+ : (?=[ \t]* set? [ \t] [^\r\n:]+ :) |
# Otherwise, it isn't valid syntax and should be ignored
: (?![ \t]* set? [ \t])
)
# Possible (unrelated) `option=value` pairs to skip past
(?:
- # Option separator. Vim uses whitespace or colons to separate options (except if
- # the alternate "vim: set " form is used, where only whitespace is used)
+ # Option separator, either
(?:
- [ \t]
+ # 1. A colon (possibly surrounded by whitespace)
+ [ \t]* : [ \t]* # vim: noai : ft=sh:noexpandtab
|
- [ \t]* : [ \t]* # Note that whitespace around colons is accepted too:
- ) # vim: noai : ft=ruby:noexpandtab
+ # 2. At least one (horizontal) whitespace character
+ [ \t] # vim: noai ft=sh noexpandtab
+ )
+
# Option's name. All recognised Vim options have an alphanumeric form.
\w*
# Possible value. Not every option takes an argument.
(?:
- # Whitespace between name and value is allowed: `vim: ft =ruby`
+ # Whitespace between name and value is allowed: `vim: ft =sh`
[ \t]*=
- # Option's value. Might be blank; `vim: ft= ` says "use no filetype".
+ # Option's value. Might be blank; `vim: ft= ` means "use no filetype".
(?:
- [^\\[ \t]] # Beware of escaped characters: titlestring=\ ft=ruby
- | # will be read by Vim as { titlestring: " ft=ruby" }.
+ [^\\\s] # Beware of escaped characters: titlestring=\ ft=sh
+ | # will be read by Vim as { titlestring: " ft=sh" }.
\\.
)*
)?
)*
# The actual filetype declaration
- [[ \t]:] (?:filetype|ft|syntax) [ \t]*=
+ [ \t:] (?:filetype|ft|syntax) [ \t]*=
# Language's name
(\w+)
- # Ensure it's followed by a legal separator
- (?=[ \t]|:|$)
- /xi
+ # Ensure it's followed by a legal separator (including EOL)
+ (?=$|\s|:)
+ ]x
MODELINES = [EMACS_MODELINE, VIM_MODELINE]
# Scope of the search for modelines
# Number of lines to check at the beginning and at the end of the file