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() |