hls-tactics-plugin: Wingman plugin for Haskell Language Server

This is a package candidate release! Here you can preview how this package release will appear once published to the main package index (which can be accomplished via the 'maintain' link below). Please note that once a package has been published to the main package index it cannot be undone! Please consult the package uploading documentation for more information.

[maintain] [Publish]

Please see the README on GitHub at https://github.com/haskell/haskell-language-server#readme


[Skip to Readme]

Properties

Versions 0.5.1.0, 1.0.0.0, 1.1.0.0, 1.2.0.0, 1.3.0.0, 1.4.0.0, 1.5.0.0, 1.5.0.1, 1.6.0.0, 1.6.1.0, 1.6.2.0, 1.7.0.0, 1.7.0.0, 1.8.0.0, 1.8.1.0, 2.0.0.0, 2.0.0.1, 2.1.0.0, 2.2.0.0
Change log None available
Dependencies aeson, base (>=4.12 && <5), containers, deepseq, directory, extra (>=1.7.8), filepath, fingertree, generic-lens, ghc, ghc-boot-th, ghc-exactprint, ghc-source-gen (>=0.4.1 && <0.5), ghcide (>=1.8 && <1.9), hls-graph, hls-plugin-api (>=1.5 && <1.6), hls-refactor-plugin, hyphenation, lens, lsp, megaparsec (>=8 && <10), mtl, parser-combinators, prettyprinter, refinery (>=0.4 && <0.5), retrie (>=0.1.1.0), syb, text, transformers, unagi-chan, unordered-containers [details]
License Apache-2.0
Copyright Sandy Maguire, Reed Mullanix
Author Sandy Maguire, Reed Mullanix
Maintainer sandy@sandymaguire.me
Category Development
Home page https://haskellwingman.dev
Bug tracker https://github.com/haskell/haskell-language-server/issues
Uploaded by hls_team at 2022-09-13T21:21:28Z

Modules

Flags

Manual Flags

NameDescriptionDefault
pedantic

Enable -Werror

Disabled

Use -f <flag> to enable a flag, or -f -<flag> to disable that flag. More info

Downloads

Maintainer's Corner

Package maintainers

For package maintainers and hackage trustees


Readme for hls-tactics-plugin-1.7.0.0

[back to package description]

Wingman for Haskell

 

Wingman for Haskell

Hackage

"Focus on the important stuff; delegate the rest"

Dedication

There's a lot of automation that can happen that isn't a replacement of humans, but of mind-numbing behavior.

--Stewart Butterfield

Overview

Wingman writes the boring, auxiliary code, so you don't have to. Generate functions from type signatures, and intelligently complete holes.

Getting Started

Wingman for Haskell is enabled by default in all official release of Haskell Language Server. Just hover over a typed hole, run the "Attempt to fill hole" code action, et voila!

Usage

When enabled, Wingman for Haskell will remove HLS support for hole-fit code actions. These code actions are provided by GHC and make typechecking extremely slow in the presence of typed holes. Because Wingman relies so heavily on typed holes, these features are in great tension.

The solution: we just remove the hole-fit actions. If you'd prefer to use these actions, you can get them back by compiling HLS without the Wingman plugin.

Editor Configuration

Enabling Jump to Hole

Set the haskell.plugin.tactics.config.hole_severity config option to 4, or hint if your editor uses a GUI for its configuration. This has the potential to negatively impact performance --- please holler if you notice any appreciable slowdown by enabling this option.

coc.nvim

The following vimscript maps Wingman code-actions to your leader key:

" use [h and ]h to navigate between holes
nnoremap <silent> [h :<C-U>call CocActionAsync('diagnosticPrevious', 'hint')<CR>
nnoremap <silent> ]h :<C-U>call <SID>JumpToNextHole()<CR>

" <leader>d to perform a pattern match, <leader>n to fill a hole
nnoremap <silent> <leader>d  :<C-u>set operatorfunc=<SID>WingmanDestruct<CR>g@l
nnoremap <silent> <leader>n  :<C-u>set operatorfunc=<SID>WingmanFillHole<CR>g@l
nnoremap <silent> <leader>r  :<C-u>set operatorfunc=<SID>WingmanRefine<CR>g@l
nnoremap <silent> <leader>c  :<C-u>set operatorfunc=<SID>WingmanUseCtor<CR>g@l
nnoremap <silent> <leader>a  :<C-u>set operatorfunc=<SID>WingmanDestructAll<CR>g@l


function! s:JumpToNextHole()
  call CocActionAsync('diagnosticNext', 'hint')
endfunction

function! s:GotoNextHole()
  " wait for the hole diagnostics to reload
  sleep 500m
  " and then jump to the next hole
  normal 0
  call <SID>JumpToNextHole()
endfunction

function! s:WingmanRefine(type)
  call CocAction('codeAction', a:type, ['refactor.wingman.refine'])
  call <SID>GotoNextHole()
endfunction

function! s:WingmanDestruct(type)
  call CocAction('codeAction', a:type, ['refactor.wingman.caseSplit'])
  call <SID>GotoNextHole()
endfunction

function! s:WingmanDestructAll(type)
  call CocAction('codeAction', a:type, ['refactor.wingman.splitFuncArgs'])
  call <SID>GotoNextHole()
endfunction

function! s:WingmanFillHole(type)
  call CocAction('codeAction', a:type, ['refactor.wingman.fillHole'])
  call <SID>GotoNextHole()
endfunction

function! s:WingmanUseCtor(type)
  call CocAction('codeAction', a:type, ['refactor.wingman.useConstructor'])
  call <SID>GotoNextHole()
endfunction

Emacs

When using Emacs, wingman actions should be available out-of-the-box and show up e.g. when using M-x helm-lsp-code-actions RET provided by helm-lsp or as popups via lsp-ui-sideline.

Additionally, if you want to bind wingman actions directly to specific keybindings or use them from Emacs Lisp, you can do so like this:

;; will define elisp functions for the given lsp code actions, prefixing the
;; given function names with "lsp"
(lsp-make-interactive-code-action wingman-fill-hole "refactor.wingman.fillHole")
(lsp-make-interactive-code-action wingman-case-split "refactor.wingman.caseSplit")
(lsp-make-interactive-code-action wingman-refine "refactor.wingman.refine")
(lsp-make-interactive-code-action wingman-split-func-args "refactor.wingman.spltFuncArgs")
(lsp-make-interactive-code-action wingman-use-constructor "refactor.wingman.useConstructor")

;; example key bindings
(define-key haskell-mode-map (kbd "C-c d") #'lsp-wingman-case-split)
(define-key haskell-mode-map (kbd "C-c n") #'lsp-wingman-fill-hole)
(define-key haskell-mode-map (kbd "C-c r") #'lsp-wingman-refine)
(define-key haskell-mode-map (kbd "C-c c") #'lsp-wingman-use-constructor)
(define-key haskell-mode-map (kbd "C-c a") #'lsp-wingman-split-func-args)

Other Editors

Please open a PR if you have a working configuration!

Features

Support

Please consider pledging on Patreon to support the project and get access to cutting-edge features.