man_help_formatter.py 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. # Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  2. # For details: https://github.com/PyCQA/pylint/blob/main/LICENSE
  3. import optparse # pylint: disable=deprecated-module
  4. import sys
  5. import time
  6. # pylint: disable=abstract-method; by design?
  7. class _ManHelpFormatter(optparse.HelpFormatter):
  8. def __init__(
  9. self, indent_increment=0, max_help_position=24, width=79, short_first=0
  10. ):
  11. super().__init__(indent_increment, max_help_position, width, short_first)
  12. self.output_level: int
  13. def format_heading(self, heading):
  14. return f".SH {heading.upper()}\n"
  15. def format_description(self, description):
  16. return description
  17. def format_option(self, option):
  18. try:
  19. optstring = option.option_strings
  20. except AttributeError:
  21. optstring = self.format_option_strings(option)
  22. if option.help:
  23. help_text = self.expand_default(option)
  24. help_string = " ".join(line.strip() for line in help_text.splitlines())
  25. help_string = help_string.replace("\\", "\\\\")
  26. help_string = help_string.replace("[current:", "[default:")
  27. else:
  28. help_string = ""
  29. return f""".IP "{optstring}"
  30. {help_string}
  31. """
  32. def format_head(self, optparser, pkginfo, section=1):
  33. long_desc = ""
  34. try:
  35. pgm = optparser._get_prog_name()
  36. except AttributeError:
  37. # py >= 2.4.X (dunno which X exactly, at least 2)
  38. pgm = optparser.get_prog_name()
  39. short_desc = self.format_short_description(pgm, pkginfo.description)
  40. if hasattr(pkginfo, "long_desc"):
  41. long_desc = self.format_long_description(pgm, pkginfo.long_desc)
  42. return f"""{self.format_title(pgm, section)}
  43. {short_desc}
  44. {self.format_synopsis(pgm)}
  45. {long_desc}"""
  46. @staticmethod
  47. def format_title(pgm, section):
  48. date = (
  49. "%d-%02d-%02d" # pylint: disable=consider-using-f-string
  50. % time.localtime()[:3]
  51. )
  52. return f'.TH {pgm} {section} "{date}" {pgm}'
  53. @staticmethod
  54. def format_short_description(pgm, short_desc):
  55. return f""".SH NAME
  56. .B {pgm}
  57. \\- {short_desc.strip()}
  58. """
  59. @staticmethod
  60. def format_synopsis(pgm):
  61. return f""".SH SYNOPSIS
  62. .B {pgm}
  63. [
  64. .I OPTIONS
  65. ] [
  66. .I <arguments>
  67. ]
  68. """
  69. @staticmethod
  70. def format_long_description(pgm, long_desc):
  71. long_desc = "\n".join(line.lstrip() for line in long_desc.splitlines())
  72. long_desc = long_desc.replace("\n.\n", "\n\n")
  73. if long_desc.lower().startswith(pgm):
  74. long_desc = long_desc[len(pgm) :]
  75. return f""".SH DESCRIPTION
  76. .B {pgm}
  77. {long_desc.strip()}
  78. """
  79. @staticmethod
  80. def format_tail(pkginfo):
  81. tail = f""".SH SEE ALSO
  82. /usr/share/doc/pythonX.Y-{getattr(pkginfo, "debian_name", "pylint")}/
  83. .SH BUGS
  84. Please report bugs on the project\'s mailing list:
  85. {pkginfo.mailinglist}
  86. .SH AUTHOR
  87. {pkginfo.author} <{pkginfo.author_email}>
  88. """
  89. if hasattr(pkginfo, "copyright"):
  90. tail += f"""
  91. .SH COPYRIGHT
  92. {pkginfo.copyright}
  93. """
  94. return tail
  95. def _generate_manpage(optparser, pkginfo, section=1, stream=sys.stdout, level=0):
  96. formatter = _ManHelpFormatter()
  97. formatter.output_level = level
  98. formatter.parser = optparser
  99. print(formatter.format_head(optparser, pkginfo, section), file=stream)
  100. print(optparser.format_option_help(formatter), file=stream)
  101. print(formatter.format_tail(pkginfo), file=stream)