Skip to content

Commit

Permalink
Draft version of basic superbol-mode for GNU/Emacs
Browse files Browse the repository at this point in the history
Also fix code for launching the LSP in VSCode platform
  • Loading branch information
nberth committed Sep 25, 2023
1 parent fce50b1 commit 915a3ba
Show file tree
Hide file tree
Showing 10 changed files with 304 additions and 26 deletions.
6 changes: 3 additions & 3 deletions .drom
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ version:0.9.0

# hash of toml configuration files
# used for generation of all files
ce91e02d93482e19b68ff8b123bea8a3:.
8288a3cd2b32b2fada49d59ebfc4d900:.
# end context for .

# begin context for .github/workflows/workflow.yml
Expand All @@ -15,7 +15,7 @@ fc10b0887fb072e04e5bcbdd5a0c6668:.github/workflows/workflow.yml

# begin context for .gitignore
# file .gitignore
90b1808274a081597c6ff82400928561:.gitignore
0727863b8e681aec0cc8d969f8cfb747:.gitignore
# end context for .gitignore

# begin context for CHANGES.md
Expand All @@ -30,7 +30,7 @@ d00f73c835ae4a1589d55ebda4ab381b:CHANGES.md

# begin context for Makefile
# file Makefile
86f0208a874473207a92c1e552fa9cb5:Makefile
8c1798510e3d14cdfd80b0ebd931773b:Makefile
# end context for Makefile

# begin context for README.md
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,6 @@ ATTIC
!.vscode/launch.json
*.vsix
*.opam.locked
/emacs/lsp-superbol-customs.el


16 changes: 16 additions & 0 deletions Makefile.header
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
# -*- Makefile -*-
PROJECT=superbol_vscode_platform
SRCDIR=src/vscode/superbol-vscode-platform

# Emacs lsp-mode source directory (https://github.com/emacs-lsp/lsp-mode):
# (could be a submodule)
LSP_MODE_SRCDIR ?= ../lsp-mode

.PHONY: compile
compile: build
cp -f _build/default/src/vscode/vscode-package-json/main.exe vscode-package-json
Expand Down Expand Up @@ -33,3 +38,14 @@ opam-cross:
drom dep --cross osx
drom dep --cross windows

# emacs-lsp:
emacs/lsp-superbol-customs.el: $(LSP_MODE_SRCDIR) package.json
emacs --batch > "$@" \
--load "$(LSP_MODE_SRCDIR)/scripts/lsp-generate-settings.el" \
--eval "(dolist (l (lsp-generate-settings \"package.json\")) (print l))" \
&& echo "Generated $@" 1>&2 \
|| rm -f "$@"

# 8.0.1
# --eval "(princ (lsp-generate-settings \"package.json\" 'lsp-superbol))" \
# --eval '(princ "\n")' \
18 changes: 13 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
# Superbol VSCode Platform for COBOL
# Superbol Studio OSS: A New Platform for COBOL

## Features

* LSP (superbol) with following capabilities:
* LSP (`superbol-free`) with following capabilities:
* Syntax diagnostics
* Go to definitions
* Find references
* Peek on copybook (Superbol PR #211)
* Semantic highlighting (Superbol PR #212)
* Peek on copybook and source text replacements
* Semantic highlighting
* File and range indentation

## Install
* VSCode extension

* GNU/Emacs mode

## VSCode Extension

### From binary and VSIX

Expand Down Expand Up @@ -65,6 +69,10 @@ In the `superbol` field past the path to the `superbol` executable.

You can check the documentation on using the extension on [this page](https://ocamlpro.github.io/superbol-vscode-platform/sphinx).

## GNU/Emacs mode

You can check the documentation on using the Superbol LSP with GNU/Emacs on [this page](https://ocamlpro.github.io/superbol-vscode-platform/sphinx/emacs.html).

## Resources

* Website: https://ocamlpro.github.io/superbol-vscode-platform
Expand Down
1 change: 1 addition & 0 deletions drom.toml
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ ATTIC
!.vscode/launch.json
*.vsix
*.opam.locked
/emacs/lsp-superbol-customs.el
"""
github-workflow-before-build = """
Expand Down
42 changes: 42 additions & 0 deletions emacs/eglot-superbol.el
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
;;; lsp-superbol.el --- Eglot LSP client for Superbol COBOL -*- lexical-binding: t; -*-
;;
;; Copyright (c) 2023 OCamlPro SAS
;;
;; All rights reserved.
;; This source code is licensed under the MIT license found in the
;; LICENSE.md file in the root directory of this source tree.

;;; Commentary:

;; Eglot LSP client for Superbol COBOL

;;; Code:

(unless (fboundp 'eglot)
(load "eglot-autoloads"))

(require 'eglot)
(require 'superbol-mode)

(defun eglot-superbol--start ()
"Superbol LSP startup function for Eglot"

;; Actually start the LSP server
(eglot-ensure)

;; Turn on fontification (even if minimal)
(funcall font-lock-fontify-buffer-function))

(add-to-list 'eglot-server-programs '(superbol-mode . ("superbol-free" "lsp")))
(add-to-list 'eglot-server-programs '(cobol-mode . ("superbol-free" "lsp")))

;; Autostart the LSP when entering superbol-mode
(add-hook 'superbol-mode-hook #'eglot-superbol--start)

;; Also load on cobol-mode
(with-eval-after-load 'cobol-mode
(add-hook 'cobol-mode-hook #'eglot-superbol--start))

(provide 'eglot-superbol)

;;; eglot-superbol.el ends here
82 changes: 82 additions & 0 deletions emacs/lsp-superbol.el
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
;;; lsp-superbol.el --- lsp-mode LSP client for Superbol COBOL -*- lexical-binding: t; -*-
;;
;; Copyright (c) 2023 OCamlPro SAS
;;
;; All rights reserved.
;; This source code is licensed under the MIT license found in the
;; LICENSE.md file in the root directory of this source tree.

;;; Commentary:

;; lsp-mode.el LSP client for Superbol COBOL

;;; Code:

(unless (fboundp 'lsp-mode)
(load "lsp-mode-autoloads"))

(require 'lsp-mode)
(require 'superbol-mode)

;; ---

(defgroup lsp-superbol nil
"Settings for the Superbol Language Server for COBOL (lsp-mode)."
:group 'lsp-mode
:link '(url-link "https://github.com/OCamlPro/superbol-vscode-extension")
:package-version '(lsp-mode . "8.0.1"))

(load (expand-file-name "lsp-superbol-customs.el"
(file-name-directory load-file-name)))

;; ---

(defun lsp-superbol--server-command ()
"Startup command for the Superbol LSP language server."
;; (list (lsp-package-path 'superbol-language-server) "lsp"))
(list (expand-file-name "superbol-free" lsp-superbol-path) "lsp"))

;; (lsp-dependency 'superbol-language-server
;; `(:system ,(executable-find (lsp-package-path 'superbol-language-server))))
;; '(:system "superbol-language-server"))

(lsp-register-client
(make-lsp-client
:new-connection (lsp-stdio-connection #'lsp-superbol--server-command)
:priority 0
:activation-fn (lsp-activate-on "superbol" "cobol" "COBOL")
:server-id 'superbol-ls
))

;; ---

;; (with-eval-after-load 'superbol-mode
(add-to-list 'lsp-language-id-configuration '(superbol-mode . "cobol"))
(add-to-list 'lsp-language-id-configuration '(cobol-mode . "cobol"))

(defun lsp-superbol--start ()
"Superbol LSP startup function for lsp-mode"

;; Enable semantic tokens
(set (make-local-variable 'lsp-semantic-tokens-enable) t)

;; Actually start the LSP server
(lsp)

;; Turn on fontification
(funcall font-lock-fontify-buffer-function))

;; Autostart the LSP when entering superbol-mode
(add-hook 'superbol-mode-hook #'lsp-superbol--start)

;; Also load on cobol-mode
(with-eval-after-load 'cobol-mode
(add-hook 'cobol-mode-hook #'lsp-superbol--start))

;; ---

(lsp-consistency-check lsp-superbol)

(provide 'lsp-superbol)

;;; lsp-superbol.el ends here
40 changes: 40 additions & 0 deletions emacs/superbol-mode.el
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
;;; superbol-mode.el --- Superbol COBOL major mode -*- lexical-binding: t; -*-
;;
;; Copyright (c) 2023 OCamlPro SAS
;;
;; All rights reserved.
;; This source code is licensed under the MIT license found in the
;; LICENSE.md file in the root directory of this source tree.

;;; Commentary:

;; Major mode for editing COBOL files using Superbol as a LSP server

;;; Code:

;; CHECKME: Force association right here?
(defun superbol-mode-enable-for-default-extensions ()
"Automatically associate `superbol-mode` with a few common COBOL file
extensions."
(dolist (regex '("\\.[cC][oO][bB]\\'"
"\\.[cC][bB][lL]\\'"
"\\.[cC][pP][yY]\\'"))
(add-to-list 'auto-mode-alist `(,regex . superbol-mode))))

;;;###autoload
(define-derived-mode superbol-mode prog-mode
"Superbol"
"SUPERBOL mode is a major mode for handling COBOL files. It is mostly intended
to be backed by an LSP."
;; XXX: could actually derive from cobol-mode, if available.

;; Straight from cobol-mode
(set (make-local-variable 'comment-start-skip)
"\\(^.\\{6\\}\\*\\|\\*>\\)\\s-* *")
(set (make-local-variable 'comment-start) "*>")
(set (make-local-variable 'comment-end) ""))

;; ---

(provide 'superbol-mode)
;;; superbol-mode.el ends here
94 changes: 91 additions & 3 deletions sphinx/emacs.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
Emacs modes
===========
GNU/Emacs modes
===============

We document two means that are available for editing COBOL files using
GNU/Emacs. One makes use of a modified version of :code:`cobol-mode`
that can be found on ELPA. The other is a new mode,
:code:`superbol-mode`, that simply makes use of the LSP to provide a
poweful COBOL IDE.

Standard file :code:`cobol-mode.el`
-----------------------------------
Expand Down Expand Up @@ -30,7 +36,7 @@ change this option using :code:`M-x customize`, save and then restart emacs.
Features
~~~~~~~~

The :code:`cobol-mode.el` provides a following features:
The :code:`cobol-mode.el` provides the following features:

* colorization
* indentation
Expand All @@ -46,3 +52,85 @@ Customization
We advise to also use the :code:`auto-complete` mode also. This mode
will propose completions while typing keywords (use TAB or RET to
complete).

Superbol-mode
-------------

The new Superbol mode is intended to provide an IDE that makes use of
the Superbol LSP to provide advanced navigation and editing facilities
for COBOL projects. It can be used in combination with any of the two
main LSP clients that exist within the GNU/Emacs ecosystem to interact
with LSP servers: `lsp-mode` and `eglot`.

Superbol-mode with `lsp-mode`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

`lsp-mode`_ appears to be the most prominent at the moment. The main
advantages for using it in our context is its support for `semantic
tokens`_, that provide a way for LSPs to issue information about the
semantics of symbols from the source code. Compared to traditional
regexp-based hightligting, semantic tokens provided by LSPs can
drastically improve code readability via more detailed hightligting of
source code elements;

.. _lsp-mode: https://github.com/emacs-lsp/lsp-mode
.. _semantic tokens:
https://code.visualstudio.com/api/language-extensions/semantic-highlight-guide

`lsp-mode` benefits from a large user-base, but is also considered
"bloated" by some.

Superbol-mode with `eglot`
~~~~~~~~~~~~~~~~~~~~~~~~~~~

Another possiblity is to use `eglot`_, that is sometimes considered
easier to configure and more lightweight than `lsp-mode` (which
notably makes it more reactive to user inputs). Being more recent, it
lacks some of the features of `lsp-mode`, among which is the support
for semantic tokens [#eglot-semtok-issue]_. However, additionally
enabling the aforementioned `cobol-mode` provides reasonable syntax
highlighting.

.. _eglot: https://elpa.gnu.org/packages/eglot.html

Setup
~~~~~

To ease the setup process, we first define an environment variable
that indicates where the ``superbol-free`` executable can be found.
We additionally define a variable that points to the root of the
source directory for the extension:

.. code-block:: shell
export SUPERBOL_DIR="<directory where superbol-free can be found>";
export SUPERBOL_VSCODE_PLATFORM_DIR="$PWD";
Then, the following command launches a GNU/Emacs instance with an
`lsp-mode`-based client configured for COBOL files:

.. code-block:: shell
emacs -L "$SUPERBOL_VSCODE_PLATFORM_DIR/emacs" \
--load lsp-superbol \
--eval "(custom-set-variables '(lsp-superbol-path \"$SUPERBOL_DIR\"))" \
--funcall superbol-mode-enable-for-default-extensions
To use `eglot`, type the following instead:

.. code-block:: shell
emacs -L "$SUPERBOL_VSCODE_PLATFORM_DIR/emacs" \
--load eglot-superbol \
--eval "(add-to-list 'exec-path \"$SUPERBOL_DIR\")" \
--funcall superbol-mode-enable-for-default-extensions
Further configuration for auto-indentation:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

`lsp-mode` provides a ``lsp-format-region`` function that may be used
to use the LSP-provided intentation. When using `eglot`, the same
functionality is provided by ``eglot-format``.

.. [#eglot-semtok-issue] Note there is a pending issue on this point
at https://github.com/joaotavora/eglot/issues/615 .
Loading

0 comments on commit 915a3ba

Please sign in to comment.