New Scala 3 syntax in Emacs

Scala 3 has a new “quiet” syntax, which means it uses whitespace and indention to delineate blocks of code, instead of the parentheses. Currently emacs-scala-mode does not support this yet fully, and while it is in the works the quick solution is to turn of automatic indention for scala 3 projects. To achieve this two things are required, it needs to be detected that a scala file is part of a scala 3 project, and second the automatic indention and reformatting needs to be turned off.

A quick, and somewhat hacky, way to detect scala 3 projects is to check the build.sbt file for the version, using projectile to find the root of the project and searching for a scalaVersion to start with 3.

(defun is-scala3-project ()
  "Check if the current project is using scala3.

Loads the build.sbt file for the project and serach for the scalaVersion."
  (projectile-with-default-dir (projectile-project-root)
    (when (file-exists-p "build.sbt")
        (insert-file-contents "build.sbt")
        (search-forward "scalaVersion := \"3" nil t)))))

Now using emacs advice-add the function adding the hooks to indent and format can be modified to no longer no longer insert the hooks for automatic formatting

(defun with-disable-for-scala3 (orig-scala-mode-map:add-self-insert-hooks &rest arguments)
    "When using scala3 skip adding indention hooks."
    (unless (is-scala3-project)
      (apply orig-scala-mode-map:add-self-insert-hooks arguments)))

(advice-add #'scala-mode-map:add-self-insert-hooks :around #'with-disable-for-scala3)

To still have some indention but not use the scala syntax specific one, the indent-line-function needs to be replaced with one purely using the previous line for reference ignoring syntax.

(defun disable-scala-indent ()
  "In scala 3 indent line does not work as expected due to whitespace grammar."
  (when (is-scala3-project)
    (setq indent-line-function 'indent-relative-maybe)))

(add-hook 'scala-mode-hook #'disable-scala-indent)

While it is more convenient to have indention supported, while the issue in emacs-scala-mode is being worked on this provides a quick fix to still have scala 3 code formatted. Also with metals and lsp supporting scala 3, the buffer can be reformatted in case formatting is an issue.