Skip to content

Commit

Permalink
add debugger and task provider (#360)
Browse files Browse the repository at this point in the history
* Bump version 2.2.2

* add debug adapter

* add task provider

* use existing getRenpyExecutablePath function

* allow debugger to launch without launch.json

requires a renpy-language file to be open

* use renpy debugger for run project command

instead of requiring an extension to supports the cmd type for debuggers

* register task provider with context.subscriptions

* update logger convention in debugger

---------

Co-authored-by: Daniel Luque <[email protected]>
  • Loading branch information
midgethetree and LuqueDaniel authored Jul 3, 2023
1 parent d39231e commit 560137f
Show file tree
Hide file tree
Showing 5 changed files with 271 additions and 15 deletions.
50 changes: 42 additions & 8 deletions package-lock.json

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

82 changes: 79 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "languague-renpy",
"displayName": "Ren'Py Language",
"description": "Adds rich support for the Ren'Py programming language to Visual Studio Code.",
"version": "2.3.5",
"version": "2.2.2",
"publisher": "LuqueDaniel",
"license": "MIT",
"homepage": "https://github.com/LuqueDaniel/vscode-language-renpy",
Expand Down Expand Up @@ -36,7 +36,8 @@
},
"activationEvents": [
"workspaceContains:**/*.rpy",
"workspaceContains:**/_ren.py"
"workspaceContains:**/_ren.py",
"onDebugResolve:renpy"
],
"main": "./dist/extension",
"browser": "./dist/extension.js",
Expand Down Expand Up @@ -133,6 +134,75 @@
"icon": "$(play)"
}
],
"debuggers": [
{
"type": "renpy",
"label": "Ren'Py",
"languages": [
"renpy"
],
"runtime": "node",
"configurationAttributes": {
"launch": {
"required": [],
"properties": {
"command": {
"type": "string",
"description": "Command to run Ren'Py with.",
"default": "run"
},
"args": {
"type": "array",
"description": "Args to run Ren'Py with.",
"default": []
}
}
}
},
"initialConfigurations": [
{
"type": "renpy",
"request": "launch",
"name": "Ren'Py: Launch",
"command": "run",
"args": []
}
],
"configurationSnippets": [
{
"label": "Ren'Py",
"description": "A new configuration for launching a Ren'Py project",
"body": {
"type": "renpy",
"request": "launch",
"name": "Ren'Py",
"command": "run",
"args": []
}
}
]
}
],
"taskDefinitions": [
{
"type": "renpy",
"required": [
"command"
],
"properties": {
"command": {
"type": "string",
"description": "Command to run Ren'Py with.",
"default": "run"
},
"args": {
"type": "array",
"description": "Args to run Ren'Py with.",
"default": []
}
}
}
],
"configuration": [
{
"title": "Ren'Py",
Expand Down Expand Up @@ -206,6 +276,11 @@
"Ignore filename issues"
],
"description": "Enable filename checks. Filenames must begin with a letter or number, and may not begin with '00', as Ren'Py uses such files for its own purposes. If set to Error or Warning, documents will be marked in the editor if the document filename does not meet Ren'Py's specifications. If set to Disabled, filename issues will be ignored."
},
"renpy.renpyExecutableLocation": {
"type": "string",
"default": "",
"description": "Location of Ren'Py installation. Should be .exe on Windows and .sh on Mac/Linux."
}
}
}
Expand Down Expand Up @@ -241,6 +316,7 @@
"typescript": "^5.1.3",
"vscode-test": "^1.6.1",
"webpack": "^5.86.0",
"webpack-cli": "^5.1.4"
"webpack-cli": "^5.1.4",
"@vscode/debugadapter": "^1.57.0"
}
}
72 changes: 72 additions & 0 deletions src/debugger.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import * as vscode from "vscode";
import { DebugSession, TerminatedEvent } from "@vscode/debugadapter";
import { getWorkspaceFolder } from "./workspace";
import { Configuration } from "./configuration";
import { logToast } from "./logger";
import { isValidExecutable } from "./extension";

function getTerminal(name: string): vscode.Terminal {
let i: number;
for (i = 0; i < vscode.window.terminals.length; i++) {
if (vscode.window.terminals[i].name === name) {
return vscode.window.terminals[i];
}
}
return vscode.window.createTerminal(name);
}

export class RenpyAdapterDescriptorFactory implements vscode.DebugAdapterDescriptorFactory {
createDebugAdapterDescriptor(session: vscode.DebugSession): vscode.ProviderResult<vscode.DebugAdapterDescriptor> {
return new vscode.DebugAdapterInlineImplementation(new RenpyDebugSession(session.configuration.command, session.configuration.args));
}
}

class RenpyDebugSession extends DebugSession {
private command = "run";
private args?: string[];

public constructor(command: string, args?: string[]) {
super();
this.command = command;
if (args) {
this.args = args;
}
}

protected override initializeRequest(): void {
const terminal = getTerminal("Ren'py Debug");
terminal.show();
let program = Configuration.getRenpyExecutablePath();

if (!isValidExecutable(program)) {
logToast(vscode.LogLevel.Error, "Ren'Py executable location not configured or is invalid.");
return;
}

program += " " + getWorkspaceFolder();
if (this.command) {
program += " " + this.command;
}
if (this.args) {
program += " " + this.args.join(" ");
}
terminal.sendText(program);
this.sendEvent(new TerminatedEvent());
}
}

export class RenpyConfigurationProvider implements vscode.DebugConfigurationProvider {
resolveDebugConfiguration(folder: vscode.WorkspaceFolder | undefined, config: vscode.DebugConfiguration): vscode.ProviderResult<vscode.DebugConfiguration> {
if (!config.type && !config.request && !config.name) {
const editor = vscode.window.activeTextEditor;
if (editor && editor.document.languageId === "renpy") {
config.type = "renpy";
config.request = "launch";
config.name = "Ren'Py: Launch";
config.command = "run";
config.args = [];
}
}
return config;
}
}
37 changes: 33 additions & 4 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import * as cp from "child_process";
import * as fs from "fs";
import { ExtensionContext, languages, commands, window, TextDocument, Position, debug, Range, workspace, Uri, LogLevel } from "vscode";
import { ExtensionContext, languages, commands, window, TextDocument, Position, debug, Range, workspace, Uri, DebugConfiguration, ProviderResult, DebugConfigurationProviderTriggerKind, tasks, LogLevel } from "vscode";
import { colorProvider } from "./color";
import { getStatusBarText, NavigationData } from "./navigation-data";
import { cleanUpPath, getAudioFolder, getImagesFolder, getNavigationJsonFilepath, getWorkspaceFolder, stripWorkspaceFromFile } from "./workspace";
Expand All @@ -20,6 +20,8 @@ import { Tokenizer } from "./tokenizer/tokenizer";
import { signatureProvider } from "./signature";
import { intializeLoggingSystems, logMessage, logToast, updateStatusBar } from "./logger";
import { Configuration } from "./configuration";
import { RenpyAdapterDescriptorFactory, RenpyConfigurationProvider } from "./debugger";
import { RenpyTaskProvider } from "./taskprovider";

export async function activate(context: ExtensionContext): Promise<void> {
intializeLoggingSystems(context);
Expand Down Expand Up @@ -154,8 +156,8 @@ export async function activate(context: ExtensionContext): Promise<void> {
debug.startDebugging(
undefined,
{
type: "cmd",
name: "Run File",
type: "renpy",
name: "Run Project",
request: "launch",
program: rpyPath,
},
Expand Down Expand Up @@ -248,6 +250,33 @@ export async function activate(context: ExtensionContext): Promise<void> {
}
}

const factory = new RenpyAdapterDescriptorFactory();
context.subscriptions.push(debug.registerDebugAdapterDescriptorFactory("renpy", factory));
const provider = new RenpyConfigurationProvider();
context.subscriptions.push(debug.registerDebugConfigurationProvider("renpy", provider));
context.subscriptions.push(
debug.registerDebugConfigurationProvider(
"renpy",
{
provideDebugConfigurations(): ProviderResult<DebugConfiguration[]> {
return [
{
type: "renpy",
request: "launch",
name: "Ren'Py: Launch",
command: "run",
args: [],
},
];
},
},
DebugConfigurationProviderTriggerKind.Dynamic
)
);

const taskProvider = new RenpyTaskProvider();
context.subscriptions.push(tasks.registerTaskProvider("renpy", taskProvider));

logMessage(LogLevel.Info, "Ren'Py extension activated!");
}

Expand Down Expand Up @@ -282,7 +311,7 @@ export function getKeywordPrefix(document: TextDocument, position: Position, ran
return;
}

function isValidExecutable(renpyExecutableLocation: string): boolean {
export function isValidExecutable(renpyExecutableLocation: string): boolean {
if (!renpyExecutableLocation || renpyExecutableLocation === "") {
return false;
}
Expand Down
Loading

0 comments on commit 560137f

Please sign in to comment.