Skip to content
Merged
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
15 changes: 14 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
},
// CSpell
"cSpell.words": [
"aiee",
"Artur",
"asar",
"ASSETDATA",
Expand All @@ -64,30 +65,42 @@
"browsable",
"CHUNKID",
"CHUNKIDS",
"clangd",
"downsample",
"EXPORTMAP",
"fguid",
"gatherable",
"HKCU",
"HKLM",
"icns",
"ICONDIR",
"ICONDIRENTRY",
"iconutil",
"IEND",
"konsole",
"millenium",
"Nwnp",
"OFPA",
"Paeth",
"peggys",
"projectfiles",
"Qfecheck",
"Regen",
"scrollview",
"SERIALSIZES",
"shelbi",
"SOFTOBJECTPATH",
"TEMPLATEINDEX",
"uasset",
"uassets",
"umap",
"UPACKAGE",
"uplugin",
"uproject",
"webfonts"
"vermillion",
"vistaesque",
"webfonts",
"wmii"
],
"[json]": {
"editor.defaultFormatter": "vscode.json-language-features"
Expand Down
32 changes: 16 additions & 16 deletions src/main/config/app.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
import STORE_CONFIG from "@/main/config/store"
import AUTO_LOCK_CONFIG from "@main/config/autoLock"
import COMPILE_DB_CONFIG from "@main/config/compileDb"
import MCP_CONFIG from "@main/config/mcp"
import STORE_CONFIG from "@main/config/store"
import UPDATER_CONFIG from "@main/config/updater"
import type { AppConfig } from "@/main/types/store"

/**
* The default configuration used when no config file exists yet, or when the existing
* one is missing fields.
* The default configuration used when no config file exists yet,
* or when the existing one is missing fields.
*/
const DEFAULT_APP_CONFIG: AppConfig = {
version: STORE_CONFIG.configVersion,
preferences: {
theme: "original",
startupBehavior: "reopen-last",
filesPaneWidth: 320,
searchIsRegex: false,
isAdvancedSearchOpened: false,
searchIncludePatterns: "",
searchExcludePatterns: "",
isShowingMyLocksOnly: false,
autoLockTickIntervalMs: AUTO_LOCK_CONFIG.tickIntervalMs,
mcpEndpoint: MCP_CONFIG.endpoint,
mcpProbeIntervalMs: MCP_CONFIG.probeIntervalMs,
isCompileDbAutoRegenEnabled: false, // Off by default since it's pretty specific
compileDbDebounceMs: COMPILE_DB_CONFIG.debounceMs,
unrealEngineRoot: "",
isAutomaticUpdateCheckEnabled: true,
updaterCheckIntervalMs: UPDATER_CONFIG.checkIntervalMs,
},
windowPlacement: {
bounds: null,
isMaximized: false,
isFullScreen: false,
},
recentProjects: [],
lfsLockCache: {},
}

export default DEFAULT_APP_CONFIG
11 changes: 11 additions & 0 deletions src/main/config/cache.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import type { AppCache } from "@/main/types/store"

/**
* The default cache used when no cache file exists yet, or when the existing one
* is missing fields.
*/
const DEFAULT_APP_CACHE: AppCache = {
lfsLocks: {},
}

export default DEFAULT_APP_CACHE
137 changes: 137 additions & 0 deletions src/main/config/compileDb.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
/**
* The configuration for the compile-database watcher.
*/
const COMPILE_DB_CONFIG = {
/**
* How long a burst of source-tree changes is left to settle before the
* regeneration runs, a branch switch can rewrite hundreds of files and has to
* collapse into a single run.
*/
debounceMs: 2500,

/**
* How long a single build-tool invocation is given before it is killed, the
* compile database takes about two seconds and a project-files step about
* five, so this only ever fires on an invocation that is stuck.
*/
stepTimeoutMs: 5 * 60 * 1000,

/**
* The buffer an invocation's output is captured into, the build tool is
* verbose enough on a failure to overrun the default one.
*/
maxOutputBufferSize: 4 * 1024 * 1024,

/**
* How much of a run's combined output is kept for the details dialog, taken
* from the tail because the build tool puts the reason it failed at the end.
*/
maxOutputChars: 8000,

/**
* The engine-relative path of the build entry point, keyed by
* `process.platform`.
*/
buildScriptPaths: {
win32: ["Engine", "Build", "BatchFiles", "Build.bat"],
darwin: ["Engine", "Build", "BatchFiles", "Mac", "Build.sh"],
linux: ["Engine", "Build", "BatchFiles", "Linux", "Build.sh"],
} as Record<string, string[]>,

/**
* The platform name the target is generated for, keyed by `process.platform`.
*/
targetPlatforms: {
win32: "Win64",
darwin: "Mac",
linux: "Linux",
} as Record<string, string>,

/**
* The build configuration the database is generated for, `Development` is what
* the editor itself is built as.
*/
configuration: "Development",

/**
* The build-tool mode that writes a clangd-readable compile database, the
* `-vscode` project-files generator writes `cl.exe` response files instead and
* cannot stand in for it.
*/
clangDatabaseMode: "-mode=GenerateClangDatabase",

/**
* The suffix every target descriptor carries, trimmed off the file name to
* recover the target name itself.
*/
targetDescriptorSuffix: ".Target.cs",

/**
* The suffix marking the editor target among a project's descriptors, the one
* the compile database has to be generated against so editor-only modules are
* covered.
*/
editorTargetDescriptorSuffix: "Editor.Target.cs",

/**
* The suffix appended to the project name when a project carries no editor
* target descriptor to read the name off.
*/
editorTargetFallbackSuffix: "Editor",

/**
* Where the engine installs are recorded on Windows, launcher installs land
* under a per-version key and source builds under the user's `Builds` key,
* keyed there by the GUID a `.uproject` carries as its association.
*/
registry: {
installedEnginesKey: "HKLM\\SOFTWARE\\EpicGames\\Unreal Engine",
installedDirectoryValueName: "InstalledDirectory",
sourceBuildsKey: "HKCU\\SOFTWARE\\Epic Games\\Unreal Engine\\Builds",
},

/**
* Where launcher installs land on macOS, joined with the prefixed version to
* stand in for the registry lookup Windows gets.
*/
macEnginesDir: "/Users/Shared/Epic Games",
macEngineDirPrefix: "UE_",

/**
* The root-relative directory holding the project's own modules.
*/
sourceRootDirName: "Source",

/**
* The root-relative directory holding the project's plugins, each of which
* carries its own `Source` tree.
*/
pluginsDirName: "Plugins",

/**
* The extensions that make a file part of the compile database.
*/
sourceExtensions: [".cpp", ".c", ".cc", ".cxx", ".h", ".hpp", ".hxx", ".inl"],

/**
* The extensions that describe the build itself rather than take part in it,
* `.cs` covers the `.Build.cs` and `.Target.cs` module descriptors, which live
* inside the source trees alongside the code they describe.
*/
moduleDescriptorExtensions: [".cs"],

/**
* The extension of a plugin's own descriptor, which sits above the plugin's
* `Source` tree rather than inside it and so is matched on its own.
*/
pluginDescriptorExtension: ".uplugin",

/**
* The directory names never descended into or watched, the build tool writes
* generated `.cpp` and `.h` files under `Intermediate` that would otherwise
* look like hand-written sources and retrigger the watcher on every run.
*/
ignoredDirNames: ["Intermediate", "Binaries", "Saved", "DerivedDataCache", ".git", "node_modules"],
}

export default COMPILE_DB_CONFIG
24 changes: 24 additions & 0 deletions src/main/config/state.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import type { AppState } from "@/main/types/store"

/**
* The default state used when no state file exists yet, or when the existing one
* is missing fields.
*/
const DEFAULT_APP_STATE: AppState = {
windowPlacement: {
bounds: null,
isMaximized: false,
isFullScreen: false,
},
recentProjects: [],
view: {
filesPaneWidth: 320,
searchIsRegex: false,
isAdvancedSearchOpened: false,
searchIncludePatterns: "",
searchExcludePatterns: "",
isShowingMyLocksOnly: false,
},
}

export default DEFAULT_APP_STATE
6 changes: 4 additions & 2 deletions src/main/config/store.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
/**
* The configuration options for the persisted application store.
* The configuration options for the persisted application stores.
*/
const STORE_CONFIG = {
dirName: "gitgame",
fileName: "config.json",
configFileName: "config.json",
stateFileName: "state.json",
cacheFileName: "cache.json",
configVersion: 1,
maxRecentProjects: 10,
}
Expand Down
39 changes: 26 additions & 13 deletions src/main/config/windows.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,37 @@ const WEB_PREFERENCES: WebPreferences = {
autoplayPolicy: "no-user-gesture-required",
}

/**
* The shared shape of every window that is not the main one, frameless, fixed
* size and centered, each role adds only what makes it its own.
*/
const SECONDARY_WINDOW: BrowserWindowConstructorOptions = {
frame: false,
resizable: false,
minimizable: false,
maximizable: false,
fullscreenable: false,
show: false,
center: true,
roundedCorners: false,
icon: appIcon,
webPreferences: WEB_PREFERENCES,
}

/**
* The default `BrowserWindow` options for every window kind the app opens,
* keyed by role.
*/
const WINDOWS_CONFIG: {
main: BrowserWindowConstructorOptions
dialog: BrowserWindowConstructorOptions
preferences: BrowserWindowConstructorOptions
} = {
main: {
width: 1280,
height: 800,
minWidth: 640,
minHeight: 480,
minWidth: 960,
minHeight: 640,
show: false,
frame: false,
thickFrame: true,
Expand All @@ -43,17 +61,12 @@ const WINDOWS_CONFIG: {
icon: appIcon,
webPreferences: WEB_PREFERENCES,
},
dialog: {
frame: false,
resizable: false,
minimizable: false,
maximizable: false,
fullscreenable: false,
show: false,
center: true,
roundedCorners: false,
icon: appIcon,
webPreferences: WEB_PREFERENCES,
// Sized per variant by the dialogs service, from `DIALOGS_CONFIG`
dialog: SECONDARY_WINDOW,
preferences: {
...SECONDARY_WINDOW,
width: 640,
height: 560,
},
}

Expand Down
13 changes: 13 additions & 0 deletions src/main/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,22 @@ import WINDOWS_CONFIG from "@main/config/windows"
import { registerAppHandlers } from "@main/lib/app/handlers"
import { startAutoLock } from "@main/lib/autoLock"
import { registerAutoLockHandlers } from "@main/lib/autoLock/handlers"
import { startCompileDb } from "@main/lib/compileDb"
import { registerCompileDbHandlers } from "@main/lib/compileDb/handlers"
import { registerDialogsHandlers } from "@main/lib/dialogs"
import { registerFileTreeHandlers } from "@main/lib/fileTree/handlers"
import { registerGitCommandsHandlers } from "@main/lib/gitCommands/handlers"
import { registerLfsCommandsHandlers } from "@main/lib/lfsCommands/handlers"
import { startMcp } from "@main/lib/mcp"
import { registerMcpHandlers } from "@main/lib/mcp/handlers"
import { startPreferences } from "@main/lib/preferences"
import { registerPreferencesHandlers } from "@main/lib/preferences/handlers"
import { registerProjectsHandlers } from "@main/lib/projects/handlers"
import { registerShellsHandlers } from "@main/lib/shells/handlers"
import { startUpdater } from "@main/lib/updater"
import { registerUpdaterHandlers } from "@main/lib/updater/handlers"
import { registerUProjectHandlers } from "@main/lib/uproject/handlers"
import { registerViewStateHandlers } from "@main/lib/viewState/handlers"
import { attachWindowStateBroadcaster, registerWindowsControlHandlers, setMainWindow } from "@main/lib/windows"
import { attachWindowPlacementPersistence, restoreWindowPlacement } from "@main/lib/windows/placement"
import { app, BrowserWindow, shell } from "electron"
Expand Down Expand Up @@ -71,6 +76,13 @@ app.whenReady().then(async () => {
registerUpdaterHandlers()
registerMcpHandlers()
registerAutoLockHandlers()
registerCompileDbHandlers()
registerViewStateHandlers()
registerPreferencesHandlers()

// Hydrate the preferences before anything paints, the renderer reads the theme
// synchronously at preload and would otherwise flash the default one
await startPreferences()

// Create the main window
await createMainWindow()
Expand All @@ -79,6 +91,7 @@ app.whenReady().then(async () => {
startUpdater()
startMcp()
startAutoLock()
startCompileDb()

// Re-create a window in the app when the dock icon is clicked (macOS)
app.on("activate", () => {
Expand Down
Loading
Loading