Exploring Picotron (Part 2): Patching System Apps

ยท 547 words ยท 3 minute read

Introduction ๐Ÿ”—

In the previous post, we saw that the built-in programs in Picotron are userland applications. Furthermore, their sources are available, which means, in theory, we can modify them to meet our needs. In this post, we will put that theory to the test.

Motivation ๐Ÿ”—

I noticed that the built-in Code Editor does not trailing whitespaces, a feature common in all modern text editors. Our goal here is to modify the Code Editor to add this functionality.

Exploring Code Editor ๐Ÿ”—

The Code Editor cartridge lives in /system/apps/code.p64. The code is surprisingly short because most of the heavy lifting is delegated to gui:attach_text_editor whose logic lives in /system/lib/gui_ed.lua. The code that handles saving the content to the file is helpfully commented:

-- save to obj
function ()
  return table.concat(ce:get_text(),"\n")
end,

Essentially, the default implementation joins every line into a giant string. This is the function that we will be changing to strip trailing whitespaces.

Patching the Code Editor ๐Ÿ”—

Because the Code Editor is just another cartridge, patching it is easy:

/> load /system/apps/code.p64

This will bring the cartridge into RAM. If we open the Code Editor workspace, we will see its code, including the function above.

There are probably a thousand and one ways to strip trailing whitespaces. The exact implementation is not important in this context. This is what I went with:

-- save to obj
function ()
  local text = ce:get_text()
  local lines = {}

  for i = 1, #text do
    local row = text[i]
    local trimmed = string.gsub(row, "%s*$", "")
    table.insert(lines, trimmed)
  end

  local all_text = table.concat(lines, "\n")
  return string.gsub(all_text, "\n*$", "\n")
end,

We can now press Ctrl + R to test out our modifications.

We have technically achieved our goal, but if we were to restart Picotron, our changes would go away because changes made to the /system directory do not persist. Of course, we can save the cartridge elsewhere, but it wouldn’t be like a “native” application – for example, clicking on the {} icon will not bring up our modified version.

To achieve that, we can replace the built-in Code Editor with our modified one. Roughly:

/> cp my-code.p64 /system/apps/code.p64

But we will have to do this manually every time Picotron starts. Or do we?

The boot process ๐Ÿ”—

In /system, we see two interesting files: boot.lua and startup.lua. From their names, it sounds like they are part of the boot process. However, being in the /system directory, we can’t change them either.

Scanning through them I saw that boot.lua will run startup.lua. startup.lua will in turn run /appdata/system/startup.lua, if it exists. Since /appdata is persisted, we can use this script to copy our modified Code Editor into /system/apps.

First, I save the modified Code Editor at /appdata/system/apps/code.p64:

/> mkdir /appdata/system/apps
/> save /appdata/system/apps/code.p64

Then I added the following to /appdata/system/startup.lua:

cp("/appdata/system/apps/code.p64", "/system/apps/code.p64")

Conclusion ๐Ÿ”—

Given that the built-in applications, not just the Code Editor, are just a bunch of userland applications, as we have demonstrated in this post, we can modify them to our hearts’ content. I am excited to see what the community will build. For a start, I think the Code Editor might benefit from having extensions – again, common among modern text editors – so that most of the customizations do not require patching the cartridge like we did here.