diff --git a/extensions/studio/src/browser/explorer-filter.ts b/extensions/studio/src/browser/explorer-filter.ts new file mode 100644 index 0000000..11de53b --- /dev/null +++ b/extensions/studio/src/browser/explorer-filter.ts @@ -0,0 +1,128 @@ +// SPDX-FileCopyrightText: 2026 Star Haven contributors +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +import { injectable, inject } from "@theia/core/shared/inversify"; +import { FrontendApplicationContribution } from "@theia/core/lib/browser"; +import { PreferenceService } from "@theia/core/lib/common/preferences/preference-service"; +import { + PreferenceContribution, + PreferenceSchema, +} from "@theia/core/lib/common/preferences/preference-schema"; +import { PreferenceScope } from "@theia/core/lib/common/preferences/preference-scope"; + +export const SHOW_ALL_FILES_PREF = "starHaven.showAllProjectFiles"; + +export const StarHavenPreferencesSchema: PreferenceSchema = { + scope: PreferenceScope.Folder, + properties: { + [SHOW_ALL_FILES_PREF]: { + type: "boolean", + default: false, + description: + "Show all engine files in the explorer. When disabled, only assets, include, and src are shown.", + }, + }, +}; + +@injectable() +export class StarHavenPreferenceContribution implements PreferenceContribution { + schema = StarHavenPreferencesSchema; +} + +// Directories/files visible in default mode (modder-facing) +const DEFAULT_VISIBLE = new Set(["assets", "include", "src", "README.md"]); + +// Additionally visible in advanced mode +const ADVANCED_VISIBLE = new Set(["ver", "tools", ".github"]); + +// Patterns to always hide (build artifacts, config) +const ALWAYS_HIDDEN: Record = { + "**/.git": true, + "**/.jj": true, + "**/.direnv": true, + "**/.cache": true, + "**/build": true, + "**/.n2_db": true, + "**/.ninja_deps": true, + "**/.run_hash": true, + "**/.starrod": true, + "**/.dx": true, + "**/venv": true, + "**/*.o": true, +}; + +// Root-level items to hide in default mode +const DEFAULT_HIDDEN: Record = { + "build.ninja": true, + "build.bat": true, + "compile_commands.json": true, + configure: true, + "flake.lock": true, + "flake.nix": true, + "pyproject.toml": true, + "requirements.txt": true, + "requirements_extra.txt": true, + "treefmt.toml": true, + run: true, + "CLAUDE.md": true, + ".clang-format": true, + ".clang-tidy": true, + ".clangd": true, + ".claude": true, + ".editorconfig": true, + ".envrc": true, + ".git-blame-ignore-revs": true, + ".gitattributes": true, + ".gitignore": true, + ".vscode": true, + ".zed": true, + ".nix-profile": true, + ".nix-profile-*-link": true, + ver: true, + tools: true, + module: true, + ".github": true, + "versioning.o": true, + "xprintf.o": true, +}; + +// In advanced mode, remove these from the hidden list +const ADVANCED_UNHIDDEN = ["ver", "tools", ".github"]; + +@injectable() +export class ExplorerFilterContribution + implements FrontendApplicationContribution +{ + @inject(PreferenceService) + protected readonly preferenceService!: PreferenceService; + + async onStart(): Promise { + await this.preferenceService.ready; + this.applyFilter(); + this.preferenceService.onPreferenceChanged((e) => { + if (e.preferenceName === SHOW_ALL_FILES_PREF) { + this.applyFilter(); + } + }); + } + + protected applyFilter(): void { + const showAll = this.preferenceService.get( + SHOW_ALL_FILES_PREF, + false, + ); + + const excludes: Record = { ...ALWAYS_HIDDEN }; + + if (!showAll) { + Object.assign(excludes, DEFAULT_HIDDEN); + } + + this.preferenceService.set( + "files.exclude", + excludes, + PreferenceScope.Workspace, + ); + } +} diff --git a/extensions/studio/src/browser/studio-frontend-module.ts b/extensions/studio/src/browser/studio-frontend-module.ts index 70362e6..139acae 100644 --- a/extensions/studio/src/browser/studio-frontend-module.ts +++ b/extensions/studio/src/browser/studio-frontend-module.ts @@ -29,6 +29,11 @@ import { EvtKeywordDecorator } from "./c-language/evt-keyword-decorator"; // import { EvtSemanticTokensContribution } from "./c-language/evt-semantic-tokens"; import { ThemeContribution } from "./themes/theme-contribution"; import { IconThemeSync } from "./icon-theme-sync"; +import { + ExplorerFilterContribution, + StarHavenPreferenceContribution, +} from "./explorer-filter"; +import { PreferenceContribution } from "@theia/core/lib/common/preferences/preference-schema"; import "../../src/browser/asset-browser/style.css"; import "../../src/browser/fonts/fonts.css"; @@ -80,4 +85,10 @@ export default new ContainerModule((bind) => { bind(IconThemeSync).toSelf().inSingletonScope(); bind(FrontendApplicationContribution).toService(IconThemeSync); + + bind(StarHavenPreferenceContribution).toSelf().inSingletonScope(); + bind(PreferenceContribution).toService(StarHavenPreferenceContribution); + + bind(ExplorerFilterContribution).toSelf().inSingletonScope(); + bind(FrontendApplicationContribution).toService(ExplorerFilterContribution); });