Returns the managed document for the given URI or if it doesn't exist it tries to read the file from the filesystem and open it from that.
Inserts a document manually or updates an existing one, acting like textDocument/didOpen if it didn't exist or fully replacing the document if it did exist.
Same as tryGet but throws an exception if the URI doesn't exist.
Processes an LSP packet and performs the document update in-memory that is requested.
Tries to get a document from a URI, returns Document.init if it is not in the in-memory cache / not sent by the client.
Unloads the given URI so it's no longer accessible. Note that this should only be done for documents loaded manually and never for LSP documents as it will break all features in that file until reopened.
Returns the currently preferred syncKind to use with the client. Additionally always supports the full sync kind.
Internal document storage. Only iterate over this using foreach, other operations are not considered officially supported.
1 import std.exception; 2 3 TextDocumentManager documents; 4 // most common usage, forward LSP events to this helper struct. 5 RequestMessageRaw incomingPacket = { 6 // dummy data 7 method: "textDocument/didOpen", 8 paramsJson: `{ 9 "textDocument": { 10 "uri": "file:///home/projects/app.d", 11 "languageId": "d", 12 "version": 123, 13 "text": "import std.stdio;\n\nvoid main()\n{\n\twriteln(\"hello world\");\n}\n" 14 } 15 }` 16 }; 17 documents.process(incomingPacket); 18 // documents.process returns false if it's not a method meant for text 19 // document management. serve-d:serverbase abstracts this away automatically. 20 21 // normally used from LSP methods where you have params like this 22 TextDocumentPositionParams params = { 23 textDocument: TextDocumentIdentifier("file:///home/projects/app.d"), 24 position: Position(4, 2) 25 }; 26 27 // if it's sent by the LSP, the document being loaded should be almost guaranteed. 28 auto doc = documents[params.textDocument.uri]; 29 // trying to index files that haven't been sent by the client will throw an Exception 30 assertThrown(documents["file:///path/to/non-registered.d"]); 31 32 // you can use tryGet to see if a Document has been opened yet and use it if so. 33 assert(documents.tryGet("file:///path/to/non-registered.d") is Document.init); 34 assert(documents.tryGet(params.textDocument.uri) !is Document.init); 35 36 // Document defines a variety of utility functions that have been optimized 37 // for speed and convenience. 38 assert(doc.lineAtScope(params.position) == "\twriteln(\"hello world\");\n"); 39 40 auto range = doc.wordRangeAt(params.position); 41 assert(doc.positionToBytes(range.start) == 34); 42 assert(doc.positionToBytes(range.end) == 41); 43 44 // when yielding (Fiber context switch) documents may be modified or deleted though: 45 46 RequestMessageRaw incomingPacket2 = { 47 // dummy data 48 method: "textDocument/didChange", 49 paramsJson: `{ 50 "textDocument": { 51 "uri": "file:///home/projects/app.d", 52 "version": 124 53 }, 54 "contentChanges": [ 55 { 56 "range": { 57 "start": { "line": 4, "character": 6 }, 58 "end": { "line": 4, "character": 8 } 59 }, 60 "text": "" 61 } 62 ] 63 }` 64 }; 65 documents.process(incomingPacket2); 66 67 assert(doc.lineAtScope(params.position) == "\twrite(\"hello world\");\n"); 68 69 RequestMessageRaw incomingPacket3 = { 70 // dummy data 71 method: "textDocument/didChange", 72 paramsJson: `{ 73 "textDocument": { 74 "uri": "file:///home/projects/app.d", 75 "version": 125 76 }, 77 "contentChanges": [ 78 { 79 "text": "replace everything" 80 } 81 ] 82 }` 83 }; 84 documents.process(incomingPacket3); 85 86 // doc.rawText is now half overwritten, you need to refetch a document when yielding or updating: 87 assert(doc.rawText != "replace everything"); 88 doc = documents[params.textDocument.uri]; 89 assert(doc.rawText == "replace everything"); 90 91 RequestMessageRaw incomingPacket4 = { 92 // dummy data 93 method: "textDocument/didClose", 94 paramsJson: `{ 95 "textDocument": { 96 "uri": "file:///home/projects/app.d" 97 } 98 }` 99 }; 100 documents.process(incomingPacket4); 101 102 assertThrown(documents[params.textDocument.uri]); 103 // so make sure that you don't keep references to documents when leaving scope or switching context.
Helper struct which should have one unique instance in the application which processes document events sent by a LSP client to an LSP server and creates an in-memory representation of all the files managed by the client.
This data structure is not thread safe.