wowtoc.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. """
  2. pygments.lexers.wowtoc
  3. ~~~~~~~~~~~~~~~~~~~~~~
  4. Lexer for World of Warcraft TOC files
  5. TOC files describe game addons.
  6. :copyright: Copyright 2006-2023 by the Pygments team, see AUTHORS.
  7. :license: BSD, see LICENSE for details.
  8. """
  9. import re
  10. from pygments.lexer import RegexLexer, bygroups
  11. from pygments.token import Comment, Name, Text, Punctuation, String, Keyword
  12. __all__ = ["WoWTocLexer"]
  13. def _create_tag_line_pattern(inner_pattern, ignore_case=False):
  14. return ((r"(?i)" if ignore_case else r"")
  15. + r"^(##)( *)" # groups 1, 2
  16. + inner_pattern # group 3
  17. + r"( *)(:)( *)(.*?)( *)$") # groups 4, 5, 6, 7, 8
  18. def _create_tag_line_token(inner_pattern, inner_token, ignore_case=False):
  19. # this function template-izes the tag line for a specific type of tag, which will
  20. # have a different pattern and different token. otherwise, everything about a tag
  21. # line is the same
  22. return (
  23. _create_tag_line_pattern(inner_pattern, ignore_case=ignore_case),
  24. bygroups(
  25. Keyword.Declaration,
  26. Text.Whitespace,
  27. inner_token,
  28. Text.Whitespace,
  29. Punctuation,
  30. Text.Whitespace,
  31. String,
  32. Text.Whitespace,
  33. ),
  34. )
  35. class WoWTocLexer(RegexLexer):
  36. """
  37. Lexer for World of Warcraft TOC files.
  38. .. versionadded:: 2.14
  39. """
  40. name = "World of Warcraft TOC"
  41. aliases = ["wowtoc"]
  42. filenames = ["*.toc"]
  43. tokens = {
  44. "root": [
  45. # official localized tags, Notes and Title
  46. # (normal part is insensitive, locale part is sensitive)
  47. _create_tag_line_token(
  48. r"((?:[nN][oO][tT][eE][sS]|[tT][iI][tT][lL][eE])-(?:ptBR|zhCN|"
  49. r"enCN|frFR|deDE|itIT|esMX|ptPT|koKR|ruRU|esES|zhTW|enTW|enGB|enUS))",
  50. Name.Builtin,
  51. ),
  52. # other official tags
  53. _create_tag_line_token(
  54. r"(Interface|Title|Notes|RequiredDeps|Dep[^: ]*|OptionalDeps|"
  55. r"LoadOnDemand|LoadWith|LoadManagers|SavedVariablesPerCharacter|"
  56. r"SavedVariables|DefaultState|Secure|Author|Version)",
  57. Name.Builtin,
  58. ignore_case=True,
  59. ),
  60. # user-defined tags
  61. _create_tag_line_token(
  62. r"(X-[^: ]*)",
  63. Name.Variable,
  64. ignore_case=True,
  65. ),
  66. # non-conforming tags, but still valid
  67. _create_tag_line_token(
  68. r"([^: ]*)",
  69. Name.Other,
  70. ),
  71. # Comments
  72. (r"^#.*$", Comment),
  73. # Addon Files
  74. (r"^.+$", Name),
  75. ]
  76. }
  77. def analyse_text(text):
  78. # at time of writing, this file suffix conflict's with one of Tex's in
  79. # markup.py. Tex's anaylse_text() appears to be definitive (binary) and does not
  80. # share any likeness to WoW TOCs, which means we wont have to compete with it by
  81. # abitrary increments in score.
  82. result = 0
  83. # while not required, an almost certain marker of WoW TOC's is the interface tag
  84. # if this tag is omitted, players will need to opt-in to loading the addon with
  85. # an options change ("Load out of date addons"). the value is also standardized:
  86. # `<major><minor><patch>`, with minor and patch being two-digit zero-padded.
  87. interface_pattern = _create_tag_line_pattern(r"(Interface)", ignore_case=True)
  88. match = re.search(interface_pattern, text)
  89. if match and re.match(r"(\d+)(\d{2})(\d{2})", match.group(7)):
  90. result += 0.8
  91. casefolded = text.casefold()
  92. # Lua file listing is good marker too, but probably conflicts with many other
  93. # lexers
  94. if ".lua" in casefolded:
  95. result += 0.1
  96. # ditto for XML files, but they're less used in WoW TOCs
  97. if ".xml" in casefolded:
  98. result += 0.05
  99. return result