Text & API Copyright (c) Panic Inc, PlaydateSDK License 1.0
Types and everything else Copyright (c) Peter Tripp, under the Apache License, Version 2.0 or the MIT license at your option.
LuaCATS stands for "Lua Comment And Type System", which is the system used by Sumneko's Lua Language Server for the sumneko.lua VSCode extension.
LuaCATS is method to provide machine readable Lua Type Annotations and comments enabling inline autocompletion and linting suggestions in your IDE. Super nifty!
- Clone this repo somewhere:
cd ~/code/
git clone https://github.com/notpeter/playdate-luacats
- Add the following to
.luarc.json
in your workspace and editworkspace.library
to reflect where you cloned playdate-luacats
{
"$schema": "https://raw.githubusercontent.com/sumneko/vscode-lua/master/setting/schema.json",
"diagnostics.globals": ["import"],
"diagnostics.severity": {
"duplicate-set-field": "Hint"
},
"format.defaultConfig": {
"indent_style": "space",
"indent_size": "4"
},
"runtime.builtin": {
"io": "disable",
"os": "disable",
"package": "disable"
},
"runtime.nonstandardSymbol": ["+=", "-=", "*=", "/=", "//=", "%=", "<<=", ">>=", "&=", "|=", "^="],
"runtime.version": "Lua 5.4",
"workspace.library": [
"/Users/peter/code/playdate-luacats"
]
}
- Enable LuaLS (Lua Language Server) support for your editor:
Editor | Instructions | Link |
---|---|---|
VSCode | cmd+shift+p "install extensions", "sumneko.lua" | sumneko.lua |
NeoVim | require'lspconfig'.lua_ls.setup{} in config |
LuaLS NeoVim Install |
Sublime | cmd_+shift+p "install package", "LSP-lua" | LSP-Lua Package |
Zed | n/a (LuaLS is built in) |
-
Close and re-open your editor; wait 5-10 seconds for LuaLS to initialize.
-
Hover over code or start typing
playdate.
and you'll get suggestions.
If you would like a minimal set of API definitions that does not include the English function annotations from Playdate SDK docs, you can use this minimal stub.lua from the notpeter/playdate-docdef repo instead of the fully annotated stub.lua in this repo.
- Types are defined in notpeter/playdate-docdef/playdate.luars
- We scrape Lua PlayDateSDK "Inside Playdate" HTML Documentation
- Then generate stub.lua with LuaCATS annotations.
Work in progress. Currently just do a git pull
periodically in your local clone.
Releases are tagged and you could subscribe to an Atom XML Feed like it's 2005.
See: CHANGELOG.md.
If you find this software useful, please consider:
- Sponsoring me on GitHub
- Purchasing something from my Itch Store
- Sending me free copies of the Playdate games you build.
tldr: Our types are _Image
and _Sprite
instead of playdate.graphics.{image,sprite}
.
Panic decided to make their type names match the location in the
global namespace playdate
table where they organized the code.
This makes it impossible to differentiate between the global object
playdate.graphics.image
and a instance of type playdate.graphics.image
.
Both have a bunch of functions and constants attached like .copy()
and
.draw(self, x, y, flip)
and .kDitherTypeNone
,
but only the image instance has .width
, .height
attributes. Without distinct types, our IDE (via LuaLS) can't tell that
one of these calls will fail at runtime while the other is fine:
xpos = playdate.graphics.image.width + 1
xpos = playdate.graphics.image.new(64, 64).width + 1
We create short names Types like _Image
with instance attributes (e.g. .width
, .height
)
and inherit everything else from their parent (e.g. playdate.graphics.image
).
We prefix with "_" to avoid conflicts.
If you are creating class objects via the class()
function
you'll want to describe your class to LuaLS and let it know
it's been added to the global namespace.
For example here's a simple class:
class("FillSprite").extends(playdate.graphics.sprite)
function FillSprite:init(w, h, color)
local img = playdate.graphics.image.new(w, h, color)
FillSprite.super.init(self, img)
end
local ts = FillSprite(64, 64 playdate.graphics.kColorBlack)
Which could be annotated like so:
---@class FillSprite: _Sprite
---@field color: integer
---@overload fun(w: integer, h:integer, color:integer): FillSprite
FillSprite = class("FillSprite").extends(playdate.graphics.sprite) or FillSprite
function FillSprite:init(w, h, color)
local img = playdate.graphics.image.new(w, h, color)
FillSprite.super.init(self, img)
self.color = color
end
local ts = FillSprite(64, 64 playdate.graphics.kColorBlack)
The FillSprite = [...] or FillSprite
becomes a no-op because
class().extends()
returns nil
but does set G_["FillSprite"]
so we end of up with
FillSprite = nil or FillSprite
, a no-op.
The @overload
defines a signature for when the name FillSprite
is invoked as a function (via __call
in it's metatable). With
Object.lua class objects this should match the signature
of the :init
constructor with the a return type
of the class instance object.
These names do not exist at runtime and are only used by LuaLS.
playdate-luacats | Offical Docs |
---|---|
_AffineTransform | playdate.geometry.affineTransform |
_AnimationLoop | playdate.graphics.animation.loop |
_Animator | playdate.graphics.animator |
_Arc | playdate.geometry.arc |
_BitCrusher | playdate.sound.bitcrusher |
_Blinker | playdate.graphics.animation.blinker |
_Channel | playdate.sound.channel |
_ControlSignal | playdate.sound.controlsignal |
_DelayLine | playdate.sound.delayline |
_DelayLineTap | playdate.sound.delaylinetap |
_Envelope | playdate.sound.envelope |
_File | playdate.file.file |
_FilePlayer | playdate.sound.fileplayer |
_Font | playdate.graphics.font |
_FrameTimer | playdate.frameTimer |
_GridView | playdate.ui.gridview |
_Image | playdate.graphics.image |
_ImageTable | playdate.graphics.imagetable |
_Instrument | playdate.sound.instrument |
_LFO | playdate.sound.lfo |
_LineSegment | playdate.geometry.lineSegment |
_Menu | playdate.menu |
_MenuItem | playdate.menu.item |
_NineSlice | playdate.graphics.nineSlice |
_OnePoleFilter | playdate.sound.onepolefilter |
_OverDrive | playdate.sound.overdrive |
_PathFinderGraph | playdate.pathfinder.graph |
_PathFinderNode | playdate.pathfinder.node |
_Point | playdate.geometry.point |
_Polygon | playdate.geometry.polygon |
_Rect | playdate.geometry.rect |
_RingMod | playdate.sound.ringmod |
_Sample | playdate.sound.sample |
_SamplePlayer | playdate.sound.sampleplayer |
_Sequence | playdate.sound.sequence |
_Signal | playdate.sound.signal |
_Size | playdate.geometry.size |
_SoundEffect | playdate.sound.effect |
_Sprite | playdate.graphics.sprite |
_Synth | playdate.sound.synth |
_TileMap | playdate.graphics.tilemap |
_Timer | playdate.timer |
_Track | playdate.sound.track |
_TwoPoleFilter | playdate.sound.twopolefilter |
_Vector2D | playdate.geometry.vector2D |
_Video | playdate.graphics.video |
_DateTime | |
_InputHandler | |
_Metadata | |
_ModTime | |
_NewClass | |
_PowerStatus | |
_SoundControlEvent | |
_SoundSource | |
_SoundTrackNote | |
_SoundTrackNoteIn | |
_SpriteCollisionData | |
_SpriteCollisionInfo | |
_SystemInfo |
See: @notpeter/playdate-luacats/tags
Our version tags correspond to PlaydateSDK versions
with a numbered suffix (e.g. luacats1
). For example: v2.1.0-luacats2
is the second
revision of annotations for SDK v2.1.0.
There are valid Semantic Versioning. The suffix use makes them technically pre-release versions but as long as we always have a suffix it'll be fine.
This was created by Peter Tripp, but much of the credit goes to @sumneko and @actboy168 for their work on lua-language-server, vscode-lua, lua-debug and related dependencies.
You can also follow me on socials:
- @notpeter on Twitter
- @[email protected] on Mastadon
- @notnotpeter on Twitch
- @notnotpeter on Discord
- @notpeter on Itch
- As of 2023-08-05 None of the other LuaCATS Definitions have any tags at all, so we're ahead of the curve. Over engineering is definitely on-brand for this project.
- As of 2023-08-05 Google q=luacats1 yields zero results.