emphasis.py 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. # Process *this* and _that_
  2. #
  3. from __future__ import annotations
  4. from .state_inline import Delimiter, StateInline
  5. def tokenize(state: StateInline, silent: bool) -> bool:
  6. """Insert each marker as a separate text token, and add it to delimiter list"""
  7. start = state.pos
  8. marker = state.src[start]
  9. if silent:
  10. return False
  11. if marker not in ("_", "*"):
  12. return False
  13. scanned = state.scanDelims(state.pos, marker == "*")
  14. for _ in range(scanned.length):
  15. token = state.push("text", "", 0)
  16. token.content = marker
  17. state.delimiters.append(
  18. Delimiter(
  19. marker=ord(marker),
  20. length=scanned.length,
  21. token=len(state.tokens) - 1,
  22. end=-1,
  23. open=scanned.can_open,
  24. close=scanned.can_close,
  25. )
  26. )
  27. state.pos += scanned.length
  28. return True
  29. def _postProcess(state: StateInline, delimiters: list[Delimiter]) -> None:
  30. i = len(delimiters) - 1
  31. while i >= 0:
  32. startDelim = delimiters[i]
  33. # /* _ */ /* * */
  34. if startDelim.marker != 0x5F and startDelim.marker != 0x2A:
  35. i -= 1
  36. continue
  37. # Process only opening markers
  38. if startDelim.end == -1:
  39. i -= 1
  40. continue
  41. endDelim = delimiters[startDelim.end]
  42. # If the previous delimiter has the same marker and is adjacent to this one,
  43. # merge those into one strong delimiter.
  44. #
  45. # `<em><em>whatever</em></em>` -> `<strong>whatever</strong>`
  46. #
  47. isStrong = (
  48. i > 0
  49. and delimiters[i - 1].end == startDelim.end + 1
  50. # check that first two markers match and adjacent
  51. and delimiters[i - 1].marker == startDelim.marker
  52. and delimiters[i - 1].token == startDelim.token - 1
  53. # check that last two markers are adjacent (we can safely assume they match)
  54. and delimiters[startDelim.end + 1].token == endDelim.token + 1
  55. )
  56. ch = chr(startDelim.marker)
  57. token = state.tokens[startDelim.token]
  58. token.type = "strong_open" if isStrong else "em_open"
  59. token.tag = "strong" if isStrong else "em"
  60. token.nesting = 1
  61. token.markup = ch + ch if isStrong else ch
  62. token.content = ""
  63. token = state.tokens[endDelim.token]
  64. token.type = "strong_close" if isStrong else "em_close"
  65. token.tag = "strong" if isStrong else "em"
  66. token.nesting = -1
  67. token.markup = ch + ch if isStrong else ch
  68. token.content = ""
  69. if isStrong:
  70. state.tokens[delimiters[i - 1].token].content = ""
  71. state.tokens[delimiters[startDelim.end + 1].token].content = ""
  72. i -= 1
  73. i -= 1
  74. def postProcess(state: StateInline) -> None:
  75. """Walk through delimiter list and replace text tokens with tags."""
  76. _postProcess(state, state.delimiters)
  77. for token in state.tokens_meta:
  78. if token and "delimiters" in token:
  79. _postProcess(state, token["delimiters"])