Skip to content

AjaiKN/roc-ts-mode

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

92 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

roc-ts-mode

https://melpa.org/packages/roc-ts-mode-badge.svg

Roc is a strongly typed functional programming language inspired by Elm, but for variety of platforms. See https://www.roc-lang.org/.

Disclaimer

This code is an early work in progress and I am a novice at Emacs Lisp. Polite suggestions and contributions are welcome.

Install

roc-ts-mode is available on MELPA.

Requirements: Emacs 29.1+.

Vanilla Emacs

If you haven’t done so already, first enable installation of packages from MELPA.

Then, run M-x package-install RET roc-ts-mode RET.

Finally, run M-x roc-ts-install-treesit-grammar (or install the Roc tree-sitter grammar another way).

Basic configuration

Add the following to your init.el:

(use-package roc-ts-mode
  :mode ("\\.roc\\'" . roc-ts-mode)
  :config
  ;; any configuration goes here (e.g., see below for language server integration)...
  )

Using straight

(straight-use-package 'roc-ts-mode)

Then, run M-x roc-ts-install-treesit-grammar (or install the Roc tree-sitter grammar another way).

In Doom Emacs

Add the following to packages.el (use M-x doom/goto-private-packages-file, typically bound to SPC h d p d):

(package! roc-ts-mode)

Then, run doom sync on the command line and restart Emacs (or use the experimental M-x doom/reload, typically bound to SPC h r r).

Finally, run M-x roc-ts-install-treesit-grammar (or install the Roc tree-sitter grammar another way).

Recommended configuration for Doom Emacs

Add the following to config.el (use M-x doom/goto-private-config-file, typically bound to SPC h d c):

(use-package! roc-ts-mode
  :mode ("\\.roc\\'" . roc-ts-mode)
  :config
  (map! :map roc-ts-mode-map
        (:localleader
         "f" #'roc-ts-format
         "b" #'roc-ts-build
         "t" #'roc-ts-test
         "r" #'roc-ts-run
         "d" #'roc-ts-dev
         "c" #'roc-ts-check
         "e" #'roc-ts-repl
         (:prefix ("s" . "roc-start")
           "a" #'roc-ts-start-app
           "p" #'roc-ts-start-pkg
           "u" #'roc-ts-start-update)))

  (set-popup-rule! (rx bol "*roc-ts-repl") :size 0.3)

  ;; Setup the LSP support:
  ;; For this to work, you'll need roc_language_server, which is distributed in
  ;; Roc releases, in your PATH.
  (when (and (modulep! :tools lsp) (not (modulep! :tools lsp +eglot)))
    (require 'lsp-mode)
    (add-to-list 'lsp-language-id-configuration '(roc-ts-mode . "roc"))
    (lsp-register-client (make-lsp-client :new-connection (lsp-stdio-connection "roc_language_server")
                                          :activation-fn (lsp-activate-on "roc")
                                          :major-modes '(roc-ts-mode)
                                          :server-id 'roc_ls)))
  (when (modulep! :tools lsp +eglot)
    (set-eglot-client! 'roc-ts-mode '("roc_language_server")))
  (add-hook 'roc-ts-mode-local-vars-hook #'lsp!)

  ;; Formatting
  (set-formatter! 'roc-ts-format '("roc" "format" "--stdin" "--stdout") :modes '(roc-ts-mode))
  (setq-hook! 'roc-ts-mode-local-vars-hook
    +format-with 'roc-ts-format)

  ;; Keywords that should trigger electric indentation
  (set-electric! 'roc-ts-mode :words '("else"))

  ;; Extra ligatures
  (when (modulep! :ui ligatures +extra)
    (set-ligatures! 'roc-ts-mode
      :true "Bool.true" :false "Bool.false"
      :not "!"
      :and "&&" :or "||")
    (setq-hook! 'roc-ts-mode-hook
      prettify-symbols-compose-predicate #'+roc-ts-symbol-compose-p)
    (defun +roc-ts-symbol-compose-p (start end match)
      "Like `prettify-symbols-default-compose-p', except that if the
match is !, it checks that it's a logical NOT rather than the !
suffix operator (syntactic sugar for Task.await; see URL
  `https://www.roc-lang.org/tutorial#the-!-suffix')."
      (and (prettify-symbols-default-compose-p start end match)
           (or (not (equal match "!"))
               (and
                ;; character before isn't a word character
                (not (eq (char-syntax (char-before start))
                         ?w))
                ;; character after is a word character or open paren
                (memq (char-syntax (char-after end))
                      '(?\( ?w))))))))

See also tad-lispy’s private module for Roc.

Features

STRT Syntax highlighting

Partially done.

After installing the package you need to install the Tree Sitter grammar. Run treesit-install-language-grammar and select roc. This should give you syntax highlighting.

Question: Should this be automated?

Relevant discussion: https://lists.gnu.org/archive/html/emacs-devel/2023-11/msg01365.html

STRT Indentation rules

Tree sitter is used to make some basic indentation rules that aim to be consistent with “roc format”, and there are tests to check that consistency. It’s still a work in progress, though.

Language server integration

NOTE: If you’re using Doom Emacs, the recommended configuration above already supports this.

You’ll need roc_language_server, which is distributed in Roc releases, in your PATH.

Option 1: Eglot

Emacs 29 comes with a built-in LSP client called Eglot. To integrate with it, add the following to your configuration:

(with-eval-after-load 'roc-ts-mode
  (require 'eglot)
  (add-to-list 'eglot-server-programs '(roc-ts-mode "roc_language_server"))
  (add-hook 'roc-ts-mode-hook #'eglot-ensure))

Option 2: LSP Mode

First, install lsp-mode if you haven’t. Then add the following to your configuration:

(with-eval-after-load 'roc-ts-mode
  (require 'lsp-mode)
  (add-to-list 'lsp-language-id-configuration '(roc-ts-mode . "roc"))
  (lsp-register-client (make-lsp-client :new-connection (lsp-stdio-connection "roc_ls")
                                        :activation-fn (lsp-activate-on "roc")
                                        :major-modes '(roc-ts-mode)
                                        :server-id 'roc_ls))
  (add-hook 'roc-ts-mode-hook #'lsp-deferred))

Roc CLI commands

You can use the following keybindings to run Roc CLI commands.

Default keybindingEmacs roc-ts-mode commandCLI commandDescription
C-c C-froc-ts-formatroc formatFormat the current buffer
C-c C-broc-ts-buildroc buildBuild the current file
C-c C-troc-ts-testroc testTest the current file
C-c C-rroc-ts-runroc runRun tests in the current file (and modules it imports)
C-c C-droc-ts-devroc devCheck current file, then run if no errors
C-c C-croc-ts-checkroc checkCheck current file for errors
C-c C-eroc-ts-replroc replOpen a Roc REPL buffer
N/Aroc-ts-versionroc versionPrint and copy the current version of Roc

If the roc CLI isn’t on your PATH, you can set roc-ts-program to the right executable path.

To use the experimental roc-ts-start-... commands, ~roc-start~ must be installed:

Default keybindingEmacs roc-ts-start commandCLI commandDescription
C-c C-s C-aroc-ts-start-approc-start appStart a new Roc app with roc-start
C-c C-s C-proc-ts-start-pkgroc-start replStart a new Roc package with roc-start
C-c C-s C-uroc-ts-start-updateroc-start updateFetch the latest packages, platforms, and app stubs

Navigation

Commands like beginning-of-defun (C-M-a by default), end-of-defun (C-M-e), and mark-defun (C-M-h) are supported. In Doom Emacs, that also means you can use the f text object (e.g., use d i f to delete the current function).

imenu (M-g i) is also supported.

Tree-sitter-based code folding is supported using the Hideshow minor mode.

License

GPLv3

About

An Emacs major mode for the Roc programming language (mirror of https://gitlab.com/tad-lispy/roc-ts-mode/, which I'm a co-maintainer of)

Resources

License

Stars

Watchers

Forks

Contributors 2

  •  
  •