Skip to content

Commit 560137f

Browse files
add debugger and task provider (#360)
* 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 <danielluque14@gmail.com>
1 parent d39231e commit 560137f

File tree

5 files changed

+271
-15
lines changed

5 files changed

+271
-15
lines changed

package-lock.json

Lines changed: 42 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 79 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "languague-renpy",
33
"displayName": "Ren'Py Language",
44
"description": "Adds rich support for the Ren'Py programming language to Visual Studio Code.",
5-
"version": "2.3.5",
5+
"version": "2.2.2",
66
"publisher": "LuqueDaniel",
77
"license": "MIT",
88
"homepage": "https://github.com/LuqueDaniel/vscode-language-renpy",
@@ -36,7 +36,8 @@
3636
},
3737
"activationEvents": [
3838
"workspaceContains:**/*.rpy",
39-
"workspaceContains:**/_ren.py"
39+
"workspaceContains:**/_ren.py",
40+
"onDebugResolve:renpy"
4041
],
4142
"main": "./dist/extension",
4243
"browser": "./dist/extension.js",
@@ -133,6 +134,75 @@
133134
"icon": "$(play)"
134135
}
135136
],
137+
"debuggers": [
138+
{
139+
"type": "renpy",
140+
"label": "Ren'Py",
141+
"languages": [
142+
"renpy"
143+
],
144+
"runtime": "node",
145+
"configurationAttributes": {
146+
"launch": {
147+
"required": [],
148+
"properties": {
149+
"command": {
150+
"type": "string",
151+
"description": "Command to run Ren'Py with.",
152+
"default": "run"
153+
},
154+
"args": {
155+
"type": "array",
156+
"description": "Args to run Ren'Py with.",
157+
"default": []
158+
}
159+
}
160+
}
161+
},
162+
"initialConfigurations": [
163+
{
164+
"type": "renpy",
165+
"request": "launch",
166+
"name": "Ren'Py: Launch",
167+
"command": "run",
168+
"args": []
169+
}
170+
],
171+
"configurationSnippets": [
172+
{
173+
"label": "Ren'Py",
174+
"description": "A new configuration for launching a Ren'Py project",
175+
"body": {
176+
"type": "renpy",
177+
"request": "launch",
178+
"name": "Ren'Py",
179+
"command": "run",
180+
"args": []
181+
}
182+
}
183+
]
184+
}
185+
],
186+
"taskDefinitions": [
187+
{
188+
"type": "renpy",
189+
"required": [
190+
"command"
191+
],
192+
"properties": {
193+
"command": {
194+
"type": "string",
195+
"description": "Command to run Ren'Py with.",
196+
"default": "run"
197+
},
198+
"args": {
199+
"type": "array",
200+
"description": "Args to run Ren'Py with.",
201+
"default": []
202+
}
203+
}
204+
}
205+
],
136206
"configuration": [
137207
{
138208
"title": "Ren'Py",
@@ -206,6 +276,11 @@
206276
"Ignore filename issues"
207277
],
208278
"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."
279+
},
280+
"renpy.renpyExecutableLocation": {
281+
"type": "string",
282+
"default": "",
283+
"description": "Location of Ren'Py installation. Should be .exe on Windows and .sh on Mac/Linux."
209284
}
210285
}
211286
}
@@ -241,6 +316,7 @@
241316
"typescript": "^5.1.3",
242317
"vscode-test": "^1.6.1",
243318
"webpack": "^5.86.0",
244-
"webpack-cli": "^5.1.4"
319+
"webpack-cli": "^5.1.4",
320+
"@vscode/debugadapter": "^1.57.0"
245321
}
246322
}

src/debugger.ts

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import * as vscode from "vscode";
2+
import { DebugSession, TerminatedEvent } from "@vscode/debugadapter";
3+
import { getWorkspaceFolder } from "./workspace";
4+
import { Configuration } from "./configuration";
5+
import { logToast } from "./logger";
6+
import { isValidExecutable } from "./extension";
7+
8+
function getTerminal(name: string): vscode.Terminal {
9+
let i: number;
10+
for (i = 0; i < vscode.window.terminals.length; i++) {
11+
if (vscode.window.terminals[i].name === name) {
12+
return vscode.window.terminals[i];
13+
}
14+
}
15+
return vscode.window.createTerminal(name);
16+
}
17+
18+
export class RenpyAdapterDescriptorFactory implements vscode.DebugAdapterDescriptorFactory {
19+
createDebugAdapterDescriptor(session: vscode.DebugSession): vscode.ProviderResult<vscode.DebugAdapterDescriptor> {
20+
return new vscode.DebugAdapterInlineImplementation(new RenpyDebugSession(session.configuration.command, session.configuration.args));
21+
}
22+
}
23+
24+
class RenpyDebugSession extends DebugSession {
25+
private command = "run";
26+
private args?: string[];
27+
28+
public constructor(command: string, args?: string[]) {
29+
super();
30+
this.command = command;
31+
if (args) {
32+
this.args = args;
33+
}
34+
}
35+
36+
protected override initializeRequest(): void {
37+
const terminal = getTerminal("Ren'py Debug");
38+
terminal.show();
39+
let program = Configuration.getRenpyExecutablePath();
40+
41+
if (!isValidExecutable(program)) {
42+
logToast(vscode.LogLevel.Error, "Ren'Py executable location not configured or is invalid.");
43+
return;
44+
}
45+
46+
program += " " + getWorkspaceFolder();
47+
if (this.command) {
48+
program += " " + this.command;
49+
}
50+
if (this.args) {
51+
program += " " + this.args.join(" ");
52+
}
53+
terminal.sendText(program);
54+
this.sendEvent(new TerminatedEvent());
55+
}
56+
}
57+
58+
export class RenpyConfigurationProvider implements vscode.DebugConfigurationProvider {
59+
resolveDebugConfiguration(folder: vscode.WorkspaceFolder | undefined, config: vscode.DebugConfiguration): vscode.ProviderResult<vscode.DebugConfiguration> {
60+
if (!config.type && !config.request && !config.name) {
61+
const editor = vscode.window.activeTextEditor;
62+
if (editor && editor.document.languageId === "renpy") {
63+
config.type = "renpy";
64+
config.request = "launch";
65+
config.name = "Ren'Py: Launch";
66+
config.command = "run";
67+
config.args = [];
68+
}
69+
}
70+
return config;
71+
}
72+
}

src/extension.ts

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

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

2426
export async function activate(context: ExtensionContext): Promise<void> {
2527
intializeLoggingSystems(context);
@@ -154,8 +156,8 @@ export async function activate(context: ExtensionContext): Promise<void> {
154156
debug.startDebugging(
155157
undefined,
156158
{
157-
type: "cmd",
158-
name: "Run File",
159+
type: "renpy",
160+
name: "Run Project",
159161
request: "launch",
160162
program: rpyPath,
161163
},
@@ -248,6 +250,33 @@ export async function activate(context: ExtensionContext): Promise<void> {
248250
}
249251
}
250252

253+
const factory = new RenpyAdapterDescriptorFactory();
254+
context.subscriptions.push(debug.registerDebugAdapterDescriptorFactory("renpy", factory));
255+
const provider = new RenpyConfigurationProvider();
256+
context.subscriptions.push(debug.registerDebugConfigurationProvider("renpy", provider));
257+
context.subscriptions.push(
258+
debug.registerDebugConfigurationProvider(
259+
"renpy",
260+
{
261+
provideDebugConfigurations(): ProviderResult<DebugConfiguration[]> {
262+
return [
263+
{
264+
type: "renpy",
265+
request: "launch",
266+
name: "Ren'Py: Launch",
267+
command: "run",
268+
args: [],
269+
},
270+
];
271+
},
272+
},
273+
DebugConfigurationProviderTriggerKind.Dynamic
274+
)
275+
);
276+
277+
const taskProvider = new RenpyTaskProvider();
278+
context.subscriptions.push(tasks.registerTaskProvider("renpy", taskProvider));
279+
251280
logMessage(LogLevel.Info, "Ren'Py extension activated!");
252281
}
253282

@@ -282,7 +311,7 @@ export function getKeywordPrefix(document: TextDocument, position: Position, ran
282311
return;
283312
}
284313

285-
function isValidExecutable(renpyExecutableLocation: string): boolean {
314+
export function isValidExecutable(renpyExecutableLocation: string): boolean {
286315
if (!renpyExecutableLocation || renpyExecutableLocation === "") {
287316
return false;
288317
}

0 commit comments

Comments
 (0)