src/Tools/VSCode/src/vscode_resources.scala
author wenzelm
Fri, 30 Dec 2016 20:36:13 +0100
changeset 64710 72ca4e5f976e
parent 64709 5e6566ab78bf
child 64716 473793d52d97
permissions -rw-r--r--
manage changes of external files; tuned;
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
64623
83f012ce2567 clarified module name;
wenzelm
parents: 64605
diff changeset
     1
/*  Title:      Tools/VSCode/src/vscode_resources.scala
64605
9c1173a7e4cb basic support for VSCode Language Server protocol;
wenzelm
parents:
diff changeset
     2
    Author:     Makarius
9c1173a7e4cb basic support for VSCode Language Server protocol;
wenzelm
parents:
diff changeset
     3
64623
83f012ce2567 clarified module name;
wenzelm
parents: 64605
diff changeset
     4
Resources for VSCode Language Server, based on file-system URIs.
64605
9c1173a7e4cb basic support for VSCode Language Server protocol;
wenzelm
parents:
diff changeset
     5
*/
9c1173a7e4cb basic support for VSCode Language Server protocol;
wenzelm
parents:
diff changeset
     6
9c1173a7e4cb basic support for VSCode Language Server protocol;
wenzelm
parents:
diff changeset
     7
package isabelle.vscode
9c1173a7e4cb basic support for VSCode Language Server protocol;
wenzelm
parents:
diff changeset
     8
9c1173a7e4cb basic support for VSCode Language Server protocol;
wenzelm
parents:
diff changeset
     9
9c1173a7e4cb basic support for VSCode Language Server protocol;
wenzelm
parents:
diff changeset
    10
import isabelle._
9c1173a7e4cb basic support for VSCode Language Server protocol;
wenzelm
parents:
diff changeset
    11
9c1173a7e4cb basic support for VSCode Language Server protocol;
wenzelm
parents:
diff changeset
    12
import java.net.{URI, URISyntaxException}
9c1173a7e4cb basic support for VSCode Language Server protocol;
wenzelm
parents:
diff changeset
    13
import java.io.{File => JFile}
9c1173a7e4cb basic support for VSCode Language Server protocol;
wenzelm
parents:
diff changeset
    14
9c1173a7e4cb basic support for VSCode Language Server protocol;
wenzelm
parents:
diff changeset
    15
64623
83f012ce2567 clarified module name;
wenzelm
parents: 64605
diff changeset
    16
object VSCode_Resources
64605
9c1173a7e4cb basic support for VSCode Language Server protocol;
wenzelm
parents:
diff changeset
    17
{
64703
a115391494ed moved main state to VSCode_Resources;
wenzelm
parents: 64640
diff changeset
    18
  /* file URIs */
a115391494ed moved main state to VSCode_Resources;
wenzelm
parents: 64640
diff changeset
    19
64605
9c1173a7e4cb basic support for VSCode Language Server protocol;
wenzelm
parents:
diff changeset
    20
  def is_wellformed(uri: String): Boolean =
9c1173a7e4cb basic support for VSCode Language Server protocol;
wenzelm
parents:
diff changeset
    21
    try { new JFile(new URI(uri)); true }
9c1173a7e4cb basic support for VSCode Language Server protocol;
wenzelm
parents:
diff changeset
    22
    catch { case _: URISyntaxException | _: IllegalArgumentException => false }
9c1173a7e4cb basic support for VSCode Language Server protocol;
wenzelm
parents:
diff changeset
    23
9c1173a7e4cb basic support for VSCode Language Server protocol;
wenzelm
parents:
diff changeset
    24
  def canonical_file(uri: String): JFile =
9c1173a7e4cb basic support for VSCode Language Server protocol;
wenzelm
parents:
diff changeset
    25
    new JFile(new URI(uri)).getCanonicalFile
9c1173a7e4cb basic support for VSCode Language Server protocol;
wenzelm
parents:
diff changeset
    26
64703
a115391494ed moved main state to VSCode_Resources;
wenzelm
parents: 64640
diff changeset
    27
a115391494ed moved main state to VSCode_Resources;
wenzelm
parents: 64640
diff changeset
    28
  /* internal state */
a115391494ed moved main state to VSCode_Resources;
wenzelm
parents: 64640
diff changeset
    29
a115391494ed moved main state to VSCode_Resources;
wenzelm
parents: 64640
diff changeset
    30
  sealed case class State(
a115391494ed moved main state to VSCode_Resources;
wenzelm
parents: 64640
diff changeset
    31
    models: Map[String, Document_Model] = Map.empty,
64708
wenzelm
parents: 64707
diff changeset
    32
    pending_input: Set[String] = Set.empty,
wenzelm
parents: 64707
diff changeset
    33
    pending_output: Set[String] = Set.empty)
64605
9c1173a7e4cb basic support for VSCode Language Server protocol;
wenzelm
parents:
diff changeset
    34
}
9c1173a7e4cb basic support for VSCode Language Server protocol;
wenzelm
parents:
diff changeset
    35
64623
83f012ce2567 clarified module name;
wenzelm
parents: 64605
diff changeset
    36
class VSCode_Resources(
64703
a115391494ed moved main state to VSCode_Resources;
wenzelm
parents: 64640
diff changeset
    37
    val options: Options,
64706
wenzelm
parents: 64704
diff changeset
    38
    val text_length: Text.Length,
64605
9c1173a7e4cb basic support for VSCode Language Server protocol;
wenzelm
parents:
diff changeset
    39
    loaded_theories: Set[String],
9c1173a7e4cb basic support for VSCode Language Server protocol;
wenzelm
parents:
diff changeset
    40
    known_theories: Map[String, Document.Node.Name],
9c1173a7e4cb basic support for VSCode Language Server protocol;
wenzelm
parents:
diff changeset
    41
    base_syntax: Outer_Syntax)
9c1173a7e4cb basic support for VSCode Language Server protocol;
wenzelm
parents:
diff changeset
    42
  extends Resources(loaded_theories, known_theories, base_syntax)
9c1173a7e4cb basic support for VSCode Language Server protocol;
wenzelm
parents:
diff changeset
    43
{
64703
a115391494ed moved main state to VSCode_Resources;
wenzelm
parents: 64640
diff changeset
    44
  private val state = Synchronized(VSCode_Resources.State())
a115391494ed moved main state to VSCode_Resources;
wenzelm
parents: 64640
diff changeset
    45
a115391494ed moved main state to VSCode_Resources;
wenzelm
parents: 64640
diff changeset
    46
a115391494ed moved main state to VSCode_Resources;
wenzelm
parents: 64640
diff changeset
    47
  /* document node name */
a115391494ed moved main state to VSCode_Resources;
wenzelm
parents: 64640
diff changeset
    48
64605
9c1173a7e4cb basic support for VSCode Language Server protocol;
wenzelm
parents:
diff changeset
    49
  def node_name(uri: String): Document.Node.Name =
9c1173a7e4cb basic support for VSCode Language Server protocol;
wenzelm
parents:
diff changeset
    50
  {
64640
f9470490e682 clarified node_name: preserve original uri;
wenzelm
parents: 64623
diff changeset
    51
    val theory = Thy_Header.thy_name(uri).getOrElse("")
f9470490e682 clarified node_name: preserve original uri;
wenzelm
parents: 64623
diff changeset
    52
    val master_dir =
f9470490e682 clarified node_name: preserve original uri;
wenzelm
parents: 64623
diff changeset
    53
      if (!VSCode_Resources.is_wellformed(uri) || theory == "") ""
f9470490e682 clarified node_name: preserve original uri;
wenzelm
parents: 64623
diff changeset
    54
      else VSCode_Resources.canonical_file(uri).getParent
f9470490e682 clarified node_name: preserve original uri;
wenzelm
parents: 64623
diff changeset
    55
    Document.Node.Name(uri, master_dir, theory)
64605
9c1173a7e4cb basic support for VSCode Language Server protocol;
wenzelm
parents:
diff changeset
    56
  }
64703
a115391494ed moved main state to VSCode_Resources;
wenzelm
parents: 64640
diff changeset
    57
a115391494ed moved main state to VSCode_Resources;
wenzelm
parents: 64640
diff changeset
    58
a115391494ed moved main state to VSCode_Resources;
wenzelm
parents: 64640
diff changeset
    59
  /* document models */
a115391494ed moved main state to VSCode_Resources;
wenzelm
parents: 64640
diff changeset
    60
a115391494ed moved main state to VSCode_Resources;
wenzelm
parents: 64640
diff changeset
    61
  def get_model(uri: String): Option[Document_Model] = state.value.models.get(uri)
a115391494ed moved main state to VSCode_Resources;
wenzelm
parents: 64640
diff changeset
    62
64709
5e6566ab78bf more explicit edits -- eliminated Clear;
wenzelm
parents: 64708
diff changeset
    63
  def update_model(session: Session, uri: String, text: String)
64703
a115391494ed moved main state to VSCode_Resources;
wenzelm
parents: 64640
diff changeset
    64
  {
a115391494ed moved main state to VSCode_Resources;
wenzelm
parents: 64640
diff changeset
    65
    state.change(st =>
64709
5e6566ab78bf more explicit edits -- eliminated Clear;
wenzelm
parents: 64708
diff changeset
    66
      {
64710
72ca4e5f976e manage changes of external files;
wenzelm
parents: 64709
diff changeset
    67
        val model = st.models.getOrElse(uri, Document_Model.init(session, uri))
72ca4e5f976e manage changes of external files;
wenzelm
parents: 64709
diff changeset
    68
        val model1 = (model.update_text(text) getOrElse model).copy(external = false)
64709
5e6566ab78bf more explicit edits -- eliminated Clear;
wenzelm
parents: 64708
diff changeset
    69
        st.copy(
64710
72ca4e5f976e manage changes of external files;
wenzelm
parents: 64709
diff changeset
    70
          models = st.models + (uri -> model1),
64709
5e6566ab78bf more explicit edits -- eliminated Clear;
wenzelm
parents: 64708
diff changeset
    71
          pending_input = st.pending_input + uri)
5e6566ab78bf more explicit edits -- eliminated Clear;
wenzelm
parents: 64708
diff changeset
    72
      })
64703
a115391494ed moved main state to VSCode_Resources;
wenzelm
parents: 64640
diff changeset
    73
  }
a115391494ed moved main state to VSCode_Resources;
wenzelm
parents: 64640
diff changeset
    74
64710
72ca4e5f976e manage changes of external files;
wenzelm
parents: 64709
diff changeset
    75
  def close_model(uri: String): Option[Document_Model] =
72ca4e5f976e manage changes of external files;
wenzelm
parents: 64709
diff changeset
    76
    state.change_result(st =>
72ca4e5f976e manage changes of external files;
wenzelm
parents: 64709
diff changeset
    77
      st.models.get(uri) match {
72ca4e5f976e manage changes of external files;
wenzelm
parents: 64709
diff changeset
    78
        case None => (None, st)
72ca4e5f976e manage changes of external files;
wenzelm
parents: 64709
diff changeset
    79
        case Some(model) =>
72ca4e5f976e manage changes of external files;
wenzelm
parents: 64709
diff changeset
    80
          (Some(model), st.copy(models = st.models + (uri -> model.copy(external = true))))
72ca4e5f976e manage changes of external files;
wenzelm
parents: 64709
diff changeset
    81
      })
72ca4e5f976e manage changes of external files;
wenzelm
parents: 64709
diff changeset
    82
72ca4e5f976e manage changes of external files;
wenzelm
parents: 64709
diff changeset
    83
  def sync_external(changed_files: Set[JFile]): Boolean =
72ca4e5f976e manage changes of external files;
wenzelm
parents: 64709
diff changeset
    84
    state.change_result(st =>
72ca4e5f976e manage changes of external files;
wenzelm
parents: 64709
diff changeset
    85
      {
72ca4e5f976e manage changes of external files;
wenzelm
parents: 64709
diff changeset
    86
        val changed =
72ca4e5f976e manage changes of external files;
wenzelm
parents: 64709
diff changeset
    87
          (for {
72ca4e5f976e manage changes of external files;
wenzelm
parents: 64709
diff changeset
    88
            (uri, model) <- st.models.iterator
72ca4e5f976e manage changes of external files;
wenzelm
parents: 64709
diff changeset
    89
            if changed_files(model.file)
72ca4e5f976e manage changes of external files;
wenzelm
parents: 64709
diff changeset
    90
            model1 <- model.update_file
72ca4e5f976e manage changes of external files;
wenzelm
parents: 64709
diff changeset
    91
          } yield (uri, model)).toList
72ca4e5f976e manage changes of external files;
wenzelm
parents: 64709
diff changeset
    92
        if (changed.isEmpty) (false, st)
72ca4e5f976e manage changes of external files;
wenzelm
parents: 64709
diff changeset
    93
        else (true, st.copy(models = (st.models /: changed)(_ + _)))
72ca4e5f976e manage changes of external files;
wenzelm
parents: 64709
diff changeset
    94
      })
72ca4e5f976e manage changes of external files;
wenzelm
parents: 64709
diff changeset
    95
64703
a115391494ed moved main state to VSCode_Resources;
wenzelm
parents: 64640
diff changeset
    96
a115391494ed moved main state to VSCode_Resources;
wenzelm
parents: 64640
diff changeset
    97
  /* pending input */
a115391494ed moved main state to VSCode_Resources;
wenzelm
parents: 64640
diff changeset
    98
a115391494ed moved main state to VSCode_Resources;
wenzelm
parents: 64640
diff changeset
    99
  def flush_input(session: Session)
a115391494ed moved main state to VSCode_Resources;
wenzelm
parents: 64640
diff changeset
   100
  {
a115391494ed moved main state to VSCode_Resources;
wenzelm
parents: 64640
diff changeset
   101
    state.change(st =>
a115391494ed moved main state to VSCode_Resources;
wenzelm
parents: 64640
diff changeset
   102
      {
a115391494ed moved main state to VSCode_Resources;
wenzelm
parents: 64640
diff changeset
   103
        val changed =
a115391494ed moved main state to VSCode_Resources;
wenzelm
parents: 64640
diff changeset
   104
          (for {
64708
wenzelm
parents: 64707
diff changeset
   105
            uri <- st.pending_input.iterator
wenzelm
parents: 64707
diff changeset
   106
            model <- st.models.get(uri)
64707
7157685b71e3 clarified Document_Model perspective and edits;
wenzelm
parents: 64706
diff changeset
   107
            res <- model.flush_edits
7157685b71e3 clarified Document_Model perspective and edits;
wenzelm
parents: 64706
diff changeset
   108
          } yield res).toList
7157685b71e3 clarified Document_Model perspective and edits;
wenzelm
parents: 64706
diff changeset
   109
7157685b71e3 clarified Document_Model perspective and edits;
wenzelm
parents: 64706
diff changeset
   110
        session.update(Document.Blobs.empty, changed.flatMap(_._1))
64703
a115391494ed moved main state to VSCode_Resources;
wenzelm
parents: 64640
diff changeset
   111
        st.copy(
64707
7157685b71e3 clarified Document_Model perspective and edits;
wenzelm
parents: 64706
diff changeset
   112
          models = (st.models /: changed) { case (ms, (_, m)) => ms + (m.uri -> m) },
64703
a115391494ed moved main state to VSCode_Resources;
wenzelm
parents: 64640
diff changeset
   113
          pending_input = Set.empty)
a115391494ed moved main state to VSCode_Resources;
wenzelm
parents: 64640
diff changeset
   114
      })
a115391494ed moved main state to VSCode_Resources;
wenzelm
parents: 64640
diff changeset
   115
  }
a115391494ed moved main state to VSCode_Resources;
wenzelm
parents: 64640
diff changeset
   116
a115391494ed moved main state to VSCode_Resources;
wenzelm
parents: 64640
diff changeset
   117
a115391494ed moved main state to VSCode_Resources;
wenzelm
parents: 64640
diff changeset
   118
  /* pending output */
a115391494ed moved main state to VSCode_Resources;
wenzelm
parents: 64640
diff changeset
   119
64708
wenzelm
parents: 64707
diff changeset
   120
  def update_output(changed_nodes: List[String]): Unit =
64703
a115391494ed moved main state to VSCode_Resources;
wenzelm
parents: 64640
diff changeset
   121
    state.change(st => st.copy(pending_output = st.pending_output ++ changed_nodes))
a115391494ed moved main state to VSCode_Resources;
wenzelm
parents: 64640
diff changeset
   122
a115391494ed moved main state to VSCode_Resources;
wenzelm
parents: 64640
diff changeset
   123
  def flush_output(channel: Channel)
a115391494ed moved main state to VSCode_Resources;
wenzelm
parents: 64640
diff changeset
   124
  {
a115391494ed moved main state to VSCode_Resources;
wenzelm
parents: 64640
diff changeset
   125
    state.change(st =>
a115391494ed moved main state to VSCode_Resources;
wenzelm
parents: 64640
diff changeset
   126
      {
a115391494ed moved main state to VSCode_Resources;
wenzelm
parents: 64640
diff changeset
   127
        val changed_iterator =
a115391494ed moved main state to VSCode_Resources;
wenzelm
parents: 64640
diff changeset
   128
          for {
64708
wenzelm
parents: 64707
diff changeset
   129
            uri <- st.pending_output.iterator
wenzelm
parents: 64707
diff changeset
   130
            model <- st.models.get(uri)
64704
08c2d80428ff re-use options from resources;
wenzelm
parents: 64703
diff changeset
   131
            rendering = model.rendering()
64703
a115391494ed moved main state to VSCode_Resources;
wenzelm
parents: 64640
diff changeset
   132
            (diagnostics, model1) <- model.publish_diagnostics(rendering)
a115391494ed moved main state to VSCode_Resources;
wenzelm
parents: 64640
diff changeset
   133
          } yield {
a115391494ed moved main state to VSCode_Resources;
wenzelm
parents: 64640
diff changeset
   134
            channel.diagnostics(model1.uri, rendering.diagnostics_output(diagnostics))
a115391494ed moved main state to VSCode_Resources;
wenzelm
parents: 64640
diff changeset
   135
            model1
a115391494ed moved main state to VSCode_Resources;
wenzelm
parents: 64640
diff changeset
   136
          }
a115391494ed moved main state to VSCode_Resources;
wenzelm
parents: 64640
diff changeset
   137
        st.copy(
a115391494ed moved main state to VSCode_Resources;
wenzelm
parents: 64640
diff changeset
   138
          models = (st.models /: changed_iterator) { case (ms, m) => ms + (m.uri -> m) },
a115391494ed moved main state to VSCode_Resources;
wenzelm
parents: 64640
diff changeset
   139
          pending_output = Set.empty)
a115391494ed moved main state to VSCode_Resources;
wenzelm
parents: 64640
diff changeset
   140
      }
a115391494ed moved main state to VSCode_Resources;
wenzelm
parents: 64640
diff changeset
   141
    )
a115391494ed moved main state to VSCode_Resources;
wenzelm
parents: 64640
diff changeset
   142
  }
64605
9c1173a7e4cb basic support for VSCode Language Server protocol;
wenzelm
parents:
diff changeset
   143
}