src/Tools/VSCode/src/build_vscode_extension.scala
changeset 75289 9c72957e5c4a
parent 75281 fab9b0bd9715
child 75290 c9ee3028c125
equal deleted inserted replaced
75288:ae330b4209d6 75289:9c72957e5c4a
    10 import isabelle._
    10 import isabelle._
    11 
    11 
    12 
    12 
    13 object Build_VSCode
    13 object Build_VSCode
    14 {
    14 {
    15   val extension_dir = Path.explode("$ISABELLE_VSCODE_HOME/extension")
    15   val extension_dir: Path = Path.explode("$ISABELLE_VSCODE_HOME/extension")
    16 
    16 
    17 
    17 
    18   /* grammar */
    18   /* build grammar */
    19 
    19 
    20   def build_grammar(options: Options, progress: Progress = new Progress): Unit =
    20   def default_logic: String = Isabelle_System.getenv("ISABELLE_LOGIC")
       
    21 
       
    22   def build_grammar(options: Options,
       
    23     logic: String = default_logic,
       
    24     dirs: List[Path] = Nil,
       
    25     progress: Progress = new Progress): Unit =
    21   {
    26   {
    22     val logic = TextMate_Grammar.default_logic
    27     val keywords =
    23     val keywords = Sessions.base_info(options, logic).check.base.overall_syntax.keywords
    28       Sessions.base_info(options, logic, dirs = dirs).check.base.overall_syntax.keywords
    24 
    29 
    25     val output_path = extension_dir + Path.explode(TextMate_Grammar.default_output(logic))
    30     val output_path = extension_dir + Path.explode("isabelle-grammar.json")
    26     progress.echo(output_path.expand.implode)
    31     progress.echo(output_path.expand.implode)
    27     File.write_backup(output_path, TextMate_Grammar.generate(keywords))
    32 
       
    33     val (minor_keywords, operators) =
       
    34       keywords.minor.iterator.toList.partition(Symbol.is_ascii_identifier)
       
    35 
       
    36     def major_keywords(pred: String => Boolean): List[String] =
       
    37       (for {
       
    38         k <- keywords.major.iterator
       
    39         kind <- keywords.kinds.get(k)
       
    40         if pred(kind)
       
    41       } yield k).toList
       
    42 
       
    43     val keywords1 =
       
    44       major_keywords(k => k != Keyword.THY_END && k != Keyword.PRF_ASM && k != Keyword.PRF_ASM_GOAL)
       
    45     val keywords2 = minor_keywords ::: major_keywords(Set(Keyword.THY_END))
       
    46     val keywords3 = major_keywords(Set(Keyword.PRF_ASM, Keyword.PRF_ASM_GOAL))
       
    47 
       
    48     def grouped_names(as: List[String]): String =
       
    49       JSON.Format("\\b(" + as.sorted.map(Library.escape_regex).mkString("|") + ")\\b")
       
    50 
       
    51     File.write_backup(output_path, """{
       
    52   "name": "Isabelle",
       
    53   "scopeName": "source.isabelle",
       
    54   "fileTypes": ["thy"],
       
    55   "uuid": """ + JSON.Format(UUID.random().toString) + """,
       
    56   "repository": {
       
    57     "comment": {
       
    58       "patterns": [
       
    59         {
       
    60           "name": "comment.block.isabelle",
       
    61           "begin": "\\(\\*",
       
    62           "patterns": [{ "include": "#comment" }],
       
    63           "end": "\\*\\)"
       
    64         }
       
    65       ]
       
    66     },
       
    67     "cartouche": {
       
    68       "patterns": [
       
    69         {
       
    70           "name": "string.quoted.other.multiline.isabelle",
       
    71           "begin": "(?:\\\\<open>|‹)",
       
    72           "patterns": [{ "include": "#cartouche" }],
       
    73           "end": "(?:\\\\<close>|›)"
       
    74         }
       
    75       ]
       
    76     }
       
    77   },
       
    78   "patterns": [
       
    79     {
       
    80       "include": "#comment"
       
    81     },
       
    82     {
       
    83       "include": "#cartouche"
       
    84     },
       
    85     {
       
    86       "name": "keyword.control.isabelle",
       
    87       "match": """ + grouped_names(keywords1) + """
       
    88     },
       
    89     {
       
    90       "name": "keyword.other.unit.isabelle",
       
    91       "match": """ + grouped_names(keywords2) + """
       
    92     },
       
    93     {
       
    94       "name": "keyword.operator.isabelle",
       
    95       "match": """ + grouped_names(operators) + """
       
    96     },
       
    97     {
       
    98       "name": "entity.name.type.isabelle",
       
    99       "match": """ + grouped_names(keywords3) + """
       
   100     },
       
   101     {
       
   102       "name": "constant.numeric.isabelle",
       
   103       "match": "\\b\\d*\\.?\\d+\\b"
       
   104     },
       
   105     {
       
   106       "name": "string.quoted.double.isabelle",
       
   107       "begin": "\"",
       
   108       "patterns": [
       
   109         {
       
   110           "name": "constant.character.escape.isabelle",
       
   111           "match": """ + JSON.Format("""\\[\"]|\\\d\d\d""") + """
       
   112         }
       
   113       ],
       
   114       "end": "\""
       
   115     },
       
   116     {
       
   117       "name": "string.quoted.backtick.isabelle",
       
   118       "begin": "`",
       
   119       "patterns": [
       
   120         {
       
   121           "name": "constant.character.escape.isabelle",
       
   122           "match": """ + JSON.Format("""\\[\`]|\\\d\d\d""") + """
       
   123         }
       
   124       ],
       
   125       "end": "`"
       
   126     },
       
   127     {
       
   128       "name": "string.quoted.verbatim.isabelle",
       
   129       "begin": """ + JSON.Format("""\{\*""") + """,
       
   130       "patterns": [
       
   131         { "match": """ + JSON.Format("""[^*]+|\*(?!\})""") + """ }
       
   132       ],
       
   133       "end": """ + JSON.Format("""\*\}""") + """
       
   134     }
       
   135   ]
       
   136 }
       
   137 """)
    28   }
   138   }
    29 
   139 
    30 
   140 
    31   /* extension */
   141   /* extension */
    32 
   142 
    62 
   172 
    63   val isabelle_tool =
   173   val isabelle_tool =
    64     Isabelle_Tool("build_vscode_extension", "build Isabelle/VSCode extension module",
   174     Isabelle_Tool("build_vscode_extension", "build Isabelle/VSCode extension module",
    65       Scala_Project.here, args =>
   175       Scala_Project.here, args =>
    66     {
   176     {
       
   177       var dirs: List[Path] = Nil
       
   178       var logic = default_logic
    67       var install = false
   179       var install = false
    68       var uninstall = false
   180       var uninstall = false
    69 
   181 
    70       val getopts = Getopts("""
   182       val getopts = Getopts("""
    71 Usage: isabelle build_vscode_extension
   183 Usage: isabelle build_vscode_extension
    72 
   184 
    73   Options are:
   185   Options are:
    74     -I           install resulting extension
   186     -I           install resulting extension
    75     -U           uninstall extension (no build)
   187     -U           uninstall extension (no build)
       
   188     -l NAME      logic session name (default ISABELLE_LOGIC=""" + quote(default_logic) + """)
    76 
   189 
    77 Build Isabelle/VSCode extension module in directory
   190 Build Isabelle/VSCode extension module in directory
    78 """ + extension_dir.expand + """
   191 """ + extension_dir.expand + """
    79 """,
   192 """,
       
   193         "d:" -> (arg => dirs = dirs ::: List(Path.explode(arg))),
       
   194         "l:" -> (arg => logic = arg),
    80         "I" -> (_ => install = true),
   195         "I" -> (_ => install = true),
    81         "U" -> (_ => uninstall = true))
   196         "U" -> (_ => uninstall = true))
    82 
   197 
    83       val more_args = getopts(args)
   198       val more_args = getopts(args)
    84       if (more_args.nonEmpty) getopts.usage()
   199       if (more_args.nonEmpty) getopts.usage()
    88 
   203 
    89       if (uninstall) {
   204       if (uninstall) {
    90         uninstall_extension(progress = progress)
   205         uninstall_extension(progress = progress)
    91       }
   206       }
    92       else {
   207       else {
    93         build_grammar(options, progress = progress)
   208         build_grammar(options, logic = logic, dirs = dirs, progress = progress)
    94         val path = build_extension(progress = progress)
   209         val path = build_extension(progress = progress)
    95         if (install) install_extension(path, progress = progress)
   210         if (install) install_extension(path, progress = progress)
    96       }
   211       }
    97     })
   212     })
    98 }
   213 }