Skip to content

Commit 310e6a4

Browse files
Kobayashipepeiborra
Kobayashi
andauthored
support selection range lsp feature (#2565)
* add selection range support * add the whole import area as a selection step * add selection range plugin to all project files * merge type signature with value definition * support ghc 9 * fix it for ghc-9.0 * remove unnecessary import * reformat GhcIde.hs * selection range: make it easier to understand * selection range: improve error handling * update lsp-types to 1.4.0.1 * add selection range to doc * fix comment for findSelectionRangesByPositions * remove a use of partial function * update author & maintainer * use foldlM1 instead of foldl1 * add testdata to cabal file * update performace tips and log level * update lsp-types in nix Co-authored-by: Pepe Iborra <[email protected]>
1 parent 6123268 commit 310e6a4

35 files changed

+838
-88
lines changed

.github/workflows/hackage.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ jobs:
3232
"hls-refine-imports-plugin", "hls-retrie-plugin",
3333
"hls-splice-plugin", "hls-tactics-plugin",
3434
"hls-call-hierarchy-plugin", "hls-alternate-number-format-plugin",
35-
"hls-qualify-imported-names-plugin",
35+
"hls-qualify-imported-names-plugin", "hls-selection-range-plugin",
3636
"haskell-language-server"]
3737
ghc: [ "9.0.2"
3838
, "8.10.7"

.github/workflows/test.yml

+4
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,10 @@ jobs:
234234
name: Test hls-qualify-imported-names-plugin test suite
235235
run: cabal test hls-qualify-imported-names-plugin --test-options="$TEST_OPTS" || cabal test hls-qualify-imported-names-plugin --test-options="$TEST_OPTS" || LSP_TEST_LOG_COLOR=0 LSP_TEST_LOG_MESSAGES=true LSP_TEST_LOG_STDERR=true cabal test hls-qualify-imported-names-plugin --test-options="$TEST_OPTS"
236236

237+
- if: matrix.test
238+
name: Test hls-selection-range-plugin test suite
239+
run: cabal test hls-selection-range-plugin --test-options="$TEST_OPTS" || cabal test hls-selection-range-plugin --test-options="$TEST_OPTS" || LSP_TEST_LOG_COLOR=0 LSP_TEST_LOG_MESSAGES=true LSP_TEST_LOG_STDERR=true cabal test hls-selection-range-plugin --test-options="$TEST_OPTS"
240+
237241
test_post_job:
238242
if: always()
239243
runs-on: ubuntu-latest

cabal-ghc90.project

+2-1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ packages:
2626
./plugins/hls-ormolu-plugin
2727
./plugins/hls-call-hierarchy-plugin
2828
./plugins/hls-alternate-number-format-plugin
29+
./plugins/hls-selection-range-plugin
2930

3031
tests: true
3132

@@ -35,7 +36,7 @@ package *
3536

3637
write-ghc-environment-files: never
3738

38-
index-state: 2022-01-11T22:05:45Z
39+
index-state: 2022-01-21T11:23:29Z
3940

4041
constraints:
4142
-- These plugins don't work on GHC9 yet

cabal-ghc921.project

+2-1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ packages:
2626
./plugins/hls-ormolu-plugin
2727
./plugins/hls-call-hierarchy-plugin
2828
./plugins/hls-alternate-number-format-plugin
29+
./plugins/hls-selection-range-plugin
2930

3031
with-compiler: ghc-9.2.1
3132

@@ -37,7 +38,7 @@ package *
3738

3839
write-ghc-environment-files: never
3940

40-
index-state: 2022-01-11T22:05:45Z
41+
index-state: 2022-01-21T11:23:29Z
4142

4243
constraints:
4344
-- These plugins don't build/work on GHC92 yet

cabal.project

+2-1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ packages:
2626
./plugins/hls-call-hierarchy-plugin
2727
./plugins/hls-alternate-number-format-plugin
2828
./plugins/hls-qualify-imported-names-plugin
29+
./plugins/hls-selection-range-plugin
2930

3031
-- Standard location for temporary packages needed for particular environments
3132
-- For example it is used in the project gitlab mirror to help in the MAcOS M1 build script
@@ -40,7 +41,7 @@ package *
4041

4142
write-ghc-environment-files: never
4243

43-
index-state: 2022-01-11T22:05:45Z
44+
index-state: 2022-01-21T11:23:29Z
4445

4546
constraints:
4647
hyphenation +embed

docs/features.md

+9-2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ Many of these are standard LSP features, but a lot of special features are provi
1818
| [Highlight references](#highlight-references) | `textDocument/documentHighlight` |
1919
| [Code actions](#code-actions) | `textDocument/codeAction` |
2020
| [Code lenses](#code-lenses) | `textDocument/codeLens` |
21+
| [Selection range](#selection-range) | `textDocument/selectionRange` |
2122

2223
The individual sections below also identify which [HLS plugin](./what-is-hls.md#hls-plugins) is responsible for providing the given functionality, which is useful if you want to raise an issue report or contribute!
2324
Additionally, not all plugins are supported on all versions of GHC, see the [GHC version support page](supported-versions.md) for details.
@@ -141,7 +142,7 @@ Code action kind: `quickfix`
141142
Rewrites imported names to be qualified.
142143

143144
![Qualify Imported Names Demo](../plugins/hls-qualify-imported-names-plugin/qualify-imported-names-demo.gif)
144-
145+
145146
For usage see the ![readme](../plugins/hls-qualify-imported-names-plugin/README.md).
146147

147148
### Refine import
@@ -239,6 +240,13 @@ Shows module name matching file path, and applies it with a click.
239240

240241
![Module Name Demo](https://user-images.githubusercontent.com/54035/110860755-78ad8680-82bd-11eb-9845-9ea4b1cc1f76.gif)
241242

243+
## Selection range
244+
Provided by: `hls-selection-range-plugin`
245+
246+
Provides haskell specific
247+
[shrink/expand selection](https://code.visualstudio.com/docs/editor/codebasics#shrinkexpand-selection)
248+
support.
249+
242250
## Missing features
243251

244252
The following features are supported by the LSP specification but not implemented in HLS.
@@ -251,7 +259,6 @@ Contributions welcome!
251259
| Jump to implementation | Unclear if useful | `textDocument/implementation` |
252260
| Renaming | [Parital implementation](https://github.com/haskell/haskell-language-server/issues/2193) | `textDocument/rename`, `textDocument/prepareRename` |
253261
| Folding | Unimplemented | `textDocument/foldingRange` |
254-
| Selection range | Unimplemented | `textDocument/selectionRange` |
255262
| Semantic tokens | Unimplemented | `textDocument/semanticTokens` |
256263
| Linked editing | Unimplemented | `textDocument/linkedEditingRange` |
257264
| Document links | Unimplemented | `textDocument/documentLink` |

docs/supported-versions.md

+1
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ As such, the functionality provided by those plugins is not available in HLS whe
5050
| `hls-splice-plugin` | 9.2 |
5151
| `hls-stylish-haskell-plugin` | 9.0, 9.2 |
5252
| `hls-tactics-plugin` | 9.2 |
53+
| `hls-selection-range-plugin` | |
5354

5455
### Using deprecated GHC versions
5556

exe/Plugins.hs

+7
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@ import Ide.Plugin.Splice as Splice
7272
import Ide.Plugin.AlternateNumberFormat as AlternateNumberFormat
7373
#endif
7474

75+
#if selectionRange
76+
import Ide.Plugin.SelectionRange as SelectionRange
77+
#endif
78+
7579
-- formatters
7680

7781
#if floskell
@@ -167,6 +171,9 @@ idePlugins includeExamples = pluginDescToIdePlugins allPlugins
167171
#endif
168172
#if alternateNumberFormat
169173
AlternateNumberFormat.descriptor "alternateNumberFormat" :
174+
#endif
175+
#if selectionRange
176+
SelectionRange.descriptor "selectionRange" :
170177
#endif
171178
-- The ghcide descriptors should come last so that the notification handlers
172179
-- (which restart the Shake build) run after everything else

flake.lock

+4-4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

flake_hackage/flake.nix

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
flake = false;
88
};
99
lsp-types = {
10-
url = "https://hackage.haskell.org/package/lsp-types-1.4.0.0/lsp-types-1.4.0.0.tar.gz";
10+
url = "https://hackage.haskell.org/package/lsp-types-1.4.0.1/lsp-types-1.4.0.1.tar.gz";
1111
flake = false;
1212
};
1313
lsp-test = {

ghcide/ghcide.cabal

+1-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ library
6464
lens,
6565
list-t,
6666
hiedb == 0.4.1.*,
67-
lsp-types ^>= 1.4.0.0,
67+
lsp-types ^>= 1.4.0.1,
6868
lsp ^>= 1.4.0.0 ,
6969
monoid-subclasses,
7070
mtl,

ghcide/src/Development/IDE/GHC/Compat.hs

+72-29
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ module Development.IDE.GHC.Compat(
3232

3333
nodeInfo',
3434
getNodeIds,
35+
nodeInfoFromSource,
36+
isAnnotationInNodeInfo,
37+
mkAstNode,
38+
combineRealSrcSpans,
3539

3640
isQualifiedImport,
3741
GhcVersion(..),
@@ -67,71 +71,75 @@ module Development.IDE.GHC.Compat(
6771
runPp,
6872
) where
6973

70-
import GHC hiding (HasSrcSpan, ModLocation, getLoc,
71-
lookupName, RealSrcSpan)
72-
import Development.IDE.GHC.Compat.Core
73-
import Development.IDE.GHC.Compat.Env
74-
import Development.IDE.GHC.Compat.ExactPrint
75-
import Development.IDE.GHC.Compat.Iface
76-
import Development.IDE.GHC.Compat.Logger
77-
import Development.IDE.GHC.Compat.Outputable
78-
import Development.IDE.GHC.Compat.Parser
79-
import Development.IDE.GHC.Compat.Plugins
80-
import Development.IDE.GHC.Compat.Units
81-
import Development.IDE.GHC.Compat.Util
74+
import Development.IDE.GHC.Compat.Core
75+
import Development.IDE.GHC.Compat.Env
76+
import Development.IDE.GHC.Compat.ExactPrint
77+
import Development.IDE.GHC.Compat.Iface
78+
import Development.IDE.GHC.Compat.Logger
79+
import Development.IDE.GHC.Compat.Outputable
80+
import Development.IDE.GHC.Compat.Parser
81+
import Development.IDE.GHC.Compat.Plugins
82+
import Development.IDE.GHC.Compat.Units
83+
import Development.IDE.GHC.Compat.Util
84+
import GHC hiding (HasSrcSpan,
85+
ModLocation,
86+
RealSrcSpan, getLoc,
87+
lookupName)
8288

8389
#if MIN_VERSION_ghc(9,0,0)
8490
import GHC.Data.StringBuffer
85-
import GHC.Driver.Session hiding (ExposePackage)
91+
import GHC.Driver.Session hiding (ExposePackage)
92+
import qualified GHC.Types.SrcLoc as SrcLoc
8693
import GHC.Utils.Error
8794
#if MIN_VERSION_ghc(9,2,0)
8895
import Data.Bifunctor
89-
import GHC.Unit.Module.ModSummary
90-
import GHC.Driver.Env as Env
96+
import GHC.Driver.Env as Env
9197
import GHC.Unit.Module.ModIface
98+
import GHC.Unit.Module.ModSummary
9299
#else
93100
import GHC.Driver.Types
94101
#endif
95102
import GHC.Iface.Env
96-
import GHC.Iface.Make (mkIfaceExports)
97-
import qualified GHC.SysTools.Tasks as SysTools
98-
import qualified GHC.Types.Avail as Avail
103+
import GHC.Iface.Make (mkIfaceExports)
104+
import qualified GHC.SysTools.Tasks as SysTools
105+
import qualified GHC.Types.Avail as Avail
99106
#else
100-
import DynFlags hiding (ExposePackage)
101-
import HscTypes
102-
import MkIface hiding (writeIfaceFile)
103107
import qualified Avail
108+
import DynFlags hiding (ExposePackage)
109+
import HscTypes
110+
import MkIface hiding (writeIfaceFile)
104111

105112
#if MIN_VERSION_ghc(8,8,0)
106-
import StringBuffer (hPutStringBuffer)
113+
import StringBuffer (hPutStringBuffer)
107114
#endif
108115
import qualified SysTools
109116

110117
#if !MIN_VERSION_ghc(8,8,0)
111-
import SrcLoc (RealLocated)
112118
import qualified EnumSet
119+
import SrcLoc (RealLocated)
113120

114121
import Foreign.ForeignPtr
115122
import System.IO
116123
#endif
117124
#endif
118125

119-
import Compat.HieAst (enrichHie)
126+
import Compat.HieAst (enrichHie)
120127
import Compat.HieBin
121128
import Compat.HieTypes
122129
import Compat.HieUtils
123-
import qualified Data.ByteString as BS
130+
import qualified Data.ByteString as BS
124131
import Data.IORef
125132

126-
import qualified Data.Map as Map
127-
import Data.List (foldl')
133+
import Data.List (foldl')
134+
import qualified Data.Map as Map
135+
import qualified Data.Set as Set
128136

129137
#if MIN_VERSION_ghc(9,0,0)
130-
import qualified Data.Set as S
138+
import qualified Data.Set as S
131139
#endif
132140

133141
#if !MIN_VERSION_ghc(8,10,0)
134-
import Bag (unitBag)
142+
import Bag (unitBag)
135143
#endif
136144

137145
#if !MIN_VERSION_ghc(9,2,0)
@@ -334,6 +342,13 @@ nodeInfo' = nodeInfo
334342
-- unhelpfulSpanFS = id
335343
#endif
336344

345+
nodeInfoFromSource :: HieAST a -> Maybe (NodeInfo a)
346+
#if MIN_VERSION_ghc(9,0,0)
347+
nodeInfoFromSource = Map.lookup SourceInfo . getSourcedNodeInfo . sourcedNodeInfo
348+
#else
349+
nodeInfoFromSource = Just . nodeInfo
350+
#endif
351+
337352
data GhcVersion
338353
= GHC86
339354
| GHC88
@@ -373,3 +388,31 @@ runPp =
373388
#else
374389
const SysTools.runPp
375390
#endif
391+
392+
isAnnotationInNodeInfo :: (FastString, FastString) -> NodeInfo a -> Bool
393+
#if MIN_VERSION_ghc(9,2,0)
394+
isAnnotationInNodeInfo (ctor, typ) = Set.member (NodeAnnotation ctor typ) . nodeAnnotations
395+
#else
396+
isAnnotationInNodeInfo p = Set.member p . nodeAnnotations
397+
#endif
398+
399+
mkAstNode :: NodeInfo a -> Span -> [HieAST a] -> HieAST a
400+
#if MIN_VERSION_ghc(9,0,0)
401+
mkAstNode n = Node (SourcedNodeInfo $ Map.singleton GeneratedInfo n)
402+
#else
403+
mkAstNode = Node
404+
#endif
405+
406+
combineRealSrcSpans :: RealSrcSpan -> RealSrcSpan -> RealSrcSpan
407+
#if MIN_VERSION_ghc(9,2,0)
408+
combineRealSrcSpans = SrcLoc.combineRealSrcSpans
409+
#else
410+
combineRealSrcSpans span1 span2
411+
= mkRealSrcSpan (mkRealSrcLoc file line_start col_start) (mkRealSrcLoc file line_end col_end)
412+
where
413+
(line_start, col_start) = min (srcSpanStartLine span1, srcSpanStartCol span1)
414+
(srcSpanStartLine span2, srcSpanStartCol span2)
415+
(line_end, col_end) = max (srcSpanEndLine span1, srcSpanEndCol span1)
416+
(srcSpanEndLine span2, srcSpanEndCol span2)
417+
file = srcSpanFile span1
418+
#endif

haskell-language-server.cabal

+11
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,11 @@ flag qualifyImportedNames
176176
default: True
177177
manual: True
178178

179+
flag selectionRange
180+
description: Enable selectionRange plugin
181+
default: True
182+
manual: True
183+
179184
-- formatters
180185

181186
flag floskell
@@ -283,6 +288,11 @@ common qualifyImportedNames
283288
build-depends: hls-qualify-imported-names-plugin ^>=1.0.0.0
284289
cpp-options: -DqualifyImportedNames
285290

291+
common selectionRange
292+
if flag(selectionRange)
293+
build-depends: hls-selection-range-plugin ^>=1.0.0.0
294+
cpp-options: -DselectionRange
295+
286296
-- formatters
287297

288298
common floskell
@@ -332,6 +342,7 @@ executable haskell-language-server
332342
, splice
333343
, alternateNumberFormat
334344
, qualifyImportedNames
345+
, selectionRange
335346
, floskell
336347
, fourmolu
337348
, ormolu

0 commit comments

Comments
 (0)