Skip to content
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

Upgrade to new version of lsp libraries #2494

Merged
merged 7 commits into from
Dec 29, 2021
Merged
Show file tree
Hide file tree
Changes from 4 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
2 changes: 1 addition & 1 deletion cabal-ghc901.project
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ package *

write-ghc-environment-files: never

index-state: 2021-11-29T12:30:10Z
index-state: 2021-12-29T12:30:08Z

constraints:
-- These plugins don't work on GHC9 yet
Expand Down
2 changes: 1 addition & 1 deletion cabal-ghc921.project
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ package *

write-ghc-environment-files: never

index-state: 2021-11-29T12:30:10Z
index-state: 2021-12-29T12:30:08Z

constraints:
-- These plugins doesn't work on GHC92 yet
Expand Down
2 changes: 1 addition & 1 deletion cabal.project
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ package *

write-ghc-environment-files: never

index-state: 2021-11-29T12:30:10Z
index-state: 2021-12-29T12:30:08Z

constraints:
hyphenation +embed
Expand Down
1 change: 0 additions & 1 deletion ghcide/bench/example/HLS

This file was deleted.

16 changes: 6 additions & 10 deletions ghcide/bench/lib/Experiments.hs
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ experiments =
let edit :: TextDocumentContentChangeEvent =TextDocumentContentChangeEvent
{ _range = Just Range {_start = bottom, _end = bottom}
, _rangeLength = Nothing, _text = t}
bottom = Position maxBoundUinteger 0
bottom = Position maxBound 0
t = T.unlines
[""
,"holef :: [Int] -> [Int]"
Expand All @@ -213,7 +213,7 @@ experiments =
flip allM docs $ \DocumentPositions{..} -> do
bottom <- pred . length . T.lines <$> documentContents doc
diags <- getCurrentDiagnostics doc
case requireDiagnostic diags (DsError, (bottom, 8), "Found hole", Nothing) of
case requireDiagnostic diags (DsError, (fromIntegral bottom, 8), "Found hole", Nothing) of
Nothing -> pure True
Just _err -> pure False
)
Expand Down Expand Up @@ -404,7 +404,7 @@ runBenchmarksFun dir allBenchmarks = do
++ ["--verbose" | verbose ?config]
++ ["--ot-memory-profiling" | Just _ <- [otMemoryProfiling ?config]]
lspTestCaps =
fullCaps {_window = Just $ WindowClientCapabilities $ Just True}
fullCaps {_window = Just $ WindowClientCapabilities (Just True) Nothing Nothing }
conf =
defaultConfig
{ logStdErr = verbose ?config,
Expand Down Expand Up @@ -585,7 +585,7 @@ setupDocumentContents config =
doc <- openDoc m "haskell"

-- Setup the special positions used by the experiments
lastLine <- length . T.lines <$> documentContents doc
lastLine <- fromIntegral . length . T.lines <$> documentContents doc
changeDoc doc [TextDocumentContentChangeEvent
{ _range = Just (Range (Position lastLine 0) (Position lastLine 0))
, _rangeLength = Nothing
Expand Down Expand Up @@ -638,9 +638,9 @@ searchSymbol doc@TextDocumentIdentifier{_uri} fileContents pos = do
return res
where
loop pos
| _line pos >= lll =
| (fromIntegral $ _line pos) >= lll =
return Nothing
| _character pos >= lengthOfLine (_line pos) =
| (fromIntegral $ _character pos) >= lengthOfLine (fromIntegral $ _line pos) =
loop (nextLine pos)
| otherwise = do
checks <- checkDefinitions pos &&^ checkCompletions pos
Expand All @@ -663,7 +663,3 @@ searchSymbol doc@TextDocumentIdentifier{_uri} fileContents pos = do
checkCompletions pos =
not . null <$> getCompletions doc pos

-- | We don't have a uinteger type yet. So hardcode the maxBound of uinteger, 2 ^ 31 - 1
-- as a constant.
maxBoundUinteger :: Int
maxBoundUinteger = 2147483647
4 changes: 2 additions & 2 deletions ghcide/ghcide.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ library
lens,
list-t,
hiedb == 0.4.1.*,
lsp-types >= 1.3.0.1 && < 1.4,
lsp == 1.2.*,
lsp-types ^>= 1.4.0.0,
lsp ^>= 1.4.0.0 ,
monoid-subclasses,
mtl,
network-uri,
Expand Down
7 changes: 6 additions & 1 deletion ghcide/src/Development/IDE/Core/Compile.hs
Original file line number Diff line number Diff line change
Expand Up @@ -564,6 +564,11 @@ indexHieFile se mod_summary srcPath !hash hf = do
done <- readTVar indexCompleted
remaining <- HashMap.size <$> readTVar indexPending
pure (done, remaining)
let
progressFrac :: Double
progressFrac = fromIntegral done / fromIntegral (done + remaining)
progressPct :: LSP.UInt
progressPct = floor $ 100 * progressFrac

whenJust (lspEnv se) $ \env -> whenJust tok $ \tok -> LSP.runLspT env $
LSP.sendNotification LSP.SProgress $ LSP.ProgressParams tok $
Expand All @@ -572,7 +577,7 @@ indexHieFile se mod_summary srcPath !hash hf = do
Percentage -> LSP.WorkDoneProgressReportParams
{ _cancellable = Nothing
, _message = Nothing
, _percentage = Just (100 * fromIntegral done / fromIntegral (done + remaining) )
, _percentage = Just progressPct
}
Explicit -> LSP.WorkDoneProgressReportParams
{ _cancellable = Nothing
Expand Down
35 changes: 26 additions & 9 deletions ghcide/src/Development/IDE/Core/OfInterest.hs
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,26 @@ module Development.IDE.Core.OfInterest(
import Control.Concurrent.Strict
import Control.Monad
import Control.Monad.IO.Class
import Data.HashMap.Strict (HashMap)
import qualified Data.HashMap.Strict as HashMap
import qualified Data.Text as T
import Data.HashMap.Strict (HashMap)
import qualified Data.HashMap.Strict as HashMap
import qualified Data.Text as T
import Development.IDE.Graph

import Control.Concurrent.STM.Stats (atomically,
modifyTVar')
import qualified Data.ByteString as BS
import Data.Maybe (catMaybes)
import Control.Concurrent.STM.Stats (atomically,
modifyTVar')
import Data.Aeson (toJSON)
import qualified Data.ByteString as BS
import Data.Maybe (catMaybes)
import Development.IDE.Core.ProgressReporting
import Development.IDE.Core.RuleTypes
import Development.IDE.Core.Shake
import Development.IDE.Plugin.Completions.Types
import Development.IDE.Types.Exports
import Development.IDE.Types.Location
import Development.IDE.Types.Logger
import Development.IDE.Types.Options (IdeTesting (..))
import qualified Language.LSP.Server as LSP
import qualified Language.LSP.Types as LSP

newtype OfInterestVar = OfInterestVar (Var (HashMap NormalizedFilePath FileOfInterestStatus))
instance IsIdeGlobal OfInterestVar
Expand Down Expand Up @@ -109,11 +114,21 @@ scheduleGarbageCollection state = do
kick :: Action ()
kick = do
files <- HashMap.keys <$> getFilesOfInterestUntracked
ShakeExtras{exportsMap, progress} <- getShakeExtras
ShakeExtras{exportsMap, ideTesting = IdeTesting testing, lspEnv, progress} <- getShakeExtras
let signal msg = when testing $ liftIO $
mRunLspT lspEnv $
LSP.sendNotification (LSP.SCustomMethod msg) $
toJSON $ map fromNormalizedFilePath files

signal "kick/start"
liftIO $ progressUpdate progress KickStarted

-- Update the exports map
results <- uses GenerateCore files <* uses GetHieAst files
results <- uses GenerateCore files
<* uses GetHieAst files
-- needed to have non local completions on the first edit
-- when the first edit breaks the module header
<* uses NonLocalCompletions files
let mguts = catMaybes results
void $ liftIO $ atomically $ modifyTVar' exportsMap (updateExportsMapMg mguts)

Expand All @@ -124,3 +139,5 @@ kick = do
when garbageCollectionScheduled $ do
void garbageCollectDirtyKeys
liftIO $ writeVar var False

signal "kick/done"
49 changes: 28 additions & 21 deletions ghcide/src/Development/IDE/Core/PositionMapping.hs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ import Data.List
import qualified Data.Text as T
import qualified Data.Vector.Unboxed as V
import Language.LSP.Types (Position (Position), Range (Range),
TextDocumentContentChangeEvent (TextDocumentContentChangeEvent))
TextDocumentContentChangeEvent (TextDocumentContentChangeEvent),
UInt)

-- | Either an exact position, or the range of text that was substituted
data PositionResult a
Expand Down Expand Up @@ -140,14 +141,17 @@ toCurrent (Range start@(Position startLine startColumn) end@(Position endLine en
where
lineDiff = linesNew - linesOld
linesNew = T.count "\n" t
linesOld = endLine - startLine
linesOld = fromIntegral endLine - fromIntegral startLine
newEndColumn :: UInt
newEndColumn
| linesNew == 0 = startColumn + T.length t
| otherwise = T.length $ T.takeWhileEnd (/= '\n') t
| linesNew == 0 = fromIntegral $ fromIntegral startColumn + T.length t
| otherwise = fromIntegral $ T.length $ T.takeWhileEnd (/= '\n') t
newColumn :: UInt
newColumn
| line == endLine = column + newEndColumn - endColumn
| line == endLine = fromIntegral $ (fromIntegral column + newEndColumn) - fromIntegral endColumn
| otherwise = column
newLine = line + lineDiff
newLine :: UInt
newLine = fromIntegral $ fromIntegral line + lineDiff

fromCurrent :: Range -> T.Text -> Position -> PositionResult Position
fromCurrent (Range start@(Position startLine startColumn) end@(Position endLine endColumn)) t (Position line column)
Expand All @@ -163,19 +167,23 @@ fromCurrent (Range start@(Position startLine startColumn) end@(Position endLine
where
lineDiff = linesNew - linesOld
linesNew = T.count "\n" t
linesOld = endLine - startLine
newEndLine = endLine + lineDiff
linesOld = fromIntegral endLine - fromIntegral startLine
newEndLine :: UInt
newEndLine = fromIntegral $ fromIntegral endLine + lineDiff
newEndColumn :: UInt
newEndColumn
| linesNew == 0 = startColumn + T.length t
| otherwise = T.length $ T.takeWhileEnd (/= '\n') t
| linesNew == 0 = fromIntegral $ fromIntegral startColumn + T.length t
| otherwise = fromIntegral $ T.length $ T.takeWhileEnd (/= '\n') t
newColumn :: UInt
newColumn
| line == newEndLine = column - (newEndColumn - endColumn)
| line == newEndLine = fromIntegral $ (fromIntegral column + fromIntegral endColumn) - newEndColumn
| otherwise = column
newLine = line - lineDiff
newLine :: UInt
newLine = fromIntegral $ fromIntegral line - lineDiff

deltaFromDiff :: T.Text -> T.Text -> PositionDelta
deltaFromDiff (T.lines -> old) (T.lines -> new) =
PositionDelta (lookupPos lnew o2nPrevs o2nNexts old2new) (lookupPos lold n2oPrevs n2oNexts new2old)
PositionDelta (lookupPos (fromIntegral lnew) o2nPrevs o2nNexts old2new) (lookupPos (fromIntegral lold) n2oPrevs n2oNexts new2old)
where
!lnew = length new
!lold = length old
Expand All @@ -194,17 +202,16 @@ deltaFromDiff (T.lines -> old) (T.lines -> new) =
f :: Int -> Int -> Int
f !a !b = if b == -1 then a else b

lookupPos :: Int -> V.Vector Int -> V.Vector Int -> V.Vector Int -> Position -> PositionResult Position
lookupPos :: UInt -> V.Vector Int -> V.Vector Int -> V.Vector Int -> Position -> PositionResult Position
lookupPos end prevs nexts xs (Position line col)
| line < 0 = PositionRange (Position 0 0) (Position 0 0)
| line >= V.length xs = PositionRange (Position end 0) (Position end 0)
| otherwise = case V.unsafeIndex xs line of
| line >= fromIntegral (V.length xs) = PositionRange (Position end 0) (Position end 0)
| otherwise = case V.unsafeIndex xs (fromIntegral line) of
-1 ->
-- look for the previous and next lines that mapped successfully
let !prev = 1 + V.unsafeIndex prevs line
!next = V.unsafeIndex nexts line
in PositionRange (Position prev 0) (Position next 0)
line' -> PositionExact (Position line' col)
let !prev = 1 + V.unsafeIndex prevs (fromIntegral line)
!next = V.unsafeIndex nexts (fromIntegral line)
in PositionRange (Position (fromIntegral prev) 0) (Position (fromIntegral next) 0)
line' -> PositionExact (Position (fromIntegral line') col)

-- Construct a mapping between lines in the diff
-- -1 for unsucessful mapping
Expand Down
14 changes: 9 additions & 5 deletions ghcide/src/Development/IDE/Core/ProgressReporting.hs
Original file line number Diff line number Diff line change
Expand Up @@ -152,13 +152,17 @@ delayedProgressReporting before after lspEnv optProgressStyle = do
}
loop _ _ | optProgressStyle == NoProgress =
forever $ liftIO $ threadDelay maxBound
loop id prev = do
loop id prevPct = do
done <- liftIO $ readTVarIO doneVar
todo <- liftIO $ readTVarIO todoVar
liftIO $ sleep after
if todo == 0 then loop id 0 else do
let next = 100 * fromIntegral done / fromIntegral todo
when (next /= prev) $
let
nextFrac :: Double
nextFrac = fromIntegral done / fromIntegral todo
nextPct :: UInt
nextPct = floor $ 100 * nextFrac
when (nextPct /= prevPct) $
LSP.sendNotification LSP.SProgress $
LSP.ProgressParams
{ _token = id
Expand All @@ -171,11 +175,11 @@ delayedProgressReporting before after lspEnv optProgressStyle = do
Percentage -> LSP.WorkDoneProgressReportParams
{ _cancellable = Nothing
, _message = Nothing
, _percentage = Just next
, _percentage = Just nextPct
}
NoProgress -> error "unreachable"
}
loop id next
loop id nextPct

updateStateForFile inProgress file = actionBracket (f succ) (const $ f pred) . const
-- This functions are deliberately eta-expanded to avoid space leaks.
Expand Down
7 changes: 4 additions & 3 deletions ghcide/src/Development/IDE/Core/RuleTypes.hs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ import Development.IDE.Spans.Common
import Development.IDE.Spans.LocalBindings
import Development.IDE.Types.Diagnostics
import GHC.Serialized (Serialized)
import Language.LSP.Types (NormalizedFilePath)
import Language.LSP.Types (Int32,
NormalizedFilePath)

data LinkableType = ObjectLinkable | BCOLinkable
deriving (Eq,Ord,Show, Generic)
Expand Down Expand Up @@ -290,13 +291,13 @@ pattern GetModificationTime = GetModificationTime_ {missingFileDiagnostics=True}
type instance RuleResult GetModificationTime = FileVersion

data FileVersion
= VFSVersion !Int
= VFSVersion !Int32
| ModificationTime !POSIXTime
deriving (Show, Generic)

instance NFData FileVersion

vfsVersion :: FileVersion -> Maybe Int
vfsVersion :: FileVersion -> Maybe Int32
vfsVersion (VFSVersion i) = Just i
vfsVersion ModificationTime{} = Nothing

Expand Down
2 changes: 1 addition & 1 deletion ghcide/src/Development/IDE/Core/Shake.hs
Original file line number Diff line number Diff line change
Expand Up @@ -1176,7 +1176,7 @@ updateFileDiagnostics fp k ShakeExtras{logger, diagnostics, hiddenDiagnostics, p
logInfo logger $ showDiagnosticsColored $ map (fp,ShowDiag,) newDiags
Just env -> LSP.runLspT env $
LSP.sendNotification LSP.STextDocumentPublishDiagnostics $
LSP.PublishDiagnosticsParams (fromNormalizedUri uri) ver (List newDiags)
LSP.PublishDiagnosticsParams (fromNormalizedUri uri) (fmap fromIntegral ver) (List newDiags)
return action

newtype Priority = Priority Double
Expand Down
4 changes: 2 additions & 2 deletions ghcide/src/Development/IDE/GHC/Error.hs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ realSrcSpanToRange real =

realSrcLocToPosition :: RealSrcLoc -> Position
realSrcLocToPosition real =
Position (srcLocLine real - 1) (srcLocCol real - 1)
Position (fromIntegral $ srcLocLine real - 1) (fromIntegral $ srcLocCol real - 1)
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will currently wrap. Should we do something else here? Like take max 0 first?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah not sure if we have another sensible alternative?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really. I think either let it wrap or max with 0.


-- | Extract a file name from a GHC SrcSpan (use message for unhelpful ones)
-- FIXME This may not be an _absolute_ file name, needs fixing.
Expand Down Expand Up @@ -111,7 +111,7 @@ rangeToRealSrcSpan nfp =

positionToRealSrcLoc :: NormalizedFilePath -> Position -> RealSrcLoc
positionToRealSrcLoc nfp (Position l c)=
Compat.mkRealSrcLoc (fromString $ fromNormalizedFilePath nfp) (l + 1) (c + 1)
Compat.mkRealSrcLoc (fromString $ fromNormalizedFilePath nfp) (fromIntegral $ l + 1) (fromIntegral $ c + 1)

isInsideSrcSpan :: Position -> SrcSpan -> Bool
p `isInsideSrcSpan` r = case srcSpanToRange r of
Expand Down
8 changes: 1 addition & 7 deletions ghcide/src/Development/IDE/LSP/Outline.hs
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,7 @@ moduleOutline ideState DocumentSymbolParams{ _textDocument = TextDocumentIdentif
(defDocumentSymbol l :: DocumentSymbol)
{ _name = pprText m
, _kind = SkFile
, _range = Range (Position 0 0) (Position 2147483647 0) -- _ltop is 0 0 0 0
-- In the lsp spec from 3.16 Position takes a uinteger,
-- where uinteger is 0 - 2^31 - 1. lsp-types currently has the type of line
-- as Int. So instead of using `maxBound :: Int` we hardcode the maxBound of
-- uinteger. 2 ^ 31 - 1 == 2147483647
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Uh oh. I think this means I got it wrong: uinteger according to the LSP specification is not, in fact a 32-bit unsigned integer, but a 31-bit unsigned integer. Presumably because it's actually a 32-bit signed integer that they just restrict to be positive. Terrible. I don't even know what to do about that.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made them an issue: microsoft/language-server-protocol#1394

But in the short term this kind of sucks...

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess I can go back and use a custom type instead of Word32 in lsp, sigh.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ouch, but we can go ahead with this lsp version? or you want to redefine the type in lso before the release
I guess we can continue using the hardcoded maxBound?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice not to release a version of lsp that disruptively requires people to change their code and then doesn't even fix the problem :(

I think the best thing might be to change to a custom type in lsp indeed. It shouldn't affect this PR too much. Either that or we should just revert the change in lsp.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm but if we use UInt31 in LSP with all the required intances, including from integral, would no be matter of replacing Word32 with UInt31 here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that's basically it. I just need to do it. I'll try and find time tomorrow.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe with a more generic name like LSPUInt? not sure if the data type could even change in the spec but I can imagine it could be bigger

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-- Check this issue for tracking https://github.com/haskell/lsp/issues/354
-- the change in lsp-types.
, _range = Range (Position 0 0) (Position maxBound 0) -- _ltop is 0 0 0 0
}
_ -> Nothing
importSymbols = maybe [] pure $
Expand Down
Loading