#+TITLE: crystal layer

#+TAGS: general|layer|multi-paradigm|programming

[[file:img/crystal.png]]

* Table of Contents                     :TOC_5_gh:noexport:
- [[#description][Description]]
  - [[#features][Features:]]
- [[#install][Install]]
- [[#configuration][Configuration]]
  - [[#choosing-a-backend][Choosing a backend]]
    - [[#company-crystal][Company-crystal]]
    - [[#lsp][LSP]]
  - [[#repl][REPL]]
  - [[#ameba][Ameba]]
- [[#key-bindings][Key bindings]]
  - [[#crystal-commands][Crystal commands]]
  - [[#repl-1][REPL]]
  - [[#ameba-1][Ameba]]

* Description
This layer provides support for the Crystal language.

** Features:
- Format on save
- Integration of [[https://play.crystal-lang.org][play.crystal-lang.org]] using [[https://github.com/veelenga/play-crystal.el][play-crystal.el]]
- Syntax checking
- Auto completion
- Test execution (=crystal spec=)
- =crystal tool= integration
- Interactive REPL ([[https://github.com/brantou/inf-crystal.el][inf-crystal.el]] and [[https://github.com/crystal-community/icr][icr]])
- Static code analysis using [[https://github.com/veelenga/ameba.el][ameba]]

* Install
To use this configuration layer, add it to your =~/.spacemacs=. You will need to
add =crystal= to the existing =dotspacemacs-configuration-layers= list in this
file.

* Configuration
All layer configurations can be done by setting layer variables in your dotfile.
No custom user config lines are necessary

** Choosing a backend
This layer provides two alternative backends to choose from.

*** Company-crystal
This is the default choice if nothing is set and no lsp layer
is loaded in your dotfile. This mode only provides very
limited IDE capabilities. Used best if only small files
are edited. To set explicitly set the following in your
dotfile:

#+BEGIN_SRC emacs-lisp
  (crystal :variables crystal-backend 'company-crystal)
#+END_SRC

*** LSP
For proper IDE support this backend should be used. It is
based on an external server which will be started automatically
by emacs, once a crystal file is opened. The key bindings are
the same for all lsp modes so if you are already familiar with
one you should be able to work the same in all modes.

To set explicitly do the following in your dotfile:

#+BEGIN_SRC emacs-lisp
  (crystal :variables
           crystal-backend 'lsp)
#+END_SRC

For this to work you will also need to obtain
the latest version of the lsp server from [[https://github.com/crystal-lang-tools/scry#installation][here]].

NOTE: Key bindings for LSP are defined in the
LSP layer. Also it is advisable to have a look
at the autocomplete layer for an optimal
intellisense config for LSP.

** REPL
To be able to connect to [[https://github.com/brantou/inf-crystal.el][inf-crystal]], you need to make sure that [[https://github.com/crystal-community/icr][icr]] is
installed.

Installation instructions can be found on the main page of [[https://github.com/crystal-community/icr#installation][icr]].

Although not in the installation instruction it seems that on macOS you can
install it with Homebrew:

#+BEGIN_SRC sh
  brew install crystal-icr
#+END_SRC

** Ameba
To be able to use [[https://github.com/veelenga/ameba.el][ameba.el]], you need to make sure that [[https://github.com/veelenga/ameba][ameba]] is installed.

Installation instructions can be found on the main page of [[https://github.com/veelenga/ameba][ameba]].

* Key bindings
** Crystal commands

| Key binding | Description                                               |
|-------------+-----------------------------------------------------------|
| ~SPC m e b~ | play-crystal submit buffer                                |
| ~SPC m e e~ | play-crystal show code in a browser                       |
| ~SPC m e i~ | download play-crystal snippet                             |
| ~SPC m e r~ | play-crystal submit region                                |
| ~SPC m g G~ | jump to definition in other window                        |
| ~SPC m g a~ | jump to matching spec file or back from spec to code file |
| ~SPC m g g~ | jump to definition                                        |
| ~SPC m t b~ | run =crystal spec= for the current buffer                 |
| ~SPC m t p~ | run =crystal spec= for the current project                |
| ~SPC m u c~ | show context                                              |
| ~SPC m u e~ | show macro expansion                                      |
| ~SPC m u f~ | format the current buffer                                 |
| ~SPC m u i~ | show implementations for given call                       |
| ~SPC m a x~ | run =crystal run= for the current file                    |

** REPL
Start a inferior crystal REPL process with ~SPC m '​~ or ~SPC m s i~.
Then you can send code to it with the bindings below:

| Key binding | Description                                 |
|-------------+---------------------------------------------|
| ~SPC m '​~   | start inferior REPL process                 |
| ~SPC m s B~ | send buffer and switch to REPL              |
| ~SPC m s F~ | send function definition and switch to REPL |
| ~SPC m s R~ | send region and switch to REPL              |
| ~SPC m s b~ | send buffer                                 |
| ~SPC m s f~ | send function definition                    |
| ~SPC m s i~ | start inferior REPL process                 |
| ~SPC m s r~ | send region                                 |
| ~SPC m s s~ | switch to REPL                              |

** Ameba

| Key binding   | Description                                    |
|---------------+------------------------------------------------|
| ~SPC m u a d~ | Prompts from a directory on which to run Ameba |
| ~SPC m u a f~ | Runs Ameba on the current visited file         |
| ~SPC m u a p~ | Runs Ameba on the entire project               |
