Skip to content

Commit

Permalink
Added auto complete to code editor.
Browse files Browse the repository at this point in the history
  • Loading branch information
jessefreeman committed Jul 23, 2023
1 parent c411d5e commit 94ed2e6
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 3 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
},
"dependencies": {
"@babel/runtime": "^7.22.6",
"@codemirror/autocomplete": "^6.9.0",
"@codemirror/lang-cpp": "^6.0.2",
"@codemirror/lang-css": "^6.2.0",
"@codemirror/lang-html": "^6.4.5",
Expand Down
3 changes: 3 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

102 changes: 99 additions & 3 deletions src/components/Editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { keymap } from "@codemirror/view";
import { createEffect, createSignal, onCleanup, onMount } from "solid-js";
import { githubDark, githubLight } from "@uiw/codemirror-theme-github";
import { useDarkMode } from "../lib/darkmode";

import { autocompletion, startCompletion } from '@codemirror/autocomplete';
const { StateCommand, Selection } = EditorState;
// The Editor component.
// It accepts the following props:
Expand All @@ -25,6 +25,96 @@ export const Editor = (props: {
// Check if the application is running in dark mode.
const isDarkMode = useDarkMode()

// // Define your own completion source
// const pv8CompletionSource = (context) => {
// // Define the PV8 API methods
// const pv8API = [
// 'DrawSprite(spriteID, x, y, flipH, flipV, drawMode, colorOffset)',
// 'DrawSprites(ids, x, y, width, flipH, flipV, drawMode, colorOffset)',
// 'DrawTile(tileID, x, y, flipH, flipV, drawMode, colorOffset)',
// 'DrawTiles(ids, x, y, width, flipH, flipV, drawMode, colorOffset)',
// 'RedrawDisplay()',
// 'RebuildTilemap()',
// // Add more API methods as needed
// ];

// // Convert the API methods to the completion format
// const options = pv8API.map(method => ({ label: method }));

// // Get the token before the cursor
// const token = context.tokenBefore();

// // Set the start of the completion range to the start of the token, if a token was found
// const from = token ? token.from : context.pos;

// return {
// from,
// to: context.pos, // The end of the completion range is the current cursor position
// options,
// };
// };

// This is a list of PV8's APIs for demonstration purposes
// You should replace this with the actual list of APIs
const pixelVisionAPI = [
{ label: "BackgroundColor", signature: "BackgroundColor(id)", type: "function", info: "Manages system colors and the background color used to clear the display." },
{ label: "Color", signature: "Color(id, value)", type: "function", info: "Allows you to read and update color values in the ColorChip." },
{ label: "DrawRect", signature: "DrawRect(x, y, width, height, color, drawMode)", type: "function", info: "Displays a rectangle with a fill color on the screen." },
{ label: "DrawMetaSprite", signature: "DrawMetaSprite(id, x, y, flipH, flipV, drawMode, colorOffset)", type: "function", info: "Draws a Sprite Collection to the display." },
{ label: "DrawSprite", signature: "DrawSprite(id, x, y, flipH, flipV, drawMode, colorOffset)", type: "function", info: "Draws a single sprite to the display." },
{ label: "DrawText", signature: "DrawText(text, x, y, drawMode, font, colorOffset, spacing)", type: "function", info: "Renders text to the display." },
{ label: "ReadSaveData", signature: "ReadSaveData(key, defaultValue)", type: "function", info: "Reads saved data by supplying a key." },
{ label: "WriteSaveData", signature: "WriteSaveData(key, value)", type: "function", info: "Writes saved data by supplying a key and value." },
{ label: "Button", signature: "Button(Buttons button, InputState state, int controllerID)", type: "function", info: "Gets the current state of any button by calling the Button() method and supplying a button ID." },
{ label: "Key", signature: "Key(key, state)", type: "function", info: "Tests for keyboard input by calling the Key() API." },
{ label: "MouseButton", signature: "MouseButton(int button, InputState state)", type: "function", info: "Gets the current state of the mouse's left (0) and right (1) buttons by calling MouseButton()API." },
{ label: "MousePosition", signature: "MousePosition()", type: "function", info: "Returns a Point for the mouse cursor's X and Y position." },
{ label: "Init", signature: "Init()", type: "function", info: "Called when a game first loads up." },
{ label: "Draw", signature: "Draw()", type: "function", info: "Called once per frame after the Update() has been completed." },
{ label: "Update", signature: "Update(timeDelta)", type: "function", info: "Called once per frame at the beginning of the game loop." },
{ label: "PauseSong", signature: "PauseSong()", type: "function", info: "Toggles the current playback state of the sequencer." },
{ label: "PlaySong", signature: "PlaySong(id, loop, startAt)", type: "function", info: "Activates the MusicChip's tracker to playback any of the songs stored in memory." },
{ label: "RewindSong", signature: "RewindSong(position, patternID)", type: "function", info: "Rewinds the currently playing song to a specific position and pattern ID." },
{ label: "StopSong", signature: "StopSong()", type: "function", info: "Stops the currently playing song." },
{ label: "Display", signature: "Display()", type: "function", info: "Gets the resolution of the display at run time." },
{ label: "RedrawDisplay", signature: "RedrawDisplay()", type: "function", info: "Executes both the Clear() and DrawTilemap() APIs in a single call." },
{ label: "ScrollPosition", signature: "ScrollPosition(x, y)", type: "function", info: "Scrolls the tilemap by calling the ScrollPosition() API and supplying a new scroll X and Y position." },
{ label: "PlaySound", signature: "PlaySound(id, channel)", type: "function", info: "Plays a single sound effect on a specific channel." },
{ label: "Sound", signature: "Sound(int id, string data)", type: "function", info: "Reads raw sound data from the SoundChip." },
{ label: "StopSound", signature: "StopSound(channel)", type: "function", info: "Stops any sound playing on a specific channel." },
{ label: "Sprite", signature: "Sprite(id, data)", type: "function", info: "Reads and writes pixel data directly to the SpriteChip's memory." },
{ label: "TotalSprites", signature: "TotalSprites(bool ignoreEmpty)", type: "function", info: "Returns the total number of sprites in the SpriteChip." },
{ label: "Flag", signature: "Flag(column, row, value)", type: "function", info: "Quickly accesses just the flag value of a tile." },
{ label: "Tile", signature: "Tile(column, row, spriteID, colorOffset, flag, flipH, flipV)", type: "function", info: "Gets the current sprite, color offset and flag values associated with a given tile ID." },
{ label: "TilemapSize", signature: "TilemapSize(width, height, clear)", type: "function", info: "Returns a Pointrepresenting the size of the tilemap in columns(X) and rows (Y)." },
{ label: "UpdateTiles", signature: "UpdateTiles(ids, column, row, width, colorOffset, flag)", type: "function", info: "Updates the color offset and flag values of multiple tiles at once." },
];


const completionSource: CompletionSource = (context: CompletionContext) => {
const beforeCursor = context.state.sliceDoc(0, context.pos);
const match = /\b\w+$/.exec(beforeCursor);

if (!match) {
return null;
}

const wordStart = match.index;

return {
from: wordStart,
to: context.pos,
options: pixelVisionAPI.map(api => ({
label: api.signature,
type: api.type,
info: api.info,
})),
};
};

// Then you can use this completion source when you configure autocompletion
const autocompleteExtension = autocompletion({ override: [completionSource] });

const insertTab: StateCommand = ({state, dispatch}) => {
// Get the current selection.
let {from, to} = state.selection.main;
Expand All @@ -51,7 +141,8 @@ export const Editor = (props: {

const tabKeymap = keymap.of([
{ key: "Tab", run: insertTab },
{ key: "Shift-Tab", run: deleteSpaces } // Add this line
{ key: "Shift-Tab", run: deleteSpaces },
{ key: "Alt-Space", run: startCompletion}
]);


Expand All @@ -73,10 +164,15 @@ export const Editor = (props: {
// Add different extensions based on whether the app is in dark mode or not.
isDarkMode() ? githubDark : githubLight,
basicSetup,
autocompletion({
override: [completionSource], // Use the PV8 completion source
}),
// startCompletion, // Start completion immediately
handleUpdate,
EditorView.lineWrapping,
...(props.extensions || []),
tabKeymap
tabKeymap,

],
}),
})
Expand Down

0 comments on commit 94ed2e6

Please sign in to comment.