-
Notifications
You must be signed in to change notification settings - Fork 93
Support text-2.0 #392
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Support text-2.0 #392
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -52,8 +52,8 @@ import Data.Ord | |
import qualified Data.HashMap.Strict as HashMap | ||
import qualified Data.Map.Strict as Map | ||
import Data.Maybe | ||
import Data.Rope.UTF16 ( Rope ) | ||
import qualified Data.Rope.UTF16 as Rope | ||
import Data.Text.Utf16.Rope ( Rope ) | ||
import qualified Data.Text.Utf16.Rope as Rope | ||
import qualified Language.LSP.Types as J | ||
import qualified Language.LSP.Types.Lens as J | ||
import System.FilePath | ||
|
@@ -136,7 +136,7 @@ applyCreateFile (J.CreateFile uri options _ann) = | |
updateVFS $ Map.insertWith | ||
(\ new old -> if shouldOverwrite then new else old) | ||
(J.toNormalizedUri uri) | ||
(VirtualFile 0 0 (Rope.fromText "")) | ||
(VirtualFile 0 0 mempty) | ||
where | ||
shouldOverwrite :: Bool | ||
shouldOverwrite = case options of | ||
|
@@ -260,7 +260,7 @@ persistFileVFS vfs uri = | |
action = do | ||
exists <- doesFileExist tfn | ||
unless exists $ do | ||
let contents = Rope.toString (_text vf) | ||
let contents = T.unpack (Rope.toText (_text vf)) | ||
writeRaw h = do | ||
-- We honour original file line endings | ||
hSetNewlineMode h noNewlineTranslation | ||
|
@@ -291,26 +291,18 @@ applyChanges = foldl' applyChange | |
applyChange :: Rope -> J.TextDocumentContentChangeEvent -> Rope | ||
applyChange _ (J.TextDocumentContentChangeEvent Nothing Nothing str) | ||
= Rope.fromText str | ||
applyChange str (J.TextDocumentContentChangeEvent (Just (J.Range (J.Position sl sc) _to)) (Just len) txt) | ||
= changeChars str start (fromIntegral len) txt | ||
where | ||
start = Rope.rowColumnCodeUnits (Rope.RowColumn (fromIntegral sl) (fromIntegral sc)) str | ||
applyChange str (J.TextDocumentContentChangeEvent (Just (J.Range (J.Position sl sc) (J.Position el ec))) Nothing txt) | ||
= changeChars str start len txt | ||
where | ||
start = Rope.rowColumnCodeUnits (Rope.RowColumn (fromIntegral sl) (fromIntegral sc)) str | ||
end = Rope.rowColumnCodeUnits (Rope.RowColumn (fromIntegral el) (fromIntegral ec)) str | ||
len = end - start | ||
applyChange str (J.TextDocumentContentChangeEvent (Just (J.Range (J.Position sl sc) (J.Position fl fc))) _ txt) | ||
= changeChars str (Rope.Position (fromIntegral sl) (fromIntegral sc)) (Rope.Position (fromIntegral fl) (fromIntegral fc)) txt | ||
applyChange str (J.TextDocumentContentChangeEvent Nothing (Just _) _txt) | ||
= str | ||
|
||
-- --------------------------------------------------------------------- | ||
|
||
changeChars :: Rope -> Int -> Int -> Text -> Rope | ||
changeChars str start len new = mconcat [before, Rope.fromText new, after'] | ||
changeChars :: Rope -> Rope.Position -> Rope.Position -> Text -> Rope | ||
changeChars str start finish new = mconcat [before', Rope.fromText new, after] | ||
where | ||
(before, after) = Rope.splitAt start str | ||
after' = Rope.drop len after | ||
(before, after) = fromJust $ Rope.splitAtPosition finish str | ||
(before', _) = fromJust $ Rope.splitAtPosition start before | ||
|
||
-- --------------------------------------------------------------------- | ||
|
||
|
@@ -336,14 +328,11 @@ data PosPrefixInfo = PosPrefixInfo | |
getCompletionPrefix :: (Monad m) => J.Position -> VirtualFile -> m (Maybe PosPrefixInfo) | ||
getCompletionPrefix pos@(J.Position l c) (VirtualFile _ _ ropetext) = | ||
return $ Just $ fromMaybe (PosPrefixInfo "" "" "" pos) $ do -- Maybe monad | ||
let headMaybe [] = Nothing | ||
headMaybe (x:_) = Just x | ||
lastMaybe [] = Nothing | ||
let lastMaybe [] = Nothing | ||
lastMaybe xs = Just $ last xs | ||
|
||
curLine <- headMaybe $ T.lines $ Rope.toText | ||
$ fst $ Rope.splitAtLine 1 $ snd $ Rope.splitAtLine (fromIntegral l) ropetext | ||
let beforePos = T.take (fromIntegral c) curLine | ||
let curRope = fst $ Rope.splitAtLine 1 $ snd $ Rope.splitAtLine (fromIntegral l) ropetext | ||
beforePos <- Rope.toText . fst <$> Rope.splitAt (fromIntegral c) curRope | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. BTW this fixes an existing bug: |
||
curWord <- | ||
if | T.null beforePos -> Just "" | ||
| T.last beforePos == ' ' -> Just "" -- don't count abc as the curword in 'abc ' | ||
|
@@ -357,6 +346,8 @@ getCompletionPrefix pos@(J.Position l c) (VirtualFile _ _ ropetext) = | |
let modParts = dropWhile (not . isUpper . T.head) | ||
$ reverse $ filter (not .T.null) xs | ||
modName = T.intercalate "." modParts | ||
-- curRope is already a single line, but it may include an enclosing '\n' | ||
let curLine = T.dropWhileEnd (== '\n') $ Rope.toText curRope | ||
return $ PosPrefixInfo curLine modName x pos | ||
|
||
-- --------------------------------------------------------------------- | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the best way to handle malformed input here? Since LSP counts by UTF-16 code units (not code points), it is possible that split happens in the middle of a code point, in which case
text-lines
returnsNothing
.(
rope-utf16-splay
in such situation silently extends split region until the end of a code point)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@alanz ? do you remember what's up here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nope. To be honest I have never really paid attention to issues of splits in the middle of code points, assuming the client will send meaningful input, since they are managing a cursor over the text and sending its positions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could throw. Maybe blowing up with an informative error message is the most sensible thing to do here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would be happy with either:
Nothing
, and propagating that up to the exported functions. InchangeFromClientVFS
we can drop the change and log, as is done in the existingNothing
branch.Thoughts @alanz ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alternatively, we can merge this with the
fromJust
and experiment with removing it with @Bodigrim out of the loop :)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking more at the code, I think we could push these failures right the way up to the LSP message response, which is probably the right thing to do, but I think we should do it separately. So my vote goes for "leave
fromJust
for now and remove subsequently", which I volunteer to look into.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is unlikely to happen in practice, so leaving as is would likely be safe, as is pushing it up to an LSP response. For the latter it at least makes us aware it is happening, and hopefully that will show up in initial developer dogfooding, or not at all.