Skip to content

Create Emacs mode for LUMOS #48

@rz1989s

Description

@rz1989s

Goal

Create an Emacs major mode for LUMOS with syntax highlighting and LSP integration.

Phase: 5.2 IDE Integration
Depends On: #45 (LSP implementation)


Problem

Emacs users have no LUMOS support:

  • ❌ No syntax highlighting
  • ❌ No auto-completion
  • ❌ No diagnostics
  • ❌ Files treated as fundamental-mode

Solution

Create lumos-mode with syntax highlighting and lsp-mode integration.


Implementation

File Structure

lumos-mode/
├── lumos-mode.el       # Main mode definition
├── lumos-mode-test.el  # Tests
└── README.md

Major Mode Implementation

File: lumos-mode.el

;;; lumos-mode.el --- Major mode for LUMOS schema language -*- lexical-binding: t -*-

;; Author: LUMOS Contributors
;; Version: 0.1.0
;; Package-Requires: ((emacs "26.1") (lsp-mode "8.0"))
;; Keywords: languages
;; URL: https://github.com/getlumos/lumos-mode

;;; Commentary:
;; Major mode for editing LUMOS schema files (.lumos)

;;; Code:

(require 'lsp-mode)

;; Syntax highlighting
(defvar lumos-mode-font-lock-keywords
  (let ((keywords '("struct" "enum" "pub"))
        (types '("u8" "u16" "u32" "u64" "u128"
                 "i8" "i16" "i32" "i64" "i128"
                 "bool" "String"
                 "PublicKey" "Signature"
                 "Vec" "Option"))
        (attributes '("solana" "account" "version" "deprecated")))
    `((,(regexp-opt keywords 'words) . font-lock-keyword-face)
      (,(regexp-opt types 'words) . font-lock-type-face)
      ("#\\[\\(.*?\\)\\]" (1 font-lock-preprocessor-face))
      (,(regexp-opt attributes 'words) . font-lock-constant-face)
      ("//.*$" . font-lock-comment-face)
      ("/\\*\\(.\\|\n\\)*?\\*/" . font-lock-comment-face))))

;; Indentation
(defun lumos-indent-line ()
  "Indent current line as LUMOS code."
  (interactive)
  (beginning-of-line)
  (if (bobp)
      (indent-line-to 0)
    (let ((not-indented t) cur-indent)
      (if (looking-at "^[ \t]*}")
          (progn
            (save-excursion
              (forward-line -1)
              (setq cur-indent (- (current-indentation) 2)))
            (if (< cur-indent 0)
                (setq cur-indent 0)))
        (save-excursion
          (while not-indented
            (forward-line -1)
            (if (looking-at "^[ \t]*}")
                (progn
                  (setq cur-indent (current-indentation))
                  (setq not-indented nil))
              (if (looking-at ".*{[ \t]*$")
                  (progn
                    (setq cur-indent (+ (current-indentation) 2))
                    (setq not-indented nil))
                (if (bobp)
                    (setq not-indented nil)))))))
      (if cur-indent
          (indent-line-to cur-indent)
        (indent-line-to 0)))))

;; LSP setup
(defgroup lumos nil
  "LUMOS language support."
  :group 'languages)

(defcustom lumos-lsp-server-command '("lumos-lsp")
  "Command to start LUMOS LSP server."
  :type '(repeat string)
  :group 'lumos)

(add-to-list 'lsp-language-id-configuration '(lumos-mode . "lumos"))

(lsp-register-client
 (make-lsp-client
  :new-connection (lsp-stdio-connection
                   (lambda () lumos-lsp-server-command))
  :major-modes '(lumos-mode)
  :server-id 'lumos-lsp
  :priority -1))

;; Mode definition
;;;###autoload
(define-derived-mode lumos-mode prog-mode "LUMOS"
  "Major mode for editing LUMOS schema files."
  (setq-local font-lock-defaults '(lumos-mode-font-lock-keywords))
  (setq-local comment-start "// ")
  (setq-local comment-end "")
  (setq-local indent-line-function 'lumos-indent-line)
  
  ;; Enable LSP
  (when (featurep 'lsp-mode)
    (lsp-deferred)))

;; File association
;;;###autoload
(add-to-list 'auto-mode-alist '("\\.lumos\\'" . lumos-mode))

(provide 'lumos-mode)
;;; lumos-mode.el ends here

Installation

Using straight.el

(use-package lumos-mode
  :straight (lumos-mode :type git :host github :repo "getlumos/lumos-mode")
  :hook (lumos-mode . lsp-deferred))

Using package.el (MELPA)

(use-package lumos-mode
  :ensure t
  :hook (lumos-mode . lsp-deferred))

Manual Installation

;; Add to load path
(add-to-list 'load-path "~/.emacs.d/lisp/lumos-mode")

;; Load mode
(require 'lumos-mode)

;; Enable LSP
(add-hook 'lumos-mode-hook #'lsp-deferred)

Features

Syntax Highlighting

  • Keywords: struct, enum, pub
  • Types: u64, PublicKey, Vec, Option
  • Attributes: #[solana], #[account], #[version]
  • Comments: // and /* */

Indentation

  • Auto-indent on newline
  • Smart brace handling
  • Configurable indent width (default: 2 spaces)

LSP Integration (via lsp-mode)

  • Auto-completion (company-mode)
  • Diagnostics (flycheck)
  • Go to definition (M-.)
  • Find references (M-?)
  • Hover documentation
  • Code actions

Additional Features

  • Comment/uncomment region (M-;)
  • Electric pair mode (auto-close braces)
  • File type auto-detection

Configuration Example

(use-package lumos-mode
  :ensure t
  :custom
  (lumos-lsp-server-command '("lumos-lsp" "--log-level" "debug"))
  :hook
  ((lumos-mode . lsp-deferred)
   (lumos-mode . company-mode)
   (lumos-mode . flycheck-mode))
  :config
  ;; Custom keybindings
  (define-key lumos-mode-map (kbd "C-c C-c") 'lsp-execute-code-action)
  (define-key lumos-mode-map (kbd "C-c C-r") 'lsp-rename))

Testing

Test File

File: lumos-mode-test.el

(require 'ert)
(require 'lumos-mode)

(ert-deftest lumos-mode-loads ()
  "Test that lumos-mode loads without error."
  (with-temp-buffer
    (lumos-mode)
    (should (eq major-mode 'lumos-mode))))

(ert-deftest lumos-mode-file-association ()
  "Test that .lumos files use lumos-mode."
  (let ((buffer (find-file-noselect "test.lumos")))
    (with-current-buffer buffer
      (should (eq major-mode 'lumos-mode))
      (kill-buffer buffer))))

(ert-deftest lumos-mode-syntax-highlighting ()
  "Test that keywords are highlighted."
  (with-temp-buffer
    (lumos-mode)
    (insert "struct Player {}")
    (font-lock-ensure)
    (goto-char (point-min))
    (should (eq (get-text-property (point) 'face) 'font-lock-keyword-face))))

Run Tests

emacs -batch -l lumos-mode.el -l lumos-mode-test.el -f ert-run-tests-batch-and-exit

Publishing

Submit to MELPA

  1. Create PR to melpa/melpa
  2. Add recipe file:

File: recipes/lumos-mode

(lumos-mode :repo "getlumos/lumos-mode"
            :fetcher github
            :files ("*.el"))

GitHub Actions CI

name: CI

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        emacs_version:
          - 27.2
          - 28.2
          - 29.1
    steps:
      - uses: actions/checkout@v4
      - uses: purcell/setup-emacs@master
        with:
          version: ${{ matrix.emacs_version }}
      - name: Run tests
        run: make test

Success Criteria

  • Major mode loads without errors
  • .lumos files auto-detect lumos-mode
  • Syntax highlighting works
  • Indentation works correctly
  • LSP integration functional
  • Auto-completion works
  • Diagnostics show inline
  • Published to MELPA
  • Tests passing
  • Documentation complete

Documentation

Create New Files

  • lumos-mode/README.md - Emacs mode documentation
  • docs/editors/emacs.md - Setup guide for Emacs users

Update Files

  • README.md - Add Emacs installation instructions
  • CHANGELOG.md - Document mode release
  • ROADMAP.md - Mark Phase 5.2 item as complete ✅

Related


Priority: Low-Medium
Complexity: Medium
Timeline: 4-5 days
Depends On: #45


📌 Remember: Update ROADMAP.md after completing this issue!

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:ecosystemCross-repo initiatives and ecosystem-wide featuresarea:vscodeVSCode extension (syntax, commands, snippets)help wantedExtra attention is neededtype:featureNew feature or functionality

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions