From 915a3ba54c8ed1fa0346303f43ec1cb426710913 Mon Sep 17 00:00:00 2001 From: Nicolas Berthier Date: Wed, 10 May 2023 18:16:35 +0200 Subject: [PATCH 1/2] Draft version of basic superbol-mode for GNU/Emacs Also fix code for launching the LSP in VSCode platform --- .drom | 6 +- .gitignore | 1 + Makefile.header | 16 ++++ README.md | 18 +++- drom.toml | 1 + emacs/eglot-superbol.el | 42 +++++++++ emacs/lsp-superbol.el | 82 ++++++++++++++++ emacs/superbol-mode.el | 40 ++++++++ sphinx/emacs.rst | 94 ++++++++++++++++++- .../superbol_languageclient.ml | 30 +++--- 10 files changed, 304 insertions(+), 26 deletions(-) create mode 100644 emacs/eglot-superbol.el create mode 100644 emacs/lsp-superbol.el create mode 100644 emacs/superbol-mode.el diff --git a/.drom b/.drom index 14355d301..360a44d7d 100644 --- a/.drom +++ b/.drom @@ -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 @@ -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 @@ -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 diff --git a/.gitignore b/.gitignore index dc253ef39..cddd5ff5a 100644 --- a/.gitignore +++ b/.gitignore @@ -28,5 +28,6 @@ ATTIC !.vscode/launch.json *.vsix *.opam.locked +/emacs/lsp-superbol-customs.el diff --git a/Makefile.header b/Makefile.header index 2e74a1e72..7e49a3459 100644 --- a/Makefile.header +++ b/Makefile.header @@ -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 @@ -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")' \ diff --git a/README.md b/README.md index 7ee54668d..9b2fcddca 100644 --- a/README.md +++ b/README.md @@ -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 @@ -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 diff --git a/drom.toml b/drom.toml index 076b1a250..35341d3d6 100644 --- a/drom.toml +++ b/drom.toml @@ -87,6 +87,7 @@ ATTIC !.vscode/launch.json *.vsix *.opam.locked +/emacs/lsp-superbol-customs.el """ github-workflow-before-build = """ diff --git a/emacs/eglot-superbol.el b/emacs/eglot-superbol.el new file mode 100644 index 000000000..4de22a2e9 --- /dev/null +++ b/emacs/eglot-superbol.el @@ -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 diff --git a/emacs/lsp-superbol.el b/emacs/lsp-superbol.el new file mode 100644 index 000000000..80c0f8448 --- /dev/null +++ b/emacs/lsp-superbol.el @@ -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 diff --git a/emacs/superbol-mode.el b/emacs/superbol-mode.el new file mode 100644 index 000000000..cbba6dead --- /dev/null +++ b/emacs/superbol-mode.el @@ -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 diff --git a/sphinx/emacs.rst b/sphinx/emacs.rst index e4c52f965..e1f3de5f0 100644 --- a/sphinx/emacs.rst +++ b/sphinx/emacs.rst @@ -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` ----------------------------------- @@ -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 @@ -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=""; + 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 . diff --git a/src/vscode/superbol-vscode-platform/superbol_languageclient.ml b/src/vscode/superbol-vscode-platform/superbol_languageclient.ml index 008f44c4e..563d3a92e 100644 --- a/src/vscode/superbol-vscode-platform/superbol_languageclient.ml +++ b/src/vscode/superbol-vscode-platform/superbol_languageclient.ml @@ -12,21 +12,21 @@ (* *) (**************************************************************************) -let command = - Vscode.Workspace.getConfiguration () - |> Vscode.WorkspaceConfiguration.get ~section:"superbol.path" - |> function Some o -> Ojs.string_of_js o - | None -> "superbol" +let config = Vscode.Workspace.getConfiguration () -let args = ["x-lsp"] - -let serverOptions = Vscode_languageclient.ServerOptions.create +let serverOptions = + let command = + match Vscode.WorkspaceConfiguration.get ~section:"superbol.path" config with + | Some o -> Ojs.string_of_js o + | None -> "superbol-free" + in + Vscode_languageclient.ServerOptions.create () ~command - ~args - () - -let documentSelector = - [| `Filter (Vscode_languageclient.DocumentFilter.createLanguage ~language:"cobol" ()) |] - -let clientOptions = Vscode_languageclient.ClientOptions.create ~documentSelector () + ~args:["lsp"] +let clientOptions = + Vscode_languageclient.ClientOptions.create () + ~documentSelector:[| + `Filter (Vscode_languageclient.DocumentFilter.createLanguage () + ~language:"cobol"); + |] From 1206449363cdaea8775035eee3476a1283dd8fc3 Mon Sep 17 00:00:00 2001 From: Nicolas Berthier Date: Mon, 25 Sep 2023 16:38:58 +0200 Subject: [PATCH 2/2] Minor tweaks in documentation of Superbol-mode --- sphinx/emacs.rst | 53 ++++++++++++++++++++++++------------------------ 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/sphinx/emacs.rst b/sphinx/emacs.rst index e1f3de5f0..c43a09d54 100644 --- a/sphinx/emacs.rst +++ b/sphinx/emacs.rst @@ -2,10 +2,10 @@ 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. +GNU/Emacs. One makes use of a modified version of +:code:`cobol-mode.el` 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 powerful COBOL IDE. Standard file :code:`cobol-mode.el` ----------------------------------- @@ -56,39 +56,40 @@ 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`. +The new Superbol mode provides 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`_ appears to be the most prominent at the moment. This +client benefits from a large user-base, but is also considered +"bloated" by some. + +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 highlighting, semantic tokens-based +highlighting can drastically improve code readability of various +source code elements based on their syntactic location; .. _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 +Another possibility 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 +enabling the aforementioned `cobol-mode.el` provides reasonable syntax highlighting. .. _eglot: https://elpa.gnu.org/packages/eglot.html @@ -96,18 +97,18 @@ highlighting. 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: +Let us first define an environment variable that indicates where the +``superbol-free`` executable can be found. Additionally, define a +variable that points to the root of the source directory for the +extension: .. code-block:: shell export SUPERBOL_DIR=""; 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: +After this, the following command launches a GNU/Emacs instance with +an `lsp-mode`-based client configured for COBOL files: .. code-block:: shell