# HG changeset patch # User wenzelm # Date 1489069164 -3600 # Node ID 6e042537555d9235f898df3a85ec3c97de6c8263 # Parent 0ae97858d8b318247f019a2f1fbff3d934ff2363 incremental document changes; diff -r 0ae97858d8b3 -r 6e042537555d src/Tools/VSCode/src/document_model.scala --- a/src/Tools/VSCode/src/document_model.scala Thu Mar 09 15:08:44 2017 +0100 +++ b/src/Tools/VSCode/src/document_model.scala Thu Mar 09 15:19:24 2017 +0100 @@ -102,16 +102,25 @@ /* edits */ - def update_text(text: String): Option[Document_Model] = + def change_text(text: String, range: Option[Line.Range] = None): Option[Document_Model] = { - val old_text = content.text - val new_text = Line.normalize(text) - Text.Edit.replace(0, old_text, new_text) match { - case Nil => None - case edits => - val content1 = Document_Model.Content(Line.Document(new_text, content.doc.text_length)) - val pending_edits1 = pending_edits ::: edits - Some(copy(content = content1, pending_edits = pending_edits1)) + val insert = Line.normalize(text) + range match { + case None => + Text.Edit.replace(0, content.text, insert) match { + case Nil => None + case edits => + val content1 = Document_Model.Content(Line.Document(insert, content.doc.text_length)) + Some(copy(content = content1, pending_edits = pending_edits ::: edits)) + } + case Some(remove) => + content.doc.change(remove, insert) match { + case None => error("Failed to apply document change: " + remove) + case Some((Nil, _)) => None + case Some((edits, doc1)) => + val content1 = Document_Model.Content(doc1) + Some(copy(content = content1, pending_edits = pending_edits ::: edits)) + } } } diff -r 0ae97858d8b3 -r 6e042537555d src/Tools/VSCode/src/protocol.scala --- a/src/Tools/VSCode/src/protocol.scala Thu Mar 09 15:08:44 2017 +0100 +++ b/src/Tools/VSCode/src/protocol.scala Thu Mar 09 15:19:24 2017 +0100 @@ -10,7 +10,6 @@ import isabelle._ - import java.io.{File => JFile} @@ -138,7 +137,7 @@ { val json: JSON.T = Map( - "textDocumentSync" -> 1, + "textDocumentSync" -> 2, "completionProvider" -> Map("resolveProvider" -> false, "triggerCharacters" -> Nil), "hoverProvider" -> true, "definitionProvider" -> true, @@ -260,34 +259,22 @@ } - sealed abstract class TextDocumentContentChange - case class TextDocumentContent(text: String) extends TextDocumentContentChange - case class TextDocumentChange(range: Line.Range, range_length: Int, text: String) - extends TextDocumentContentChange - - object TextDocumentContentChange - { - def unapply(json: JSON.T): Option[TextDocumentContentChange] = - for { text <- JSON.string(json, "text") } - yield { - (JSON.value(json, "range"), JSON.int(json, "rangeLength")) match { - case (Some(Range(range)), Some(range_length)) => - TextDocumentChange(range, range_length, text) - case _ => TextDocumentContent(text) - } - } - } + sealed case class TextDocumentChange(range: Option[Line.Range], text: String) object DidChangeTextDocument { - def unapply(json: JSON.T): Option[(JFile, Long, List[TextDocumentContentChange])] = + def unapply_change(json: JSON.T): Option[TextDocumentChange] = + for { text <- JSON.string(json, "text") } + yield TextDocumentChange(JSON.value(json, "range", Range.unapply _), text) + + def unapply(json: JSON.T): Option[(JFile, Long, List[TextDocumentChange])] = json match { case Notification("textDocument/didChange", Some(params)) => for { doc <- JSON.value(params, "textDocument") uri <- JSON.string(doc, "uri") version <- JSON.long(doc, "version") - changes <- JSON.array(params, "contentChanges", TextDocumentContentChange.unapply _) + changes <- JSON.array(params, "contentChanges", unapply_change _) } yield (Url.canonical_file(uri), version, changes) case _ => None } diff -r 0ae97858d8b3 -r 6e042537555d src/Tools/VSCode/src/server.scala --- a/src/Tools/VSCode/src/server.scala Thu Mar 09 15:08:44 2017 +0100 +++ b/src/Tools/VSCode/src/server.scala Thu Mar 09 15:19:24 2017 +0100 @@ -1,9 +1,11 @@ /* Title: Tools/VSCode/src/server.scala Author: Makarius -Server for VS Code Language Server Protocol 2.0, see also +Server for VS Code Language Server Protocol 2.0/3.0, see also https://github.com/Microsoft/language-server-protocol https://github.com/Microsoft/language-server-protocol/blob/master/protocol.md + +PIDE protocol extensions depend on system option "vscode_pide_extensions". */ package isabelle.vscode @@ -143,7 +145,14 @@ private def update_document(file: JFile, text: String) { - resources.update_model(session, file, text) + resources.change_model(session, file, text) + delay_input.invoke() + delay_output.invoke() + } + + private def change_document(file: JFile, changes: List[Protocol.TextDocumentChange]) + { + changes.foreach(change => resources.change_model(session, file, change.text, change.range)) delay_input.invoke() delay_output.invoke() } @@ -351,12 +360,9 @@ case Protocol.Initialize(id) => init(id) case Protocol.Shutdown(id) => shutdown(id) case Protocol.Exit(()) => exit() - case Protocol.DidOpenTextDocument(file, lang, version, text) => - update_document(file, text) - case Protocol.DidChangeTextDocument(file, version, List(Protocol.TextDocumentContent(text))) => - update_document(file, text) - case Protocol.DidCloseTextDocument(file) => - close_document(file) + case Protocol.DidOpenTextDocument(file, _, _, text) => update_document(file, text) + case Protocol.DidChangeTextDocument(file, _, changes) => change_document(file, changes) + case Protocol.DidCloseTextDocument(file) => close_document(file) case Protocol.Completion(id, node_pos) => completion(id, node_pos) case Protocol.Hover(id, node_pos) => hover(id, node_pos) case Protocol.GotoDefinition(id, node_pos) => goto_definition(id, node_pos) diff -r 0ae97858d8b3 -r 6e042537555d src/Tools/VSCode/src/vscode_resources.scala --- a/src/Tools/VSCode/src/vscode_resources.scala Thu Mar 09 15:08:44 2017 +0100 +++ b/src/Tools/VSCode/src/vscode_resources.scala Thu Mar 09 15:19:24 2017 +0100 @@ -122,12 +122,12 @@ case None => false } - def update_model(session: Session, file: JFile, text: String) + def change_model(session: Session, file: JFile, text: String, range: Option[Line.Range] = None) { state.change(st => { val model = st.models.getOrElse(file, Document_Model.init(session, node_name(file))) - val model1 = (model.update_text(text) getOrElse model).external(false) + val model1 = (model.change_text(text, range) getOrElse model).external(false) st.update_models(Some(file -> model1)) }) } @@ -147,7 +147,7 @@ (file, model) <- st.models.iterator if changed_files(file) && model.external_file text <- read_file_content(file) - model1 <- model.update_text(text) + model1 <- model.change_text(text) } yield (file, model1)).toList st.update_models(changed_models) }) @@ -193,7 +193,7 @@ } yield { val model = Document_Model.init(session, node_name) - val model1 = (model.update_text(text) getOrElse model).external(true) + val model1 = (model.change_text(text) getOrElse model).external(true) (file, model1) }).toList