image.py 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. # Process ![image](<src> "title")
  2. from __future__ import annotations
  3. from ..common.utils import isStrSpace, normalizeReference
  4. from ..token import Token
  5. from .state_inline import StateInline
  6. def image(state: StateInline, silent: bool) -> bool:
  7. label = None
  8. href = ""
  9. oldPos = state.pos
  10. max = state.posMax
  11. if state.src[state.pos] != "!":
  12. return False
  13. if state.pos + 1 < state.posMax and state.src[state.pos + 1] != "[":
  14. return False
  15. labelStart = state.pos + 2
  16. labelEnd = state.md.helpers.parseLinkLabel(state, state.pos + 1, False)
  17. # parser failed to find ']', so it's not a valid link
  18. if labelEnd < 0:
  19. return False
  20. pos = labelEnd + 1
  21. if pos < max and state.src[pos] == "(":
  22. #
  23. # Inline link
  24. #
  25. # [link]( <href> "title" )
  26. # ^^ skipping these spaces
  27. pos += 1
  28. while pos < max:
  29. ch = state.src[pos]
  30. if not isStrSpace(ch) and ch != "\n":
  31. break
  32. pos += 1
  33. if pos >= max:
  34. return False
  35. # [link]( <href> "title" )
  36. # ^^^^^^ parsing link destination
  37. start = pos
  38. res = state.md.helpers.parseLinkDestination(state.src, pos, state.posMax)
  39. if res.ok:
  40. href = state.md.normalizeLink(res.str)
  41. if state.md.validateLink(href):
  42. pos = res.pos
  43. else:
  44. href = ""
  45. # [link]( <href> "title" )
  46. # ^^ skipping these spaces
  47. start = pos
  48. while pos < max:
  49. ch = state.src[pos]
  50. if not isStrSpace(ch) and ch != "\n":
  51. break
  52. pos += 1
  53. # [link]( <href> "title" )
  54. # ^^^^^^^ parsing link title
  55. res = state.md.helpers.parseLinkTitle(state.src, pos, state.posMax)
  56. if pos < max and start != pos and res.ok:
  57. title = res.str
  58. pos = res.pos
  59. # [link]( <href> "title" )
  60. # ^^ skipping these spaces
  61. while pos < max:
  62. ch = state.src[pos]
  63. if not isStrSpace(ch) and ch != "\n":
  64. break
  65. pos += 1
  66. else:
  67. title = ""
  68. if pos >= max or state.src[pos] != ")":
  69. state.pos = oldPos
  70. return False
  71. pos += 1
  72. else:
  73. #
  74. # Link reference
  75. #
  76. if "references" not in state.env:
  77. return False
  78. # /* [ */
  79. if pos < max and state.src[pos] == "[":
  80. start = pos + 1
  81. pos = state.md.helpers.parseLinkLabel(state, pos)
  82. if pos >= 0:
  83. label = state.src[start:pos]
  84. pos += 1
  85. else:
  86. pos = labelEnd + 1
  87. else:
  88. pos = labelEnd + 1
  89. # covers label == '' and label == undefined
  90. # (collapsed reference link and shortcut reference link respectively)
  91. if not label:
  92. label = state.src[labelStart:labelEnd]
  93. label = normalizeReference(label)
  94. ref = state.env["references"].get(label, None)
  95. if not ref:
  96. state.pos = oldPos
  97. return False
  98. href = ref["href"]
  99. title = ref["title"]
  100. #
  101. # We found the end of the link, and know for a fact it's a valid link
  102. # so all that's left to do is to call tokenizer.
  103. #
  104. if not silent:
  105. content = state.src[labelStart:labelEnd]
  106. tokens: list[Token] = []
  107. state.md.inline.parse(content, state.md, state.env, tokens)
  108. token = state.push("image", "img", 0)
  109. token.attrs = {"src": href, "alt": ""}
  110. token.children = tokens or None
  111. token.content = content
  112. if title:
  113. token.attrSet("title", title)
  114. # note, this is not part of markdown-it JS, but is useful for renderers
  115. if label and state.md.options.get("store_labels", False):
  116. token.meta["label"] = label
  117. state.pos = pos
  118. state.posMax = max
  119. return True