36 private val state = Synchronized(VSCode_Resources.State()) |
36 private val state = Synchronized(VSCode_Resources.State()) |
37 |
37 |
38 |
38 |
39 /* document node name */ |
39 /* document node name */ |
40 |
40 |
41 def node_name(uri: String): Document.Node.Name = |
41 def node_file(name: Document.Node.Name): JFile = new JFile(name.node) |
42 { |
42 |
43 val theory = Thy_Header.thy_name_bootstrap(uri).getOrElse("") |
43 def node_name(file: JFile): Document.Node.Name = |
44 val master_dir = |
44 { |
45 if (!Url.is_wellformed_file(uri) || theory == "") "" |
45 val node = file.getPath |
46 else Thy_Header.dir_name(uri) |
46 val theory = Thy_Header.thy_name_bootstrap(node).getOrElse("") |
47 Document.Node.Name(uri, master_dir, theory) |
47 val master_dir = if (theory == "") "" else file.getParent |
|
48 Document.Node.Name(node, master_dir, theory) |
48 } |
49 } |
49 |
50 |
50 override def append(dir: String, source_path: Path): String = |
51 override def append(dir: String, source_path: Path): String = |
51 { |
52 { |
52 val path = source_path.expand |
53 val path = source_path.expand |
53 if (dir == "" || path.is_absolute) Url.print_file(path.file) |
54 if (dir == "" || path.is_absolute) File.platform_path(path) |
54 else if (path.is_current) dir |
55 else if (path.is_current) dir |
55 else Url.normalize_file(dir + "/" + path.implode) |
56 else if (path.is_basic && !dir.endsWith("/") && !dir.endsWith(JFile.separator)) |
|
57 dir + JFile.separator + File.platform_path(path) |
|
58 else if (path.is_basic) dir + File.platform_path(path) |
|
59 else new JFile(dir + JFile.separator + File.platform_path(path)).getCanonicalPath |
56 } |
60 } |
57 |
61 |
58 override def with_thy_reader[A](name: Document.Node.Name, f: Reader[Char] => A): A = |
62 override def with_thy_reader[A](name: Document.Node.Name, f: Reader[Char] => A): A = |
59 { |
63 { |
60 val uri = name.node |
64 val file = node_file(name) |
61 get_model(uri) match { |
65 get_model(file) match { |
62 case Some(model) => |
66 case Some(model) => |
63 val reader = new CharSequenceReader(model.doc.make_text) |
67 f(new CharSequenceReader(model.doc.make_text)) |
64 f(reader) |
68 case None if file.isFile => |
65 |
|
66 case None => |
|
67 val file = Url.parse_file(uri) |
|
68 if (!file.isFile) error("No such file: " + quote(file.toString)) |
|
69 |
|
70 val reader = Scan.byte_reader(file) |
69 val reader = Scan.byte_reader(file) |
71 try { f(reader) } finally { reader.close } |
70 try { f(reader) } finally { reader.close } |
|
71 case None => |
|
72 error("No such file: " + quote(file.toString)) |
72 } |
73 } |
73 } |
74 } |
74 |
75 |
75 |
76 |
76 /* document models */ |
77 /* document models */ |
77 |
78 |
78 def get_model(uri: String): Option[Document_Model] = state.value.models.get(uri) |
79 def get_model(file: JFile): Option[Document_Model] = state.value.models.get(file) |
79 |
80 def get_model(name: Document.Node.Name): Option[Document_Model] = get_model(node_file(name)) |
80 def update_model(session: Session, uri: String, text: String) |
81 |
|
82 def update_model(session: Session, file: JFile, text: String) |
81 { |
83 { |
82 state.change(st => |
84 state.change(st => |
83 { |
85 { |
84 val model = st.models.getOrElse(uri, Document_Model.init(session, uri)) |
86 val model = st.models.getOrElse(file, Document_Model.init(session, node_name(file))) |
85 val model1 = (model.update_text(text) getOrElse model).external(false) |
87 val model1 = (model.update_text(text) getOrElse model).external(false) |
86 st.copy( |
88 st.copy( |
87 models = st.models + (uri -> model1), |
89 models = st.models + (file -> model1), |
88 pending_input = st.pending_input + uri) |
90 pending_input = st.pending_input + file) |
89 }) |
91 }) |
90 } |
92 } |
91 |
93 |
92 def close_model(uri: String): Option[Document_Model] = |
94 def close_model(file: JFile): Option[Document_Model] = |
93 state.change_result(st => |
95 state.change_result(st => |
94 st.models.get(uri) match { |
96 st.models.get(file) match { |
95 case None => (None, st) |
97 case None => (None, st) |
96 case Some(model) => |
98 case Some(model) => |
97 (Some(model), st.copy(models = st.models + (uri -> model.external(true)))) |
99 (Some(model), st.copy(models = st.models + (file -> model.external(true)))) |
98 }) |
100 }) |
99 |
101 |
100 def sync_models(changed_files: Set[JFile]): Boolean = |
102 def sync_models(changed_files: Set[JFile]): Boolean = |
101 state.change_result(st => |
103 state.change_result(st => |
102 { |
104 { |
103 val changed_models = |
105 val changed_models = |
104 (for { |
106 (for { |
105 (uri, model) <- st.models.iterator |
107 (file, model) <- st.models.iterator |
106 if changed_files(model.file) |
108 if changed_files(file) && model.external_file |
107 model1 <- model.update_file |
109 model1 <- |
108 } yield (uri, model1)).toList |
110 (try { model.update_text(File.read(file)) } |
|
111 catch { case ERROR(_) => None }) |
|
112 } yield (file, model1)).toList |
109 if (changed_models.isEmpty) (false, st) |
113 if (changed_models.isEmpty) (false, st) |
110 else (true, |
114 else (true, |
111 st.copy( |
115 st.copy( |
112 models = (st.models /: changed_models)(_ + _), |
116 models = (st.models /: changed_models)(_ + _), |
113 pending_input = (st.pending_input /: changed_models.iterator.map(_._1))(_ + _))) |
117 pending_input = (st.pending_input /: changed_models.iterator.map(_._1))(_ + _))) |
157 { |
161 { |
158 state.change(st => |
162 state.change(st => |
159 { |
163 { |
160 val changed_models = |
164 val changed_models = |
161 (for { |
165 (for { |
162 uri <- st.pending_input.iterator |
166 file <- st.pending_input.iterator |
163 model <- st.models.get(uri) |
167 model <- st.models.get(file) |
164 res <- model.flush_edits |
168 (edits, model1) <- model.flush_edits |
165 } yield res).toList |
169 } yield (edits, (file, model1))).toList |
166 |
170 |
167 session.update(Document.Blobs.empty, changed_models.flatMap(_._1)) |
171 session.update(Document.Blobs.empty, changed_models.flatMap(_._1)) |
168 st.copy( |
172 st.copy( |
169 models = (st.models /: changed_models) { case (ms, (_, m)) => ms + (m.uri -> m) }, |
173 models = (st.models /: changed_models.iterator.map(_._2))(_ + _), |
170 pending_input = Set.empty) |
174 pending_input = Set.empty) |
171 }) |
175 }) |
172 } |
176 } |
173 |
177 |
174 |
178 |
175 /* pending output */ |
179 /* pending output */ |
176 |
180 |
177 def update_output(changed_nodes: List[String]): Unit = |
181 def update_output(changed_nodes: List[JFile]): Unit = |
178 state.change(st => st.copy(pending_output = st.pending_output ++ changed_nodes)) |
182 state.change(st => st.copy(pending_output = st.pending_output ++ changed_nodes)) |
179 |
183 |
180 def flush_output(channel: Channel) |
184 def flush_output(channel: Channel) |
181 { |
185 { |
182 state.change(st => |
186 state.change(st => |
183 { |
187 { |
184 val changed_iterator = |
188 val changed_iterator = |
185 for { |
189 for { |
186 uri <- st.pending_output.iterator |
190 file <- st.pending_output.iterator |
187 model <- st.models.get(uri) |
191 model <- st.models.get(file) |
188 rendering = model.rendering() |
192 rendering = model.rendering() |
189 (diagnostics, model1) <- model.publish_diagnostics(rendering) |
193 (diagnostics, model1) <- model.publish_diagnostics(rendering) |
190 } yield { |
194 } yield { |
191 channel.diagnostics(model1.uri, rendering.diagnostics_output(diagnostics)) |
195 channel.diagnostics(file, rendering.diagnostics_output(diagnostics)) |
192 model1 |
196 (file, model1) |
193 } |
197 } |
194 st.copy( |
198 st.copy( |
195 models = (st.models /: changed_iterator) { case (ms, m) => ms + (m.uri -> m) }, |
199 models = (st.models /: changed_iterator)(_ + _), |
196 pending_output = Set.empty) |
200 pending_output = Set.empty) |
197 } |
201 } |
198 ) |
202 ) |
199 } |
203 } |
200 } |
204 } |