chore: more server fixes

This commit is contained in:
Wojciech Nawrocki 2020-08-15 00:26:29 +02:00 committed by Leonardo de Moura
parent 7b9363c828
commit bbcc718c8d
3 changed files with 19 additions and 17 deletions

View file

@ -12,8 +12,11 @@ universes u
structure String :=
(data : List Char)
/-- A character position in an UTF-8 encoded string.
To represent codepoint positions, use a plain `Nat`. -/
/-- A byte position in a `String`. Internally, `String`s are UTF-8 encoded.
Codepoint positions (counting the Unicode codepoints rather than bytes)
are represented by plain `Nat`s instead.
Indexing a `String` by a byte position is constant-time, while codepoint
positions need to be translated internally to byte positions in linear-time. -/
abbrev String.Pos := Nat
structure Substring :=

View file

@ -72,12 +72,5 @@ text.source.codepointPosToUtf8PosFrom colPos chr
def leanPosToLspPos (text : FileMap) : Lean.Position → Lsp.Position
| ⟨ln, col⟩ => ⟨ln-1, text.source.codepointPosToUtf16PosFrom col (text.positions.get! $ ln - 1)⟩
def replaceLspRange (text : FileMap) (r : Lsp.Range) (newText : String) : FileMap :=
let start := text.lspPosToUtf8Pos r.start;
let «end» := text.lspPosToUtf8Pos r.«end»;
let pre := text.source.extract 0 start;
let post := text.source.extract «end» text.source.bsize;
(pre ++ newText ++ post).toFileMap
end FileMap
end Lean

View file

@ -130,17 +130,23 @@ writeLspNotification "textDocument/publishDiagnostics"
def handleDidOpen (p : DidOpenTextDocumentParams) : ServerM Unit := do
let doc := p.textDocument;
-- LSP is EOL agnostic, so we first split on "\r\n" to avoid possibly redundant line breaks.
let splitOnEOLs (s : String) : List String := (do
line ← s.splitOn "\r\n";
line ← line.splitOn "\n";
line ← line.splitOn "\r";
pure line);
let text := ("\n".intercalate $ splitOnEOLs doc.text).toFileMap;
-- NOTE(WN): `toFileMap` marks line beginnings as immediately following
-- "\n", which should be enough to handle both LF and CRLF correctly.
-- This is because LSP always refers to characters by (line, column),
-- so if we get the line number correct it shouldn't matter that there
-- is a CR there.
let text := doc.text.toFileMap;
(msgLog, newDoc) ← monadLift $ compileDocument doc.version text;
updateOpenDocuments doc.uri newDoc;
sendDiagnostics doc.uri newDoc msgLog
private def replaceLspRange (text : FileMap) (r : Lsp.Range) (newText : String) : FileMap :=
let start := text.lspPosToUtf8Pos r.start;
let «end» := text.lspPosToUtf8Pos r.«end»;
let pre := text.source.extract 0 start;
let post := text.source.extract «end» text.source.bsize;
(pre ++ newText ++ post).toFileMap
def handleDidChange (p : DidChangeTextDocumentParams) : ServerM Unit := do
let docId := p.textDocument;
let changes := p.contentChanges;
@ -152,7 +158,7 @@ else changes.forM $ fun change =>
match change with
| TextDocumentContentChangeEvent.rangeChange (range : Range) (newText : String) => do
let startOff := oldDoc.text.lspPosToUtf8Pos range.start;
let newDocText := oldDoc.text.replaceLspRange range newText;
let newDocText := replaceLspRange oldDoc.text range newText;
(msgLog, newDoc) ← monadLift $
updateDocument oldDoc startOff newVersion newDocText;
updateOpenDocuments docId.uri newDoc;