# The last line to generate, null if finish at the last line
var last_line: nullable Int = null is writable
+ # When highlighting a node, show its messages (errors, warnings), if any.
+ #
+ # default: true
+ var show_messages = true is writable
+
+ # When highlighting a node, attach a full popupable infobox, if any.
+ #
+ # If `false`, only a simple `title` tooltip is used.
+ #
+ # default: true
+ var show_infobox = true is writable
+
init
do
html.add_class("nitcode")
end
+ # When highlighting a node, also consider the loose tokens around it.
+ #
+ # Loose tokens are tokens discarded from the AST but attached before
+ # or after some non-loose tokens. See `Token::is_loose`.
+ #
+ # When this flag is set to `true`, the loose tokens that are before the
+ # first token and after the last token are also highlighted.
+ #
+ # Default: false.
+ var include_loose_tokens = false is writable
+
+ # When highlighting a node, the first and the last lines are fully included.
+ #
+ # If the highlighted node starts (or ends) in the middle of a line,
+ # this flags forces the whole line to be highlighted.
+ #
+ # Default: false
+ var include_whole_lines = false is writable
+
# 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))
+
+ var f
+ var l
+
+ if n isa Token then
+ f = n
+ l = n
+ else
+ assert n isa Prod
+ f = n.first_token
+ if f == null then return
+ l = n.last_token
+ if l == null then return
+ end
+
+ if include_loose_tokens then
+ if f.prev_looses.not_empty then f = f.prev_looses.first
+ if l.next_looses.not_empty then l = l.next_looses.last
+ end
+
+ if include_whole_lines then
+ f = f.first_real_token_in_line
+ l = l.last_real_token_in_line
+ end
+
+ htmlize(f, l)
end
private fun full_tag(anode: ANode, hv: HighlightVisitor): nullable HTMLTag
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
+ infobox = pa.decorate_tag(hv, tag, anode)
end
end
+ if infobox != null and not show_infobox then
+ tag.attr("title", infobox.title)
+ tag.classes.add "titled"
+ infobox = null
+ end
var messages = anode.location.messages
- if messages != null then
+ if messages != null and show_messages then
tag.css("border-bottom", "solid 2px red")
if infobox == null then
infobox = new HInfoBox(hv, "Messages")
c = n
end
- assert stack.is_empty
- assert stack2.is_empty
+ #assert stack.is_empty
+ #assert stack2.is_empty
end
# Return a default CSS content related to CSS classes used in the `html` tree.
do
return """
.nitcode a { color: inherit; cursor:pointer; }
+.nitcode .titled:hover { text-decoration: underline; } /* underline titles */
.nitcode .popupable:hover { text-decoration: underline; cursor:help; } /* underline titles */
.nitcode .foldable { display: block } /* for block productions*/
.nitcode .line{ display: block } /* for lines */
# The module HTML page
fun href: String
do
- return name + ".html"
+ return c_name + ".html"
end
redef fun linkto do return linkto_text(name)
res.new_field("class").text(mclass.name)
else
res.new_field("redef class").text(mclass.name)
- res.new_field("intro").add mclass.intro.linkto_text("in {mclass.intro.mmodule.to_s}")
+ res.new_field("intro").add mclass.intro.linkto_text("in {mclass.intro_mmodule.to_s}")
end
var mdoc = self.mdoc
if mdoc == null then mdoc = mclass.intro.mdoc
end
redef class CallSite
- super HInfoBoxable
redef fun infobox(v)
do
var res = new HInfoBox(v, "call {mpropdef}")
fun infobox(v: HighlightVisitor): nullable HInfoBox do return null
end
+redef class AQclassid
+ redef fun decorate_tag(v, res, token)
+ do
+ if token != n_id then return null
+ return parent.decorate_tag(v, res, token)
+ end
+end
+
+redef class AQid
+ redef fun decorate_tag(v, res, token)
+ do
+ if token != n_id then return null
+ return parent.decorate_tag(v, res, token)
+ end
+end
+
redef class AStdClassdef
redef fun make_tag(v)
do
redef fun make_tag(v)
do
var res = super
- var p = parent
- if p != null then p.decorate_tag(v, res, self)
res.add_class("nc_o")
return res
end
redef class AVarFormExpr
redef fun decorate_tag(v, res, token)
do
+ if token != n_id then return null
var variable = self.variable
if variable == null then return null
res.add_class("nc_v")
redef class AVardeclExpr
redef fun decorate_tag(v, res, token)
do
+ if token != n_id then return null
var variable = self.variable
if variable == null then return null
res.add_class("nc_v")
end
end
-redef class AForExpr
+redef class AForGroup
redef fun decorate_tag(v, res, token)
do
if not token isa TId then return null
redef class AParam
redef fun decorate_tag(v, res, token)
do
+ if token != n_id then return null
var mp = mparameter
if mp == null then return null
var variable = self.variable
redef class AAssertExpr
redef fun decorate_tag(v, res, token)
do
+ if not token isa TId then return null
res.add_class("nc_ast")
return null
end
redef class ALabel
redef fun decorate_tag(v, res, token)
do
+ if not token isa TId then return null
res.add_class("nc_la")
return null
end
redef class AModuledecl
redef fun decorate_tag(v, res, token)
do
+ if not token isa TId then return null
res.add_class("nc_def")
res.add_class("nc_m")
var p = parent
redef class AStdImport
redef fun decorate_tag(v, res, token)
do
+ if not token isa TId then return null
res.add_class("nc_m")
var mm = mmodule
if mm == null then return null
redef class AAttrPropdef
redef fun decorate_tag(v, res, token)
do
+ if not token isa TId then return null
res.add_class("nc_def")
var mpd: nullable MPropDef
mpd = mreadpropdef
redef fun make_tag(v)
do
var res = super
- var p = parent
- if p != null then p.decorate_tag(v, res, self)
res.add_class("nc_i")
return res
end
redef fun make_tag(v)
do
var res = super
- var p = parent
- if p != null then p.decorate_tag(v, res, self)
res.add_class("nc_a")
return res
end
redef class AAttrFormExpr
redef fun decorate_tag(v, res, token)
do
+ if not token isa TAttrid then return null
var p = mproperty
if p == null then return null
return p.intro.infobox(v)
redef fun make_tag(v)
do
var res = super
- var p = parent
- if p != null then p.decorate_tag(v, res, self)
res.add_class("nc_t")
return res
end
redef class AType
redef fun decorate_tag(v, res, token)
do
+ if not token isa TClassid then return null
var mt = mtype
if mt == null then return null
mt = mt.undecorate
redef class AFormaldef
redef fun decorate_tag(v, res, token)
do
+ if not token isa TClassid then return null
res.add_class("nc_vt")
if mtype == null then return null
return mtype.infobox(v)
redef class ATypePropdef
redef fun decorate_tag(v, res, token)
do
+ if not token isa TClassid then return null
res.add_class("nc_def")
var md = mpropdef
if md == null then return null
redef fun make_tag(v)
do
var res = super
- if not parent isa ADoc then
+ if is_loose then
res.add_class("nc_c")
end
return res
do
var res = super
res.add_class("nc_l")
- var p = parent
- if p != null then p.decorate_tag(v, res, self)
return res
end
end
# Workaround to tag strings
res.classes.remove("nc_l")
res.add_class("nc_s")
- return null
+ return super
end
end
redef class AExpr