1"""
2 pygments.lexers.installers
3 ~~~~~~~~~~~~~~~~~~~~~~~~~~
4
5 Lexers for installer/packager DSLs and formats.
6
7 :copyright: Copyright 2006-2025 by the Pygments team, see AUTHORS.
8 :license: BSD, see LICENSE for details.
9"""
10
11import re
12
13from pygments.lexer import RegexLexer, include, bygroups, using, this, default
14from pygments.token import Text, Comment, Operator, Keyword, Name, String, \
15 Punctuation, Generic, Number, Whitespace
16
17__all__ = ['NSISLexer', 'RPMSpecLexer',
18 'DebianSourcesLexer', 'SourcesListLexer',
19 'DebianControlLexer']
20
21
22class NSISLexer(RegexLexer):
23 """
24 For NSIS scripts.
25 """
26 name = 'NSIS'
27 url = 'http://nsis.sourceforge.net/'
28 aliases = ['nsis', 'nsi', 'nsh']
29 filenames = ['*.nsi', '*.nsh']
30 mimetypes = ['text/x-nsis']
31 version_added = '1.6'
32
33 flags = re.IGNORECASE
34
35 tokens = {
36 'root': [
37 (r'([;#].*)(\n)', bygroups(Comment, Whitespace)),
38 (r"'.*?'", String.Single),
39 (r'"', String.Double, 'str_double'),
40 (r'`', String.Backtick, 'str_backtick'),
41 include('macro'),
42 include('interpol'),
43 include('basic'),
44 (r'\$\{[a-z_|][\w|]*\}', Keyword.Pseudo),
45 (r'/[a-z_]\w*', Name.Attribute),
46 (r'\s+', Whitespace),
47 (r'[\w.]+', Text),
48 ],
49 'basic': [
50 (r'(\n)(Function)(\s+)([._a-z][.\w]*)\b',
51 bygroups(Whitespace, Keyword, Whitespace, Name.Function)),
52 (r'\b([_a-z]\w*)(::)([a-z][a-z0-9]*)\b',
53 bygroups(Keyword.Namespace, Punctuation, Name.Function)),
54 (r'\b([_a-z]\w*)(:)', bygroups(Name.Label, Punctuation)),
55 (r'(\b[ULS]|\B)([!<>=]?=|\<\>?|\>)\B', Operator),
56 (r'[|+-]', Operator),
57 (r'\\', Punctuation),
58 (r'\b(Abort|Add(?:BrandingImage|Size)|'
59 r'Allow(?:RootDirInstall|SkipFiles)|AutoCloseWindow|'
60 r'BG(?:Font|Gradient)|BrandingText|BringToFront|Call(?:InstDLL)?|'
61 r'(?:Sub)?Caption|ChangeUI|CheckBitmap|ClearErrors|CompletedText|'
62 r'ComponentText|CopyFiles|CRCCheck|'
63 r'Create(?:Directory|Font|Shortcut)|Delete(?:INI(?:Sec|Str)|'
64 r'Reg(?:Key|Value))?|DetailPrint|DetailsButtonText|'
65 r'Dir(?:Show|Text|Var|Verify)|(?:Disabled|Enabled)Bitmap|'
66 r'EnableWindow|EnumReg(?:Key|Value)|Exch|Exec(?:Shell|Wait)?|'
67 r'ExpandEnvStrings|File(?:BufSize|Close|ErrorText|Open|'
68 r'Read(?:Byte)?|Seek|Write(?:Byte)?)?|'
69 r'Find(?:Close|First|Next|Window)|FlushINI|Function(?:End)?|'
70 r'Get(?:CurInstType|CurrentAddress|DlgItem|DLLVersion(?:Local)?|'
71 r'ErrorLevel|FileTime(?:Local)?|FullPathName|FunctionAddress|'
72 r'InstDirError|LabelAddress|TempFileName)|'
73 r'Goto|HideWindow|Icon|'
74 r'If(?:Abort|Errors|FileExists|RebootFlag|Silent)|'
75 r'InitPluginsDir|Install(?:ButtonText|Colors|Dir(?:RegKey)?)|'
76 r'Inst(?:ProgressFlags|Type(?:[GS]etText)?)|Int(?:CmpU?|Fmt|Op)|'
77 r'IsWindow|LangString(?:UP)?|'
78 r'License(?:BkColor|Data|ForceSelection|LangString|Text)|'
79 r'LoadLanguageFile|LockWindow|Log(?:Set|Text)|MessageBox|'
80 r'MiscButtonText|Name|Nop|OutFile|(?:Uninst)?Page(?:Ex(?:End)?)?|'
81 r'PluginDir|Pop|Push|Quit|Read(?:(?:Env|INI|Reg)Str|RegDWORD)|'
82 r'Reboot|(?:Un)?RegDLL|Rename|RequestExecutionLevel|ReserveFile|'
83 r'Return|RMDir|SearchPath|Section(?:Divider|End|'
84 r'(?:(?:Get|Set)(?:Flags|InstTypes|Size|Text))|Group(?:End)?|In)?|'
85 r'SendMessage|Set(?:AutoClose|BrandingImage|Compress(?:ionLevel|'
86 r'or(?:DictSize)?)?|CtlColors|CurInstType|DatablockOptimize|'
87 r'DateSave|Details(?:Print|View)|Error(?:s|Level)|FileAttributes|'
88 r'Font|OutPath|Overwrite|PluginUnload|RebootFlag|ShellVarContext|'
89 r'Silent|StaticBkColor)|'
90 r'Show(?:(?:I|Uni)nstDetails|Window)|Silent(?:Un)?Install|Sleep|'
91 r'SpaceTexts|Str(?:CmpS?|Cpy|Len)|SubSection(?:End)?|'
92 r'Uninstall(?:ButtonText|(?:Sub)?Caption|EXEName|Icon|Text)|'
93 r'UninstPage|Var|VI(?:AddVersionKey|ProductVersion)|WindowIcon|'
94 r'Write(?:INIStr|Reg(:?Bin|DWORD|(?:Expand)?Str)|Uninstaller)|'
95 r'XPStyle)\b', Keyword),
96 (r'\b(CUR|END|(?:FILE_ATTRIBUTE_)?'
97 r'(?:ARCHIVE|HIDDEN|NORMAL|OFFLINE|READONLY|SYSTEM|TEMPORARY)|'
98 r'HK(CC|CR|CU|DD|LM|PD|U)|'
99 r'HKEY_(?:CLASSES_ROOT|CURRENT_(?:CONFIG|USER)|DYN_DATA|'
100 r'LOCAL_MACHINE|PERFORMANCE_DATA|USERS)|'
101 r'ID(?:ABORT|CANCEL|IGNORE|NO|OK|RETRY|YES)|'
102 r'MB_(?:ABORTRETRYIGNORE|DEFBUTTON[1-4]|'
103 r'ICON(?:EXCLAMATION|INFORMATION|QUESTION|STOP)|'
104 r'OK(?:CANCEL)?|RETRYCANCEL|RIGHT|SETFOREGROUND|TOPMOST|USERICON|'
105 r'YESNO(?:CANCEL)?)|SET|SHCTX|'
106 r'SW_(?:HIDE|SHOW(?:MAXIMIZED|MINIMIZED|NORMAL))|'
107 r'admin|all|auto|both|bottom|bzip2|checkbox|colored|current|false|'
108 r'force|hide|highest|if(?:diff|newer)|lastused|leave|left|'
109 r'listonly|lzma|nevershow|none|normal|off|on|pop|push|'
110 r'radiobuttons|right|show|silent|silentlog|smooth|textonly|top|'
111 r'true|try|user|zlib)\b', Name.Constant),
112 ],
113 'macro': [
114 (r'\!(addincludedir(?:dir)?|addplugindir|appendfile|cd|define|'
115 r'delfilefile|echo(?:message)?|else|endif|error|execute|'
116 r'if(?:macro)?n?(?:def)?|include|insertmacro|macro(?:end)?|packhdr|'
117 r'search(?:parse|replace)|system|tempfilesymbol|undef|verbose|'
118 r'warning)\b', Comment.Preproc),
119 ],
120 'interpol': [
121 (r'\$(R?[0-9])', Name.Builtin.Pseudo), # registers
122 (r'\$(ADMINTOOLS|APPDATA|CDBURN_AREA|COOKIES|COMMONFILES(?:32|64)|'
123 r'DESKTOP|DOCUMENTS|EXE(?:DIR|FILE|PATH)|FAVORITES|FONTS|HISTORY|'
124 r'HWNDPARENT|INTERNET_CACHE|LOCALAPPDATA|MUSIC|NETHOOD|PICTURES|'
125 r'PLUGINSDIR|PRINTHOOD|PROFILE|PROGRAMFILES(?:32|64)|QUICKLAUNCH|'
126 r'RECENT|RESOURCES(?:_LOCALIZED)?|SENDTO|SM(?:PROGRAMS|STARTUP)|'
127 r'STARTMENU|SYSDIR|TEMP(?:LATES)?|VIDEOS|WINDIR|\{NSISDIR\})',
128 Name.Builtin),
129 (r'\$(CMDLINE|INSTDIR|OUTDIR|LANGUAGE)', Name.Variable.Global),
130 (r'\$[a-z_]\w*', Name.Variable),
131 ],
132 'str_double': [
133 (r'"', String.Double, '#pop'),
134 (r'\$(\\[nrt"]|\$)', String.Escape),
135 include('interpol'),
136 (r'[^"]+', String.Double),
137 ],
138 'str_backtick': [
139 (r'`', String.Double, '#pop'),
140 (r'\$(\\[nrt"]|\$)', String.Escape),
141 include('interpol'),
142 (r'[^`]+', String.Double),
143 ],
144 }
145
146
147class RPMSpecLexer(RegexLexer):
148 """
149 For RPM ``.spec`` files.
150 """
151
152 name = 'RPMSpec'
153 aliases = ['spec']
154 filenames = ['*.spec']
155 mimetypes = ['text/x-rpm-spec']
156 url = 'https://rpm-software-management.github.io/rpm/manual/spec.html'
157 version_added = '1.6'
158
159 _directives = ('(?:package|prep|build|install|clean|check|pre[a-z]*|'
160 'post[a-z]*|trigger[a-z]*|files)')
161
162 tokens = {
163 'root': [
164 (r'#.*$', Comment),
165 include('basic'),
166 ],
167 'description': [
168 (r'^(%' + _directives + ')(.*)$',
169 bygroups(Name.Decorator, Text), '#pop'),
170 (r'\s+', Whitespace),
171 (r'.', Text),
172 ],
173 'changelog': [
174 (r'\*.*$', Generic.Subheading),
175 (r'^(%' + _directives + ')(.*)$',
176 bygroups(Name.Decorator, Text), '#pop'),
177 (r'\s+', Whitespace),
178 (r'.', Text),
179 ],
180 'string': [
181 (r'"', String.Double, '#pop'),
182 (r'\\([\\abfnrtv"\']|x[a-fA-F0-9]{2,4}|[0-7]{1,3})', String.Escape),
183 include('interpol'),
184 (r'.', String.Double),
185 ],
186 'basic': [
187 include('macro'),
188 (r'(?i)^(Name|Version|Release|Epoch|Summary|Group|License|Packager|'
189 r'Vendor|Icon|URL|Distribution|Prefix|Patch[0-9]*|Source[0-9]*|'
190 r'Requires\(?[a-z]*\)?|[a-z]+Req|Obsoletes|Suggests|Provides|Conflicts|'
191 r'Build[a-z]+|[a-z]+Arch|Auto[a-z]+)(:)(.*)$',
192 bygroups(Generic.Heading, Punctuation, using(this))),
193 (r'^%description', Name.Decorator, 'description'),
194 (r'^%changelog', Name.Decorator, 'changelog'),
195 (r'^(%' + _directives + ')(.*)$', bygroups(Name.Decorator, Text)),
196 (r'%(attr|defattr|dir|doc(?:dir)?|setup|config(?:ure)?|'
197 r'make(?:install)|ghost|patch[0-9]+|find_lang|exclude|verify)',
198 Keyword),
199 include('interpol'),
200 (r"'.*?'", String.Single),
201 (r'"', String.Double, 'string'),
202 (r'\s+', Whitespace),
203 (r'.', Text),
204 ],
205 'macro': [
206 (r'%define.*$', Comment.Preproc),
207 (r'%\{\!\?.*%define.*\}', Comment.Preproc),
208 (r'(%(?:if(?:n?arch)?|else(?:if)?|endif))(.*)$',
209 bygroups(Comment.Preproc, Text)),
210 ],
211 'interpol': [
212 (r'%\{?__[a-z_]+\}?', Name.Function),
213 (r'%\{?_([a-z_]+dir|[a-z_]+path|prefix)\}?', Keyword.Pseudo),
214 (r'%\{\?\w+\}', Name.Variable),
215 (r'\$\{?RPM_[A-Z0-9_]+\}?', Name.Variable.Global),
216 (r'%\{[a-zA-Z]\w+\}', Keyword.Constant),
217 ]
218 }
219
220
221class DebianSourcesLexer(RegexLexer):
222 """
223 Lexer that highlights debian.sources files.
224 """
225
226 name = 'Debian Sources file'
227 aliases = ['debian.sources']
228 filenames = ['*.sources']
229 version_added = '2.19'
230 url = 'https://manpages.debian.org/bookworm/apt/sources.list.5.en.html#THE_DEB_AND_DEB-SRC_TYPES:_GENERAL_FORMAT'
231
232 tokens = {
233 'root': [
234 (r'^(Signed-By)(:)(\s*)', bygroups(Keyword, Punctuation, Whitespace), 'signed-by'),
235 (r'^([a-zA-Z\-0-9\.]*?)(:)(\s*)(.*?)$',
236 bygroups(Keyword, Punctuation, Whitespace, String)),
237 ],
238 'signed-by': [
239 (r' -----END PGP PUBLIC KEY BLOCK-----\n', Text, '#pop'),
240 (r'.+\n', Text),
241 ],
242 }
243
244
245class SourcesListLexer(RegexLexer):
246 """
247 Lexer that highlights debian sources.list files.
248 """
249
250 name = 'Debian Sourcelist'
251 aliases = ['debsources', 'sourceslist', 'sources.list']
252 filenames = ['sources.list']
253 version_added = '0.7'
254 mimetype = ['application/x-debian-sourceslist']
255 url = 'https://wiki.debian.org/SourcesList'
256
257 tokens = {
258 'root': [
259 (r'\s+', Whitespace),
260 (r'#.*?$', Comment),
261 (r'^(deb(?:-src)?)(\s+)',
262 bygroups(Keyword, Whitespace), 'distribution')
263 ],
264 'distribution': [
265 (r'#.*?$', Comment, '#pop'),
266 (r'\$\(ARCH\)', Name.Variable),
267 (r'[^\s$[]+', String),
268 (r'\[', String.Other, 'escaped-distribution'),
269 (r'\$', String),
270 (r'\s+', Whitespace, 'components')
271 ],
272 'escaped-distribution': [
273 (r'\]', String.Other, '#pop'),
274 (r'\$\(ARCH\)', Name.Variable),
275 (r'[^\]$]+', String.Other),
276 (r'\$', String.Other)
277 ],
278 'components': [
279 (r'#.*?$', Comment, '#pop:2'),
280 (r'$', Text, '#pop:2'),
281 (r'\s+', Whitespace),
282 (r'\S+', Keyword.Pseudo),
283 ]
284 }
285
286 def analyse_text(text):
287 for line in text.splitlines():
288 line = line.strip()
289 if line.startswith('deb ') or line.startswith('deb-src '):
290 return True
291
292
293class DebianControlLexer(RegexLexer):
294 """
295 Lexer for Debian ``control`` files and ``apt-cache show <pkg>`` outputs.
296 """
297 name = 'Debian Control file'
298 url = 'https://www.debian.org/doc/debian-policy/ch-controlfields.html'
299 aliases = ['debcontrol', 'control']
300 filenames = ['control']
301 version_added = '0.9'
302
303 tokens = {
304 'root': [
305 (r'^(Description)', Keyword, 'description'),
306 (r'^(Maintainer|Uploaders|Changed-By)(:)(\s*)',
307 bygroups(Keyword, Punctuation, Whitespace),
308 'maintainer'),
309 (r'^((?:Build-|Pre-)?Depends(?:-Indep|-Arch)?)(:)(\s*)',
310 bygroups(Keyword, Punctuation, Whitespace), 'package_list'),
311 (r'^(Recommends|Suggests|Enhances|Breaks|Replaces|Provides|Conflicts)(:)(\s*)',
312 bygroups(Keyword, Punctuation, Whitespace), 'package_list'),
313 (r'^((?:Python-)?Version)(:)(\s*)(\S+)$',
314 bygroups(Keyword, Punctuation, Whitespace, Number)),
315 (r'^((?:Installed-)?Size)(:)(\s*)(\S+)$',
316 bygroups(Keyword, Punctuation, Whitespace, Number)),
317 (r'^(MD5Sum|SHA1|SHA256)(:)(\s*)(\S+)$',
318 bygroups(Keyword, Punctuation, Whitespace, Number)),
319 (r'^([a-zA-Z\-0-9\.]*?)(:)(\s*)(.*?)$',
320 bygroups(Keyword, Punctuation, Whitespace, String)),
321 ],
322 'maintainer': [
323 (r'<[^>]+>$', Generic.Strong, '#pop'),
324 (r'<[^>]+>', Generic.Strong),
325 (r',\n?', Whitespace),
326 (r'[^,<]+$', Text, '#pop'),
327 (r'[^,<]+', Text),
328 ],
329 'description': [
330 (r'(.*)(Homepage)(: )(\S+)',
331 bygroups(Text, String, Name, Name.Class)),
332 (r':.*\n', Generic.Strong),
333 (r' .*\n', Text),
334 default('#pop'),
335 ],
336 'package_list': [
337 (r'(\$)(\{)(\w+)(\s*)(:)(\s*)(\w+)(\})',
338 bygroups(Operator, Punctuation, Name.Entity, Whitespace,
339 Punctuation, Whitespace, Text, Punctuation)),
340 (r'\(', Punctuation, 'package_list_vers'),
341 (r'\|', Operator),
342 (r'\n\s', Whitespace),
343 (r'\n', Whitespace, '#pop'),
344 (r'[,\s]', Text),
345 (r'[+.a-zA-Z0-9-]+', Name.Function),
346 (r'\[.*?\]', Name.Entity),
347 ],
348 'package_list_vers': [
349 (r'\)', Punctuation, '#pop'),
350 (r'([><=]+)(\s*)([^)]+)', bygroups(Operator, Whitespace, Number)),
351 ]
352 }