Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,11 @@
"default": true,
"description": "If false, do not update Luau-LSP and Selene configurations unless the Force Language Update is done"
},
"slVscodeEdit.syntax.useGitHubDefinitions": {
"type": "boolean",
"default": true,
"description": "Fetch LSL definition files from GitHub instead of the Second Life viewer"
},
"slVscodeEdit.ui.statusTimeoutSeconds": {
"type": "number",
"default": 3,
Expand Down
1 change: 1 addition & 0 deletions src/interfaces/configinterface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export enum ConfigKey {
PreprocessorConstantsInSLua = 'preprocessor.constantsInSLua',
PreprocessorLSLSwitchStatements = 'preprocessor.lsl.switchStatements',
LastSyntaxID = 'syntax.lastID',
UseGitHubDefinitions = 'syntax.useGitHubDefinitions',
AskIfViewerScriptMismatchesMaster = 'sync.askIfViewerScriptMismatchesMaster',
CompareHashBeforeSync = 'sync.compareHashBeforeSync',
KeepViewerFileOpen = 'sync.keepViewerFileOpen',
Expand Down
17 changes: 17 additions & 0 deletions src/shared/languagerepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import { LSLKeywords } from "./lslkeywords";
import { LuaTypeDefinitions } from "./luadefsinterface";
import { sortObjectKeysRecursive } from '../utils';

const GitHubRawBase = "https://raw.githubusercontent.com/secondlife/lsl-definitions/main/generated";

export interface LanguageInfo {
id: string;
lsl?: LSLKeywords;
Expand Down Expand Up @@ -156,6 +158,21 @@ export class LanguageRepository {
}
}

public async fetchFromGitHub(filename: string): Promise<string | null> {
const url = `${GitHubRawBase}/${filename}`;
try {
const response = await fetch(url);
if (!response.ok) {
console.warn(`GitHub fetch failed for ${filename}: HTTP ${response.status}`);
return null;
}
return await response.text();
} catch (error) {
console.error(`Error fetching ${filename} from GitHub:`, error);
return null;
}
}

private async requestLanguageSyntax(socket: JSONRPCInterface, kind: string): Promise<any | null> {
const params = { kind };
try {
Expand Down
34 changes: 34 additions & 0 deletions src/shared/languageservice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,10 +112,20 @@ export class LanguageService implements DisposableLike {
force?: boolean,
syntaxCacheSupported?: boolean,
): Promise<boolean> {
// Try GitHub first if enabled (most reliable, no viewer dependency)
if (this.host.config.getConfig(ConfigKey.UseGitHubDefinitions, true)) {
const githubOk = await this.configureSyntaxFromGitHub(syntaxId);
if (githubOk) {
return true;
}
}

// Fallback to viewer cache if available

@tapple tapple Aug 14, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The viewer should take priority over github, if available. The viewer will have the exact version that matches what you can run on the simulator you are standing in. Github will tend to have beta stuff and may only work on beta grid.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The viewer pulls the version of the files that it serves from the simulator it is talking to, even if it is beta version.
The files provided by the viewer should be considered canon.

if (syntaxCacheSupported && socket) {
return await this.configureSyntaxFromViewerCache(syntaxId, socket);
}

// Last resort: fetch from viewer and generate locally
const syntax = await this.repository.getSyntax(syntaxId, {
force,
socket,
Expand Down Expand Up @@ -146,6 +156,30 @@ export class LanguageService implements DisposableLike {
return true;
}

private async configureSyntaxFromGitHub(syntaxId: string): Promise<boolean> {
const selene = new SelenePlugin(this.host);
const seleneYml = await this.repository.fetchFromGitHub("secondlife_selene.yml");
if (typeof seleneYml === "string") {
await selene.configureFromViewerCache(syntaxId, seleneYml);
} else {
console.warn("github_fetch: secondlife_selene.yml missing or invalid, skipping Selene configuration");
}

const luauLSP = new LuaLSPPlugin(this.host);
const dLuau = await this.repository.fetchFromGitHub("secondlife.d.luau");
const docs = await this.repository.fetchFromGitHub("secondlife.docs.json");
if (typeof dLuau === "string" && typeof docs === "string") {
await luauLSP.configureFromViewerCache(syntaxId, dLuau, docs);
} else {
console.warn("github_fetch: secondlife.d.luau or secondlife.docs.json missing or invalid, skipping Luau-LSP configuration");
return false;
}

this.languageVersion = syntaxId;
await ConfigService.getInstance().setConfig<string>(ConfigKey.LastSyntaxID, syntaxId, { target: "global" });
return true;
}

private async configureSyntaxFromViewerCache(
syntaxId: string,
socket: JSONRPCInterface,
Expand Down