Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 11 additions & 4 deletions Beam/Broker/DocumentState.lean
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ inductive SyncFileAction where
structure SyncFileDecision where
action : SyncFileAction
version : Nat
nextVersion : Nat
docs : Docs

structure VersionMarkResult where
Expand Down Expand Up @@ -103,7 +104,8 @@ private def docStateOfSnapshot (version : Nat) (snapshot : FileSnapshot) : DocSt

/--
Decide how a freshly read file snapshot should update the broker's LSP document
mirror.
mirror. `nextVersion` is the session-wide allocator, retained when documents close.
Only opens and source changes consume a revision; unchanged and superseded reads preserve it.

Request handlers reserve nonzero `readSeq` values before reading the filesystem.
If an older read finishes after a newer read has already been applied, the older
Expand All @@ -114,26 +116,30 @@ newer LSP document versions.
def syncFileDecision
(docs : Docs)
(uri : DocumentUri)
(snapshot : FileSnapshot) : SyncFileDecision :=
(snapshot : FileSnapshot)
(nextVersion : Nat) : SyncFileDecision :=
match docs.get? uri with
| none =>
let version := 1
let version := nextVersion
{
action := .open
version
nextVersion := version + 1
docs := docs.insert uri (docStateOfSnapshot version snapshot)
}
| some docState =>
if snapshot.readSeq != 0 && snapshot.readSeq < docState.syncSnapshotSeq then
{
action := .unchanged
version := docState.version
nextVersion
docs
}
else if docState.textHash == snapshot.textHash then
{
action := .unchanged
version := docState.version
nextVersion
docs := docs.insert uri {
docState with
textTraceHash := snapshot.textTraceHash
Expand All @@ -143,10 +149,11 @@ def syncFileDecision
}
}
else
let version := docState.version + 1
let version := nextVersion
{
action := .change
version
nextVersion := version + 1
docs := docs.insert uri {
(docStateOfSnapshot version snapshot) with
checkpointedVersion? := none
Expand Down
6 changes: 4 additions & 2 deletions Beam/Broker/OpenDocs.lean
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ namespace OpenDocs

structure SessionView where
root : System.FilePath
sessionToken : String
docs : DocumentState.Docs := {}

inductive DiskStatus where
Expand Down Expand Up @@ -48,6 +49,7 @@ def docDiskStatus (path : System.FilePath) (docState : DocState) : IO DiskStatus

def docJson
(root : System.FilePath)
(sessionToken : String)
(uri : DocumentUri)
(docState : DocState) : IO Json := do
let path? := System.Uri.fileUriToPath? uri
Expand All @@ -65,7 +67,7 @@ def docJson
pure <| Json.mkObj <|
[
("uri", toJson uri),
("version", toJson docState.version),
("snapshot", toJson ({ session := sessionToken, revision := docState.version } : SnapshotRef)),
("diskStatus", toJson status),
("checkpointed", toJson checkpointed)
] ++
Expand All @@ -84,7 +86,7 @@ def sessionJson (session? : Option SessionView) : IO Json := do
]
| some session =>
let files ← session.docs.toList.mapM fun (uri, docState) =>
docJson session.root uri docState
docJson session.root session.sessionToken uri docState
pure <| Json.mkObj [
("active", toJson true),
("files", Json.arr files.toArray)
Expand Down
38 changes: 17 additions & 21 deletions Beam/Broker/Pending.lean
Original file line number Diff line number Diff line change
Expand Up @@ -206,39 +206,45 @@ private def observeSyncFileProgress
progress?

private def trackedPublishDiagnosticsParam?
(trackedUri? : Option DocumentUri)
(tracked? : Option (DocumentUri × Nat))
(diagnosticParam : PublishDiagnosticsParams) : Option PublishDiagnosticsParams :=
match trackedUri? with
| some uri =>
match tracked? with
| some (uri, version) =>
let diagnosticParam := normalizePublishDiagnostics diagnosticParam
if diagnosticParam.uri == uri then
if diagnosticParam.uri == uri &&
diagnosticParam.version?.all (· == Int.ofNat version) then
some diagnosticParam
else
none
| none =>
none

private def diagnosticStreamKey (diagnostic : Diagnostic) : String :=
(toJson diagnostic).compress
private def diagnosticStreamKey
(snapshot? : Option SnapshotRef) (diagnostic : Diagnostic) : String :=
(toJson (snapshot?, diagnostic)).compress

private def emitNewTrackedDiagnostics
(root : System.FilePath)
(sessionToken : String)
(seen : Std.TreeSet String compare)
(diagnosticParam : PublishDiagnosticsParams)
(diagnosticScope : DiagnosticScope)
(emitDiagnostic? : Option (StreamDiagnostic → IO Unit) := none) :
IO (Std.TreeSet String compare) := do
let snapshot? := diagnosticParam.version?.bind fun version =>
if version > 0 then some { session := sessionToken, revision := version.toNat }
else none
let mut seen := seen
let diagnostics := filterSyncDiagnostics diagnosticScope diagnosticParam.diagnostics
for diagnostic in diagnostics do
let key := diagnosticStreamKey diagnostic
let key := diagnosticStreamKey snapshot? diagnostic
if !seen.contains key then
seen := seen.insert key
match emitDiagnostic? with
| some emitDiagnostic =>
try
emitDiagnostic <|
streamDiagnosticOfDiagnostic root diagnosticParam.uri diagnosticParam.version? diagnostic
streamDiagnosticOfDiagnostic root diagnosticParam.uri snapshot? diagnostic
catch _ =>
pure ()
| none =>
Expand All @@ -264,30 +270,20 @@ def observeProgress

def observePublishDiagnostics
(root : System.FilePath)
(sessionToken : String)
(pending : PendingRequest)
(diagnosticParam : PublishDiagnosticsParams) : IO Unit := do
match trackedPublishDiagnosticsParam? (pending.tracked?.map Prod.fst) diagnosticParam with
match trackedPublishDiagnosticsParam? pending.tracked? diagnosticParam with
| none =>
pure ()
| some diagnosticParam =>
pending.diagnosticsSeenRef.set true
pending.diagnosticsRef.set diagnosticParam.diagnostics
let seen ← pending.seenDiagnosticKeysRef.get
let seen ←
emitNewTrackedDiagnostics root seen diagnosticParam pending.diagnosticScope pending.emitDiagnostic?
emitNewTrackedDiagnostics root sessionToken seen diagnosticParam pending.diagnosticScope pending.emitDiagnostic?
pending.seenDiagnosticKeysRef.set seen

def observeDiagnostics
[ToJson α]
(root : System.FilePath)
(pending : PendingRequest)
(param : α) : IO Unit := do
match fromJson? (toJson param) with
| .ok (diagnosticParam : PublishDiagnosticsParams) =>
observePublishDiagnostics root pending diagnosticParam
| .error _ =>
pure ()

end PendingRequest

namespace PendingRequestStore
Expand Down
Loading
Loading