Mnemo

Usage

Collect Mnemosyne Logs

Run Mnemosyne from the Docker image collecting logging output:

docker run --rm -p 10003:10003 mnemo/argot-server \
|tee ~/.argot-server/argot-$(date +%Y-%m-%d-%H-%M-%S).log

Install and Run Mnemosyne Locally

Assuming you have a local Common Lisp environment with Quicklisp, you need only:

Set up Argot Server

  1. If you don’t already have it, install Quicklisp.

  2. Make sure your ASDF is recent enough:

    (asdf:asdf-version)

    If your version is < 3.3.4.3, you can upgrade by copying a newer version of ASDF in your ~/common-lisp directory, creating it if necessary:

    mkdir -p ~/common-lisp
    curl https://gitlab.common-lisp.net/asdf/asdf/-/archive/3.3.4.3/asdf-3.3.4.3.tar.gz | tar xzC ~/common-lisp
  3. Clone the Argot-server and its dependency repositories into your ~/quicklisp/local-projects directory:

    cd ~/quicklisp/local-projects
    git clone https://gitlab.com/GrammaTech/Mnemosyne/argot-server.git
    git clone https://gitlab.com/GrammaTech/Mnemosyne/jsonrpc.git
    git clone https://gitlab.com/GrammaTech/Mnemosyne/cl-lsp.git
    git clone https://gitlab.com/GrammaTech/Mnemosyne/lsp-server.git
    git clone --recurse-submodules https://gitlab.com/GrammaTech/Mnemosyne/argot.git
    git clone https://github.com/eschulte/cloogle.git
    # Assuming you have access
    git clone https://git.grammatech.com/synthesis/refactoring-mutations.git

    If you intend to work with Python, you should install pyls, and if you intend to work with JavaScript, you should install javascript-typescript-langserver

    pip install python-language-server[all]
    npm install -g javascript-typescript-langserver
  4. Evaluate the following Lisp code in your REPL to start the server:

    (ql:quickload '(:argot-server))
    (defparameter *argot-server* (argot-server:launch-server))

    This starts the server with all the muses currently available. Muses are enabled conditionally based on what is present in the environment: for instance, support for Python and JavaScript language servers depends on whether pyls or javascript-typescript-stdio are available on your path.

    After this command, Argot Server will be running in the background, and *argot-server* will be set to a handle you can use to stop the server with argot-server:server-handle-stop.

    Note that running Argot Server will result in log files being written under the ~/.argot-server/ directory.

Editor Setup

Install an LSP client for your editor. Most text editors and IDEs support LSP and Mnemosyne should work with most full featured LSP clients.

VS Code Walkthrough

Support for VS Code is provided through a Mnemosyne VS Code extension.

  1. Download the .vsix file for the latest release of the Mnemosyne extension from its releases page.

  2. Install the .vsix file in the usual way.

  3. Once the Argot Server is running, call Mnemosyne: Connect to Argot Server from the Command Palette.

  4. You can now request an LSP CodeAction. Open a new file, insert the following, and save it with a .js extension:

    // For JS
    const x = 2 + 2
    x + y

    Select the contents of the file. You should see a lightbulb icon appear to indicate code actions are available. You can click on the lightbulb, or press Ctrl+., to bring up a drop-down of code actions. Select Inline Variable and you should see:

    // For JS
    const x = 2 + 2
    2 + 2 + y

Emacs Walkthrough

  1. Emacs users can use Eglot. (If you already use [lsp-mode][], it should work, but is not tested.)

    Eglot requires at least Emacs 26.1. Users of older Ubuntu distributions can easily upgrade using a [PPA][].

    Eglot is included in the ELPA package repository, so assuming a clean Emacs, installation is as simple as M-x package-install eglot. Existing Emacs users may want to upgrade their installed packages first.

    It is possible to explicitly connect to Argot Server with C-u M-x eglot using localhost:10003 for the host and port. However, this will have to be repeated for each project in each language. It is easier to just configure Eglot to use Argot Server by default for the supported languages:

    (add-to-list 'eglot-server-programs '(lisp-mode . ("localhost" 10003)))
    (add-to-list 'eglot-server-programs '(js-mode . ("localhost" 10003)))
    (add-to-list 'eglot-server-programs '(python-mode . ("localhost" 10003)))
  2. From an Emacs buffer, in a Lisp, Python, or JavaScript project, connect to Argot with M-x eglot. Start working in this buffer and you'll see Eglot providing contextual information and completions. (You can see the raw LSP traffic with M-x eglot-events-buffer.)

  3. You can now request a generic LSP CodeAction. Place something like the following in an Emacs buffer (NOTE: this is a simple example to start):

    ;; For Lisp
    (let ((x (+ 2 2)))
    (+ y x))
    // For JS
    const x = 2 + 2
    x + y

    Then mark a region in the buffer containing the above form and no other forms and call M-x eglot-code-actions. This will send the region to the argot-lsp server which will return a list of applicable refactorings to Emacs. Hit TAB to view all possible refactorings. Try Inline Variable and you should see:

    ;; For Lisp
    (let ((x (+ 2 2)))
    (+ y (+ 2 2)))
    // For JS
    const x = 2 + 2
    2 + 2 + y

Vim Walkthrough

The easiest way to get running with Vim is to use LanguageClient-neovim, which notwithstanding its name supports Vim as well as Neovim.

  1. Install the Plug package manager. You will need curl and git.

    curl -fLo ~/.vim/autoload/plug.vim --create-dirs \
    https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim
  2. In your ~/.vim/vimrc, configure the language client (and, optionally, fzf for multi-entry selection).

    call plug#begin('~/.vim/plugged')

    Plug 'autozimu/LanguageClient-neovim', {
    \ 'branch': 'next',
    \ 'do': 'bash install.sh',
    \ }

    " (Optional) Multi-entry selection UI.
    Plug 'junegunn/fzf'

    call plug#end()

    " Required for operations modifying multiple buffers like rename.
    set hidden

    " Required for autocompletion operations.
    set omnifunc=LanguageClient#complete
    set completeopt+=longest,menuone

    let g:LanguageClient_serverCommands = {
    \ 'javascript': ['tcp://localhost:10003'],
    \ 'python': ['tcp://localhost:10003'],
    \ 'lisp': ['tcp://localhost:10003'],
    \ }
  3. In the shell, install the client by running:

    vim +PlugInstall +UpdateRemotePlugins +qa
  4. Restart Vim and find a JavaScript file. You can now request a generic LSP CodeAction. Place something like the following in an buffer:

    const x = 2 + 2
    x + y

    Then use visual mode to highlight the above form and type :call LanguageClient#textDocument_visualCodeAction(). This will send the region to the Argot Server which will return a list of applicable refactorings. (You may be prompted at this point to download fzf). Try Inline Variable and you should see:

    const x = 2 + 2
    2 + 2 + y

Install and Run Muses

See Muses for a list of potentially useful automated assistants. Installing multiple Muses is recommended as many collaborate together and their combined effect should be greater than the sum of their parts. Each Muse is an independent module which communicates with the Argot Server using LSP and Argot.

Mnemosyne-relevant LSP Commands and Extensions

For the moment, you have to explicitly ask for help. You can do this with an LSP Code Action Request. E.g., in Emacs with Eglot you trigger a code action by highlighting a region of code and then running M-x eglot-code-action.