| author | wenzelm | 
| Fri, 27 Mar 2020 22:01:27 +0100 | |
| changeset 71601 | 97ccf48c2f0c | 
| parent 70796 | 2739631ac368 | 
| child 71726 | a5fda30edae2 | 
| permissions | -rw-r--r-- | 
| 56208 | 1 | /* Title: Pure/PIDE/resources.scala | 
| 43651 
511df47bcadc
some support for theory files within Isabelle/Scala session;
 wenzelm parents: diff
changeset | 2 | Author: Makarius | 
| 
511df47bcadc
some support for theory files within Isabelle/Scala session;
 wenzelm parents: diff
changeset | 3 | |
| 56208 | 4 | Resources for theories and auxiliary files. | 
| 43651 
511df47bcadc
some support for theory files within Isabelle/Scala session;
 wenzelm parents: diff
changeset | 5 | */ | 
| 
511df47bcadc
some support for theory files within Isabelle/Scala session;
 wenzelm parents: diff
changeset | 6 | |
| 
511df47bcadc
some support for theory files within Isabelle/Scala session;
 wenzelm parents: diff
changeset | 7 | package isabelle | 
| 
511df47bcadc
some support for theory files within Isabelle/Scala session;
 wenzelm parents: diff
changeset | 8 | |
| 44953 | 9 | |
| 48885 | 10 | import scala.annotation.tailrec | 
| 56823 
37be55461dbe
more frugal access to theory text via Reader, reduced costs for I/O text decoding;
 wenzelm parents: 
56801diff
changeset | 11 | import scala.util.parsing.input.Reader | 
| 48885 | 12 | |
| 48409 | 13 | import java.io.{File => JFile}
 | 
| 44953 | 14 | |
| 15 | ||
| 65359 | 16 | class Resources( | 
| 70683 
8c7706b053c7
find theory files via session structure: much faster Prover IDE startup;
 wenzelm parents: 
70682diff
changeset | 17 | val sessions_structure: Sessions.Structure, | 
| 65361 | 18 | val session_base: Sessions.Base, | 
| 65359 | 19 | val log: Logger = No_Logger) | 
| 43651 
511df47bcadc
some support for theory files within Isabelle/Scala session;
 wenzelm parents: diff
changeset | 20 | {
 | 
| 66959 | 21 | resources => | 
| 64839 | 22 | |
| 69255 
800b1ce96fce
more general support for Isabelle/PIDE file formats -- less hardwired Bibtex operations;
 wenzelm parents: 
69008diff
changeset | 23 | |
| 
800b1ce96fce
more general support for Isabelle/PIDE file formats -- less hardwired Bibtex operations;
 wenzelm parents: 
69008diff
changeset | 24 | /* file formats */ | 
| 
800b1ce96fce
more general support for Isabelle/PIDE file formats -- less hardwired Bibtex operations;
 wenzelm parents: 
69008diff
changeset | 25 | |
| 
800b1ce96fce
more general support for Isabelle/PIDE file formats -- less hardwired Bibtex operations;
 wenzelm parents: 
69008diff
changeset | 26 | val file_formats: File_Format.Environment = File_Format.environment() | 
| 
800b1ce96fce
more general support for Isabelle/PIDE file formats -- less hardwired Bibtex operations;
 wenzelm parents: 
69008diff
changeset | 27 | |
| 
800b1ce96fce
more general support for Isabelle/PIDE file formats -- less hardwired Bibtex operations;
 wenzelm parents: 
69008diff
changeset | 28 | def make_theory_name(name: Document.Node.Name): Option[Document.Node.Name] = | 
| 
800b1ce96fce
more general support for Isabelle/PIDE file formats -- less hardwired Bibtex operations;
 wenzelm parents: 
69008diff
changeset | 29 | file_formats.get(name).flatMap(_.make_theory_name(resources, name)) | 
| 
800b1ce96fce
more general support for Isabelle/PIDE file formats -- less hardwired Bibtex operations;
 wenzelm parents: 
69008diff
changeset | 30 | |
| 
800b1ce96fce
more general support for Isabelle/PIDE file formats -- less hardwired Bibtex operations;
 wenzelm parents: 
69008diff
changeset | 31 | def make_theory_content(thy_name: Document.Node.Name): Option[String] = | 
| 
800b1ce96fce
more general support for Isabelle/PIDE file formats -- less hardwired Bibtex operations;
 wenzelm parents: 
69008diff
changeset | 32 | file_formats.get_theory(thy_name).flatMap(_.make_theory_content(resources, thy_name)) | 
| 
800b1ce96fce
more general support for Isabelle/PIDE file formats -- less hardwired Bibtex operations;
 wenzelm parents: 
69008diff
changeset | 33 | |
| 
800b1ce96fce
more general support for Isabelle/PIDE file formats -- less hardwired Bibtex operations;
 wenzelm parents: 
69008diff
changeset | 34 | def make_preview(snapshot: Document.Snapshot): Option[Present.Preview] = | 
| 
800b1ce96fce
more general support for Isabelle/PIDE file formats -- less hardwired Bibtex operations;
 wenzelm parents: 
69008diff
changeset | 35 | file_formats.get(snapshot.node_name).flatMap(_.make_preview(snapshot)) | 
| 
800b1ce96fce
more general support for Isabelle/PIDE file formats -- less hardwired Bibtex operations;
 wenzelm parents: 
69008diff
changeset | 36 | |
| 
800b1ce96fce
more general support for Isabelle/PIDE file formats -- less hardwired Bibtex operations;
 wenzelm parents: 
69008diff
changeset | 37 | def is_hidden(name: Document.Node.Name): Boolean = | 
| 
800b1ce96fce
more general support for Isabelle/PIDE file formats -- less hardwired Bibtex operations;
 wenzelm parents: 
69008diff
changeset | 38 | !name.is_theory || name.theory == Sessions.root_name || file_formats.is_theory(name) | 
| 
800b1ce96fce
more general support for Isabelle/PIDE file formats -- less hardwired Bibtex operations;
 wenzelm parents: 
69008diff
changeset | 39 | |
| 65250 | 40 |   def thy_path(path: Path): Path = path.ext("thy")
 | 
| 41 | ||
| 64839 | 42 | |
| 44953 | 43 | /* file-system operations */ | 
| 44 | ||
| 45 | def append(dir: String, source_path: Path): String = | |
| 48711 
8d381fdef898
need to expand path in order to resolve imports like "~~/src/Tools/Code_Generator";
 wenzelm parents: 
48710diff
changeset | 46 | (Path.explode(dir) + source_path).expand.implode | 
| 44953 | 47 | |
| 65488 | 48 | def append(node_name: Document.Node.Name, source_path: Path): String = | 
| 49 | append(node_name.master_dir, source_path) | |
| 50 | ||
| 70683 
8c7706b053c7
find theory files via session structure: much faster Prover IDE startup;
 wenzelm parents: 
70682diff
changeset | 51 | def make_theory_node(dir: String, file: Path, theory: String): Document.Node.Name = | 
| 
8c7706b053c7
find theory files via session structure: much faster Prover IDE startup;
 wenzelm parents: 
70682diff
changeset | 52 |   {
 | 
| 
8c7706b053c7
find theory files via session structure: much faster Prover IDE startup;
 wenzelm parents: 
70682diff
changeset | 53 | val node = append(dir, file) | 
| 
8c7706b053c7
find theory files via session structure: much faster Prover IDE startup;
 wenzelm parents: 
70682diff
changeset | 54 | val master_dir = append(dir, file.dir) | 
| 
8c7706b053c7
find theory files via session structure: much faster Prover IDE startup;
 wenzelm parents: 
70682diff
changeset | 55 | Document.Node.Name(node, master_dir, theory) | 
| 
8c7706b053c7
find theory files via session structure: much faster Prover IDE startup;
 wenzelm parents: 
70682diff
changeset | 56 | } | 
| 
8c7706b053c7
find theory files via session structure: much faster Prover IDE startup;
 wenzelm parents: 
70682diff
changeset | 57 | |
| 70716 | 58 | def loaded_theory_node(theory: String): Document.Node.Name = | 
| 59 | Document.Node.Name(theory, "", theory) | |
| 60 | ||
| 46737 | 61 | |
| 64657 | 62 | /* source files of Isabelle/ML bootstrap */ | 
| 63 | ||
| 64 | def source_file(raw_name: String): Option[String] = | |
| 65 |   {
 | |
| 66 |     if (Path.is_wellformed(raw_name)) {
 | |
| 67 |       if (Path.is_valid(raw_name)) {
 | |
| 68 | def check(p: Path): Option[Path] = if (p.is_file) Some(p) else None | |
| 69 | ||
| 70 | val path = Path.explode(raw_name) | |
| 71 | val path1 = | |
| 72 | if (path.is_absolute || path.is_current) check(path) | |
| 73 |           else {
 | |
| 74 |             check(Path.explode("~~/src/Pure") + path) orElse
 | |
| 75 |               (if (Isabelle_System.getenv("ML_SOURCES") == "") None
 | |
| 76 |                else check(Path.explode("$ML_SOURCES") + path))
 | |
| 77 | } | |
| 78 | Some(File.platform_path(path1 getOrElse path)) | |
| 79 | } | |
| 80 | else None | |
| 81 | } | |
| 82 | else Some(raw_name) | |
| 83 | } | |
| 84 | ||
| 85 | ||
| 46737 | 86 | /* theory files */ | 
| 87 | ||
| 66698 
5b9dc3f7bcde
prefer sequential file-system access, but parallel parse;
 wenzelm parents: 
66697diff
changeset | 88 | def loaded_files(syntax: Outer_Syntax, name: Document.Node.Name): () => List[Path] = | 
| 66695 | 89 |   {
 | 
| 66918 
ec2b50aeb0dd
more robust treatment of UTF8 in raw byte sources;
 wenzelm parents: 
66917diff
changeset | 90 | val (is_utf8, raw_text) = | 
| 
ec2b50aeb0dd
more robust treatment of UTF8 in raw byte sources;
 wenzelm parents: 
66917diff
changeset | 91 | with_thy_reader(name, reader => (Scan.reader_is_utf8(reader), reader.source.toString)) | 
| 66698 
5b9dc3f7bcde
prefer sequential file-system access, but parallel parse;
 wenzelm parents: 
66697diff
changeset | 92 |     () => {
 | 
| 66917 
fcf84cd6c94f
clarified check, assuming that load commands are plain ASCII;
 wenzelm parents: 
66850diff
changeset | 93 |       if (syntax.load_commands_in(raw_text)) {
 | 
| 66918 
ec2b50aeb0dd
more robust treatment of UTF8 in raw byte sources;
 wenzelm parents: 
66917diff
changeset | 94 | val text = Symbol.decode(Scan.reader_decode_utf8(is_utf8, raw_text)) | 
| 66698 
5b9dc3f7bcde
prefer sequential file-system access, but parallel parse;
 wenzelm parents: 
66697diff
changeset | 95 | val spans = syntax.parse_spans(text) | 
| 
5b9dc3f7bcde
prefer sequential file-system access, but parallel parse;
 wenzelm parents: 
66697diff
changeset | 96 | val dir = Path.explode(name.master_dir) | 
| 
5b9dc3f7bcde
prefer sequential file-system access, but parallel parse;
 wenzelm parents: 
66697diff
changeset | 97 | spans.iterator.map(Command.span_files(syntax, _)._1).flatten. | 
| 66700 | 98 | map(a => (dir + Path.explode(a)).expand).toList | 
| 66698 
5b9dc3f7bcde
prefer sequential file-system access, but parallel parse;
 wenzelm parents: 
66697diff
changeset | 99 | } | 
| 
5b9dc3f7bcde
prefer sequential file-system access, but parallel parse;
 wenzelm parents: 
66697diff
changeset | 100 | else Nil | 
| 66696 
8f863dae78a0
clarified pure_files, based on uniform loaded_files;
 wenzelm parents: 
66695diff
changeset | 101 | } | 
| 66695 | 102 | } | 
| 103 | ||
| 69560 | 104 | def pure_files(syntax: Outer_Syntax): List[Path] = | 
| 66701 | 105 |   {
 | 
| 69560 | 106 |     val pure_dir = Path.explode("~~/src/Pure")
 | 
| 66701 | 107 | val roots = | 
| 108 |       for { (name, _) <- Thy_Header.ml_roots }
 | |
| 69560 | 109 | yield (pure_dir + Path.explode(name)).expand | 
| 66701 | 110 | val files = | 
| 111 |       for {
 | |
| 112 | (path, (_, theory)) <- roots zip Thy_Header.ml_roots | |
| 113 | file <- loaded_files(syntax, Document.Node.Name(path.implode, path.dir.implode, theory))() | |
| 114 | } yield file | |
| 115 | roots ::: files | |
| 116 | } | |
| 66696 
8f863dae78a0
clarified pure_files, based on uniform loaded_files;
 wenzelm parents: 
66695diff
changeset | 117 | |
| 67104 
a2fa0c6a7aff
clarified theory_name vs. loaded_theory: proper import_name for already loaded theories from other sessions (amending 4c98c929a12a);
 wenzelm parents: 
67060diff
changeset | 118 | def theory_name(qualifier: String, theory: String): String = | 
| 
a2fa0c6a7aff
clarified theory_name vs. loaded_theory: proper import_name for already loaded theories from other sessions (amending 4c98c929a12a);
 wenzelm parents: 
67060diff
changeset | 119 | if (Long_Name.is_qualified(theory) || session_base.global_theories.isDefinedAt(theory)) | 
| 
a2fa0c6a7aff
clarified theory_name vs. loaded_theory: proper import_name for already loaded theories from other sessions (amending 4c98c929a12a);
 wenzelm parents: 
67060diff
changeset | 120 | theory | 
| 
a2fa0c6a7aff
clarified theory_name vs. loaded_theory: proper import_name for already loaded theories from other sessions (amending 4c98c929a12a);
 wenzelm parents: 
67060diff
changeset | 121 | else Long_Name.qualify(qualifier, theory) | 
| 65471 
05e5bffcf1d8
clarified loaded_theories: map to qualified theory name;
 wenzelm parents: 
65467diff
changeset | 122 | |
| 70683 
8c7706b053c7
find theory files via session structure: much faster Prover IDE startup;
 wenzelm parents: 
70682diff
changeset | 123 | def find_theory_node(theory: String): Option[Document.Node.Name] = | 
| 70712 
a3cfe859d915
find theories via session directories only -- ignore known_theories;
 wenzelm parents: 
70683diff
changeset | 124 |   {
 | 
| 
a3cfe859d915
find theories via session directories only -- ignore known_theories;
 wenzelm parents: 
70683diff
changeset | 125 | val thy_file = thy_path(Path.basic(Long_Name.base_name(theory))) | 
| 
a3cfe859d915
find theories via session directories only -- ignore known_theories;
 wenzelm parents: 
70683diff
changeset | 126 | val session = session_base.theory_qualifier(theory) | 
| 
a3cfe859d915
find theories via session directories only -- ignore known_theories;
 wenzelm parents: 
70683diff
changeset | 127 | val dirs = | 
| 
a3cfe859d915
find theories via session directories only -- ignore known_theories;
 wenzelm parents: 
70683diff
changeset | 128 |       sessions_structure.get(session) match {
 | 
| 
a3cfe859d915
find theories via session directories only -- ignore known_theories;
 wenzelm parents: 
70683diff
changeset | 129 | case Some(info) => info.dirs | 
| 
a3cfe859d915
find theories via session directories only -- ignore known_theories;
 wenzelm parents: 
70683diff
changeset | 130 | case None => Nil | 
| 
a3cfe859d915
find theories via session directories only -- ignore known_theories;
 wenzelm parents: 
70683diff
changeset | 131 | } | 
| 
a3cfe859d915
find theories via session directories only -- ignore known_theories;
 wenzelm parents: 
70683diff
changeset | 132 |     dirs.collectFirst({
 | 
| 
a3cfe859d915
find theories via session directories only -- ignore known_theories;
 wenzelm parents: 
70683diff
changeset | 133 |       case dir if (dir + thy_file).is_file => make_theory_node("", dir + thy_file, theory) })
 | 
| 
a3cfe859d915
find theories via session directories only -- ignore known_theories;
 wenzelm parents: 
70683diff
changeset | 134 | } | 
| 70683 
8c7706b053c7
find theory files via session structure: much faster Prover IDE startup;
 wenzelm parents: 
70682diff
changeset | 135 | |
| 65445 
e9e7f5f5794c
more qualifier treatment, but in the end it is still ignored;
 wenzelm parents: 
65441diff
changeset | 136 | def import_name(qualifier: String, dir: String, s: String): Document.Node.Name = | 
| 67104 
a2fa0c6a7aff
clarified theory_name vs. loaded_theory: proper import_name for already loaded theories from other sessions (amending 4c98c929a12a);
 wenzelm parents: 
67060diff
changeset | 137 |   {
 | 
| 
a2fa0c6a7aff
clarified theory_name vs. loaded_theory: proper import_name for already loaded theories from other sessions (amending 4c98c929a12a);
 wenzelm parents: 
67060diff
changeset | 138 | val theory = theory_name(qualifier, Thy_Header.import_name(s)) | 
| 70717 
cceb10dcc9f9
clarified import_name: observe directory notation more strictly;
 wenzelm parents: 
70716diff
changeset | 139 | def theory_node = make_theory_node(dir, thy_path(Path.explode(s)), theory) | 
| 
cceb10dcc9f9
clarified import_name: observe directory notation more strictly;
 wenzelm parents: 
70716diff
changeset | 140 | |
| 
cceb10dcc9f9
clarified import_name: observe directory notation more strictly;
 wenzelm parents: 
70716diff
changeset | 141 | if (!Thy_Header.is_base_name(s)) theory_node | 
| 
cceb10dcc9f9
clarified import_name: observe directory notation more strictly;
 wenzelm parents: 
70716diff
changeset | 142 | else if (session_base.loaded_theory(theory)) loaded_theory_node(theory) | 
| 67104 
a2fa0c6a7aff
clarified theory_name vs. loaded_theory: proper import_name for already loaded theories from other sessions (amending 4c98c929a12a);
 wenzelm parents: 
67060diff
changeset | 143 |     else {
 | 
| 70683 
8c7706b053c7
find theory files via session structure: much faster Prover IDE startup;
 wenzelm parents: 
70682diff
changeset | 144 |       find_theory_node(theory) match {
 | 
| 67104 
a2fa0c6a7aff
clarified theory_name vs. loaded_theory: proper import_name for already loaded theories from other sessions (amending 4c98c929a12a);
 wenzelm parents: 
67060diff
changeset | 145 | case Some(node_name) => node_name | 
| 70717 
cceb10dcc9f9
clarified import_name: observe directory notation more strictly;
 wenzelm parents: 
70716diff
changeset | 146 | case None => if (Long_Name.is_qualified(s)) loaded_theory_node(theory) else theory_node | 
| 67104 
a2fa0c6a7aff
clarified theory_name vs. loaded_theory: proper import_name for already loaded theories from other sessions (amending 4c98c929a12a);
 wenzelm parents: 
67060diff
changeset | 147 | } | 
| 65472 | 148 | } | 
| 67104 
a2fa0c6a7aff
clarified theory_name vs. loaded_theory: proper import_name for already loaded theories from other sessions (amending 4c98c929a12a);
 wenzelm parents: 
67060diff
changeset | 149 | } | 
| 51634 
553953ad8165
more general Thy_Load.import_name, e.g. relevant for Isabelle/eclipse -- NB: Thy_Load serves as main hub for funny overriding to adapt to provers and editors;
 wenzelm parents: 
51293diff
changeset | 150 | |
| 65529 | 151 | def import_name(name: Document.Node.Name, s: String): Document.Node.Name = | 
| 66966 | 152 | import_name(session_base.theory_qualifier(name), name.master_dir, s) | 
| 65489 | 153 | |
| 70633 | 154 | def import_name(info: Sessions.Info, s: String): Document.Node.Name = | 
| 155 | import_name(info.name, info.dir.implode, s) | |
| 156 | ||
| 70718 
5bb025e24224
clarified inversion of file name to theory name, notably for Windows;
 wenzelm parents: 
70717diff
changeset | 157 | def find_theory(file: JFile): Option[Document.Node.Name] = | 
| 70673 
b0172698d0d3
theory_name based on session_directories: no need for expensive all_known;
 wenzelm parents: 
70652diff
changeset | 158 |   {
 | 
| 70718 
5bb025e24224
clarified inversion of file name to theory name, notably for Windows;
 wenzelm parents: 
70717diff
changeset | 159 |     for {
 | 
| 
5bb025e24224
clarified inversion of file name to theory name, notably for Windows;
 wenzelm parents: 
70717diff
changeset | 160 | qualifier <- session_base.session_directories.get(File.canonical(file).getParentFile) | 
| 
5bb025e24224
clarified inversion of file name to theory name, notably for Windows;
 wenzelm parents: 
70717diff
changeset | 161 | theory_base <- proper_string(Thy_Header.theory_name(file.getName)) | 
| 
5bb025e24224
clarified inversion of file name to theory name, notably for Windows;
 wenzelm parents: 
70717diff
changeset | 162 | theory = theory_name(qualifier, theory_base) | 
| 
5bb025e24224
clarified inversion of file name to theory name, notably for Windows;
 wenzelm parents: 
70717diff
changeset | 163 | theory_node <- find_theory_node(theory) | 
| 
5bb025e24224
clarified inversion of file name to theory name, notably for Windows;
 wenzelm parents: 
70717diff
changeset | 164 | if File.eq(theory_node.path.file, file) | 
| 
5bb025e24224
clarified inversion of file name to theory name, notably for Windows;
 wenzelm parents: 
70717diff
changeset | 165 | } yield theory_node | 
| 70673 
b0172698d0d3
theory_name based on session_directories: no need for expensive all_known;
 wenzelm parents: 
70652diff
changeset | 166 | } | 
| 
b0172698d0d3
theory_name based on session_directories: no need for expensive all_known;
 wenzelm parents: 
70652diff
changeset | 167 | |
| 70713 
fd188463066e
clarified theory imports completion, based on session directories and current master directory (no support for local session-subdirectories);
 wenzelm parents: 
70712diff
changeset | 168 | def complete_import_name(context_name: Document.Node.Name, s: String): List[String] = | 
| 66767 | 169 |   {
 | 
| 70713 
fd188463066e
clarified theory imports completion, based on session directories and current master directory (no support for local session-subdirectories);
 wenzelm parents: 
70712diff
changeset | 170 | val context_session = session_base.theory_qualifier(context_name) | 
| 
fd188463066e
clarified theory imports completion, based on session directories and current master directory (no support for local session-subdirectories);
 wenzelm parents: 
70712diff
changeset | 171 | val context_dir = | 
| 
fd188463066e
clarified theory imports completion, based on session directories and current master directory (no support for local session-subdirectories);
 wenzelm parents: 
70712diff
changeset | 172 |       try { Some(context_name.master_dir_path) }
 | 
| 
fd188463066e
clarified theory imports completion, based on session directories and current master directory (no support for local session-subdirectories);
 wenzelm parents: 
70712diff
changeset | 173 |       catch { case ERROR(_) => None }
 | 
| 
fd188463066e
clarified theory imports completion, based on session directories and current master directory (no support for local session-subdirectories);
 wenzelm parents: 
70712diff
changeset | 174 |     (for {
 | 
| 
fd188463066e
clarified theory imports completion, based on session directories and current master directory (no support for local session-subdirectories);
 wenzelm parents: 
70712diff
changeset | 175 | (session, (info, _)) <- sessions_structure.imports_graph.iterator | 
| 
fd188463066e
clarified theory imports completion, based on session directories and current master directory (no support for local session-subdirectories);
 wenzelm parents: 
70712diff
changeset | 176 | dir <- (if (session == context_session) context_dir.toList else info.dirs).iterator | 
| 
fd188463066e
clarified theory imports completion, based on session directories and current master directory (no support for local session-subdirectories);
 wenzelm parents: 
70712diff
changeset | 177 | theory <- Thy_Header.try_read_dir(dir).iterator | 
| 
fd188463066e
clarified theory imports completion, based on session directories and current master directory (no support for local session-subdirectories);
 wenzelm parents: 
70712diff
changeset | 178 | if Completion.completed(s)(theory) | 
| 
fd188463066e
clarified theory imports completion, based on session directories and current master directory (no support for local session-subdirectories);
 wenzelm parents: 
70712diff
changeset | 179 |     } yield {
 | 
| 
fd188463066e
clarified theory imports completion, based on session directories and current master directory (no support for local session-subdirectories);
 wenzelm parents: 
70712diff
changeset | 180 | if (session == context_session || session_base.global_theories.isDefinedAt(theory)) theory | 
| 
fd188463066e
clarified theory imports completion, based on session directories and current master directory (no support for local session-subdirectories);
 wenzelm parents: 
70712diff
changeset | 181 | else Long_Name.qualify(session, theory) | 
| 
fd188463066e
clarified theory imports completion, based on session directories and current master directory (no support for local session-subdirectories);
 wenzelm parents: 
70712diff
changeset | 182 | }).toList.sorted | 
| 66767 | 183 | } | 
| 184 | ||
| 64656 | 185 | def with_thy_reader[A](name: Document.Node.Name, f: Reader[Char] => A): A = | 
| 186 |   {
 | |
| 66771 
925d10a7a610
clarified error for bad session-qualified imports;
 wenzelm parents: 
66767diff
changeset | 187 | val path = name.path | 
| 69393 
ed0824ef337e
static type for Library.using: avoid Java 11 warnings on "Illegal reflective access";
 wenzelm parents: 
69255diff
changeset | 188 | if (path.is_file) using(Scan.byte_reader(path.file))(f) | 
| 66771 
925d10a7a610
clarified error for bad session-qualified imports;
 wenzelm parents: 
66767diff
changeset | 189 | else if (name.node == name.theory) | 
| 
925d10a7a610
clarified error for bad session-qualified imports;
 wenzelm parents: 
66767diff
changeset | 190 |       error("Cannot load theory " + quote(name.theory))
 | 
| 
925d10a7a610
clarified error for bad session-qualified imports;
 wenzelm parents: 
66767diff
changeset | 191 |     else error ("Cannot load theory file " + path)
 | 
| 64656 | 192 | } | 
| 193 | ||
| 65359 | 194 | def check_thy_reader(node_name: Document.Node.Name, reader: Reader[Char], | 
| 195 | start: Token.Pos = Token.Pos.command, strict: Boolean = true): Document.Node.Header = | |
| 46737 | 196 |   {
 | 
| 64826 
c97296294f6d
clarified check_thy_reader: check node_name here;
 wenzelm parents: 
64825diff
changeset | 197 |     if (node_name.is_theory && reader.source.length > 0) {
 | 
| 57615 
df1b3452d71c
more explicit discrimination of empty nodes -- suppress from Theories panel;
 wenzelm parents: 
56913diff
changeset | 198 |       try {
 | 
| 66713 | 199 | val header = Thy_Header.read(reader, start, strict) | 
| 48885 | 200 | |
| 65439 | 201 | val base_name = node_name.theory_base_name | 
| 70638 
f164cec7ac22
clarified signature: prefer operations without position;
 wenzelm parents: 
70634diff
changeset | 202 | if (base_name != header.name) | 
| 
f164cec7ac22
clarified signature: prefer operations without position;
 wenzelm parents: 
70634diff
changeset | 203 |           error("Bad theory name " + quote(header.name) +
 | 
| 
f164cec7ac22
clarified signature: prefer operations without position;
 wenzelm parents: 
70634diff
changeset | 204 | " for file " + thy_path(Path.basic(base_name)) + Position.here(header.pos) + | 
| 
f164cec7ac22
clarified signature: prefer operations without position;
 wenzelm parents: 
70634diff
changeset | 205 | Completion.report_theories(header.pos, List(base_name))) | 
| 48885 | 206 | |
| 70638 
f164cec7ac22
clarified signature: prefer operations without position;
 wenzelm parents: 
70634diff
changeset | 207 | val imports_pos = | 
| 
f164cec7ac22
clarified signature: prefer operations without position;
 wenzelm parents: 
70634diff
changeset | 208 |           header.imports_pos.map({ case (s, pos) =>
 | 
| 67296 
888aa91f0556
clarified check, notably for bibtex theory (amending 5f082b1fa9fa);
 wenzelm parents: 
67294diff
changeset | 209 | val name = import_name(node_name, s) | 
| 
888aa91f0556
clarified check, notably for bibtex theory (amending 5f082b1fa9fa);
 wenzelm parents: 
67294diff
changeset | 210 | if (Sessions.exclude_theory(name.theory_base_name)) | 
| 
888aa91f0556
clarified check, notably for bibtex theory (amending 5f082b1fa9fa);
 wenzelm parents: 
67294diff
changeset | 211 |               error("Bad theory name " + quote(name.theory_base_name) + Position.here(pos))
 | 
| 
888aa91f0556
clarified check, notably for bibtex theory (amending 5f082b1fa9fa);
 wenzelm parents: 
67294diff
changeset | 212 | (name, pos) | 
| 
888aa91f0556
clarified check, notably for bibtex theory (amending 5f082b1fa9fa);
 wenzelm parents: 
67294diff
changeset | 213 | }) | 
| 70638 
f164cec7ac22
clarified signature: prefer operations without position;
 wenzelm parents: 
70634diff
changeset | 214 | Document.Node.Header(imports_pos, header.keywords, header.abbrevs) | 
| 57615 
df1b3452d71c
more explicit discrimination of empty nodes -- suppress from Theories panel;
 wenzelm parents: 
56913diff
changeset | 215 | } | 
| 
df1b3452d71c
more explicit discrimination of empty nodes -- suppress from Theories panel;
 wenzelm parents: 
56913diff
changeset | 216 |       catch { case exn: Throwable => Document.Node.bad_header(Exn.message(exn)) }
 | 
| 50414 
e17a1f179bb0
explore theory_body_files via future, for improved performance;
 wenzelm parents: 
50291diff
changeset | 217 | } | 
| 57615 
df1b3452d71c
more explicit discrimination of empty nodes -- suppress from Theories panel;
 wenzelm parents: 
56913diff
changeset | 218 | else Document.Node.no_header | 
| 46737 | 219 | } | 
| 46748 
8f3ae4d04a2d
refined node_header -- more direct buffer access (again);
 wenzelm parents: 
46737diff
changeset | 220 | |
| 65359 | 221 | def check_thy(name: Document.Node.Name, start: Token.Pos = Token.Pos.command, | 
| 222 | strict: Boolean = true): Document.Node.Header = | |
| 223 | with_thy_reader(name, check_thy_reader(name, _, start, strict)) | |
| 50566 
b43c4f660320
tuned signature: use thy_load to adapt to prover/editor specific view on sources;
 wenzelm parents: 
50415diff
changeset | 224 | |
| 
b43c4f660320
tuned signature: use thy_load to adapt to prover/editor specific view on sources;
 wenzelm parents: 
50415diff
changeset | 225 | |
| 64673 
b5965890e54d
more uniform treatment of file name vs. theory name and special header;
 wenzelm parents: 
64657diff
changeset | 226 | /* special header */ | 
| 
b5965890e54d
more uniform treatment of file name vs. theory name and special header;
 wenzelm parents: 
64657diff
changeset | 227 | |
| 
b5965890e54d
more uniform treatment of file name vs. theory name and special header;
 wenzelm parents: 
64657diff
changeset | 228 | def special_header(name: Document.Node.Name): Option[Document.Node.Header] = | 
| 65445 
e9e7f5f5794c
more qualifier treatment, but in the end it is still ignored;
 wenzelm parents: 
65441diff
changeset | 229 |   {
 | 
| 
e9e7f5f5794c
more qualifier treatment, but in the end it is still ignored;
 wenzelm parents: 
65441diff
changeset | 230 | val imports = | 
| 67215 | 231 | if (name.theory == Sessions.root_name) List(import_name(name, Sessions.theory_name)) | 
| 232 | else if (Thy_Header.is_ml_root(name.theory)) List(import_name(name, Thy_Header.ML_BOOTSTRAP)) | |
| 65489 | 233 | else if (Thy_Header.is_bootstrap(name.theory)) List(import_name(name, Thy_Header.PURE)) | 
| 65445 
e9e7f5f5794c
more qualifier treatment, but in the end it is still ignored;
 wenzelm parents: 
65441diff
changeset | 234 | else Nil | 
| 
e9e7f5f5794c
more qualifier treatment, but in the end it is still ignored;
 wenzelm parents: 
65441diff
changeset | 235 | if (imports.isEmpty) None | 
| 
e9e7f5f5794c
more qualifier treatment, but in the end it is still ignored;
 wenzelm parents: 
65441diff
changeset | 236 | else Some(Document.Node.Header(imports.map((_, Position.none)))) | 
| 
e9e7f5f5794c
more qualifier treatment, but in the end it is still ignored;
 wenzelm parents: 
65441diff
changeset | 237 | } | 
| 64673 
b5965890e54d
more uniform treatment of file name vs. theory name and special header;
 wenzelm parents: 
64657diff
changeset | 238 | |
| 
b5965890e54d
more uniform treatment of file name vs. theory name and special header;
 wenzelm parents: 
64657diff
changeset | 239 | |
| 64797 | 240 | /* blobs */ | 
| 241 | ||
| 242 | def undefined_blobs(nodes: Document.Nodes): List[Document.Node.Name] = | |
| 243 |     (for {
 | |
| 244 | (node_name, node) <- nodes.iterator | |
| 65361 | 245 | if !session_base.loaded_theory(node_name) | 
| 64797 | 246 | cmd <- node.load_commands.iterator | 
| 247 | name <- cmd.blobs_undefined.iterator | |
| 248 | } yield name).toList | |
| 249 | ||
| 250 | ||
| 56316 
b1cf8ddc2e04
propagate deps_changed, to resolve missing files without requiring jEdit events (e.g. buffer load/save);
 wenzelm parents: 
56315diff
changeset | 251 | /* document changes */ | 
| 50566 
b43c4f660320
tuned signature: use thy_load to adapt to prover/editor specific view on sources;
 wenzelm parents: 
50415diff
changeset | 252 | |
| 56316 
b1cf8ddc2e04
propagate deps_changed, to resolve missing files without requiring jEdit events (e.g. buffer load/save);
 wenzelm parents: 
56315diff
changeset | 253 | def parse_change( | 
| 56315 | 254 | reparse_limit: Int, | 
| 255 | previous: Document.Version, | |
| 256 | doc_blobs: Document.Blobs, | |
| 68336 
09ac56914b29
Document.update includes node consolidation / presentation as regular print operation: avoid user operations on protocol thread;
 wenzelm parents: 
68317diff
changeset | 257 | edits: List[Document.Edit_Text], | 
| 70796 
2739631ac368
discontinued pointless dump_checkpoint and share_common_data -- superseded by base logic image in Isabelle/MMT;
 wenzelm parents: 
70740diff
changeset | 258 | consolidate: List[Document.Node.Name]): Session.Change = | 
| 
2739631ac368
discontinued pointless dump_checkpoint and share_common_data -- superseded by base logic image in Isabelle/MMT;
 wenzelm parents: 
70740diff
changeset | 259 | Thy_Syntax.parse_change(resources, reparse_limit, previous, doc_blobs, edits, consolidate) | 
| 55134 
1b67b17cdad5
propagate update of outer syntax keywords: global propertiesChanged, buffer TokenMarker.markTokens, text area repainting;
 wenzelm parents: 
54521diff
changeset | 260 | |
| 56316 
b1cf8ddc2e04
propagate deps_changed, to resolve missing files without requiring jEdit events (e.g. buffer load/save);
 wenzelm parents: 
56315diff
changeset | 261 |   def commit(change: Session.Change) { }
 | 
| 66959 | 262 | |
| 263 | ||
| 264 | /* theory and file dependencies */ | |
| 265 | ||
| 69007 | 266 | def dependencies( | 
| 267 | thys: List[(Document.Node.Name, Position.T)], | |
| 69008 
d55783ea6cf6
more detailed session dependencies, with conditions for theories;
 wenzelm parents: 
69007diff
changeset | 268 | progress: Progress = No_Progress): Dependencies[Unit] = | 
| 
d55783ea6cf6
more detailed session dependencies, with conditions for theories;
 wenzelm parents: 
69007diff
changeset | 269 | Dependencies.empty[Unit].require_thys((), thys, progress = progress) | 
| 
d55783ea6cf6
more detailed session dependencies, with conditions for theories;
 wenzelm parents: 
69007diff
changeset | 270 | |
| 
d55783ea6cf6
more detailed session dependencies, with conditions for theories;
 wenzelm parents: 
69007diff
changeset | 271 | def session_dependencies(info: Sessions.Info, progress: Progress = No_Progress) | 
| 
d55783ea6cf6
more detailed session dependencies, with conditions for theories;
 wenzelm parents: 
69007diff
changeset | 272 | : Dependencies[Options] = | 
| 
d55783ea6cf6
more detailed session dependencies, with conditions for theories;
 wenzelm parents: 
69007diff
changeset | 273 |   {
 | 
| 
d55783ea6cf6
more detailed session dependencies, with conditions for theories;
 wenzelm parents: 
69007diff
changeset | 274 |     (Dependencies.empty[Options] /: info.theories)({ case (dependencies, (options, thys)) =>
 | 
| 
d55783ea6cf6
more detailed session dependencies, with conditions for theories;
 wenzelm parents: 
69007diff
changeset | 275 | dependencies.require_thys(options, | 
| 70633 | 276 |         for { (thy, pos) <- thys } yield (import_name(info, thy), pos),
 | 
| 69008 
d55783ea6cf6
more detailed session dependencies, with conditions for theories;
 wenzelm parents: 
69007diff
changeset | 277 | progress = progress) | 
| 
d55783ea6cf6
more detailed session dependencies, with conditions for theories;
 wenzelm parents: 
69007diff
changeset | 278 | }) | 
| 
d55783ea6cf6
more detailed session dependencies, with conditions for theories;
 wenzelm parents: 
69007diff
changeset | 279 | } | 
| 69007 | 280 | |
| 66959 | 281 | object Dependencies | 
| 282 |   {
 | |
| 69008 
d55783ea6cf6
more detailed session dependencies, with conditions for theories;
 wenzelm parents: 
69007diff
changeset | 283 | def empty[A]: Dependencies[A] = new Dependencies[A](Nil, Map.empty) | 
| 69007 | 284 | |
| 285 | private def show_path(names: List[Document.Node.Name]): String = | |
| 286 |       names.map(name => quote(name.theory)).mkString(" via ")
 | |
| 287 | ||
| 288 | private def cycle_msg(names: List[Document.Node.Name]): String = | |
| 289 | "Cyclic dependency of " + show_path(names) | |
| 290 | ||
| 291 | private def required_by(initiators: List[Document.Node.Name]): String = | |
| 292 | if (initiators.isEmpty) "" | |
| 293 | else "\n(required by " + show_path(initiators.reverse) + ")" | |
| 66959 | 294 | } | 
| 295 | ||
| 69008 
d55783ea6cf6
more detailed session dependencies, with conditions for theories;
 wenzelm parents: 
69007diff
changeset | 296 | final class Dependencies[A] private( | 
| 66959 | 297 | rev_entries: List[Document.Node.Entry], | 
| 69008 
d55783ea6cf6
more detailed session dependencies, with conditions for theories;
 wenzelm parents: 
69007diff
changeset | 298 | seen: Map[Document.Node.Name, A]) | 
| 66959 | 299 |   {
 | 
| 69008 
d55783ea6cf6
more detailed session dependencies, with conditions for theories;
 wenzelm parents: 
69007diff
changeset | 300 | private def cons(entry: Document.Node.Entry): Dependencies[A] = | 
| 
d55783ea6cf6
more detailed session dependencies, with conditions for theories;
 wenzelm parents: 
69007diff
changeset | 301 | new Dependencies[A](entry :: rev_entries, seen) | 
| 66959 | 302 | |
| 69008 
d55783ea6cf6
more detailed session dependencies, with conditions for theories;
 wenzelm parents: 
69007diff
changeset | 303 | def require_thy(adjunct: A, | 
| 69007 | 304 | thy: (Document.Node.Name, Position.T), | 
| 305 | initiators: List[Document.Node.Name] = Nil, | |
| 69008 
d55783ea6cf6
more detailed session dependencies, with conditions for theories;
 wenzelm parents: 
69007diff
changeset | 306 | progress: Progress = No_Progress): Dependencies[A] = | 
| 69007 | 307 |     {
 | 
| 308 | val (name, pos) = thy | |
| 309 | ||
| 310 | def message: String = | |
| 311 | "The error(s) above occurred for theory " + quote(name.theory) + | |
| 312 | Dependencies.required_by(initiators) + Position.here(pos) | |
| 313 | ||
| 69008 
d55783ea6cf6
more detailed session dependencies, with conditions for theories;
 wenzelm parents: 
69007diff
changeset | 314 | if (seen.isDefinedAt(name)) this | 
| 69007 | 315 |       else {
 | 
| 69008 
d55783ea6cf6
more detailed session dependencies, with conditions for theories;
 wenzelm parents: 
69007diff
changeset | 316 | val dependencies1 = new Dependencies[A](rev_entries, seen + (name -> adjunct)) | 
| 69007 | 317 | if (session_base.loaded_theory(name)) dependencies1 | 
| 318 |         else {
 | |
| 319 |           try {
 | |
| 320 | if (initiators.contains(name)) error(Dependencies.cycle_msg(initiators)) | |
| 321 | ||
| 322 | progress.expose_interrupt() | |
| 323 | val header = | |
| 324 |               try { check_thy(name, Token.Pos.file(name.node)).cat_errors(message) }
 | |
| 325 |               catch { case ERROR(msg) => cat_error(msg, message) }
 | |
| 326 | val entry = Document.Node.Entry(name, header) | |
| 70638 
f164cec7ac22
clarified signature: prefer operations without position;
 wenzelm parents: 
70634diff
changeset | 327 | dependencies1.require_thys(adjunct, header.imports_pos, | 
| 69008 
d55783ea6cf6
more detailed session dependencies, with conditions for theories;
 wenzelm parents: 
69007diff
changeset | 328 | initiators = name :: initiators, progress = progress).cons(entry) | 
| 69007 | 329 | } | 
| 330 |           catch {
 | |
| 331 | case e: Throwable => | |
| 332 | dependencies1.cons(Document.Node.Entry(name, Document.Node.bad_header(Exn.message(e)))) | |
| 333 | } | |
| 334 | } | |
| 335 | } | |
| 336 | } | |
| 337 | ||
| 69008 
d55783ea6cf6
more detailed session dependencies, with conditions for theories;
 wenzelm parents: 
69007diff
changeset | 338 | def require_thys(adjunct: A, | 
| 69007 | 339 | thys: List[(Document.Node.Name, Position.T)], | 
| 340 | progress: Progress = No_Progress, | |
| 69008 
d55783ea6cf6
more detailed session dependencies, with conditions for theories;
 wenzelm parents: 
69007diff
changeset | 341 | initiators: List[Document.Node.Name] = Nil): Dependencies[A] = | 
| 
d55783ea6cf6
more detailed session dependencies, with conditions for theories;
 wenzelm parents: 
69007diff
changeset | 342 | (this /: thys)(_.require_thy(adjunct, _, progress = progress, initiators = initiators)) | 
| 66959 | 343 | |
| 344 | def entries: List[Document.Node.Entry] = rev_entries.reverse | |
| 69008 
d55783ea6cf6
more detailed session dependencies, with conditions for theories;
 wenzelm parents: 
69007diff
changeset | 345 | |
| 67059 | 346 | def theories: List[Document.Node.Name] = entries.map(_.name) | 
| 69008 
d55783ea6cf6
more detailed session dependencies, with conditions for theories;
 wenzelm parents: 
69007diff
changeset | 347 | def adjunct_theories: List[(A, Document.Node.Name)] = theories.map(name => (seen(name), name)) | 
| 66959 | 348 | |
| 349 | def errors: List[String] = entries.flatMap(_.header.errors) | |
| 350 | ||
| 69008 
d55783ea6cf6
more detailed session dependencies, with conditions for theories;
 wenzelm parents: 
69007diff
changeset | 351 | def check_errors: Dependencies[A] = | 
| 67056 | 352 |       errors match {
 | 
| 353 | case Nil => this | |
| 354 | case errs => error(cat_lines(errs)) | |
| 355 | } | |
| 356 | ||
| 70674 
29bb1ebb188f
clarified signature: proper Document.Node.Ordering conforming to equality (e.g. required in situations where theory names are ambiguous due to overlapping session directories);
 wenzelm parents: 
70673diff
changeset | 357 | lazy val theory_graph: Document.Node.Name.Graph[Unit] = | 
| 70652 | 358 |     {
 | 
| 359 | val regular = theories.toSet | |
| 360 | val irregular = | |
| 361 |         (for {
 | |
| 362 | entry <- entries.iterator | |
| 363 | imp <- entry.header.imports | |
| 364 | if !regular(imp) | |
| 365 | } yield imp).toSet | |
| 366 | ||
| 70674 
29bb1ebb188f
clarified signature: proper Document.Node.Ordering conforming to equality (e.g. required in situations where theory names are ambiguous due to overlapping session directories);
 wenzelm parents: 
70673diff
changeset | 367 | Document.Node.Name.make_graph( | 
| 70652 | 368 | irregular.toList.map(name => ((name, ()), Nil)) ::: | 
| 369 | entries.map(entry => ((entry.name, ()), entry.header.imports))) | |
| 370 | } | |
| 70650 | 371 | |
| 66959 | 372 | lazy val loaded_theories: Graph[String, Outer_Syntax] = | 
| 373 |       (session_base.loaded_theories /: entries)({ case (graph, entry) =>
 | |
| 374 | val name = entry.name.theory | |
| 70638 
f164cec7ac22
clarified signature: prefer operations without position;
 wenzelm parents: 
70634diff
changeset | 375 | val imports = entry.header.imports.map(_.theory) | 
| 66959 | 376 | |
| 377 | val graph1 = (graph /: (name :: imports))(_.default_node(_, Outer_Syntax.empty)) | |
| 378 | val graph2 = (graph1 /: imports)(_.add_edge(_, name)) | |
| 379 | ||
| 380 | val syntax0 = if (name == Thy_Header.PURE) List(Thy_Header.bootstrap_syntax) else Nil | |
| 381 | val syntax1 = (name :: graph2.imm_preds(name).toList).map(graph2.get_node(_)) | |
| 382 | val syntax = Outer_Syntax.merge(syntax0 ::: syntax1) + entry.header | |
| 383 | ||
| 384 | graph2.map_node(name, _ => syntax) | |
| 385 | }) | |
| 386 | ||
| 69561 | 387 | def loaded_files(pure: Boolean): List[(String, List[Path])] = | 
| 66959 | 388 |     {
 | 
| 69560 | 389 | val loaded_files = | 
| 390 | theories.map(_.theory) zip | |
| 391 | Par_List.map((e: () => List[Path]) => e(), | |
| 392 | theories.map(name => | |
| 393 | resources.loaded_files(loaded_theories.get_node(name.theory), name))) | |
| 394 | ||
| 69561 | 395 |       if (pure) {
 | 
| 69560 | 396 | val pure_files = resources.pure_files(overall_syntax) | 
| 397 |         loaded_files.map({ case (name, files) =>
 | |
| 398 | (name, if (name == Thy_Header.PURE) pure_files ::: files else files) }) | |
| 399 | } | |
| 400 | else loaded_files | |
| 66959 | 401 | } | 
| 402 | ||
| 403 | def imported_files: List[Path] = | |
| 404 |     {
 | |
| 405 | val base_theories = | |
| 67059 | 406 | loaded_theories.all_preds(theories.map(_.theory)). | 
| 66959 | 407 | filter(session_base.loaded_theories.defined(_)) | 
| 408 | ||
| 70740 | 409 | base_theories.map(theory => session_base.known_theories(theory).name.path) ::: | 
| 410 | base_theories.flatMap(session_base.known_loaded_files(_)) | |
| 66959 | 411 | } | 
| 412 | ||
| 413 | lazy val overall_syntax: Outer_Syntax = | |
| 414 | Outer_Syntax.merge(loaded_theories.maximals.map(loaded_theories.get_node(_))) | |
| 415 | ||
| 416 | override def toString: String = entries.toString | |
| 417 | } | |
| 43651 
511df47bcadc
some support for theory files within Isabelle/Scala session;
 wenzelm parents: diff
changeset | 418 | } |