558 |
563 |
559 def convert(range: Text.Range): Text.Range = range.map(convert) |
564 def convert(range: Text.Range): Text.Range = range.map(convert) |
560 def revert(range: Text.Range): Text.Range = range.map(revert) |
565 def revert(range: Text.Range): Text.Range = range.map(revert) |
561 |
566 |
562 |
567 |
563 def node: Node |
568 /* local node content */ |
564 def nodes: List[(Node.Name, Node)] |
569 |
565 |
570 val node: Node = version.nodes(node_name) |
566 def commands_loading: List[Command] |
571 |
567 def commands_loading_ranges(pred: Node.Name => Boolean): List[Text.Range] |
572 def nodes: List[(Node.Name, Node)] = |
568 def current_command(other_node_name: Node.Name, offset: Text.Offset): Option[Command] |
573 (node_name :: node.load_commands.flatMap(_.blobs_names)). |
|
574 map(name => (name, version.nodes(name))) |
569 |
575 |
570 def node_files: List[Node.Name] = |
576 def node_files: List[Node.Name] = |
571 snippet_command match { |
577 snippet_command match { |
572 case None => List(node_name) |
578 case None => List(node_name) |
573 case Some(command) => node_name :: command.blobs_names |
579 case Some(command) => node_name :: command.blobs_names |
574 } |
580 } |
|
581 |
|
582 |
|
583 /* theory load commands */ |
|
584 |
|
585 val commands_loading: List[Command] = |
|
586 if (node_name.is_theory) Nil |
|
587 else version.nodes.commands_loading(node_name) |
|
588 |
|
589 def commands_loading_ranges(pred: Node.Name => Boolean): List[Text.Range] = |
|
590 (for { |
|
591 cmd <- node.load_commands.iterator |
|
592 blob_name <- cmd.blobs_names.iterator |
|
593 if pred(blob_name) |
|
594 start <- node.command_start(cmd) |
|
595 } yield convert(cmd.core_range + start)).toList |
|
596 |
|
597 |
|
598 /* command as add-on snippet */ |
575 |
599 |
576 def command_snippet(command: Command): Snapshot = |
600 def command_snippet(command: Command): Snapshot = |
577 { |
601 { |
578 val node_name = command.node_name |
602 val node_name = command.node_name |
579 |
603 |
609 markup.to_XML(Text.Range(0, text.length), text, elements) |
637 markup.to_XML(Text.Range(0, text.length), text, elements) |
610 } |
638 } |
611 } |
639 } |
612 } |
640 } |
613 |
641 |
614 def messages: List[(XML.Tree, Position.T)] |
642 |
615 def exports: List[Export.Entry] |
643 /* messages */ |
616 def exports_map: Map[String, Export.Entry] |
644 |
617 |
645 lazy val messages: List[(XML.Tree, Position.T)] = |
618 def find_command(id: Document_ID.Generic): Option[(Node, Command)] |
646 (for { |
|
647 (command, start) <- |
|
648 Document.Node.Commands.starts_pos( |
|
649 node.commands.iterator, Token.Pos.file(node_name.node)) |
|
650 pos = command.span.keyword_pos(start).position(command.span.name) |
|
651 (_, tree) <- state.command_results(version, command).iterator |
|
652 } yield (tree, pos)).toList |
|
653 |
|
654 |
|
655 /* exports */ |
|
656 |
|
657 lazy val exports: List[Export.Entry] = |
|
658 state.node_exports(version, node_name).iterator.map(_._2).toList |
|
659 |
|
660 lazy val exports_map: Map[String, Export.Entry] = |
|
661 (for (entry <- exports.iterator) yield (entry.name, entry)).toMap |
|
662 |
|
663 |
|
664 /* find command */ |
|
665 |
|
666 def find_command(id: Document_ID.Generic): Option[(Node, Command)] = |
|
667 state.lookup_id(id) match { |
|
668 case None => None |
|
669 case Some(st) => |
|
670 val command = st.command |
|
671 val node = version.nodes(command.node_name) |
|
672 if (node.commands.contains(command)) Some((node, command)) else None |
|
673 } |
|
674 |
619 def find_command_position(id: Document_ID.Generic, offset: Symbol.Offset) |
675 def find_command_position(id: Document_ID.Generic, offset: Symbol.Offset) |
620 : Option[Line.Node_Position] |
676 : Option[Line.Node_Position] = |
|
677 for ((node, command) <- find_command(id)) |
|
678 yield { |
|
679 val name = command.node_name.node |
|
680 val sources_iterator = |
|
681 node.commands.iterator.takeWhile(_ != command).map(_.source) ++ |
|
682 (if (offset == 0) Iterator.empty |
|
683 else Iterator.single(command.source(Text.Range(0, command.chunk.decode(offset))))) |
|
684 val pos = (Line.Position.zero /: sources_iterator)(_.advance(_)) |
|
685 Line.Node_Position(name, pos) |
|
686 } |
|
687 |
|
688 def current_command(other_node_name: Node.Name, offset: Text.Offset): Option[Command] = |
|
689 if (other_node_name.is_theory) { |
|
690 val other_node = version.nodes(other_node_name) |
|
691 val iterator = other_node.command_iterator(revert(offset) max 0) |
|
692 if (iterator.hasNext) { |
|
693 val (command0, _) = iterator.next |
|
694 other_node.commands.reverse.iterator(command0).find(command => !command.is_ignored) |
|
695 } |
|
696 else other_node.commands.reverse.iterator.find(command => !command.is_ignored) |
|
697 } |
|
698 else version.nodes.commands_loading(other_node_name).headOption |
|
699 |
|
700 |
|
701 /* command results */ |
|
702 |
|
703 def command_results(range: Text.Range): Command.Results = |
|
704 Command.State.merge_results( |
|
705 select[List[Command.State]](range, Markup.Elements.full, command_states => |
|
706 { case _ => Some(command_states) }).flatMap(_.info)) |
|
707 |
|
708 def command_results(command: Command): Command.Results = |
|
709 state.command_results(version, command) |
|
710 |
|
711 |
|
712 /* command ids: static and dynamic */ |
|
713 |
|
714 def command_id_map: Map[Document_ID.Generic, Command] = |
|
715 state.command_id_map(version, version.nodes(node_name).commands) |
|
716 |
|
717 |
|
718 /* cumulate markup */ |
621 |
719 |
622 def cumulate[A]( |
720 def cumulate[A]( |
623 range: Text.Range, |
721 range: Text.Range, |
624 info: A, |
722 info: A, |
625 elements: Markup.Elements, |
723 elements: Markup.Elements, |
626 result: List[Command.State] => (A, Text.Markup) => Option[A], |
724 result: List[Command.State] => (A, Text.Markup) => Option[A], |
627 status: Boolean = false): List[Text.Info[A]] |
725 status: Boolean = false): List[Text.Info[A]] = |
|
726 { |
|
727 val former_range = revert(range).inflate_singularity |
|
728 val (chunk_name, command_iterator) = |
|
729 commands_loading.headOption match { |
|
730 case None => (Symbol.Text_Chunk.Default, node.command_iterator(former_range)) |
|
731 case Some(command) => (Symbol.Text_Chunk.File(node_name.node), Iterator((command, 0))) |
|
732 } |
|
733 val markup_index = Command.Markup_Index(status, chunk_name) |
|
734 (for { |
|
735 (command, command_start) <- command_iterator |
|
736 chunk <- command.chunks.get(chunk_name).iterator |
|
737 states = state.command_states(version, command) |
|
738 res = result(states) |
|
739 markup_range <- (former_range - command_start).try_restrict(chunk.range).iterator |
|
740 markup = Command.State.merge_markup(states, markup_index, markup_range, elements) |
|
741 Text.Info(r0, a) <- markup.cumulate[A](markup_range, info, elements, |
|
742 { |
|
743 case (a, Text.Info(r0, b)) => res(a, Text.Info(convert(r0 + command_start), b)) |
|
744 }).iterator |
|
745 r1 <- convert(r0 + command_start).try_restrict(range).iterator |
|
746 } yield Text.Info(r1, a)).toList |
|
747 } |
628 |
748 |
629 def select[A]( |
749 def select[A]( |
630 range: Text.Range, |
750 range: Text.Range, |
631 elements: Markup.Elements, |
751 elements: Markup.Elements, |
632 result: List[Command.State] => Text.Markup => Option[A], |
752 result: List[Command.State] => Text.Markup => Option[A], |
633 status: Boolean = false): List[Text.Info[A]] |
753 status: Boolean = false): List[Text.Info[A]] = |
634 |
754 { |
635 def command_results(range: Text.Range): Command.Results |
755 def result1(states: List[Command.State]): (Option[A], Text.Markup) => Option[Option[A]] = |
636 def command_results(command: Command): Command.Results |
756 { |
637 |
757 val res = result(states) |
638 def command_id_map: Map[Document_ID.Generic, Command] |
758 (_: Option[A], x: Text.Markup) => |
|
759 res(x) match { |
|
760 case None => None |
|
761 case some => Some(some) |
|
762 } |
|
763 } |
|
764 for (Text.Info(r, Some(x)) <- cumulate(range, None, elements, result1, status)) |
|
765 yield Text.Info(r, x) |
|
766 } |
639 } |
767 } |
640 |
768 |
641 |
769 |
642 /* model */ |
770 /* model */ |
643 |
771 |
1127 case (edits, Node.Edits(es)) => es ::: edits |
1255 case (edits, Node.Edits(es)) => es ::: edits |
1128 case (edits, _) => edits |
1256 case (edits, _) => edits |
1129 }) |
1257 }) |
1130 |
1258 |
1131 new Snapshot(this, version, node_name, edits, snippet_command) |
1259 new Snapshot(this, version, node_name, edits, snippet_command) |
1132 { |
|
1133 /* local node content */ |
|
1134 |
|
1135 val node: Node = version.nodes(node_name) |
|
1136 |
|
1137 def nodes: List[(Node.Name, Node)] = |
|
1138 (node_name :: node.load_commands.flatMap(_.blobs_names)). |
|
1139 map(name => (name, version.nodes(name))) |
|
1140 |
|
1141 val commands_loading: List[Command] = |
|
1142 if (node_name.is_theory) Nil |
|
1143 else version.nodes.commands_loading(node_name) |
|
1144 |
|
1145 def commands_loading_ranges(pred: Node.Name => Boolean): List[Text.Range] = |
|
1146 (for { |
|
1147 cmd <- node.load_commands.iterator |
|
1148 blob_name <- cmd.blobs_names.iterator |
|
1149 if pred(blob_name) |
|
1150 start <- node.command_start(cmd) |
|
1151 } yield convert(cmd.core_range + start)).toList |
|
1152 |
|
1153 def current_command(other_node_name: Node.Name, offset: Text.Offset): Option[Command] = |
|
1154 if (other_node_name.is_theory) { |
|
1155 val other_node = version.nodes(other_node_name) |
|
1156 val iterator = other_node.command_iterator(revert(offset) max 0) |
|
1157 if (iterator.hasNext) { |
|
1158 val (command0, _) = iterator.next |
|
1159 other_node.commands.reverse.iterator(command0).find(command => !command.is_ignored) |
|
1160 } |
|
1161 else other_node.commands.reverse.iterator.find(command => !command.is_ignored) |
|
1162 } |
|
1163 else version.nodes.commands_loading(other_node_name).headOption |
|
1164 |
|
1165 def xml_markup( |
|
1166 range: Text.Range = Text.Range.full, |
|
1167 elements: Markup.Elements = Markup.Elements.full): XML.Body = |
|
1168 state.xml_markup(version, node_name, range = range, elements = elements) |
|
1169 |
|
1170 lazy val messages: List[(XML.Tree, Position.T)] = |
|
1171 (for { |
|
1172 (command, start) <- |
|
1173 Document.Node.Commands.starts_pos( |
|
1174 node.commands.iterator, Token.Pos.file(node_name.node)) |
|
1175 pos = command.span.keyword_pos(start).position(command.span.name) |
|
1176 (_, tree) <- state.command_results(version, command).iterator |
|
1177 } yield (tree, pos)).toList |
|
1178 |
|
1179 lazy val exports: List[Export.Entry] = |
|
1180 state.node_exports(version, node_name).iterator.map(_._2).toList |
|
1181 |
|
1182 lazy val exports_map: Map[String, Export.Entry] = |
|
1183 (for (entry <- exports.iterator) yield (entry.name, entry)).toMap |
|
1184 |
|
1185 |
|
1186 /* find command */ |
|
1187 |
|
1188 def find_command(id: Document_ID.Generic): Option[(Node, Command)] = |
|
1189 state.lookup_id(id) match { |
|
1190 case None => None |
|
1191 case Some(st) => |
|
1192 val command = st.command |
|
1193 val node = version.nodes(command.node_name) |
|
1194 if (node.commands.contains(command)) Some((node, command)) else None |
|
1195 } |
|
1196 |
|
1197 def find_command_position(id: Document_ID.Generic, offset: Symbol.Offset) |
|
1198 : Option[Line.Node_Position] = |
|
1199 for ((node, command) <- find_command(id)) |
|
1200 yield { |
|
1201 val name = command.node_name.node |
|
1202 val sources_iterator = |
|
1203 node.commands.iterator.takeWhile(_ != command).map(_.source) ++ |
|
1204 (if (offset == 0) Iterator.empty |
|
1205 else Iterator.single(command.source(Text.Range(0, command.chunk.decode(offset))))) |
|
1206 val pos = (Line.Position.zero /: sources_iterator)(_.advance(_)) |
|
1207 Line.Node_Position(name, pos) |
|
1208 } |
|
1209 |
|
1210 |
|
1211 /* cumulate markup */ |
|
1212 |
|
1213 def cumulate[A]( |
|
1214 range: Text.Range, |
|
1215 info: A, |
|
1216 elements: Markup.Elements, |
|
1217 result: List[Command.State] => (A, Text.Markup) => Option[A], |
|
1218 status: Boolean = false): List[Text.Info[A]] = |
|
1219 { |
|
1220 val former_range = revert(range).inflate_singularity |
|
1221 val (chunk_name, command_iterator) = |
|
1222 commands_loading.headOption match { |
|
1223 case None => (Symbol.Text_Chunk.Default, node.command_iterator(former_range)) |
|
1224 case Some(command) => (Symbol.Text_Chunk.File(node_name.node), Iterator((command, 0))) |
|
1225 } |
|
1226 val markup_index = Command.Markup_Index(status, chunk_name) |
|
1227 (for { |
|
1228 (command, command_start) <- command_iterator |
|
1229 chunk <- command.chunks.get(chunk_name).iterator |
|
1230 states = state.command_states(version, command) |
|
1231 res = result(states) |
|
1232 markup_range <- (former_range - command_start).try_restrict(chunk.range).iterator |
|
1233 markup = Command.State.merge_markup(states, markup_index, markup_range, elements) |
|
1234 Text.Info(r0, a) <- markup.cumulate[A](markup_range, info, elements, |
|
1235 { |
|
1236 case (a, Text.Info(r0, b)) => res(a, Text.Info(convert(r0 + command_start), b)) |
|
1237 }).iterator |
|
1238 r1 <- convert(r0 + command_start).try_restrict(range).iterator |
|
1239 } yield Text.Info(r1, a)).toList |
|
1240 } |
|
1241 |
|
1242 def select[A]( |
|
1243 range: Text.Range, |
|
1244 elements: Markup.Elements, |
|
1245 result: List[Command.State] => Text.Markup => Option[A], |
|
1246 status: Boolean = false): List[Text.Info[A]] = |
|
1247 { |
|
1248 def result1(states: List[Command.State]): (Option[A], Text.Markup) => Option[Option[A]] = |
|
1249 { |
|
1250 val res = result(states) |
|
1251 (_: Option[A], x: Text.Markup) => |
|
1252 res(x) match { |
|
1253 case None => None |
|
1254 case some => Some(some) |
|
1255 } |
|
1256 } |
|
1257 for (Text.Info(r, Some(x)) <- cumulate(range, None, elements, result1, status)) |
|
1258 yield Text.Info(r, x) |
|
1259 } |
|
1260 |
|
1261 |
|
1262 /* command results */ |
|
1263 |
|
1264 def command_results(range: Text.Range): Command.Results = |
|
1265 Command.State.merge_results( |
|
1266 select[List[Command.State]](range, Markup.Elements.full, command_states => |
|
1267 { case _ => Some(command_states) }).flatMap(_.info)) |
|
1268 |
|
1269 def command_results(command: Command): Command.Results = |
|
1270 state.command_results(version, command) |
|
1271 |
|
1272 |
|
1273 /* command ids: static and dynamic */ |
|
1274 |
|
1275 def command_id_map: Map[Document_ID.Generic, Command] = |
|
1276 state.command_id_map(version, version.nodes(node_name).commands) |
|
1277 |
|
1278 |
|
1279 /* output */ |
|
1280 |
|
1281 override def toString: String = |
|
1282 "Snapshot(node = " + node_name.node + ", version = " + version.id + |
|
1283 (if (is_outdated) ", outdated" else "") + ")" |
|
1284 } |
|
1285 } |
1260 } |
1286 } |
1261 } |
1287 } |
1262 } |