| author | paulson <lp15@cam.ac.uk> | 
| Fri, 11 Apr 2025 21:56:56 +0100 | |
| changeset 82486 | 451f428c5814 | 
| parent 82142 | 508a673c87ac | 
| permissions | -rw-r--r-- | 
| 76508 
ecb9e6d29698
support for the Prism.js syntax highlighter -- via external Node.js process;
 wenzelm parents: diff
changeset | 1 | /* Title: Pure/Tools/prismjs.scala | 
| 
ecb9e6d29698
support for the Prism.js syntax highlighter -- via external Node.js process;
 wenzelm parents: diff
changeset | 2 | Author: Makarius | 
| 
ecb9e6d29698
support for the Prism.js syntax highlighter -- via external Node.js process;
 wenzelm parents: diff
changeset | 3 | |
| 
ecb9e6d29698
support for the Prism.js syntax highlighter -- via external Node.js process;
 wenzelm parents: diff
changeset | 4 | Support for the Prism.js syntax highlighter -- via external Node.js process. | 
| 
ecb9e6d29698
support for the Prism.js syntax highlighter -- via external Node.js process;
 wenzelm parents: diff
changeset | 5 | */ | 
| 
ecb9e6d29698
support for the Prism.js syntax highlighter -- via external Node.js process;
 wenzelm parents: diff
changeset | 6 | |
| 
ecb9e6d29698
support for the Prism.js syntax highlighter -- via external Node.js process;
 wenzelm parents: diff
changeset | 7 | package isabelle | 
| 
ecb9e6d29698
support for the Prism.js syntax highlighter -- via external Node.js process;
 wenzelm parents: diff
changeset | 8 | |
| 
ecb9e6d29698
support for the Prism.js syntax highlighter -- via external Node.js process;
 wenzelm parents: diff
changeset | 9 | |
| 
ecb9e6d29698
support for the Prism.js syntax highlighter -- via external Node.js process;
 wenzelm parents: diff
changeset | 10 | object Prismjs {
 | 
| 
ecb9e6d29698
support for the Prism.js syntax highlighter -- via external Node.js process;
 wenzelm parents: diff
changeset | 11 | /* component resources */ | 
| 
ecb9e6d29698
support for the Prism.js syntax highlighter -- via external Node.js process;
 wenzelm parents: diff
changeset | 12 | |
| 
ecb9e6d29698
support for the Prism.js syntax highlighter -- via external Node.js process;
 wenzelm parents: diff
changeset | 13 |   val HOME: Path = Path.explode("$ISABELLE_PRISMJS_HOME")
 | 
| 
ecb9e6d29698
support for the Prism.js syntax highlighter -- via external Node.js process;
 wenzelm parents: diff
changeset | 14 | |
| 76513 | 15 |   sealed case class Language(names: List[String]) {
 | 
| 16 | require(names.nonEmpty) | |
| 17 | ||
| 18 | def name: String = names.head | |
| 19 | def alias: List[String] = names.tail | |
| 20 | override def toString: String = name | |
| 21 | } | |
| 22 | ||
| 23 |   lazy val languages: List[Language] = {
 | |
| 76508 
ecb9e6d29698
support for the Prism.js syntax highlighter -- via external Node.js process;
 wenzelm parents: diff
changeset | 24 |     val components_path = HOME + Path.explode("components.json")
 | 
| 
ecb9e6d29698
support for the Prism.js syntax highlighter -- via external Node.js process;
 wenzelm parents: diff
changeset | 25 | val components_json = JSON.parse(File.read(components_path)) | 
| 
ecb9e6d29698
support for the Prism.js syntax highlighter -- via external Node.js process;
 wenzelm parents: diff
changeset | 26 |     JSON.value(components_json, "languages") match {
 | 
| 
ecb9e6d29698
support for the Prism.js syntax highlighter -- via external Node.js process;
 wenzelm parents: diff
changeset | 27 | case Some(JSON.Object(langs)) => | 
| 78592 | 28 |         (for (case (name, JSON.Object(info)) <- langs.iterator if name != "meta") yield {
 | 
| 76508 
ecb9e6d29698
support for the Prism.js syntax highlighter -- via external Node.js process;
 wenzelm parents: diff
changeset | 29 | val alias = | 
| 
ecb9e6d29698
support for the Prism.js syntax highlighter -- via external Node.js process;
 wenzelm parents: diff
changeset | 30 |             JSON.Value.List.unapply(info.getOrElse("alias", Nil), JSON.Value.String.unapply)
 | 
| 
ecb9e6d29698
support for the Prism.js syntax highlighter -- via external Node.js process;
 wenzelm parents: diff
changeset | 31 | .getOrElse(Nil) | 
| 76513 | 32 | Language(name :: alias) | 
| 76516 | 33 | }).toList.sortBy(_.name) | 
| 76508 
ecb9e6d29698
support for the Prism.js syntax highlighter -- via external Node.js process;
 wenzelm parents: diff
changeset | 34 |       case _ => error("Failed to determine languages from " + components_path)
 | 
| 
ecb9e6d29698
support for the Prism.js syntax highlighter -- via external Node.js process;
 wenzelm parents: diff
changeset | 35 | } | 
| 
ecb9e6d29698
support for the Prism.js syntax highlighter -- via external Node.js process;
 wenzelm parents: diff
changeset | 36 | } | 
| 
ecb9e6d29698
support for the Prism.js syntax highlighter -- via external Node.js process;
 wenzelm parents: diff
changeset | 37 | |
| 76513 | 38 | def check_language(name: String): Unit = | 
| 39 |     if (!languages.exists(_.names.contains(name))) error("Unknown language " + quote(name))
 | |
| 76508 
ecb9e6d29698
support for the Prism.js syntax highlighter -- via external Node.js process;
 wenzelm parents: diff
changeset | 40 | |
| 76513 | 41 | |
| 42 | /* generate JavaScript */ | |
| 76508 
ecb9e6d29698
support for the Prism.js syntax highlighter -- via external Node.js process;
 wenzelm parents: diff
changeset | 43 | |
| 
ecb9e6d29698
support for the Prism.js syntax highlighter -- via external Node.js process;
 wenzelm parents: diff
changeset | 44 | def prelude(lang: JS.Source): JS.Source = | 
| 
ecb9e6d29698
support for the Prism.js syntax highlighter -- via external Node.js process;
 wenzelm parents: diff
changeset | 45 | cat_lines(List( | 
| 
ecb9e6d29698
support for the Prism.js syntax highlighter -- via external Node.js process;
 wenzelm parents: diff
changeset | 46 | Nodejs.require_fs, | 
| 76510 | 47 |       Nodejs.require_path("const prismjs", HOME),
 | 
| 48 |       Nodejs.require_path("prismjs.load", HOME + Path.explode("components"), dir = true),
 | |
| 49 |       JS.function("prismjs.load", lang),
 | |
| 76508 
ecb9e6d29698
support for the Prism.js syntax highlighter -- via external Node.js process;
 wenzelm parents: diff
changeset | 50 | """ | 
| 76513 | 51 | function prismjs_encode(t) {
 | 
| 52 |   if (t instanceof prismjs.Token) {
 | |
| 53 | var types = [t.type] | |
| 54 |     if (Array.isArray(t.alias)) { for (a of t.alias) { types.push(a) } }
 | |
| 55 |     else if (t.alias !== undefined) { types.push(t.alias) }
 | |
| 56 |     return {"types": types, "content": prismjs_encode(t.content) }
 | |
| 57 | } | |
| 58 |   else if (Array.isArray(t)) { return t.map(prismjs_encode) }
 | |
| 76508 
ecb9e6d29698
support for the Prism.js syntax highlighter -- via external Node.js process;
 wenzelm parents: diff
changeset | 59 |   else { return t }
 | 
| 
ecb9e6d29698
support for the Prism.js syntax highlighter -- via external Node.js process;
 wenzelm parents: diff
changeset | 60 | } | 
| 
ecb9e6d29698
support for the Prism.js syntax highlighter -- via external Node.js process;
 wenzelm parents: diff
changeset | 61 | |
| 
ecb9e6d29698
support for the Prism.js syntax highlighter -- via external Node.js process;
 wenzelm parents: diff
changeset | 62 | function prismjs_tokenize(text, lang) {
 | 
| 76513 | 63 | return prismjs.tokenize(text, prismjs.languages[lang]).map(prismjs_encode) | 
| 76508 
ecb9e6d29698
support for the Prism.js syntax highlighter -- via external Node.js process;
 wenzelm parents: diff
changeset | 64 | } | 
| 
ecb9e6d29698
support for the Prism.js syntax highlighter -- via external Node.js process;
 wenzelm parents: diff
changeset | 65 | """)) | 
| 
ecb9e6d29698
support for the Prism.js syntax highlighter -- via external Node.js process;
 wenzelm parents: diff
changeset | 66 | |
| 76513 | 67 | def main(lang: JS.Source, input: Path, output: Path): JS.Source = | 
| 68 | Nodejs.write_file(output, | |
| 69 |       JS.json_print(JS.function("prismjs_tokenize", Nodejs.read_file(input), lang)))
 | |
| 70 | ||
| 76508 
ecb9e6d29698
support for the Prism.js syntax highlighter -- via external Node.js process;
 wenzelm parents: diff
changeset | 71 | |
| 
ecb9e6d29698
support for the Prism.js syntax highlighter -- via external Node.js process;
 wenzelm parents: diff
changeset | 72 | /* tokenize */ | 
| 
ecb9e6d29698
support for the Prism.js syntax highlighter -- via external Node.js process;
 wenzelm parents: diff
changeset | 73 | |
| 76513 | 74 |   sealed case class Token(types: List[String], content: Content) {
 | 
| 75 | def string: String = content.string | |
| 76514 
2615cf68f6f4
ML support for the Prism.js syntax highlighter -- via Isabelle/Scala;
 wenzelm parents: 
76513diff
changeset | 76 | def yxml: String = YXML.string_of_body(Encode.token(this)) | 
| 76513 | 77 | } | 
| 78 |   sealed abstract class Content { def string: String }
 | |
| 79 | case class Atom(string: String) extends Content | |
| 80 |   case class Nested(tokens: List[Token]) extends Content {
 | |
| 76514 
2615cf68f6f4
ML support for the Prism.js syntax highlighter -- via Isabelle/Scala;
 wenzelm parents: 
76513diff
changeset | 81 | def string: String = tokens.map(_.string).mkString | 
| 
2615cf68f6f4
ML support for the Prism.js syntax highlighter -- via Isabelle/Scala;
 wenzelm parents: 
76513diff
changeset | 82 | } | 
| 
2615cf68f6f4
ML support for the Prism.js syntax highlighter -- via Isabelle/Scala;
 wenzelm parents: 
76513diff
changeset | 83 | |
| 
2615cf68f6f4
ML support for the Prism.js syntax highlighter -- via Isabelle/Scala;
 wenzelm parents: 
76513diff
changeset | 84 |   object Encode {
 | 
| 
2615cf68f6f4
ML support for the Prism.js syntax highlighter -- via Isabelle/Scala;
 wenzelm parents: 
76513diff
changeset | 85 | import XML.Encode._ | 
| 
2615cf68f6f4
ML support for the Prism.js syntax highlighter -- via Isabelle/Scala;
 wenzelm parents: 
76513diff
changeset | 86 | def token(tok: Token): XML.Body = | 
| 
2615cf68f6f4
ML support for the Prism.js syntax highlighter -- via Isabelle/Scala;
 wenzelm parents: 
76513diff
changeset | 87 | pair(list(string), content)(tok.types, tok.content) | 
| 
2615cf68f6f4
ML support for the Prism.js syntax highlighter -- via Isabelle/Scala;
 wenzelm parents: 
76513diff
changeset | 88 |     def content: T[Content] = {
 | 
| 
2615cf68f6f4
ML support for the Prism.js syntax highlighter -- via Isabelle/Scala;
 wenzelm parents: 
76513diff
changeset | 89 | variant[Content](List( | 
| 
2615cf68f6f4
ML support for the Prism.js syntax highlighter -- via Isabelle/Scala;
 wenzelm parents: 
76513diff
changeset | 90 |         { case Atom(a) => (List(a), Nil) },
 | 
| 
2615cf68f6f4
ML support for the Prism.js syntax highlighter -- via Isabelle/Scala;
 wenzelm parents: 
76513diff
changeset | 91 |         { case Nested(a) => (Nil, list(token)(a)) }
 | 
| 
2615cf68f6f4
ML support for the Prism.js syntax highlighter -- via Isabelle/Scala;
 wenzelm parents: 
76513diff
changeset | 92 | )) | 
| 
2615cf68f6f4
ML support for the Prism.js syntax highlighter -- via Isabelle/Scala;
 wenzelm parents: 
76513diff
changeset | 93 | } | 
| 76513 | 94 | } | 
| 95 | ||
| 96 | def decode(json: JSON.T): Option[Token] = | |
| 97 | JSON.Value.String.unapply(json).map(string => Token(Nil, Atom(string))) orElse | |
| 98 |       (for {
 | |
| 99 | types <- JSON.strings(json, "types") | |
| 100 | content_json <- JSON.value(json, "content") | |
| 101 | content <- | |
| 102 | JSON.Value.String.unapply(content_json).map(Atom.apply) orElse | |
| 103 | JSON.Value.List.unapply(content_json, decode).map(Nested.apply) | |
| 104 | } yield Token(types, content)) | |
| 76508 
ecb9e6d29698
support for the Prism.js syntax highlighter -- via external Node.js process;
 wenzelm parents: diff
changeset | 105 | |
| 
ecb9e6d29698
support for the Prism.js syntax highlighter -- via external Node.js process;
 wenzelm parents: diff
changeset | 106 |   def tokenize(text: String, language: String): List[Token] = {
 | 
| 76513 | 107 | check_language(language) | 
| 76508 
ecb9e6d29698
support for the Prism.js syntax highlighter -- via external Node.js process;
 wenzelm parents: diff
changeset | 108 | |
| 
ecb9e6d29698
support for the Prism.js syntax highlighter -- via external Node.js process;
 wenzelm parents: diff
changeset | 109 | val json = | 
| 
ecb9e6d29698
support for the Prism.js syntax highlighter -- via external Node.js process;
 wenzelm parents: diff
changeset | 110 |       Isabelle_System.with_tmp_file("input", ext = "json") { input =>
 | 
| 
ecb9e6d29698
support for the Prism.js syntax highlighter -- via external Node.js process;
 wenzelm parents: diff
changeset | 111 |         Isabelle_System.with_tmp_file("output", ext = "json") { output =>
 | 
| 
ecb9e6d29698
support for the Prism.js syntax highlighter -- via external Node.js process;
 wenzelm parents: diff
changeset | 112 | File.write(input, text) | 
| 
ecb9e6d29698
support for the Prism.js syntax highlighter -- via external Node.js process;
 wenzelm parents: diff
changeset | 113 | val lang = JS.value(language) | 
| 76513 | 114 | Nodejs.execute(prelude(lang) + "\n" + main(lang, input, output)) | 
| 76508 
ecb9e6d29698
support for the Prism.js syntax highlighter -- via external Node.js process;
 wenzelm parents: diff
changeset | 115 | JSON.parse(File.read(output)) | 
| 
ecb9e6d29698
support for the Prism.js syntax highlighter -- via external Node.js process;
 wenzelm parents: diff
changeset | 116 | } | 
| 
ecb9e6d29698
support for the Prism.js syntax highlighter -- via external Node.js process;
 wenzelm parents: diff
changeset | 117 | } | 
| 
ecb9e6d29698
support for the Prism.js syntax highlighter -- via external Node.js process;
 wenzelm parents: diff
changeset | 118 | |
| 76513 | 119 |     JSON.Value.List.unapply(json, decode).getOrElse(error("Malformed JSON: " + json))
 | 
| 76508 
ecb9e6d29698
support for the Prism.js syntax highlighter -- via external Node.js process;
 wenzelm parents: diff
changeset | 120 | } | 
| 76514 
2615cf68f6f4
ML support for the Prism.js syntax highlighter -- via Isabelle/Scala;
 wenzelm parents: 
76513diff
changeset | 121 | |
| 
2615cf68f6f4
ML support for the Prism.js syntax highlighter -- via Isabelle/Scala;
 wenzelm parents: 
76513diff
changeset | 122 | |
| 
2615cf68f6f4
ML support for the Prism.js syntax highlighter -- via Isabelle/Scala;
 wenzelm parents: 
76513diff
changeset | 123 | /* Scala functions in ML */ | 
| 
2615cf68f6f4
ML support for the Prism.js syntax highlighter -- via Isabelle/Scala;
 wenzelm parents: 
76513diff
changeset | 124 | |
| 
2615cf68f6f4
ML support for the Prism.js syntax highlighter -- via Isabelle/Scala;
 wenzelm parents: 
76513diff
changeset | 125 |   object Languages extends Scala.Fun_Strings("Prismjs.languages") {
 | 
| 
2615cf68f6f4
ML support for the Prism.js syntax highlighter -- via Isabelle/Scala;
 wenzelm parents: 
76513diff
changeset | 126 | val here = Scala_Project.here | 
| 
2615cf68f6f4
ML support for the Prism.js syntax highlighter -- via Isabelle/Scala;
 wenzelm parents: 
76513diff
changeset | 127 | def apply(args: List[String]): List[String] = | 
| 
2615cf68f6f4
ML support for the Prism.js syntax highlighter -- via Isabelle/Scala;
 wenzelm parents: 
76513diff
changeset | 128 | languages.map(language => cat_lines(language.names)) | 
| 
2615cf68f6f4
ML support for the Prism.js syntax highlighter -- via Isabelle/Scala;
 wenzelm parents: 
76513diff
changeset | 129 | } | 
| 
2615cf68f6f4
ML support for the Prism.js syntax highlighter -- via Isabelle/Scala;
 wenzelm parents: 
76513diff
changeset | 130 | |
| 
2615cf68f6f4
ML support for the Prism.js syntax highlighter -- via Isabelle/Scala;
 wenzelm parents: 
76513diff
changeset | 131 |   object Tokenize extends Scala.Fun_Strings("Prismjs.tokenize", thread = true) {
 | 
| 
2615cf68f6f4
ML support for the Prism.js syntax highlighter -- via Isabelle/Scala;
 wenzelm parents: 
76513diff
changeset | 132 | val here = Scala_Project.here | 
| 
2615cf68f6f4
ML support for the Prism.js syntax highlighter -- via Isabelle/Scala;
 wenzelm parents: 
76513diff
changeset | 133 | def apply(args: List[String]): List[String] = | 
| 
2615cf68f6f4
ML support for the Prism.js syntax highlighter -- via Isabelle/Scala;
 wenzelm parents: 
76513diff
changeset | 134 |       args match {
 | 
| 
2615cf68f6f4
ML support for the Prism.js syntax highlighter -- via Isabelle/Scala;
 wenzelm parents: 
76513diff
changeset | 135 | case List(text, language) => tokenize(text, language).map(_.yxml) | 
| 
2615cf68f6f4
ML support for the Prism.js syntax highlighter -- via Isabelle/Scala;
 wenzelm parents: 
76513diff
changeset | 136 |         case _ => error("Bad arguments")
 | 
| 
2615cf68f6f4
ML support for the Prism.js syntax highlighter -- via Isabelle/Scala;
 wenzelm parents: 
76513diff
changeset | 137 | } | 
| 
2615cf68f6f4
ML support for the Prism.js syntax highlighter -- via Isabelle/Scala;
 wenzelm parents: 
76513diff
changeset | 138 | } | 
| 
2615cf68f6f4
ML support for the Prism.js syntax highlighter -- via Isabelle/Scala;
 wenzelm parents: 
76513diff
changeset | 139 | } |