I would like to enter math formulae in Scaladoc documentation of mathematical Scala code. In Java, I found a library called LatexTaglet that can do exactly this for Javadoc, by writing formulae in Latex:
http://latextaglet.sourceforge.net/
And it seems to integrate well with Maven (reporting/plugins section of a POM). Is there an equivalent library for Scaladoc? If not, how could I integrate this library with SBT?
I also considered using MathML (http://www.w3.org/Math/), but looks too verbose. Is there an editor you would recommend? Does MathML integrate well with Scaladoc?
Thank you for your help!
To follow on #mergeconflict answer, here is how I did it
As there is no proper solution, what I did is to implement a crawler that parse all generated html files, and replace any found "import tag" (see code below), by the import of the MathJax script:
lazy val mathFormulaInDoc = taskKey[Unit]("add MathJax script import in doc html to display nice latex formula")
mathFormulaInDoc := {
val apiDir = (doc in Compile).value
val docDir = apiDir // /"some"/"subfolder" // in my case, only api/some/solder is parsed
// will replace this "importTag" by "scriptLine
val importTag = "##import MathJax"
val scriptLine = "<script type=\"text/javascript\" src=\"https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML\"> </script>"
// find all html file and apply patch
if(docDir.isDirectory)
listHtmlFile(docDir).foreach { f =>
val content = Source.fromFile(f).getLines().mkString("\n")
if(content.contains(importTag)) {
val writer = new PrintWriter(f)
writer.write(content.replace(importTag, scriptLine))
writer.close()
}
}
}
// attach this task to doc task
mathFormulaInDoc <<= mathFormulaInDoc triggeredBy (doc in Compile)
// function that find html files recursively
def listHtmlFile(dir: java.io.File): List[java.io.File] = {
dir.listFiles.toList.flatMap { f =>
if(f.getName.endsWith(".html")) List(f)
else if(f.isDirectory) listHtmlFile(f)
else List[File]()
}
}
As you could see, this crawler task is attached to the doc task, to it is done automatically by sbt doc.
Here is an example of doc that will be rendered with formula
/**
* Compute the energy using formula:
*
* ##import MathJax
*
* $$e = m\times c^2$$
*/
def energy(m: Double, c: Double) = m*c*c
Now, it would be possible to improve this code. For example:
add the script import in the html head section
avoid reading the whole files (maybe add a rule that the import tag should be in the first few lines
add the script to the sbt package, and add it to the target/api folder using some suitable task
The short answer is: no. LaTeXTaglet is made possible by the JavaDoc Taglet API. There is no equivalent in Scaladoc, therefore no clean solution.
However, I can think of a hack that might be easy enough to do:
There's a library called MathJax, which looks for LaTeX-style math formulae in an HTML page and dynamically renders it in place. I've used it before, it's pretty nice; all you have to do is include the script. So you could do two things:
Edit and rebuild the Scaladoc source to include MathJax, or...
Write a little post-processor crawl all of Scaladoc's HTML output after it runs, and inject MathJax into each file.
That way, you could just write LaTeX formulae directly in your Scala comments and they should be rendered in the browser. Of course if you wanted a non-hacky solution, I'd suggest you create a taglet-like API for Scaladoc ;)
The forthcoming scala3 aka Dotty has in-built support for markdown which allows rendering simple math formulas using a subset of Latex.
I solved this by using the same approach as Spark did.
Put this JavaScript in a file somewhere in your project:
// From Spark, licensed APL2
// https://github.com/apache/spark/commit/36827ddafeaa7a683362eb8da31065aaff9676d5
function injectMathJax() {
var script = document.createElement('script');
script.type = 'text/javascript';
script.async = true;
script.onload = function(){
MathJax.Hub.Config({
displayAlign: "left",
tex2jax: {
inlineMath: [ ["$", "$"], ["\\\\(","\\\\)"] ],
displayMath: [ ["$$","$$"], ["\\[", "\\]"] ],
processEscapes: true,
skipTags: ['script', 'noscript', 'style', 'textarea', 'pre', 'a']
}
});
};
script.src = ('https:' == document.location.protocol ? 'https://' : 'http://') +
'cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-MML-AM_CHTML';
document.getElementsByTagName('head')[0].appendChild(script);
}
document.addEventListener('DOMContentLoaded', injectMathJax)
and this little bit into your build.sbt:
lazy val injectMathJax = taskKey[Unit]("Injects MathJax Javascript into Scaladoc template.js")
injectMathJax := {
val docPath = (Compile / doc).value
val templateJsOutput = docPath / "lib" / "template.js"
streams.value.log.info(s"Adding MathJax initialization to $templateJsOutput")
// change this path, obviously
IO.append(templateJsOutput, IO.readBytes(file("doc/static/js/mathjax_init.js")))
},
injectMathJax := (injectMathJax triggeredBy (Compile / doc)).value
I'll eventually get around to building and publicly releasing a plugin for this, as I'm likely going to be using Scala 2.x for a very long time.
Caveats to this approach:
Formulae must be in $ or $$ in Scaladoc comments.
It's best to further enclose them in the comment with another element. I've been using <blockquote>.
For at least the Scaladoc included with Scala 2.11.x, a formula will only show on class, object, and trait top-level symbols. Something in the toggle to show the full comment breaks when MathJax-inject elements are present. I've not figured it out yet, but if I do, I'll submit a patch to Scaladoc directly.
Example:
/**
* A Mean Absolute Scaled Error implementation
*
* Non-seasonal MASE formula:
* <blockquote>
* $$
* \mathrm{MASE} = \mathrm{mean}\left( \frac{\left| e_j \right|}{\frac{1}{T-1}\sum_{t=2}^T \left| Y_t-Y_{t-1}\right|} \right) = \frac{\frac{1}{J}\sum_{j}\left| e_j \right|}{\frac{1}{T-1}\sum_{t=2}^T \left| Y_t-Y_{t-1}\right|}
* $$
* </blockquote>
**/
object MeanAbsoluteScaledError {
Related
I am developing an extension for visual studio code using language server protocol, and I am including the support for "Go to symbol in workspace". My problem is that I don't know how to select the matches...
Actually I use this function I wrote:
function IsInside(word1, word2)
{
var ret = "";
var i1 = 0;
var lenMatch =0, maxLenMatch = 0, minLenMatch = word1.length;
for(var i2=0;i2<word2.length;i2++)
{
if(word1[i1]==word2[i2])
{
lenMatch++;
if(lenMatch>maxLenMatch) maxLenMatch = lenMatch;
ret+=word1[i1];
i1++;
if(i1==word1.length)
{
if(lenMatch<minLenMatch) minLenMatch = lenMatch;
// Trying to filter like VSCode does.
return maxLenMatch>=word1.length/2 && minLenMatch>=2? ret : undefined;
}
} else
{
ret+="Z";
if(lenMatch>0 && lenMatch<minLenMatch)
minLenMatch = lenMatch;
lenMatch=0;
}
}
return undefined;
}
That return the sortText if the word1 is inside the word2, undefined otherwise. My problem are cases like this:
My algorithm see that 'aller' is inside CallServer, but the interface does not mark it like expected.
There is a library or something that I must use for this? the code of VSCode is big and complex and I don't know where start looking for this information...
VSCode's API docs for provideWorkspaceSymbols() provide the following guidance (which I don't think your example violates):
The query-parameter should be interpreted in a relaxed way as the editor will apply its own highlighting and scoring on the results. A good rule of thumb is to match case-insensitive and to simply check that the characters of query appear in their order in a candidate symbol. Don't use prefix, substring, or similar strict matching.
These docs were added in response to this discussion, where somebody had very much the same issue as you.
Having a brief look at VSCode sources, internally it seems to use filters.matchFuzzy2() for the highlighting (see here and here). I don't think it's exposed in the API, so you would probably have to copy it if you wanted the behavior to match exactly.
I want to get html from markdown on Jupyter Notebook.
like this.
from IPython import display
display.Code("import this")._repr_html_()
But I get:
IPython.core.display.Markdown object has no attribute '_repr_html_'.
Any idea?
Here is an example of using the markdown package to convert markdown to HTML and combining it with other HTML
pip install markdown
import ipywidgets as widgets
import markdown
#Convert markdown to html
html = markdown.markdown("""# Pandas and Plotly guide
Here we have [Pandas](https://pandas.pydata.org/) and [Plotly Express library](https://plotly.com/python/plotly-express/) used in combination with:
* Ipyvuetify (ipywidgets Vuetify UI framework)
* Ipymonaco ( a text editor widget)
Available plot types:
""")
# copy some html from the plotly express website
html += """<ul>
<li><strong>Basics</strong>: <code>scatter</code>, <code>line</code>, <code>area</code>, <code>bar</code>, <code>funnel</code>, <code>timeline</code></li>
</ul>"""
help_links = widgets.HTML(value = html)
help_links
I don't think it is (directly) possible; the Markdown -> HTML conversion for, say, mdout = md("## string ..."); display(mdout) seems to happen in JavaScript, in the append_markdown function, defined here:
https://github.com/jupyter/notebook/blob/238828e/notebook/static/notebook/js/outputarea.js#L730
Of course, if someone can come up with a way, to do a JavaScript call from Jupyter Python cell to perform this conversion, and then get the results back in Python before doing the display(...), then it would be possible :)
For more discussion, see:
https://discourse.jupyter.org/t/how-to-obtain-html-string-from-markdown-as-jupyter-does-it/10589
EDIT: However, I just found a method to cheat through this (see also IPython: Adding Javascript scripts to IPython notebook) - you don't get the HTML string directly back in Python, but you can send the markdown string from Python, and control the display() of the converted string; the trick is to write in a separate <div>, and have JavaScript store the result of the conversion there.
So you can put this in a code (Python) cell in Jupyter:
def js_convert_md_html(instring_md):
js_convert = """
<div id="_my_special_div"></div>
<script>
//import * as markdown from "base/js/markdown"; //import declarations may only appear at top level of a module
//define(['base/js/markdown'], function ttttest(markdown) {{ // Mismatched anonymous define() module:
// console.log(markdown);
//}});
//const markdown = require('base/js/markdown'); // redeclaration of const markdown
//console.log(markdown); // is there!
function do_convert_md_html(instr) {{
//return instr.toUpperCase();
markdown.render(instr, {{
with_math: true,
clean_tables: true,
sanitize: true,
}}, function (err, html) {{
//console.log(html); //ok
$("#_my_special_div").html(html);
}});
}}
var myinputstring = '{0}';
do_convert_md_html(myinputstring);
</script>
""".format(instring_md)
return HTML(js_convert)
jsobj = js_convert_md_html("*hello* **world** $$x_2 = e^{x}$$")
display(jsobj)
This results with:
Overview
After looking around the internet for a while, I have not found a good way to omit certain folders from being watched by sbt 1.0.x in a Play Framework application.
Solutions posted for older versions of sbt:
How to exclude a folder from compilation
How to not watch a file for changes in Play Framework
There are a few more, but all more or less the same.
And the release notes for 1.0.2 show that the += and ++= behavior was maintained, but everything else was dropped.
https://www.scala-sbt.org/1.x/docs/sbt-1.0-Release-Notes.html
Source code verifies: https://www.scala-sbt.org/1.0.4/api/sbt/Watched$.html
Would love to see if anyone using sbt 1.0.x has found a solution or workaround to this issue. Thanks!
Taking the approach of how SBT excludes managedSources from watchSources I was able to omit a custom folder from being watched like so:
watchSources := {
val directoryToExclude = "/Users/mgalic/sandbox/scala/scala-seed-project/src/main/scala/dirToExclude"
val filesToExclude = (new File(directoryToExclude) ** "*.scala").get.toSet
val customSourcesFilter = new FileFilter {
override def accept(pathname: File): Boolean = filesToExclude.contains(pathname)
override def toString = s"CustomSourcesFilter($filesToExclude)"
}
watchSources.value.map { source =>
new Source(
source.base,
source.includeFilter,
source.excludeFilter || customSourcesFilter,
source.recursive
)
}
},
Here we use PathFinder to get all the *.scala sources from directoryToExclude:
val filesToExclude = (new File(directoryToExclude) ** "*.scala").get.toSet
Then we create customSourcesFilter using filesToExclude, which we then add to every current WatchSource:
watchSources.value.map { source =>
new Source(
...
source.excludeFilter || customSourcesFilter,
...
)
}
Note the above solution is just something that worked for me, that is, I do not know what is the recommend approach of solving this problem.
I want to write Scala code that can be then translated to EmberJS code.
Can it be done? If not out of the box any suggestion as to how that can be achieved by hacking ScalaJS?
Regards.
Scala.js can emit any kind of JavaScript code, so technically the answer is yes. However, since Ember requires you to define "components" using classes of sorts of its own design, it can be a bit ugly to write in Scala.js. For example, this example taken from the front page:
App.GravatarImageComponent = Ember.Component.extend({
size: 200,
email: '',
gravatarUrl: function() {
var email = this.get('email'),
size = this.get('size');
return 'http://www.gravatar.com/avatar/' + hex_md5(email) + '?s=' + size;
}.property('email', 'size')
});
would have to be written in Scala.js as:
import scala.scalajs.js
import js.Dynamic.{global => g, literal => lit}
g.App.GravatarImageComponent = g.Ember.Component.extend(lit(
size = 200,
email = "",
gravatarUrl = ({ (ths: js.Dynamic) =>
val email = ths.get("email")
val size = ths.get("size")
s"http://www.gravatar.com/avatar/${g.hex_md5(email)}?s=$size"
}: js.ThisFunction).asInstanceOf[js.Dynamic].property("email", "size")
))
which is, well ... JavaScript-ish.
Powerful UI libraries for JavaScript kind of rely so much on the dynamic and weird aspects of JavaScript that they don't fit super well in Scala.js. I am planning to write a React.js-like UI library specifically designed for Scala.js this semester to address this issue.
I'm trying to create a plugin for JSDoc.
I'm following the documentation (which, ironically, is lacking) and I'm not sure how to do this.
My plugin is loaded properly, and I'm trying a simple example. Here's my plugin (which loads, because I can throw an error from there to stop jsdoc from running):
visitNode: function(node, e, parser, currentSourceName) {
if(node.type === 109){
if(!e.comment || e.comment ==="#undocumented"){
var startComment = '/**',
endComment = '\n*/';
var params = node.getParams(),
paramsComment = '';
for(var i=0; i<params.length; i++){
paramsComment += '\n* #param ' + params[i];
}
e.comment = startComment +
paramsComment +
endComment;
}
}
please note that node.type === 109 is equivalent to Token.FUNCTION, which should be available as per their example here, but Token is undefined in the plugin.
If you know of a better site which explains how to write a JSDoc plugin, then that would be very much appreciated too... thanks
I also had this problem and it seems strange that JSDoc does not have some kind of already made option for that or at least a plugin.
Anyway creating this plugin has solved my problem. I am using JSDoc version 3.4:
'use strict';
exports.handlers = {
symbolFound:function(e) {
if(e.astnode.type === "FunctionDeclaration" ) {
if( (e.comment==="#undocumented")){
e.comment = '/** undocumented */';
}
}
}
};