Skip to content

Commit d40c3e7

Browse files
committed
Add MarkupContent to HoverResponse
And deprecate the old MarkedString as per the LSP spec. Closes #141 Addresses some of #134
1 parent 7f1e0d1 commit d40c3e7

11 files changed

+138
-33
lines changed

ChangeLog.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Revision history for haskell-lsp
22

3+
## 0.8.3.0
4+
5+
* Add `MarkupContent` to `HoverResponse`, and (some) json roundtrip tests.
6+
37
## 0.8.2.0 -- 2019-04-11
48

59
* Add `applyTextEdit` and `editTextEdit` helpers

example/Main.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ reactor lf inp = do
238238

239239
let
240240
ht = Just $ J.Hover ms (Just range)
241-
ms = J.List [J.CodeString $ J.LanguageString "lsp-hello" "TYPE INFO" ]
241+
ms = J.HoverContentsMS $ J.List [J.CodeString $ J.LanguageString "lsp-hello" "TYPE INFO" ]
242242
range = J.Range pos pos
243243
reactorSend $ RspHover $ Core.makeResponseMessage req ht
244244

haskell-lsp-types/ChangeLog.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Revision history for haskell-lsp-types
22

3+
## 0.8.3.0
4+
5+
* Add `MarkupContent` to `HoverResponse`, and (some) json roundtrip tests.
6+
37
## 0.8.2.0 -- 2019-04-11
48

59
* Add `applyTextEdit` and `editTextEdit` helpers

haskell-lsp-types/haskell-lsp-types.cabal

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: haskell-lsp-types
2-
version: 0.8.2.0
2+
version: 0.8.3.0
33
synopsis: Haskell library for the Microsoft Language Server Protocol, data types
44

55
description: An implementation of the types to allow language implementors to

haskell-lsp-types/src/Language/Haskell/LSP/Types/DataTypesJSON.hs

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,15 @@ import Data.Aeson.TH
1818
import Data.Aeson.Types
1919
import Data.Text (Text)
2020
import qualified Data.Text as T
21+
import Language.Haskell.LSP.Types.ClientCapabilities
2122
import Language.Haskell.LSP.Types.Command
2223
import Language.Haskell.LSP.Types.Constants
23-
import Language.Haskell.LSP.Types.ClientCapabilities
2424
import Language.Haskell.LSP.Types.Diagnostic
2525
import Language.Haskell.LSP.Types.DocumentFilter
2626
import Language.Haskell.LSP.Types.List
27-
import Language.Haskell.LSP.Types.Message
2827
import Language.Haskell.LSP.Types.Location
28+
import Language.Haskell.LSP.Types.MarkupContent
29+
import Language.Haskell.LSP.Types.Message
2930
import Language.Haskell.LSP.Types.Symbol
3031
import Language.Haskell.LSP.Types.TextDocument
3132
import Language.Haskell.LSP.Types.Uri
@@ -1749,11 +1750,10 @@ interface Hover {
17491750
}
17501751
17511752
1752-
Where MarkedString is defined as follows:
17531753
/**
17541754
* MarkedString can be used to render human readable text. It is either a markdown string
17551755
* or a code-block that provides a language and a code snippet. The language identifier
1756-
* is sematically equal to the optional language identifier in fenced code blocks in GitHub
1756+
* is semantically equal to the optional language identifier in fenced code blocks in GitHub
17571757
* issues. See https://help.github.com/articles/creating-and-highlighting-code-blocks/#syntax-highlighting
17581758
*
17591759
* The pair of a language and a value is an equivalent to markdown:
@@ -1762,7 +1762,8 @@ Where MarkedString is defined as follows:
17621762
* ```
17631763
*
17641764
* Note that markdown strings will be sanitized - that means html will be escaped.
1765-
*/
1765+
* @deprecated use MarkupContent instead.
1766+
*/
17661767
type MarkedString = string | { language: string; value: string };
17671768
17681769
error: code and message set in case an exception happens during the hover
@@ -1780,6 +1781,7 @@ data LanguageString =
17801781

17811782
deriveJSON lspOptions ''LanguageString
17821783

1784+
{-# DEPRECATED MarkedString, PlainString, CodeString "Use MarkupContent instead, since 3.3.0 (11/24/2017)" #-}
17831785
data MarkedString =
17841786
PlainString T.Text
17851787
| CodeString LanguageString
@@ -1792,9 +1794,32 @@ instance FromJSON MarkedString where
17921794
parseJSON (A.String t) = pure $ PlainString t
17931795
parseJSON o = CodeString <$> parseJSON o
17941796

1797+
-- -------------------------------------
1798+
1799+
data HoverContents =
1800+
HoverContentsMS (List MarkedString)
1801+
| HoverContents MarkupContent
1802+
deriving (Read,Show,Eq)
1803+
1804+
instance ToJSON HoverContents where
1805+
toJSON (HoverContentsMS x) = toJSON x
1806+
toJSON (HoverContents x) = toJSON x
1807+
instance FromJSON HoverContents where
1808+
parseJSON v@(A.String _) = HoverContentsMS <$> parseJSON v
1809+
parseJSON v@(A.Null) = HoverContentsMS <$> parseJSON v
1810+
parseJSON v@(A.Array _) = HoverContentsMS <$> parseJSON v
1811+
parseJSON v@(A.Object o) = do
1812+
mk <- o .:? "kind" :: Parser (Maybe MarkupKind)
1813+
case mk of
1814+
Nothing -> HoverContentsMS <$> parseJSON v
1815+
_ -> HoverContents <$> parseJSON v
1816+
parseJSON _ = fail "HoverContents"
1817+
1818+
-- -------------------------------------
1819+
17951820
data Hover =
17961821
Hover
1797-
{ _contents :: List MarkedString
1822+
{ _contents :: HoverContents
17981823
, _range :: Maybe Range
17991824
} deriving (Read,Show,Eq)
18001825

haskell-lsp-types/src/Language/Haskell/LSP/Types/MarkupContent.hs

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,15 @@ import Language.Haskell.LSP.Types.Constants
2323
* are reserved for internal usage.
2424
*/
2525
export namespace MarkupKind {
26-
/**
27-
* Plain text is supported as a content format
28-
*/
29-
export const PlainText: 'plaintext' = 'plaintext';
26+
/**
27+
* Plain text is supported as a content format
28+
*/
29+
export const PlainText: 'plaintext' = 'plaintext';
3030
31-
/**
32-
* Markdown is supported as a content format
33-
*/
34-
export const Markdown: 'markdown' = 'markdown';
31+
/**
32+
* Markdown is supported as a content format
33+
*/
34+
export const Markdown: 'markdown' = 'markdown';
3535
}
3636
export type MarkupKind = 'plaintext' | 'markdown';
3737
-}
@@ -78,15 +78,15 @@ instance FromJSON MarkupKind where
7878
* remove HTML from the markdown to avoid script execution.
7979
*/
8080
export interface MarkupContent {
81-
/**
82-
* The type of the Markup
83-
*/
84-
kind: MarkupKind;
81+
/**
82+
* The type of the Markup
83+
*/
84+
kind: MarkupKind;
8585
86-
/**
87-
* The content itself
88-
*/
89-
value: string;
86+
/**
87+
* The content itself
88+
*/
89+
value: string;
9090
}
9191
-}
9292

haskell-lsp.cabal

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: haskell-lsp
2-
version: 0.8.2.0
2+
version: 0.8.3.0
33
synopsis: Haskell library for the Microsoft Language Server Protocol
44

55
description: An implementation of the types, and basic message server to
@@ -44,7 +44,7 @@ library
4444
, filepath
4545
, hslogger
4646
, hashable
47-
, haskell-lsp-types >= 0.8
47+
, haskell-lsp-types >= 0.8.3
4848
, lens >= 4.15.2
4949
, mtl
5050
, network-uri
@@ -94,6 +94,7 @@ test-suite haskell-lsp-test
9494
main-is: Main.hs
9595
other-modules: Spec
9696
CapabilitiesSpec
97+
JsonSpec
9798
DiagnosticsSpec
9899
MethodSpec
99100
ServerCapabilitiesSpec
@@ -102,22 +103,24 @@ test-suite haskell-lsp-test
102103
WorkspaceEditSpec
103104
WorkspaceFoldersSpec
104105
build-depends: base
106+
, QuickCheck
105107
, aeson
106108
, bytestring
107109
, containers
108110
, data-default
109111
, directory
110112
, filepath
111-
, hspec
112113
, hashable
114+
, haskell-lsp
115+
, hspec
113116
-- , hspec-jenkins
114117
, lens >= 4.15.2
115118
, network-uri
119+
, quickcheck-instances
116120
, sorted-list == 0.2.1.*
117-
, yi-rope
118-
, haskell-lsp
119-
, text
120121
, stm
122+
, text
123+
, yi-rope
121124
ghc-options: -threaded -rtsopts -with-rtsopts=-N -Wall
122125
default-language: Haskell2010
123126

test/JsonSpec.hs

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
{-# LANGUAGE DataKinds #-}
2+
{-# LANGUAGE FlexibleInstances #-}
3+
{-# LANGUAGE OverloadedStrings #-}
4+
{-# LANGUAGE TypeSynonymInstances #-}
5+
{-# OPTIONS_GHC -fno-warn-orphans #-}
6+
-- | Test for JSON serialization
7+
module JsonSpec where
8+
9+
import Language.Haskell.LSP.Types
10+
11+
import Data.Aeson
12+
import Test.Hspec
13+
import Test.Hspec.QuickCheck
14+
import Test.QuickCheck hiding (Success)
15+
import Test.QuickCheck.Instances ()
16+
17+
-- import Debug.Trace
18+
-- ---------------------------------------------------------------------
19+
20+
{-# ANN module ("HLint: ignore Redundant do" :: String) #-}
21+
22+
main :: IO ()
23+
main = hspec spec
24+
25+
spec :: Spec
26+
spec = describe "dispatcher" jsonSpec
27+
28+
-- ---------------------------------------------------------------------
29+
30+
jsonSpec :: Spec
31+
jsonSpec = do
32+
describe "General JSON instances round trip" $ do
33+
-- DataTypesJSON
34+
prop "LanguageString" (propertyJsonRoundtrip :: LanguageString -> Bool)
35+
prop "MarkedString" (propertyJsonRoundtrip :: MarkedString -> Bool)
36+
prop "MarkupContent" (propertyJsonRoundtrip :: MarkupContent -> Bool)
37+
prop "HoverContents" (propertyJsonRoundtrip :: HoverContents -> Bool)
38+
39+
40+
-- ---------------------------------------------------------------------
41+
42+
propertyJsonRoundtrip :: (Eq a, ToJSON a, FromJSON a) => a -> Bool
43+
propertyJsonRoundtrip a = Success a == fromJSON (toJSON a)
44+
45+
-- ---------------------------------------------------------------------
46+
47+
instance Arbitrary LanguageString where
48+
arbitrary = LanguageString <$> arbitrary <*> arbitrary
49+
50+
instance Arbitrary MarkedString where
51+
arbitrary = oneof [PlainString <$> arbitrary, CodeString <$> arbitrary]
52+
53+
instance Arbitrary MarkupContent where
54+
arbitrary = MarkupContent <$> arbitrary <*> arbitrary
55+
56+
instance Arbitrary MarkupKind where
57+
arbitrary = oneof [pure MkPlainText,pure MkMarkdown]
58+
59+
instance Arbitrary HoverContents where
60+
arbitrary = oneof [HoverContentsMS <$> arbitrary, HoverContents <$> arbitrary]
61+
62+
-- | make lists of maximum length 3 for test performance
63+
smallList :: Gen a -> Gen [a]
64+
smallList = resize 3 . listOf
65+
66+
instance (Arbitrary a) => Arbitrary (List a) where
67+
arbitrary = List <$> arbitrary
68+
69+
-- ---------------------------------------------------------------------

test/ServerCapabilitiesSpec.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ spec = describe "server capabilities" $ do
2424
describe "encodes" $
2525
it "just id" $
2626
encode (FoldingRangeOptionsDynamicDocument Nothing (Just "foo")) `shouldBe` "{\"id\":\"foo\"}"
27-
it "decodes" $
27+
it "decodes" $
2828
let input = "{\"hoverProvider\": true, \"colorProvider\": {\"id\": \"abc123\", \"documentSelector\": " <> documentFiltersJson <> "}}"
2929
Just caps = decode input :: Maybe InitializeResponseCapabilitiesInner
3030
in caps ^. colorProvider `shouldBe` Just (ColorOptionsDynamicDocument (Just documentFilters) (Just "abc123"))

test/WorkspaceEditSpec.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,6 @@ spec = do
2020
describe "editTextEdit" $
2121
it "edits a multiline text edit" $
2222
let orig = TextEdit (Range (Position 1 1) (Position 2 2)) "hello\nworld"
23-
inner = TextEdit (Range (Position 0 3) (Position 1 3)) "ios\ngo"
23+
inner = TextEdit (Range (Position 0 3) (Position 1 3)) "ios\ngo"
2424
expected = TextEdit (Range (Position 1 1) (Position 2 2)) "helios\ngold"
2525
in editTextEdit orig inner `shouldBe` expected

test/WorkspaceFoldersSpec.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ spec = describe "workspace folders" $
3232
in handleMessage initCb tvarCtx clStr jsonStr
3333

3434
let starterWorkspaces = List [wf0]
35-
initParams = InitializeParams
35+
initParams = InitializeParams
3636
Nothing Nothing (Just (Uri "/foo")) Nothing fullCaps Nothing (Just starterWorkspaces)
3737
initMsg :: InitializeRequest
3838
initMsg = RequestMessage "2.0" (IdInt 0) Initialize initParams

0 commit comments

Comments
 (0)