After #989 and #993 the use of the `yaml` package is isolated in the lib modules `Dhall.Yaml` and `Dhall.YamlToDhall` so it is easier to add support for compilers that cant use the `yaml`package like eta or ghcjs.
With this one we would add support for [eta](https://eta-lang.org/), a fork of ghc that compiles to jvm bytecode.
Main changes:
* Add conditional to cabal file and cpp conditions to the main modules for yaml to use a specific module for eta, `Dhall.Yaml.Eta` that replaces calls to the `yaml`package to ffi calls to the java lib [jackson](https://github.com/FasterXML/jackson), one of the most popular ones in the java world.
* Add the java files that contains the ffi calls
* Mark `buildable: False` the subpackages that cant be built by eta for now
One effect of use the cabal file for cabal and etlas (the build tool for eta) is stack and cabal builds show those warnings:
```
Warning: Cabal file warning in D:\ws\eta\dhall\dhall-haskell\dhall-json\dhall-js
on.cabal@ 69:9:
Unknown field: "maven-depends"
Warning: Cabal file warning in D:\ws\eta\dhall\dhall-haskell\dhall-json\dhall-js
on.cabal@ 74:9:
Unknown field: "java-sources"
```
I've not found a way to avoid them other than use another file for etlas build (`etlas.dhall`). It would suppose duplicate most of the logic, though.
* Type on Hover 1/2: Backend
Adds a function typeAt that, given an annotated expression and a text
position finds the type of the subexpression at that position.
* Type on Hover 2/2: Frontend
Exposes the new type-on-hover functionality as part of the hover
handler.
* Simplify explainDiagnosis
As suggested by @Gabriel439
* Simplify `inside`
Adressing @Gabriel439's comment.
* Simplify typeAt' by assuming well-typedness
* Simply srcAt
Use choice operator `<|>` instead of case distinction
`dhall diff` slightly misbehaves when diffing the following expression with
itself:
```dhall
λ(f : List Bool -> Bool) → f ([] : List Bool)
```
... producing the following diff:
```
λ(… : …
→ …)
→ …@…
- [ … ] : List …
+ [ … ] : List …
```
This is because there are two places in the `Dhall.Diff` module responsible
for comparing lists:
* Once in `diffApplicationExpression`, which compares two lists with at least
one type annotation between them
* Once in `diffPrimitiveExpression`, which compares two lists if neither one has
a type annotation
Those cases exhaustively cover all possible pairs of lists, but there was a
third (incorrect) fallback case that prematurely gave up and displayed them as
different. This fallback would trigger when applying a function to an empty
list, since the diffing algorithm wouldn't have a chance to return back to the
top-level `diffExpression` and try to compare the lists correctly in
`diffApplicationExpression`.
After this change, the diff now doesn't include a spurious difference:
```
λ(… : …
→ …)
→ …@…
…
```
The `--file` option was essentially broken since it passed in the
file path instead of the directory, meaning that transitive imports
would not be computed correctly (they'd be off by one path component).
At the moment the VSCode plugin contains a hacked-together prototype of
a dhall-to-json (and -to-yaml) preview feature. We should ultimately
move that kind of functionality to dhall-lsp-server to 1) minimise the
amount of VSCode specific code and 2) avoid having to work with and fix
bugs in typescript code ;)
This commit takes us most of the way there; what is missing is the
ability to create files (via a WorkspaceEditRequest), which is not yet
implemented by haskell-lsp-types. I will wait with exposing the
corresponding command (and removing the existing preview code) in
vscode-dhall-lsp-server until this is fixed upstream.
* Find unused bindings inside nested lets
The removeUnusedBindings rule only matches the first bound variable in a
nested let block (of the form "let ... let ... in ..."). This means that
so far the linter missed cases like
let a = 0 let b = 0 in a.
This simple fix unfolds all let blocks (syntactically this means
inserting `in's everywhere) before applying the linting rules; the
LetInLet rule folds everything back together in the end. Applied to the
example from above we now return the correct result,
let a = 0 in a.
* Rewrite `lint` in a more explicit style; add comments
* Don't export implementation details
* Fix `freeIn` to correctly handle de Briujn indices
Previously we had "x@0" `freeIn` "x@1" == True (but "x@1" `freeIn` "x@0"
== False). The fix is to use subst instead of shift to change
occurrences of the given variable.
* Fix `removeUnusedBindings` to update de Bruijn indices
Whenever we remove an unused binding we need to update any references to
variables outside the let block, so that
let a = 0 let a = 0 in a@1
gets correctly rewritten into
let a = 0 in a (a = a@0)
instead of
let a = 0 let a = 0 in a@1
~> let a = 0 in a@1
~> a@1
* Refactor Dhall.LSP.Backend.Formatting
Exposes `formatExpr :: Text -> Expr a Import -> Text` that can be reused
in the lintAndFormat command.
* Implement linting backend in Dhall.LSP.Backend.Linting
Exposes `suggest :: Eq a => Expr Src a -> [Suggestion]` and
`lintAndFormatDocument :: Text -> Either ParseError Text`.
* Fix unusedBindings
* Implement linter diagnostics
* Improve linting diagnostic ranges
In VSCode we now mark the "let" following a superfluous "in".
let a = 0 in let b = a in b
~
Previously we got
let a = 0 in let b = a in b
~
which was slightly confusing
* Implement executeCommand handler for "Lint and Format"
This exposes the command "dhall.server.lint", which should be called
from the vscode plugin to lint and format the current dhall file. Needs
a correspondingly patched vscode-dhall-lsp-server (branch lint).
* Remove dummy LSP handlers
* Publish diagnostics directly
So far we were using haskell-lsp's diagnostics infrastructure.
haskell-lsp is geared towards plugin-based language servers like
haskell-ide-engine, which means that their approach to handling
diagnostics (on a per-plugin basis) doesn't really fit our use-case.
This commit changes our diagnostics implementation to send
protocol-level messages directly, rather than going through haskell-lsp.
* Refactor diagnostics handler
Reduce clutter and clean up Dhall.LSP.Handlers.Diagnostics a bit.
* Remove unused import
* Don't flush diagnostics on file close
The LSP protocol does not expect (or require) us to flush diagnostics at
any point. This change doesn't have any user-visible impact (since we
recompute diagnostics on file open anyway).
* Use LSP VFS instead of disk IO
Rather than reading the files from disk each time, we now simply query
haskell-lsp's "virtual file system". This also allows us to check code
before it has been saved (though we do not implement this).
* Clean up dhall-lsp-server's Main.hs
Also adds haddock comments.
* Remove TODO comment
The comment talks about adding a mechanism for protocol-level logging to
dhall-lsp-server. Since the VSCode LSP implementation has this feature
already baked in on the client side, we don't have to implement it
ourselves.
* Simplify dhall-lsp-server's infrastructure
So far we had a system where we set up the LSP message handlers to relay
messages to a separate dispatcher thread via a shared channel. Since our
language server is at the same time designed in a completely synchronous
manner, this complication turns out to be unnecessary.
* Remove sample code
* Fix unused variable warning
* Reorganise dhall-lsp-server's module hierarchy
Prefixes all modules with "Dhall.LSP.".
Previously:
Backend.Dhall.
.Diagnostics
.Formatting
LSP.
.Handlers
.Handlers.
.Diagnostics
.DocumentFormatting
.Server
Now:
Dhall.LSP.
.Backend.
.Diagnostics
.Formatting
.Handlers
.Handlers.
.Diagnostics
.DocumentFormatting
.Server
* Make dhall-lsp-server tests compile again
They still fail though!
Fixes https://github.com/dhall-lang/dhall-lang/issues/579
`Natural/fold` was misbehaving on GHCJS due to the use of `Natural`
arithmetic (for some reason). This is a problem I've seen and fixed
before, but needed to be fixed again after the migration to the new
`Dhall.Eval` normalization engine.
The fix is easy: use `Integer` instead of `Natural` for the accumulator
of the fold and the bug disappears.
* Avoid clash between Backend.Dhall.Diagnostics.Range and Language.Haskell.LSP.Types.Range
* Ignore .cache dirs created by tests
* Fix rest of compile errors and warnings
* Refactor Diagnostics backend
This commits refactors Backend.Dhall.Diagnostics, cleaning things up and
adding comments along the way. We also lose Backend.Dhall.DhallErrors.
The user-facing result is a step backwards, as we revert to using Dhall's
Show instances to print errors, which gives us error messages that don't
fit the LSP use case very well at the moment. In the future
we should change Dhall's error printing API (the Show instances) to make
them more generally useful (in particular for the LSP use case), thus
saving us from having to duplicate code (as was previously did, when
dhall-lsp-server was not yet part of the upstream project).
* Proof of concept: Provide detailed error messages
This proof of concept provides detailed explanations on hovering over type
errors. Currently this is done by injecting the explanation directly into
the hover text, which 1. conflicts with the short error messages, which
are still being displayed at the same time and 2. is not particularly
readable, since the explanations are meant to be rendered at least 80
characters wide.
For future work I am planning to instead only add an "explain" link to the
hover window, which when clicked opens the explanation in a separate
window (inspired by how the haskell ide engine presents documentation
links). This will require a small amount of client-side logic.
* Explain error messages via VSCode Command URIs
The first proof of concept simply spit out the explanations as hover text;
in order to make the feature a bit more useful, we now encode the
explanation text into a VSCode command URI (that still needs to be
implemented client-side), so that upon hovering over an error the user is
presented with a clickable "Explain error message" link.
The feature is still in the prototype stage!
* Use custom URI scheme instead of command URIs
Use URIs of the form "dhall-explain:?text" to present detailed
explanations on hovering. Previously we used command URIs, which are
specific to VSCode.
Needs a correspondingly patched vscode-lsp-server to handle the
"dhall-explain" URI scheme.
* Fix handling of relative imports in diagnostics
In refactoring the diagnostics backend I forgot to initialise the settings
passed to the Dhall type-checker, which are needed to properly resolve
relative imports. An easy fix for a silly mistake ;)
* Remove outdated TODO comment
* Make GHC stricter when building dhall-lsp-server
Add -Wall and -fwarn-incomplete-uni-patterns to the GHC options when
building dhall-lsp-server. This brings it in line with the rest of
dhall-haskell.
* Fix warnings when building dhall-lsp-server
* Fix review comments
Fixes Gabriel's PR comments. Note that I leave a proper fix to
DhallException for the future (I want to work on something else for a bit
;)).
* Use underscores to pacify warnings
Part of https://github.com/dhall-lang/dhall-lang/issues/563
This flag freezes imports in the same way as the Prelude by providing a
fallback unprotected import without an integrity check. The primary use
case for this is caching imports with a graceful fallback, which is why
the flag is named `--cache`
* dhall-lsp-server: Revert from Relude to standard Prelude
The code so far used Relude in place of the standard Prelude. Reverting
back to the standard Prelude brings dhall-lsp-server in line with the
rest of the dhall-haskell family, while also reducing the barrier to
contribution.
This change causes a number of additional explicit imports; creating a
"Library" module to gather the common imports could perhaps solve both
problems, i.e. reducing overhead while not having to resort to a custom
prelude. (This is left for a future refactoring.)
* dhall-lsp-server: Exclude trailing whitespace in diagnostics
Dhall's current parser includes trailing whitespace in source range
annotations. Until now, we simply passed these "loose" ranges on to the
LSP client when generating diagnostic messages; this behaviour is fixed
in the present commit.
Previously (assuming funcTion is misspelled):
funcTion argument
~~~~~~~~~
Now:
funcTion argument
~~~~~~~~
* Refactor lines' to return NonEmpty list
Thanks to Gabriel for pointing this out! Since "lines'" always returns at
least a singleton list containing the empty line we can reflect this in
its type; this allows us to get rid of a test for non-emptiness in
"offsetToPosition".
In yaml-0.11, Text.Libyaml was split into the libyaml package. Hence,
as dhall-json imports that module, a libyaml dependency is needed when
yaml >= 0.11. This necessitates an automatic flag.
As Dhall's bounds don't allow base 4.13, this doesn't actually affect
anyone running in a supported configuration (i.e., without
--allow-newer). Further note that base 4.13 (i.e., GHC 8.8) isn't
tested in CI at present.
This could well be the last GHC 8.8-related change needed to
code (bounds will definitely need to be adjusted). In this case, a
Dhall release with relaxed bounds will suffice to finish off GHC 8.8
support.
However, it's also possible that dependencies might bundle together
breaking changes with 8.8 support, in which case adaptations will
still need to be made.
Fixes https://github.com/dhall-lang/dhall-haskell/issues/882
This allows users to supply the Dhall expression by path instead of via
standard input. This also ensures that transitive imports are resolved
appropriately relative to the file's path.
In other words, instead of this:
```
$ dhall <<< './foo/bar.dhall'
```
Users can now do:
```
$ dhall --file foo/bar.dhall
```
Before, `dhall-to-json`/`dhall-to-yaml` would use approximate
representations for special `Double` values. Specifically, `NaN`
would encode as `null` and `±Infinity` would encode as the minimum
and maximum `Double` values.
After this change, YAML will now use `nan`/`inf`/`-inf` to encode
these values (since special `Double` values are natively supported
by YAML) and the JSON encoding will reject them by default. The
user can restore the old behavior for the JSON encoding by enabling
the `--approximate-special-doubles` flag.
Allow to generare quoted scalars if needed via providing a custom encode
options to Data.Yaml.encodeWith. So far two corner cases from yaml
itself (an empty scalar, and special strings) are omitted in the
implementation.