--- a/src/Pure/Thy/thy_resources.scala Fri Mar 16 18:42:35 2018 +0100
+++ b/src/Pure/Thy/thy_resources.scala Fri Mar 16 22:20:09 2018 +0100
@@ -68,10 +68,11 @@
theories: List[(String, Position.T)],
qualifier: String = Sessions.DRAFT,
master_dir: String = "",
+ id: String = Library.UUID(),
progress: Progress = No_Progress): Theories_Result =
{
val requirements =
- resources.load_theories(session, theories, qualifier = qualifier,
+ resources.load_theories(session, id, theories, qualifier = qualifier,
master_dir = master_dir, progress = progress)
val result = Future.promise[Theories_Result]
@@ -99,6 +100,9 @@
check_state
result.join
session.commands_changed -= consumer
+
+ resources.unload_theories(session, id, requirements)
+
result.join
}
}
@@ -106,30 +110,45 @@
/* internal state */
- sealed case class State(theories: Map[Document.Node.Name, Theory] = Map.empty)
+ sealed case class State(
+ theories: Map[Document.Node.Name, Theory] = Map.empty,
+ required: Multi_Map[Document.Node.Name, String] = Multi_Map.empty)
+ {
+ def update(theory_edits: List[((Document.Node.Name, Theory), List[Document.Edit_Text])],
+ new_required: Multi_Map[Document.Node.Name, String]): (List[Document.Edit_Text], State) =
+ {
+ val edits = theory_edits.flatMap(_._2)
+ val st = State(theories ++ theory_edits.map(_._1), new_required)
+ (edits, st)
+ }
+ }
final class Theory private[Thy_Resources](
val node_name: Document.Node.Name,
val node_header: Document.Node.Header,
- val text: String)
+ val text: String,
+ val node_required: Boolean)
{
override def toString: String = node_name.toString
def node_perspective: Document.Node.Perspective_Text =
- Document.Node.Perspective(true, Text.Perspective.full, Document.Node.Overlays.empty)
+ Document.Node.Perspective(node_required, Text.Perspective.empty, Document.Node.Overlays.empty)
def node_edits(old: Option[Theory]): List[Document.Edit_Text] =
{
- val text_edits =
- if (old.isEmpty) Text.Edit.inserts(0, text)
- else Text.Edit.replace(0, old.get.text, text)
+ val (text_edits, old_required) =
+ if (old.isEmpty) (Text.Edit.inserts(0, text), false)
+ else (Text.Edit.replace(0, old.get.text, text), old.get.node_required)
- if (text_edits.isEmpty) Nil
+ if (text_edits.isEmpty && node_required == old_required) Nil
else
List(node_name -> Document.Node.Deps(node_header),
node_name -> Document.Node.Edits(text_edits),
node_name -> node_perspective)
}
+
+ def unload: Theory =
+ if (node_required) new Theory(node_name, node_header, text, false) else this
}
}
@@ -140,18 +159,19 @@
private val state = Synchronized(Thy_Resources.State())
- def read_thy(node_name: Document.Node.Name): Thy_Resources.Theory =
+ def load_thy(node_name: Document.Node.Name): Thy_Resources.Theory =
{
val path = node_name.path
if (!node_name.is_theory) error("Not a theory file: " + path)
val text = File.read(path)
val node_header = resources.check_thy_reader(node_name, Scan.char_reader(text))
- new Thy_Resources.Theory(node_name, node_header, text)
+ new Thy_Resources.Theory(node_name, node_header, text, true)
}
def load_theories(
session: Session,
+ id: String,
theories: List[(String, Position.T)],
qualifier: String = Sessions.DRAFT,
master_dir: String = "",
@@ -162,24 +182,44 @@
yield (import_name(qualifier, master_dir, thy), pos)
val dependencies = resources.dependencies(import_names, progress = progress).check_errors
- val loaded_theories = dependencies.theories.map(read_thy(_))
+ val loaded_theories = dependencies.theories.map(load_thy(_))
val edits =
state.change_result(st =>
{
val theory_edits =
- for {
- theory <- loaded_theories
+ (for {
+ theory <- loaded_theories.iterator
node_name = theory.node_name
edits = theory.node_edits(st.theories.get(node_name))
if edits.nonEmpty
- } yield ((node_name, theory), edits)
-
- val st1 = st.copy(theories = st.theories ++ theory_edits.map(_._1))
- (theory_edits.flatMap(_._2), st1)
+ } yield ((node_name, theory), edits)).toList
+ val required =
+ (st.required /: loaded_theories)({ case (req, thy) => req.insert(thy.node_name, id) })
+ st.update(theory_edits, required)
})
session.update(Document.Blobs.empty, edits)
dependencies.theories
}
+
+ def unload_theories(session: Session, id: String, theories: List[Document.Node.Name])
+ {
+ val edits =
+ state.change_result(st =>
+ {
+ val theory_edits =
+ (for {
+ node_name <- theories.iterator
+ theory <- st.theories.get(node_name)
+ theory1 = theory.unload
+ edits = theory1.node_edits(Some(theory))
+ if edits.nonEmpty
+ } yield ((node_name, theory1), edits)).toList
+ val required =
+ (st.required /: theories)({ case (req, node_name) => req.remove(node_name, id) })
+ st.update(theory_edits, required)
+ })
+ session.update(Document.Blobs.empty, edits)
+ }
}
--- a/src/Pure/Tools/server_commands.scala Fri Mar 16 18:42:35 2018 +0100
+++ b/src/Pure/Tools/server_commands.scala Fri Mar 16 22:20:09 2018 +0100
@@ -170,12 +170,14 @@
}
yield Args(session_id, theories, qualifier = qualifier, master_dir = master_dir)
- def command(args: Args, session: Thy_Resources.Session, progress: Progress = No_Progress)
- : (JSON.Object.T, Thy_Resources.Theories_Result) =
+ def command(args: Args,
+ session: Thy_Resources.Session,
+ id: String = Library.UUID(),
+ progress: Progress = No_Progress): (JSON.Object.T, Thy_Resources.Theories_Result) =
{
val result =
session.use_theories(args.theories, qualifier = args.qualifier,
- master_dir = args.master_dir, progress = progress)
+ master_dir = args.master_dir, id = id, progress = progress)
val result_json =
JSON.Object(