Neovim for Aston University CompSci

How-to guide for using neovim as an all-in-one IDE on the Computer Science course at Aston University. This is highly opinionated and written with a GNU/Linux system in mind.


CS1OOP

On this module, the university expects people to use certain software, and provides no support to anyone that falls outside those expectations.

Processing

The first bit of software is the Processing IDE, for writing processing which is a java-like language for learning how to code. But it is not available in most distro repos, and either way, you might not want to use their IDE since it has a very limited feature set.

Luckily though, you can also use (neo)vim.

Personally I did not install that plugin and I simply downloaded the ftdetect and syntax files from it. To run my sketches, I just ran `processing-java` in a terminal. Here is a wrapper I made as a "quick run":


    #!/bin/bash
    SKETCH=$(pwd)
    if [[ $# -ne 0 ]]; then
    	SKETCH=$(realpath $1)
    fi
    processing-java --sketch=$SKETCH --run
                

There is no LSP server for processing, so you'll have to do without any fancier IDE features. However, it is similar enough to java that you might be able to hack jdtls into working on it, but I haven't tried that. An inferior alternative is to setup your completion plugin to use the current open buffer as a completion source instead. Here is an example for nvim-cmp:


    vim.api.nvim_create_autocmd("FileType", {
      -- none or any other group you want
      group = vim.api.nvim_create_augroup("ProcessingCmp", {clear = true}),
      pattern = {"processing"},
      callback = function()
        require("cmp").setup.buffer({sources = {{name = "buffer"}}})
      end,
    })
                

Java

For java, Aston University wants students to use Eclipse. I don't think Eclipse is a bad IDE, but I still prefer using neovim which I use for programming in all other languages as well. So, here is a quick-start guide for using neovim instead.

The most important plugin is nvim-jdtls. It only needs eclipse.jdt.ls but there are more dependecies to get the most out of it. In this guide, I will use a directory at $HOME/.local/share/java-ide to store all the needed software that will be installed, although you can use any other path you choose for your system.

=> You should make sure you have at least a Java 17 (or newer) SDK and a Python 3.9 or newer installed.

Firstly, install the Eclipse JDT Language Server. You might be able to do this through your package manager, but if not download or build it from the github repository. Now, I'll assume you downloaded jdt.ls manually and unarchived it into $HOME/.local/share/java-ide/jdt-ls.

Next, you should install java-debug and vscode-java-test.

Now that all of the dependencies are installed, you can get to setting up neovim. Using your favourite plugin manager, install:

After installing all of those plugins you should also install telescope-dap by saving the dap.lua file from the repo into the $XDG_DATA_HOME/nvim/your-plugin-manager/telescope.nvim/lua/telescope/_extensions directory *note: replace 'your-plugin-manager' with the directory structure of your plugin manager

Here is a minimal configuration using lazy.nvim:


    {
      {
        "mfussenegger/nvim-dap",
        -- Load the other two along with this
        dependencies = {
          "rcarriga/nvim-dap-ui",
          "theHamsta/nvim-dap-virtual-text",
          "nvim-telescope/telescope.nvim",
        },
        lazy = true,
        ft = { "java" },
        config = function()
          require("telescope").load_extension("dap")
        end
      },
      {
        "rcarriga/nvim-dap-ui",
        dependencies = {
          "mfussenegger/nvim-dap",
          "nvim-neotest/nvim-nio",
        },
        lazy = true,
        config = function()
          require("dapui").setup({})
        end
      },
      {
        "theHamsta/nvim-dap-virtual-text",
        dependencies = { "mfussenegger/nvim-dap" },
        lazy = true,
        opts = {
          enabled = true,
        }
      },
      {
        "mfussenegger/nvim-jdtls",
        lazy = true,
        ft = {"java"},
      }
    }
                

Finally, you will need to setup nvim-jdtls. This is done in $XDG_CONFIG_HOME/nvim/ftplugin/java.lua. There are instructions for doing this in the README of nvim-jdtls. Here is my full configuration for reference.


    local home = os.getenv("HOME")

    -- get capabilities from your completion plugin. here I use nvim-cmp
    local capabilities = require("cmp_nvim_lsp").default_capabilities()

    -- figure out the workspace name
    -- if you have a better way use that instead
    local root_markers = {"gradlew", "mvnw", ".git", "pom.xml"}
    local root_dir = require("jdtls.setup").find_root(root_markers)

    -- I am using $HOME/.local/share/eclipse/project_name as my data dir
    -- but you can set this to be anything you want. It simply needs to be unique per project.
    local workspace_dir = home .. "/.local/share/eclipse/" .. vim.fn.fnamemodify(root_dir, ":p:h:t")

    -- load java-debug
    -- replace path with where you installed java-debug
    local bundles = {
      vim.fn.glob(
        home ..
        "/.local/share/java-ide/com.microsoft.java.debug.plugin/target/com.microsoft.java.debug.plugin-*.jar",
        true
      )
    }

    -- load vscode-java-test
    -- replace path with where you installed vscode-java-test
    for _, bundle in ipairs(
      vim.split(
        vim.fn.glob(
          home ..
          "/.local/share/java-ide/vscode-java-test/server/*.jar"
        ),
        '\n')
      ) do
      table.insert(bundles, bundle)
    end

    -- nvim-jdtls options
    local opts = {
      capabilites = capabilities,
      cmd = {
        -- path of your Java 17 (or newer) binary that will be used to run jdtls
        "/usr/bin/java",

        "-Declipse.application=org.eclipse.jdt.ls.core.id1",
        "-Dosgi.bundles.defaultStartLevel=4",
        "-Declipse.product=org.eclipse.jdt.ls.core.product",
        "-Dlog.protocol=true",
        "-Dlog.level=ALL",

        -- max memory the LSP can take
        "-Xmx1g",

        "--add-modules=ALL-SYSTEM",
        "--add-opens", "java.base/java.util=ALL-UNNAMED",
        "--add-opens", "java.base/java.lang=ALL-UNNAMED",

        -- replace _1.6.700.v20240213-1244 with the version of jdtls that you downloaded
        "-jar",
        home ..
        "/.local/java-ide/jdt-ls/plugins/org.eclipse.equinox.launcher_1.6.700.v20240213-1244.jar",

        "-configuration", home .. "/.local/java-ide/jdt-ls/config_linux",
        "-data", workspace_dir,
      },
      root_dir = root_dir,
      -- jdtls settings
      settings = {
        java = {
          configuration = {
            runtimes = {
              {
                name = "JavaSE-17",
                path = "/usr/lib/jvm/openjdk17/bin/java",
                default = true,
              },
              {
                name = "JavaSE-21",
                path = "/usr/lib/jvm/openjdk21/bin/java",
              },
            },
          },
        },
      },
      init_options = {
        bundles = bundles,
      },
    }

    require("jdtls").start_or_attach(opts)
                

nvim-jdtls can work without most of that configuration, but it might not be the way you expect it. For example, you can omit adding any java runtimes, but this will cause the lsp server to always use the java version that it's running on and will not provide documentation for the standard library among other things.

You should also set some keybinds for nvim-jdtls, LSP and, DAP (& dapui) to have a complete experience. With that, your neovim should be ready for java development.


Aston AutoFeedback and other "Runnables"

For some odd reason, none of the labs documents ever mention this, but you can upload to autofeedback without using their ".launch" files. The same applies for the JavaFX run and any other files like that. Simply open up the file you want to run and check its M2_GOALS key. Whatever the value of that key is what you should pass as the target to maven. For example, uploading to autofeedback is as simple as running mvn -f pom.xml autofeedback:uploadSubmission in a terminal. Obviously, you will need to have maven installed on your computer. There are probably vim plugins for interacting with maven, but I found this to be suitably simple and easy enough.

Alternatively, you can setup a script (or even a vim function) that reads the target from the file and runs it. You can then keybind that as well to make it even more comfortable.

Another thing that you might be asked to do is run classes by right-clicking on their respective package in Eclipse. Afaik, there is no equivalent to this in nvim-jdtls, but what you can do is use nvim-dap to launch a debug-session for any class with a main() function. This can be done by running :lua require("dap").continue() which will bring up a telescope UI for selecting a class if there are multiple with main() functions. I have bound this to <space>dc as a "quick-run" keybind.

If you get a notification that there are no configurations available, run :JdtUpdateDebugConfig. If that doesn't work, try running :JdtUpdateConfig first.


JUnit and other testing frameworks

To run tests with nvim-jdtls and dap, you can open the tests class and run :lua require("jdtls").test_class() for running all tests, and :lua require("jdtls").test_nearest_method() for only running the test nearest to your cursor. This will run the tests via nvim-dap, so you should open the dap UI to see the results.

You can bind these to something more comfortable. I use <space>tc and <space>tm respectively.

If that is not suitable for you, you can install the neotest-java plugin, which uses neotest for interacting with tests. I don't use this however, so you should look into setting it up yourself.


PlantUML

You should download the plantuml.jar file if you plan on making PlantUML diagrams, but it is not needed if all you want to do is edit the PlantUML text files. There are multiple plugins that add PlantUML support to neovim. I recommend plantuml-syntax. You can also install plantuml-previewer but plantuml-syntax is good enough for me personaly.


What about JavaFX?

Unfortunately, there is no support for JavaFX files for vim. I just treat the fxml files as normal xml syntax, although there are differences. I have also tried getting an XML language server working but it does not seem doable without major modifications. Unless you're in for a coding adventure to make your own JavaFX plugin, there is nothing more you can do it improve your experience writing JavaFX scripts.