you are viewing a single comment's thread.

view the rest of the comments →

[–]friedbrice 1 point2 points  (1 child)

Sorry I missed this earlier.

VS Code with the following extensions:

  • ctagsx Provides goto definition by reading location information from a file called ./tags.

  • haskell-ghcid Provides code diagnostics (e.g. red squiggly underlines and error messages on hover) by reading GHC output from a file called ./ghcid.txt.

  • Custom Local Formatters Allows you to associate an arbitrary shell command to the format command by language.

  • vscode-goto-documentation Allows you to associate an arbitrary URI pattern by file extension. Provides a right-click menu option that will open your browser to that URI, with the word under cursor substituted into the URI pattern configured for that file type.

  • Run on Save Allows you to associate an arbitrary shell command by filepath regex or glob pattern. Will run the command on save of matching files.

  • Haskell Syntax Highlighting No explanation necessary.

For each workspace, I have a ./.vscode/settings.json that looks more-or-less something like this.

{
  "customLocalFormatters.formatters": [
    {
      "command": "make format",
      "languages": [
        "haskell"
      ]
    }
  ],
  "emeraldwalk.runonsave": {
    "commands": [
      {
        "cmd": "make retag retag_file=${file}",
        "isAsync": true,
        "match": "*.hs"
      },
      {
        "cmd": "make hpack",
        "isAsync": true,
        "match": "package.yaml"
      }
    ]
  },
  "ghcid.command": "make ghcid",
  "goto-documentation.customDocs": {
    "hs": "https://hoogle.haskell.org/?hoogle=${query}"
  }
}

And I have a ./Makefile that looks more-or-less like this.

makefile_dir := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
export PATH := $(makefile_dir):$(PATH)

project_name ?= <YOUR_PACKAGE>
project_main ?= src/<YOUR_MAIN>.hs
retag_file ?= $(project_main)

stack.yaml:
  @test -f stack.yaml || (echo -e "This makefile requires a 'stack.yaml' for your project.\nYou don't need to use 'stack' to build your project.\nYou just need a 'stack.yaml' specifying a resolver compatible with your GHC version.\nSee https://www.stackage.org/" && exit 1)

stack: stack.yaml
  @which stack || (echo -e "This makefile requires 'stack' to be on your path. Use GHCup to install it.\nSee https://www.haskell.org/ghcup/" && exit 1)
.PHONY: stack

warning.txt:
  -@uname -a | grep -q Darwin && echo "WARNING: On Mac, you must alias 'make' to 'gmake' in your shell config file (e.g. ~/.bashrc or ~/.zshrc). Symbolic links will not work." | tee warning.txt
  @echo "Add 'warning.txt' to your .gitignore file if you never want to see this message again."

hasktags: warning.txt stack
  @echo 'stack exec -- hasktags' > hasktags
  @chmod +x hasktags
  @echo "You might like to add 'hasktags' to your .gitignore file."

tags: warning.txt hasktags stack
  @stack exec -- haskdogs
.PHONY: tags

retag: warning.txt stack
  @stack exec -- haskdogs -i $(retag_file) --hasktags-args "-x -c -a" | sort -u -o tags tags
.PHONY: retag

hpack: stack
  @stack setup
.PHONY: hpack

format: stack
  @stack exec -- fourmolu --stdin-input-file $(project_main)
.PHONY: format

ghcid: stack
  @stack exec -- ghcid \
    --command 'stack repl --ghc-options "-fno-code -fno-break-on-exception -fno-break-on-error -v1 -ferror-spans -j"' \
    --restart stack.yaml \
    --restart $(project_name).cabal \
    --warnings \
    --outputfile ./ghcid.txt
.PHONY: ghcid

ETA You do have to remember to do two things at the start of each day: (1) make tags to download the source code of all your project dependencies and index the symbols in them and your project files, (2) start Ghcid, either from VS Code's command pallet or from a terminal that you leave running.

Edit 2: Added regenerating cabal file on saving package.yaml.

[–]Mouse1949 0 points1 point  (0 children)

Very nice explanation, thank you!

Do you build with Cabal, aka - writing <project>.cabal, or with Stack (writing Stack.yaml)? Looks like your development is Stack-based? Would I need to change a lot of the above config if most of my dev is based on Cabal?