@@ -129,41 +129,104 @@ updateVFS f vfs@VFS{vfsMap} = vfs { vfsMap = f vfsMap }
129
129
130
130
-- ---------------------------------------------------------------------
131
131
132
+ applyCreateFile :: J. CreateFile -> VFS -> VFS
133
+ applyCreateFile (J. CreateFile uri options) =
134
+ updateVFS $ Map. insertWith
135
+ (\ new old -> if shouldOverwrite then new else old)
136
+ (J. toNormalizedUri uri)
137
+ (VirtualFile 0 0 (Rope. fromText " " ))
138
+ where
139
+ shouldOverwrite :: Bool
140
+ shouldOverwrite = case options of
141
+ Nothing -> False -- default
142
+ Just (J. CreateFileOptions Nothing Nothing ) -> False -- default
143
+ Just (J. CreateFileOptions Nothing (Just True ) ) -> False -- `ignoreIfExists` is True
144
+ Just (J. CreateFileOptions Nothing (Just False )) -> True -- `ignoreIfExists` is False
145
+ Just (J. CreateFileOptions (Just True ) Nothing ) -> True -- `overwrite` is True
146
+ Just (J. CreateFileOptions (Just True ) (Just True ) ) -> True -- `overwrite` wins over `ignoreIfExists`
147
+ Just (J. CreateFileOptions (Just True ) (Just False )) -> True -- `overwrite` is True
148
+ Just (J. CreateFileOptions (Just False ) Nothing ) -> False -- `overwrite` is False
149
+ Just (J. CreateFileOptions (Just False ) (Just True ) ) -> False -- `overwrite` is False
150
+ Just (J. CreateFileOptions (Just False ) (Just False )) -> False -- `overwrite` wins over `ignoreIfExists`
151
+
152
+ applyRenameFile :: J. RenameFile -> VFS -> VFS
153
+ applyRenameFile (J. RenameFile oldUri' newUri' options) vfs =
154
+ let oldUri = J. toNormalizedUri oldUri'
155
+ newUri = J. toNormalizedUri newUri'
156
+ in case Map. lookup oldUri (vfsMap vfs) of
157
+ -- nothing to rename
158
+ Nothing -> vfs
159
+ Just file -> case Map. lookup newUri (vfsMap vfs) of
160
+ -- the target does not exist, just move over
161
+ Nothing -> updateVFS (Map. insert newUri file . Map. delete oldUri) vfs
162
+ Just _ -> if shouldOverwrite
163
+ then updateVFS (Map. insert newUri file . Map. delete oldUri) vfs
164
+ else vfs
165
+ where
166
+ shouldOverwrite :: Bool
167
+ shouldOverwrite = case options of
168
+ Nothing -> False -- default
169
+ Just (J. RenameFileOptions Nothing Nothing ) -> False -- default
170
+ Just (J. RenameFileOptions Nothing (Just True ) ) -> False -- `ignoreIfExists` is True
171
+ Just (J. RenameFileOptions Nothing (Just False )) -> True -- `ignoreIfExists` is False
172
+ Just (J. RenameFileOptions (Just True ) Nothing ) -> True -- `overwrite` is True
173
+ Just (J. RenameFileOptions (Just True ) (Just True ) ) -> True -- `overwrite` wins over `ignoreIfExists`
174
+ Just (J. RenameFileOptions (Just True ) (Just False )) -> True -- `overwrite` is True
175
+ Just (J. RenameFileOptions (Just False ) Nothing ) -> False -- `overwrite` is False
176
+ Just (J. RenameFileOptions (Just False ) (Just True ) ) -> False -- `overwrite` is False
177
+ Just (J. RenameFileOptions (Just False ) (Just False )) -> False -- `overwrite` wins over `ignoreIfExists`
178
+
179
+ -- NOTE: we are ignoring the `recursive` option here because we don't know which file is a directory
180
+ applyDeleteFile :: J. DeleteFile -> VFS -> VFS
181
+ applyDeleteFile (J. DeleteFile uri _options) =
182
+ updateVFS $ Map. delete (J. toNormalizedUri uri)
183
+
184
+
185
+ applyTextDocumentEdit :: J. TextDocumentEdit -> VFS -> IO VFS
186
+ applyTextDocumentEdit (J. TextDocumentEdit vid (J. List edits)) vfs = do
187
+ -- all edits are supposed to be applied at once
188
+ -- so apply from bottom up so they don't affect others
189
+ let sortedEdits = sortOn (Down . (^. J. range)) edits
190
+ changeEvents = map editToChangeEvent sortedEdits
191
+ ps = J. DidChangeTextDocumentParams vid (J. List changeEvents)
192
+ notif = J. NotificationMessage " " J. STextDocumentDidChange ps
193
+ let (vfs',ls) = changeFromClientVFS vfs notif
194
+ mapM_ (debugM " haskell-lsp.applyTextDocumentEdit" ) ls
195
+ return vfs'
196
+
197
+ where
198
+ editToChangeEvent (J. TextEdit range text) = J. TextDocumentContentChangeEvent (Just range) Nothing text
199
+
200
+ applyDocumentChange :: J. DocumentChange -> VFS -> IO VFS
201
+ applyDocumentChange (J. InL change) = applyTextDocumentEdit change
202
+ applyDocumentChange (J. InR (J. InL change)) = return . applyCreateFile change
203
+ applyDocumentChange (J. InR (J. InR (J. InL change))) = return . applyRenameFile change
204
+ applyDocumentChange (J. InR (J. InR (J. InR change))) = return . applyDeleteFile change
205
+
132
206
-- ^ Applies the changes from a 'ApplyWorkspaceEditRequest' to the 'VFS'
133
207
changeFromServerVFS :: VFS -> J. Message 'J.WorkspaceApplyEdit -> IO VFS
134
208
changeFromServerVFS initVfs (J. RequestMessage _ _ _ params) = do
135
209
let J. ApplyWorkspaceEditParams _label edit = params
136
210
J. WorkspaceEdit mChanges mDocChanges = edit
137
211
case mDocChanges of
138
- Just (J. List textDocEdits ) -> applyEdits textDocEdits
212
+ Just (J. List docChanges ) -> applyDocumentChanges docChanges
139
213
Nothing -> case mChanges of
140
- Just cs -> applyEdits $ HashMap. foldlWithKey' changeToTextDocumentEdit [] cs
214
+ Just cs -> applyDocumentChanges $ map J. InL $ HashMap. foldlWithKey' changeToTextDocumentEdit [] cs
141
215
Nothing -> do
142
216
debugM " haskell-lsp.changeVfs" " No changes"
143
217
return initVfs
144
218
145
219
where
146
-
147
220
changeToTextDocumentEdit acc uri edits =
148
221
acc ++ [J. TextDocumentEdit (J. VersionedTextDocumentIdentifier uri (Just 0 )) edits]
149
222
150
- -- applyEdits :: [J.TextDocumentEdit] -> VFS
151
- applyEdits :: [J. TextDocumentEdit ] -> IO VFS
152
- applyEdits = foldM f initVfs . sortOn (^. J. textDocument . J. version)
153
-
154
- f :: VFS -> J. TextDocumentEdit -> IO VFS
155
- f vfs (J. TextDocumentEdit vid (J. List edits)) = do
156
- -- all edits are supposed to be applied at once
157
- -- so apply from bottom up so they don't affect others
158
- let sortedEdits = sortOn (Down . (^. J. range)) edits
159
- changeEvents = map editToChangeEvent sortedEdits
160
- ps = J. DidChangeTextDocumentParams vid (J. List changeEvents)
161
- notif = J. NotificationMessage " " J. STextDocumentDidChange ps
162
- let (vfs',ls) = changeFromClientVFS vfs notif
163
- mapM_ (debugM " haskell-lsp.changeFromServerVFS" ) ls
164
- return vfs'
165
-
166
- editToChangeEvent (J. TextEdit range text) = J. TextDocumentContentChangeEvent (Just range) Nothing text
223
+ applyDocumentChanges :: [J. DocumentChange ] -> IO VFS
224
+ applyDocumentChanges = foldM (flip applyDocumentChange) initVfs . sortOn project
225
+
226
+ -- for sorting [DocumentChange]
227
+ project :: J. DocumentChange -> J. TextDocumentVersion -- type TextDocumentVersion = Maybe Int
228
+ project (J. InL textDocumentEdit) = textDocumentEdit ^. J. textDocument . J. version
229
+ project _ = Nothing
167
230
168
231
-- ---------------------------------------------------------------------
169
232
virtualFileName :: FilePath -> J. NormalizedUri -> VirtualFile -> FilePath
0 commit comments