Why a Mini-IDE for the Agon Light?

In an earlier post I introduced my Python script agon_automate.py, which sends commands to the Agon Light and runs automations or remote control tasks on it. No keyboard switching, no typing things in by hand.

Still, it gets tedious when you sit in your editor and just want to push a program over to the physical Agon Light (or the Console 8) and start it. Especially during development, when you do that all day long.

As a fan of vi, vim and particularly neovim, I put together a small „IDE" for neovim. With it I write my BBC Basic programs comfortably on my main machine and send them to the Agon with a short command. No switching apps, no typing the filename.

Hooking the Automation Script into neovim

I mostly live in neovim, but since some people prefer VIM I ported the script over as well. I’ll explain everything from the neovim side first, because I wrote the script natively in Lua (neovim’s scripting language). The VIM version sits at the bottom of this post. Less thoroughly tested, but it works.

-- Save file, transfer to Agon und Run it.
vim.cmd [[ command! AgonRun :w ++ff=dos | :!python ~/bin/agon_automate.py script ~/bin/agonbasic.script % ]]

-- Send one short command to Agon
vim.cmd [[command! -nargs=1 AgonCommand execute ':!python ~/bin/agon_automate.py direct <args>' | redraw!]]

-- Add the command AgonPaste to NeoVim
vim.api.nvim_create_user_command('AgonPaste', function()
  -- Determine the path for the temporary file in the temp directory
  local temp_file_path = vim.fn.tempname() .. "_AgonPaste.tmp"

  -- Open the temporary file in write mode
  local file = io.open(temp_file_path, "w")
  if not file then
    print("Error opening file: " .. temp_file_path)
    return
  end

  -- Get the content of the register
  local register_content = vim.fn.getreg('"')

  -- Write the content to the file and close the file
  file:write(register_content)
  file:close()

  -- Execute the external Python command with the script mode
  local command = "python " .. vim.loop.os_homedir() .. "/bin/agon_automate.py script " .. temp_file_path
  vim.fn.system(command)

  -- Remove the temporary file after sending
  os.remove(temp_file_path)
end, {})

Drop the script into a place your neovim config actually loads. Usually that’s init.lua under .config/nvim/init.lua. For more elaborate setups it might live elsewhere, for example in a folder or file under .config/nvim/lua/.

One thing to watch out for: if you have an init.vim, neovim is running VimScript, not Lua natively. Since init.lua is loaded first, your existing config might stop being applied. In that case this line in init.lua helps: vim.cmd('source ~/.config/nvim/init.vim').

There is no single standard for neovim configs, so with a more complex setup the file may have a different name.

Please adapt the script to your environment. That means python vs python3 and the correct paths to agon_automate.py and your automation script (mine is agonbasic.script). Specifically these three lines:

vim.cmd [[ command! AgonRun :w ++ff=dos | :!python ~/bin/agon_automate.py script ~/bin/agonbasic.script % ]]
...
vim.cmd [[command! -nargs=1 AgonCommand execute ':!python ~/bin/agon_automate.py direct <args>' | redraw!]]
...
local command = "python " .. vim.loop.os_homedir() .. "/bin/agon_automate.py script " .. temp_file_path

Reload neovim, open some BBC Basic code and have a play.

What can I actually do with it?

The script exposes three commands. In vi you trigger commands from Normal mode with a colon. So instead of pressing i for Insert, you press : and type one of the commands below.

AgonCommand

Sends short commands straight from the editor to the Agon Light.

:AgonCommand LIST

That fires LIST at the Agon to list a BBC Basic program. If you know agon_automate.py already, it is the same as running python agon_automate.py direct "LIST" in the terminal.

AgonRun

This saves the current file in DOS line-ending format (the Agon struggles with Unix line endings) and kicks off the automation.

You need to point the script to agon_automate.py and to your automation script (mine is ~/bin/agonbasic.script). My automation script looks like this:

*BYE
hexload vdp {FILENAME}
{COMMAND python ~/bin/send.py {FILENAME} {DEVICE}}{WAIT 2}
load /bbcbasic.bin
run
LOAD "{FILENAME}"
{WAIT 2}
RUN

You can build a different one for whatever workflow you need, not just Basic. Mine is tailored to my BBC Basic workflow on the Agon.

The current file’s name is passed automatically.

:AgonRun

No extra parameters. The file gets saved, transferred, loaded and executed. Or whatever your own automation does. Same effect as python agon_automate.py script agonbasic.script filename.

AgonPaste

This is the real time saver. You have pushed your code to the Agon with AgonRun and started it. Now you want to change a single line.

Instead of editing it directly on the Agon (and ending up with two versions) or re-transferring everything, you copy the line in neovim with yy (yank line) and run:

:AgonPaste

Quick refresher: in vi most things pass through the default buffer, kind of like a clipboard. Anything you delete with dd or copy with yy ends up there. AgonPaste sends exactly that buffer to the Agon. You can also mark multiple lines with V, yank them with y, and transfer them.

In the video I change a line in the BASIC program Matrix, press yy on that line and run :AgonPaste. The change goes over. Then I restart the program on the Agon with :AgonCommand RUN.

If you know vi, it will be clear that you can push more than one line this way (5yy for five lines, or V for visual mode and then y).

VIM

Functionally identical. The only difference is that the script is written in VimScript, because VIM doesn’t natively understand Lua. The file you want is ~/.vimrc or ~/.config/nvim/init.vim. Drop the script below in there, everything else works as described above.

The whole setup is built around my BBC Basic workflow, but you can easily rework the pieces for your own needs.

" Save the current file with DOS file format and run a Python script with the current file as an argument
command! AgonRun w ++ff=dos | !python3 ~/bin/agon_automate.py script ~/bin/agonbasic.script %

" Send a single command to the Python script directly
command! -nargs=1 AgonCommand execute '!python3 ~/bin/agon_automate.py direct <args>' | redraw!

" Define a function to paste the content of the default register into a temporary file and execute a Python script with it
function! AgonPaste()
  " Create a temporary file path
  let temp_file_path = tempname() . "_AgonPaste.tmp"

  " Write the content of the default register to the temporary file
  call writefile([getreg('"')], temp_file_path)

  " Execute the Python script with the temporary file
  let command = 'python3 ' . $HOME . '/bin/agon_automate.py script ' . temp_file_path
  call system(command)

  " Remove the temporary file
  call delete(temp_file_path)
endfunction
command! AgonPaste call AgonPaste()

I gave the VIM script a quick run and it works. Since I mostly stay in neovim though, I can’t say much about its long-term stability.

If you run into questions, hit a snag, or just want to drop a friendly note, leave a comment.