more detailed export "PIDE/files": store offset of the load command, within the pro-forma loaded_theory_command --- this allows to restrict output messages for blobs;
enforce rebuild of Isabelle/ML;
--- a/src/Pure/Build/build.scala Tue Aug 05 16:04:05 2025 +0200
+++ b/src/Pure/Build/build.scala Tue Aug 05 21:44:54 2025 +0200
@@ -728,16 +728,17 @@
val thy_file = migrate_file(thy_file0)
val blobs =
- blobs_files0.map { name0 =>
+ blobs_files0.map { case (command_offset, name0) =>
val name = migrate_file(name0)
val file = read_source_file(name0)
val bytes = file.bytes
val text = decode(bytes.text)
val chunk = Symbol.Text_Chunk(text)
+ val content = Some((file.digest, chunk))
- Command.Blob(Document.Node.Name(name), Path.explode(name), Some((file.digest, chunk))) ->
- Document.Blobs.Item(bytes, text, chunk, changed = false)
+ Command.Blob(command_offset, Document.Node.Name(name), Path.explode(name), content) ->
+ Document.Blobs.Item(bytes, text, chunk, command_offset = command_offset)
}
val thy_source = decode(read_source_file(thy_file0).bytes.text)
--- a/src/Pure/Build/build_job.scala Tue Aug 05 16:04:05 2025 +0200
+++ b/src/Pure/Build/build_job.scala Tue Aug 05 21:44:54 2025 +0200
@@ -150,20 +150,23 @@
def session_blobs(node_name: Document.Node.Name): List[(Command.Blob, Document.Blobs.Item)] =
session_background.base.theory_load_commands.get(node_name.theory) match {
case None => Nil
- case Some(spans) =>
+ case Some(load_commands) =>
val syntax = session_background.base.theory_syntax(node_name)
val master_dir = Path.explode(node_name.master_dir)
- for (span <- spans; file <- span.loaded_files(syntax).files)
- yield {
+ for {
+ (command_span, command_offset) <- load_commands
+ file <- command_span.loaded_files(syntax).files
+ } yield {
val src_path = Path.explode(file)
val blob_name = Document.Node.Name(File.symbolic_path(master_dir + src_path))
val bytes = session_sources(blob_name.node).bytes
val text = bytes.text
val chunk = Symbol.Text_Chunk(text)
+ val content = Some((SHA1.digest(bytes), chunk))
- Command.Blob(blob_name, src_path, Some((SHA1.digest(bytes), chunk))) ->
- Document.Blobs.Item(bytes, text, chunk, changed = false)
+ Command.Blob(command_offset, blob_name, src_path, content) ->
+ Document.Blobs.Item(bytes, text, chunk, command_offset = command_offset)
}
}
@@ -307,9 +310,11 @@
export_text(Export.DOCUMENT_ID, command.id.toString, compress = false)
}
- export_text(Export.FILES,
- cat_lines(snapshot.node_files.map(name => File.symbolic_path(name.path))),
- compress = false)
+ export_(Export.FILES,
+ {
+ import XML.Encode._
+ list(pair(int, string))(snapshot.node_export_files)
+ })
for ((blob_name, i) <- snapshot.node_files.tail.zipWithIndex) {
val xml = snapshot.switch(blob_name).xml_markup()
--- a/src/Pure/Build/export.scala Tue Aug 05 16:04:05 2025 +0200
+++ b/src/Pure/Build/export.scala Tue Aug 05 21:44:54 2025 +0200
@@ -502,7 +502,7 @@
def db_source: Option[String] = {
val theory_context = session_context.theory(theory)
for {
- name <- theory_context.files0(permissive = true).headOption
+ (_, name) <- theory_context.files0(permissive = true).headOption
file <- get_source_file(name)
} yield Symbol.output(unicode_symbols, file.bytes.text)
}
@@ -549,13 +549,15 @@
case _ => None
}
- def files0(permissive: Boolean = false): List[String] =
- split_lines(apply(FILES, permissive = permissive).text)
+ def files0(permissive: Boolean = false): List[(Int, String)] = {
+ import XML.Decode._
+ list(pair(int, string))(apply(FILES, permissive = permissive).yxml())
+ }
- def files(permissive: Boolean = false): Option[(String, List[String])] =
+ def files(permissive: Boolean = false): Option[(String, List[(Int, String)])] =
files0(permissive = permissive) match {
case Nil => None
- case a :: bs => Some((a, bs))
+ case (_, a) :: bs => Some((a, bs))
}
override def toString: String = "Export.Theory_Context(" + quote(theory) + ")"
--- a/src/Pure/Build/resources.scala Tue Aug 05 16:04:05 2025 +0200
+++ b/src/Pure/Build/resources.scala Tue Aug 05 21:44:54 2025 +0200
@@ -7,6 +7,7 @@
package isabelle
+import scala.collection.mutable
import scala.util.parsing.input.Reader
import java.io.{File => JFile}
@@ -88,14 +89,20 @@
def load_commands(
syntax: Outer_Syntax,
name: Document.Node.Name
- ) : () => List[Command_Span.Span] = {
+ ) : () => List[(Command_Span.Span, Symbol.Offset)] = {
val (is_utf8, raw_text) =
with_thy_reader(name, reader => (Scan.reader_is_utf8(reader), reader.source.toString))
() =>
{
if (syntax.has_load_commands(raw_text)) {
- val text = Symbol.decode(Scan.reader_decode_utf8(is_utf8, raw_text))
- syntax.parse_spans(text).filter(_.is_load_command(syntax))
+ val spans = syntax.parse_spans(Symbol.decode(Scan.reader_decode_utf8(is_utf8, raw_text)))
+ val result = new mutable.ListBuffer[(Command_Span.Span, Symbol.Offset)]
+ var offset = 1
+ for (span <- spans) {
+ if (span.is_load_command(syntax)) { result += (span -> offset) }
+ offset += span.length
+ }
+ result.toList
}
else Nil
}
@@ -115,7 +122,7 @@
(file, theory) <- Thy_Header.ml_roots.iterator
node = append_path("~~/src/Pure", Path.explode(file))
node_name = Document.Node.Name(node, theory = theory)
- name <- loaded_files(syntax, node_name, load_commands(syntax, node_name)()).iterator
+ name <- loaded_files(syntax, node_name, load_commands(syntax, node_name)().map(_._1)).iterator
} yield name).toList
def global_theory(theory: String): Boolean =
@@ -375,9 +382,9 @@
def get_syntax(name: Document.Node.Name): Outer_Syntax =
loaded_theories.get_node(name.theory)
- lazy val load_commands: List[(Document.Node.Name, List[Command_Span.Span])] =
+ lazy val load_commands: List[(Document.Node.Name, List[(Command_Span.Span, Symbol.Offset)])] =
theories.zip(
- Par_List.map((e: () => List[Command_Span.Span]) => e(),
+ Par_List.map((e: () => List[(Command_Span.Span, Symbol.Offset)]) => e(),
theories.map(name => resources.load_commands(get_syntax(name), name))))
.filter(p => p._2.nonEmpty)
@@ -394,8 +401,8 @@
def loaded_files: List[Document.Node.Name] =
for {
- (name, spans) <- load_commands
- file <- loaded_files(name, spans)._2
+ (name, cmds) <- load_commands
+ file <- loaded_files(name, cmds.map(_._1))._2
} yield file
def imported_files: List[Path] = {
--- a/src/Pure/Build/sessions.scala Tue Aug 05 16:04:05 2025 +0200
+++ b/src/Pure/Build/sessions.scala Tue Aug 05 21:44:54 2025 +0200
@@ -102,7 +102,7 @@
document_theories: List[Document.Node.Name] = Nil,
loaded_theories: Graph[String, Outer_Syntax] = Graph.string, // cumulative imports
used_theories: List[(Document.Node.Name, Options)] = Nil, // new imports
- theory_load_commands: Map[String, List[Command_Span.Span]] = Map.empty,
+ theory_load_commands: Map[String, List[(Command_Span.Span, Symbol.Offset)]] = Map.empty,
known_theories: Map[String, Document.Node.Entry] = Map.empty,
known_loaded_files: Map[String, List[Path]] = Map.empty,
overall_syntax: Outer_Syntax = Outer_Syntax.empty,
@@ -301,11 +301,11 @@
catch { case ERROR(msg) => (Nil, List(msg)) }
val theory_load_commands =
- (for ((name, span) <- load_commands.iterator) yield name.theory -> span).toMap
+ (for ((name, cmd) <- load_commands.iterator) yield name.theory -> cmd).toMap
val loaded_files: List[(String, List[Path])] =
- for ((name, spans) <- load_commands) yield {
- val (theory, files) = dependencies.loaded_files(name, spans)
+ for ((name, cmds) <- load_commands) yield {
+ val (theory, files) = dependencies.loaded_files(name, cmds.map(_._1))
theory -> files.map(file => Path.explode(file.node))
}
--- a/src/Pure/PIDE/command.scala Tue Aug 05 16:04:05 2025 +0200
+++ b/src/Pure/PIDE/command.scala Tue Aug 05 21:44:54 2025 +0200
@@ -15,6 +15,7 @@
/* blobs */
sealed case class Blob(
+ command_offset: Symbol.Offset,
name: Document.Node.Name,
src_path: Path,
content: Option[(SHA1.Digest, Symbol.Text_Chunk)]
@@ -454,7 +455,7 @@
val src_path = Path.explode(file)
val name = Document.Node.Name(resources.append_path(node_name.master_dir, src_path))
val content = get_blob(name).map(blob => (blob.bytes.sha1_digest, blob.chunk))
- Blob(name, src_path, content)
+ Blob(0, name, src_path, content)
}).user_error)
Blobs_Info(blobs, index = loaded_files.index)
}
@@ -496,6 +497,9 @@
def blobs_names: List[Document.Node.Name] =
for (case Exn.Res(blob) <- blobs) yield blob.name
+ def blobs_files: List[(Symbol.Offset, Document.Node.Name)] =
+ for (case Exn.Res(blob) <- blobs) yield (blob.command_offset, blob.name)
+
def blobs_undefined: List[Document.Node.Name] =
for (case Exn.Res(blob) <- blobs if blob.content.isEmpty) yield blob.name
--- a/src/Pure/PIDE/document.scala Tue Aug 05 16:04:05 2025 +0200
+++ b/src/Pure/PIDE/document.scala Tue Aug 05 21:44:54 2025 +0200
@@ -46,7 +46,8 @@
bytes: Bytes,
source: String,
chunk: Symbol.Text_Chunk,
- changed: Boolean
+ command_offset: Symbol.Offset = 0,
+ changed: Boolean = false
) {
def source_wellformed: Boolean = bytes.wellformed_text.nonEmpty
def unchanged: Item = if (changed) copy(changed = false) else this
@@ -588,6 +589,10 @@
def node_files: List[Node.Name] =
node_name :: node.load_commands.flatMap(_.blobs_names)
+ def node_export_files: List[(Symbol.Offset, String)] =
+ for ((i, name) <- (0, node_name) :: node.load_commands.flatMap(_.blobs_files))
+ yield (i, File.symbolic_path(name.path))
+
def node_consolidated(name: Node.Name): Boolean =
state.node_consolidated(version, name)
@@ -605,7 +610,16 @@
case _ => None
}
}
- else None
+ else {
+ for {
+ command <- version.nodes.commands_loading(node_name).find(_.span.is_theory)
+ (symbol_offset, _) <- command.blobs_files.find({ case (_, name) => node_name == name })
+ } yield {
+ val chunk_offset = command.chunk.decode(symbol_offset)
+ val command_range = switch(command.node_name).command_range(Text.Range(chunk_offset))
+ command -> command_range.getOrElse(Text.Range.offside)
+ }
+ }
/* pending edits */
--- a/src/Pure/PIDE/document_info.scala Tue Aug 05 16:04:05 2025 +0200
+++ b/src/Pure/PIDE/document_info.scala Tue Aug 05 21:44:54 2025 +0200
@@ -103,7 +103,7 @@
Theory(theory_name,
static_session = sessions_structure.theory_qualifier(theory_name),
dynamic_session = session_name,
- files = files,
+ files = files.map(_._2),
entities = theory_export.entity_iterator.toList,
others = theory_export.others.keySet.toList)
Some(theory)
--- a/src/Pure/PIDE/protocol.scala Tue Aug 05 16:04:05 2025 +0200
+++ b/src/Pure/PIDE/protocol.scala Tue Aug 05 21:44:54 2025 +0200
@@ -346,7 +346,7 @@
val blobs_xml: XML.Body = {
val encode_blob: T[Exn.Result[Command.Blob]] =
variant(List(
- { case Exn.Res(Command.Blob(a, b, c)) =>
+ { case Exn.Res(Command.Blob(_, a, b, c)) =>
(Nil, triple(string, string, option(string))(
(a.node, b.implode, c.map(p => p._1.toString)))) },
{ case Exn.Exn(e) => (Nil, string(Exn.message(e))) }))
--- a/src/Pure/ROOT.ML Tue Aug 05 16:04:05 2025 +0200
+++ b/src/Pure/ROOT.ML Tue Aug 05 21:44:54 2025 +0200
@@ -1,6 +1,6 @@
(* Title: Pure/ROOT.ML
Author: Makarius
- UUID: a83d12be-3568-49ab-9484-a84de5cee2bf
+ UUID: 65c4f1c9-5db7-4528-b719-40dbb49a0791
Main entry point for the Isabelle/Pure bootstrap process.