|
""" |
|
pygments.lexers.make |
|
~~~~~~~~~~~~~~~~~~~~ |
|
|
|
Lexers for Makefiles and similar. |
|
|
|
:copyright: Copyright 2006-2025 by the Pygments team, see AUTHORS. |
|
:license: BSD, see LICENSE for details. |
|
""" |
|
|
|
import re |
|
|
|
from pygments.lexer import Lexer, RegexLexer, include, bygroups, \ |
|
do_insertions, using |
|
from pygments.token import Text, Comment, Operator, Keyword, Name, String, \ |
|
Punctuation, Whitespace |
|
from pygments.lexers.shell import BashLexer |
|
|
|
__all__ = ['MakefileLexer', 'BaseMakefileLexer', 'CMakeLexer'] |
|
|
|
|
|
class MakefileLexer(Lexer): |
|
""" |
|
Lexer for BSD and GNU make extensions (lenient enough to handle both in |
|
the same file even). |
|
|
|
*Rewritten in Pygments 0.10.* |
|
""" |
|
|
|
name = 'Makefile' |
|
aliases = ['make', 'makefile', 'mf', 'bsdmake'] |
|
filenames = ['*.mak', '*.mk', 'Makefile', 'makefile', 'Makefile.*', 'GNUmakefile'] |
|
mimetypes = ['text/x-makefile'] |
|
url = 'https://en.wikipedia.org/wiki/Make_(software)' |
|
version_added = '' |
|
|
|
r_special = re.compile( |
|
r'^(?:' |
|
|
|
r'\.\s*(include|undef|error|warning|if|else|elif|endif|for|endfor)|' |
|
|
|
r'\s*(ifeq|ifneq|ifdef|ifndef|else|endif|-?include|define|endef|:|vpath)|' |
|
|
|
r'\s*(if|else|endif))(?=\s)') |
|
r_comment = re.compile(r'^\s*@?#') |
|
|
|
def get_tokens_unprocessed(self, text): |
|
ins = [] |
|
lines = text.splitlines(keepends=True) |
|
done = '' |
|
lex = BaseMakefileLexer(**self.options) |
|
backslashflag = False |
|
for line in lines: |
|
if self.r_special.match(line) or backslashflag: |
|
ins.append((len(done), [(0, Comment.Preproc, line)])) |
|
backslashflag = line.strip().endswith('\\') |
|
elif self.r_comment.match(line): |
|
ins.append((len(done), [(0, Comment, line)])) |
|
else: |
|
done += line |
|
yield from do_insertions(ins, lex.get_tokens_unprocessed(done)) |
|
|
|
def analyse_text(text): |
|
|
|
if re.search(r'\$\([A-Z_]+\)', text): |
|
return 0.1 |
|
|
|
|
|
class BaseMakefileLexer(RegexLexer): |
|
""" |
|
Lexer for simple Makefiles (no preprocessing). |
|
""" |
|
|
|
name = 'Base Makefile' |
|
aliases = ['basemake'] |
|
filenames = [] |
|
mimetypes = [] |
|
url = 'https://en.wikipedia.org/wiki/Make_(software)' |
|
version_added = '0.10' |
|
|
|
tokens = { |
|
'root': [ |
|
|
|
(r'^(?:[\t ]+.*\n|\n)+', using(BashLexer)), |
|
|
|
(r'\$[<@$+%?|*]', Keyword), |
|
(r'\s+', Whitespace), |
|
(r'#.*?\n', Comment), |
|
(r'((?:un)?export)(\s+)(?=[\w${}\t -]+\n)', |
|
bygroups(Keyword, Whitespace), 'export'), |
|
(r'(?:un)?export\s+', Keyword), |
|
|
|
(r'([\w${}().-]+)(\s*)([!?:+]?=)([ \t]*)((?:.*\\\n)+|.*\n)', |
|
bygroups( |
|
Name.Variable, Whitespace, Operator, Whitespace, |
|
using(BashLexer))), |
|
|
|
(r'"(\\\\|\\[^\\]|[^"\\])*"', String.Double), |
|
(r"'(\\\\|\\[^\\]|[^'\\])*'", String.Single), |
|
|
|
(r'([^\n:]+)(:+)([ \t]*)', bygroups( |
|
Name.Function, Operator, Whitespace), |
|
'block-header'), |
|
|
|
(r'\$\(', Keyword, 'expansion'), |
|
], |
|
'expansion': [ |
|
(r'[^\w$().-]+', Text), |
|
(r'[\w.-]+', Name.Variable), |
|
(r'\$', Keyword), |
|
(r'\(', Keyword, '#push'), |
|
(r'\)', Keyword, '#pop'), |
|
], |
|
'export': [ |
|
(r'[\w${}-]+', Name.Variable), |
|
(r'\n', Text, '#pop'), |
|
(r'\s+', Whitespace), |
|
], |
|
'block-header': [ |
|
(r'[,|]', Punctuation), |
|
(r'#.*?\n', Comment, '#pop'), |
|
(r'\\\n', Text), |
|
(r'\$\(', Keyword, 'expansion'), |
|
(r'[a-zA-Z_]+', Name), |
|
(r'\n', Whitespace, '#pop'), |
|
(r'.', Text), |
|
], |
|
} |
|
|
|
|
|
class CMakeLexer(RegexLexer): |
|
""" |
|
Lexer for CMake files. |
|
""" |
|
name = 'CMake' |
|
url = 'https://cmake.org/documentation/' |
|
aliases = ['cmake'] |
|
filenames = ['*.cmake', 'CMakeLists.txt'] |
|
mimetypes = ['text/x-cmake'] |
|
version_added = '1.2' |
|
|
|
tokens = { |
|
'root': [ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(r'\b(\w+)([ \t]*)(\()', bygroups(Name.Builtin, Whitespace, |
|
Punctuation), 'args'), |
|
include('keywords'), |
|
include('ws') |
|
], |
|
'args': [ |
|
(r'\(', Punctuation, '#push'), |
|
(r'\)', Punctuation, '#pop'), |
|
(r'(\$\{)(.+?)(\})', bygroups(Operator, Name.Variable, Operator)), |
|
(r'(\$ENV\{)(.+?)(\})', bygroups(Operator, Name.Variable, Operator)), |
|
(r'(\$<)(.+?)(>)', bygroups(Operator, Name.Variable, Operator)), |
|
(r'(?s)".*?"', String.Double), |
|
(r'\\\S+', String), |
|
(r'\[(?P<level>=*)\[[\w\W]*?\](?P=level)\]', String.Multiline), |
|
(r'[^)$"# \t\n]+', String), |
|
(r'\n', Whitespace), |
|
include('keywords'), |
|
include('ws') |
|
], |
|
'string': [ |
|
|
|
], |
|
'keywords': [ |
|
(r'\b(WIN32|UNIX|APPLE|CYGWIN|BORLAND|MINGW|MSVC|MSVC_IDE|MSVC60|' |
|
r'MSVC70|MSVC71|MSVC80|MSVC90)\b', Keyword), |
|
], |
|
'ws': [ |
|
(r'[ \t]+', Whitespace), |
|
(r'#\[(?P<level>=*)\[[\w\W]*?\](?P=level)\]', Comment), |
|
(r'#.*\n', Comment), |
|
] |
|
} |
|
|
|
def analyse_text(text): |
|
exp = ( |
|
r'^[ \t]*CMAKE_MINIMUM_REQUIRED[ \t]*' |
|
r'\([ \t]*VERSION[ \t]*\d+(\.\d+)*[ \t]*' |
|
r'([ \t]FATAL_ERROR)?[ \t]*\)[ \t]*' |
|
r'(#[^\n]*)?$' |
|
) |
|
if re.search(exp, text, flags=re.MULTILINE | re.IGNORECASE): |
|
return 0.8 |
|
return 0.0 |
|
|