You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

125 lines
6.8 KiB

2 years ago
2 years ago
5 years ago
5 years ago
  1. import wx # type: ignore
  2. import wx.richtext # type: ignore
  3. import colored # type: ignore
  4. import re
  5. from gooey.python_bindings import types as t
  6. kColorList = ["#000000", "#800000", "#008000", "#808000", "#000080", "#800080", "#008080", "#c0c0c0",
  7. "#808080", "#ff0000", "#00ff00", "#ffff00", "#0000ff", "#ff00ff", "#00ffff", "#ffffff", "#000000",
  8. "#00005f", "#000087", "#0000af", "#0000d7", "#0000ff", "#005f00", "#005f5f", "#005f87", "#005faf",
  9. "#005fd7", "#005fff", "#008700", "#00875f", "#008787", "#0087af", "#0087d7", "#0087ff", "#00af00",
  10. "#00af5f", "#00af87", "#00afaf", "#00afd7", "#00afff", "#00d700", "#00d75f", "#00d787", "#00d7af",
  11. "#00d7d7", "#00d7ff", "#00ff00", "#00ff5f", "#00ff87", "#00ffaf", "#00ffd7", "#00ffff", "#5f0000",
  12. "#5f005f", "#5f0087", "#5f00af", "#5f00d7", "#5f00ff", "#5f5f00", "#5f5f5f", "#5f5f87", "#5f5faf",
  13. "#5f5fd7", "#5f5fff", "#5f8700", "#5f875f", "#5f8787", "#5f87af", "#5f87d7", "#5f87ff", "#5faf00",
  14. "#5faf5f", "#5faf87", "#5fafaf", "#5fafd7", "#5fafff", "#5fd700", "#5fd75f", "#5fd787", "#5fd7af",
  15. "#5fd7d7", "#5fd7ff", "#5fff00", "#5fff5f", "#5fff87", "#5fffaf", "#5fffd7", "#5fffff", "#870000",
  16. "#87005f", "#870087", "#8700af", "#8700d7", "#8700ff", "#875f00", "#875f5f", "#875f87", "#875faf",
  17. "#875fd7", "#875fff", "#878700", "#87875f", "#878787", "#8787af", "#8787d7", "#8787ff", "#87af00",
  18. "#87af5f", "#87af87", "#87afaf", "#87afd7", "#87afff", "#87d700", "#87d75f", "#87d787", "#87d7af",
  19. "#87d7d7", "#87d7ff", "#87ff00", "#87ff5f", "#87ff87", "#87ffaf", "#87ffd7", "#87ffff", "#af0000",
  20. "#af005f", "#af0087", "#af00af", "#af00d7", "#af00ff", "#af5f00", "#af5f5f", "#af5f87", "#af5faf",
  21. "#af5fd7", "#af5fff", "#af8700", "#af875f", "#af8787", "#af87af", "#af87d7", "#af87ff", "#afaf00",
  22. "#afaf5f", "#afaf87", "#afafaf", "#afafd7", "#afafff", "#afd700", "#afd75f", "#afd787", "#afd7af",
  23. "#afd7d7", "#afd7ff", "#afff00", "#afff5f", "#afff87", "#afffaf", "#afffd7", "#afffff", "#d70000",
  24. "#d7005f", "#d70087", "#d700af", "#d700d7", "#d700ff", "#d75f00", "#d75f5f", "#d75f87", "#d75faf",
  25. "#d75fd7", "#d75fff", "#d78700", "#d7875f", "#d78787", "#d787af", "#d787d7", "#d787ff", "#d7af00",
  26. "#d7af5f", "#d7af87", "#d7afaf", "#d7afd7", "#d7afff", "#d7d700", "#d7d75f", "#d7d787", "#d7d7af",
  27. "#d7d7d7", "#d7d7ff", "#d7ff00", "#d7ff5f", "#d7ff87", "#d7ffaf", "#d7ffd7", "#d7ffff", "#ff0000",
  28. "#ff005f", "#ff0087", "#ff00af", "#ff00d7", "#ff00ff", "#ff5f00", "#ff5f5f", "#ff5f87", "#ff5faf",
  29. "#ff5fd7", "#ff5fff", "#ff8700", "#ff875f", "#ff8787", "#ff87af", "#ff87d7", "#ff87ff", "#ffaf00",
  30. "#ffaf5f", "#ffaf87", "#ffafaf", "#ffafd7", "#ffafff", "#ffd700", "#ffd75f", "#ffd787", "#ffd7af",
  31. "#ffd7d7", "#ffd7ff", "#ffff00", "#ffff5f", "#ffff87", "#ffffaf", "#ffffd7", "#ffffff", "#080808",
  32. "#121212", "#1c1c1c", "#262626", "#303030", "#3a3a3a", "#444444", "#4e4e4e", "#585858", "#626262",
  33. "#6c6c6c", "#767676", "#808080", "#8a8a8a", "#949494", "#9e9e9e", "#a8a8a8", "#b2b2b2", "#bcbcbc",
  34. "#c6c6c6", "#d0d0d0", "#dadada", "#e4e4e4", "#eeeeee"]
  35. class RichTextConsole(wx.richtext.RichTextCtrl):
  36. """
  37. An advanced rich test console panel supporting some Xterm control codes.
  38. """
  39. def __init__(self, parent):
  40. super(wx.richtext.RichTextCtrl, self).__init__(parent, -1, "", style=wx.richtext.RE_MULTILINE | wx.richtext.RE_READONLY)
  41. self.regex_urls=re.compile(r'\b((?:file://|https?://|mailto:)[^][\s<>|]*)')
  42. self.url_colour = wx.Colour(0,0,255)
  43. self.esc = colored.style.ESC
  44. self.end = colored.style.END
  45. self.noop = lambda *args, **kwargs: None
  46. self.actionsMap = {
  47. colored.style.BOLD: self.BeginBold,
  48. colored.style.RES_BOLD: self.EndBold,
  49. colored.style.UNDERLINED: self.BeginUnderline,
  50. colored.style.RES_UNDERLINED: self.EndUnderline,
  51. colored.style.RESET: self.EndAllStyles,
  52. }
  53. # Actions for coloring text
  54. for index, hex in enumerate(kColorList):
  55. escSeq = '{}{}{}'.format(colored.fore.ESC, index, colored.fore.END)
  56. wxcolor = wx.Colour(int(hex[1:3],16), int(hex[3:5],16), int(hex[5:],16), alpha=wx.ALPHA_OPAQUE)
  57. # NB : we use a default parameter to force the evaluation of the binding
  58. self.actionsMap[escSeq] = lambda bindedColor=wxcolor: self.BeginTextColour(bindedColor)
  59. self.Bind(wx.EVT_MOUSEWHEEL, self.onMouseWheel)
  60. def PreprocessAndWriteText(self, content):
  61. """Write text into console, while capturing URLs and making
  62. them blue, underlined, and clickable.
  63. """
  64. textStream=iter(re.split(self.regex_urls, content))
  65. # The odd elements in textStream are plaintext;
  66. # the even elements are URLs.
  67. for plaintext in textStream:
  68. url=next(textStream, None)
  69. self.WriteText(plaintext)
  70. if url:
  71. self.BeginTextColour(self.url_colour)
  72. self.BeginUnderline()
  73. self.BeginURL(url)
  74. self.WriteText(url)
  75. self.EndURL()
  76. self.EndUnderline()
  77. self.EndTextColour()
  78. def AppendText(self, content):
  79. """
  80. wx method overridden to capture the terminal control character and translate them into wx styles.
  81. Complexity : o(len(content))
  82. """
  83. self.SetInsertionPointEnd()
  84. unprocIndex = 0
  85. while True:
  86. # Invariant : unprocIndex is the starting index of the unprocessed part of the buffer
  87. escPos = content.find(self.esc, unprocIndex)
  88. if escPos == -1:
  89. break
  90. # Invariant : found an escape sequence starting at escPos
  91. # NB : we flush all the characters before the escape sequence, if any
  92. if content[unprocIndex:escPos]:
  93. self.PreprocessAndWriteText(content[unprocIndex:escPos])
  94. endEsc = content.find(self.end, escPos)
  95. if endEsc == -1:
  96. unprocIndex = escPos + len(self.esc)
  97. continue
  98. # Invariant : end of sequence has been found
  99. self.actionsMap.get(content[escPos:endEsc+1], self.noop)()
  100. unprocIndex = endEsc + 1
  101. # Invariant : unprocessed end of buffer is escape-free, ready to be printed
  102. self.PreprocessAndWriteText(content[unprocIndex:])
  103. self.ShowPosition(self.GetInsertionPoint())
  104. def onMouseWheel(self, event):
  105. if event.GetModifiers()==2 and event.GetWheelAxis()==wx.MOUSE_WHEEL_VERTICAL:
  106. if event.GetWheelRotation() >= event.GetWheelDelta():
  107. r=1.1
  108. elif event.GetWheelRotation() <= -event.GetWheelDelta():
  109. r=1.0/1.1
  110. else:
  111. return
  112. self.SetFontScale(self.GetFontScale() * r, True)
  113. else:
  114. event.Skip()