- protected fun do_highlight(first_token: Token, last_token: nullable Token)
- do
- var stack2 = new Array[HTMLTag]
- var stack = new Array[Prod]
- var line = 0
- var c: nullable Token = first_token
- var hv = self
- 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
- if not stack2.is_empty then html = stack2.first
- end
-
- # Return a default CSS content related to CSS classes used in the `html` tree.
- # Could be inlined in the `.html` file of saved as a specific `.css` file.
- fun css_content: String
- 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 */
-.nitcode .line:hover{ background-color: #FFFFE0; } /* current line */
-.nitcode :target { background-color: #FFF3C2 } /* target highlight*/
-/* lexical raw tokens. independent of usage or semantic: */
-.nitcode .nc_c { color: gray; font-style: italic; } /* comment */
-.nitcode .nc_d { color: #3D8127; font-style: italic; } /* documentation comments */
-.nitcode .nc_k { font-weight: bold; } /* keyword */
-.nitcode .nc_o {} /* operator */
-.nitcode .nc_i {} /* standard identifier */
-.nitcode .nc_t { color: #445588; font-weight: bold; } /* type/class identifier */
-.nitcode .nc_a { color: #445588; font-style: italic; } /* old style attribute identifier */
-.nitcode .nc_l { color: #009999; } /* char and number literal */
-.nitcode .nc_s { color: #8F1546; } /* string literal */
-/* syntactic token usage. added because of their position in the AST */
-.nitcode .nc_ast { color: blue; } /* assert label */
-.nitcode .nc_la { color: blue; } /* break/continue label */
-.nitcode .nc_m { color: #445588; } /* module name */
-/* syntactic groups */
-.nitcode .nc_def { font-weight: bold; color: blue; } /* name used in a definition */
- .nitcode .nc_def.nc_a { color: blue; } /* name used in a attribute definition */
- .nitcode .nc_def.nc_t { color: blue; } /* name used in a class or vt definition */
-.nitcode .nc_ss { color: #9E6BEB; } /* superstrings */
-.nitcode .nc_cdef {} /* A whole class definition */
-.nitcode .nc_pdef {} /* A whole property definition */
-/* semantic token usage */
-.nitcode .nc_v { font-style: italic; } /* local variable or parameter */
-.nitcode .nc_vt { font-style: italic; } /* virtual type or formal type */
-
-.nitcode .nc_error { border: 1px red solid;} /* not used */
-.popover { max-width: 800px !important; }
-"""
- end
-
- # Additional content to inject in the <head> tag
- # Note: does not include `css_content`; handle it yourself.
- fun head_content: String
- do
- return """<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css">\n"""
- end
-
- # Additional content to inject just before the closing </body> tag
- fun foot_content: String
- do
- return """
-<script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
-<script src="http://netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script>
-<script>$(".popupable").popover({html:true, placement:'top'})/*initialize bootstrap popover*/</script>"""
- end
-
- # Fully process `content` as a Nit source file.
- #
- # Set `print_errors = true` to print errors in the code to the console.
- fun highlightcode(content: String, print_errors: nullable Bool): HLCode
- do
- # Prepare a stand-alone tool context
- var tc = new ToolContext
- tc.nit_dir = tc.locate_nit_dir # still use the common lib to have core
- tc.keep_going = true # no exit, obviously
- if print_errors != true then tc.opt_warn.value = -1 # no output
-
- # Prepare an stand-alone model and model builder.
- # Unfortunately, models are enclosing and append-only.
- # There is no way (yet?) to have a shared module `core` with
- # isolated and throwable user modules.
- var model = new Model
- var mb = new ModelBuilder(model, tc)
-
- # Parse the code
- var source = new SourceFile.from_string("", content + "\n")
- var lexer = new Lexer(source)
- var parser = new Parser(lexer)
- var tree = parser.parse
-
- var hlcode = new HLCode(self, content, source)
-
- # Check syntax error
- var eof = tree.n_eof
- if eof isa AError then
- mb.error(eof, eof.message)
- highlight_source(source)
- return hlcode
- end
- var amodule = tree.n_base.as(not null)
-
- # Load the AST as a module in the model
- # Then process it
- mb.load_rt_module(null, amodule, "")
- mb.run_phases
-
- # Highlight the processed module
- highlight_node(amodule)
- return hlcode
- end
-end
-
-redef class HTMLTag
- # Attach the infobox to the node by using BootStrap popover
- fun attach_infobox(infobox: HInfoBox)
- do
- classes.add("popupable")
- attrs["title"] = infobox.title
- var href = infobox.href
- if href != null then
- attrs["data-title"] = """<a href="{{{href}}}">{{{infobox.title}}}</a>"""
- end
- attrs["data-content"] = infobox.content.write_to_string
- attrs["data-toggle"] = "popover"
- end
-end
-
-
-# A generic information container that can be used to decorate AST entities
-class HInfoBox
- # The visitor used for contextualisation, if needed
- var visitor: HighlightVisitor
-
- # A short title for the AST element
- var title: String
-
- # The primary link where the entity points
- # null if no link
- var href: nullable String = null
-
- # The content of the popuped infobox
- var content = new HTMLTag("div")
-
- # Append a new field in the popuped infobox
- fun new_field(title: String): HTMLTag
- do
- content.open("b").text(title)
- content.append(" ")
- var res = content.open("span")
- content.open("br")
- return res
- end
-
- # Append a new dropdown in the popuped content
- fun new_dropdown(title, text: String, text_is_html: nullable Bool): HTMLTag
- do
- content.add_raw_html """<div class="dropdown"> <a data-toggle="dropdown" href="#"><b>"""
- content.append(title)
- content.add_raw_html "</b> "
- if text_is_html == true then
- content.add_raw_html(text)
- else content.append(text)
- content.add_raw_html """<span class="caret"></span></a>"""
- var res = content.open("ul").add_class("dropdown-menu").attr("role", "menu").attr("aria-labelledby", "dLabel")
- content.add_raw_html "</div>"
- return res
- end