src/Tools/VSCode/src/vscode_resources.scala
changeset 64777 ca09695eb43c
parent 64775 dd3797f1e0d6
child 64779 6cdcc271dbd5
equal deleted inserted replaced
64776:3f20c63f71be 64777:ca09695eb43c
    17 object VSCode_Resources
    17 object VSCode_Resources
    18 {
    18 {
    19   /* internal state */
    19   /* internal state */
    20 
    20 
    21   sealed case class State(
    21   sealed case class State(
    22     models: Map[String, Document_Model] = Map.empty,
    22     models: Map[JFile, Document_Model] = Map.empty,
    23     pending_input: Set[String] = Set.empty,
    23     pending_input: Set[JFile] = Set.empty,
    24     pending_output: Set[String] = Set.empty)
    24     pending_output: Set[JFile] = Set.empty)
    25 }
    25 }
    26 
    26 
    27 class VSCode_Resources(
    27 class VSCode_Resources(
    28     val options: Options,
    28     val options: Options,
    29     val text_length: Text.Length,
    29     val text_length: Text.Length,
    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))(_ + _)))
   127            yield (model.node_name, Position.none)).toList
   131            yield (model.node_name, Position.none)).toList
   128 
   132 
   129         val loaded_models =
   133         val loaded_models =
   130           (for {
   134           (for {
   131             dep <- thy_info.dependencies("", thys).deps.iterator
   135             dep <- thy_info.dependencies("", thys).deps.iterator
   132             uri = dep.name.node
   136             file = node_file(dep.name)
   133             if !st.models.isDefinedAt(uri)
   137             if !st.models.isDefinedAt(file)
   134             text <-
   138             text <-
   135               try { Some(File.read(Url.parse_file(uri))) }
   139               try { Some(File.read(file)) }
   136               catch { case ERROR(_) => None }
   140               catch { case ERROR(_) => None }
   137           }
   141           }
   138           yield {
   142           yield {
   139             val model = Document_Model.init(session, uri)
   143             val model = Document_Model.init(session, node_name(file))
   140             val model1 = (model.update_text(text) getOrElse model).external(true)
   144             val model1 = (model.update_text(text) getOrElse model).external(true)
   141             (uri, model1)
   145             (file, model1)
   142           }).toList
   146           }).toList
   143 
   147 
   144         if (loaded_models.isEmpty) (false, st)
   148         if (loaded_models.isEmpty) (false, st)
   145         else
   149         else
   146           (true,
   150           (true,
   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 }