- init
- do
- html.add_class("nitcode")
- end
-
- # The entry-point of the highlighting.
- # Will fill `html` with the generated HTML content.
- fun enter_visit(n: ANode)
- do
- n.parentize_tokens
- var s = n.location.file
- htmlize(s.first_token.as(not null), s.last_token.as(not null))
- end
-
- private fun full_tag(anode: ANode, hv: HighlightVisitor): nullable HTMLTag
- do
- var tag = anode.make_tag(hv)
- if tag == null then return null
- var infobox = anode.infobox(hv)
- if infobox == null and anode isa Token then
- var pa = anode.parent
- if pa != null then
- var c = anode
- if c isa TId or c isa TClassid or c isa TAttrid or c isa TokenLiteral or c isa TokenOperator or c isa TComment and pa isa ADoc then
- infobox = pa.decorate_tag(hv, tag, anode)
- end
- end
- end
- var messages = anode.location.messages
- if messages != null then
- tag.css("border-bottom", "solid 2px red")
- if infobox == null then
- infobox = new HInfoBox(hv, "Messages")
- end
- var c = infobox.new_dropdown("{messages.length} message(s)", "")
- for m in messages do
- c.open("li").append(m.text)
- end
- end
- if infobox != null then
- tag.attach_infobox(infobox)
- end
- return tag
- end
-
- # Produce HTML between two tokens
- protected fun htmlize(first_token, last_token: Token)
- do
- var stack2 = new Array[HTMLTag]
- var stack = new Array[Prod]
- var line = 0
- var c: nullable Token = first_token
- var hv = new HighlightVisitor
- while c != null do
- var starting
-
- # Handle start of line
- var cline = c.location.line_start
- if cline != line then
- # Handle starting block productions,
- # Because c could be a detached token, get prods in
- # the first AST token
- var c0 = c.first_token_in_line
- starting = null
- if c0 != null then starting = c0.starting_prods
- if starting != null then for p in starting do
- if not p.is_block then continue
- var tag = full_tag(p, hv)
- if tag == null then continue
- tag.add_class("foldable")
- stack2.add(html)
- html.add tag
- html = tag
- stack.add(p)
- end
-
- # Add a div for the whole line
- var tag = new HTMLTag("span")
- var p = line_id_prefix
- if p != "" then tag.attrs["id"] = "{p}{cline}"
- tag.classes.add "line"
- stack2.add(html)
- html.add tag
- html = tag
- line = cline
- end
-
- # Add the blank, verbatim
- html.add_raw_html c.blank_before
-
- # Handle starting span production
- starting = c.starting_prods
- if starting != null then for p in starting do
- if not p.is_span then continue
- var tag = full_tag(p, hv)
- if tag == null then continue
- stack2.add(html)
- html.add tag
- html = tag
- stack.add(p)
- end
-
- # Add the token
- if c isa TEol then
- html.append "\n"
- else
- var tag = full_tag(c, hv)
- if tag != null then html.add tag
- end
-
- # Handle ending span productions
- var ending = c.ending_prods
- if ending != null then for p in ending do
- if not p.is_span then continue
- if stack.is_empty or p != stack.last then continue
- stack.pop
- html = stack2.pop
- end
-
- # Handle end of line and end of file
- var n = c.next_token
- if c == last_token then n = null
- if n == null or n.location.line_start != line then
- # closes the line div
- html = stack2.pop
-
- # close the block production divs
- var c0 = c.last_token_in_line
- ending = null
- if c0 != null then ending = c0.ending_prods
- if ending != null then for p in ending do
- if not p.is_block then continue
- if stack.is_empty or p != stack.last then continue
- stack.pop
- html = stack2.pop
- end
- end
-
- c = n
- end
- #assert stack.is_empty
- #assert stack2.is_empty
- end