Skip to content

Commit 4769e0f

Browse files
authored
Merge branch 'main' into perf
2 parents e9728e0 + b7a8ab9 commit 4769e0f

33 files changed

Lines changed: 1342 additions & 706 deletions

.github/workflows/release.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ jobs:
4747
user-email: ${{ github.event.inputs.email }}
4848
run: dotnet run --project build -- -t Release
4949
- name: Publish to Open VSX Registry
50-
uses: HaaLeo/publish-vscode-extension@v1
50+
uses: HaaLeo/publish-vscode-extension@v2
5151
id: publishToOpenVSX
5252
with:
5353
packagePath: "./release"

.vscode-test.js

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,12 @@
11

2-
/** @type {import('@vscode/test-cli').TestConfig} */
2+
/** @type {import('@vscode/test-cli').IBaseTestConfiguration} */
33
module.exports = {
44
vscode: 'stable',
55
extensionDevelopmentPath: "release",
6-
// extensionTestsEnv: { NODE_ENV: 'test' },
7-
// extensionTestsPath: './release/bin/client/test/suite',
86
files: './release/bin/client/test/suite/**/*.test.js',
7+
workspaceFolder: "./release/bin/client/test/sample",
98
launchArgs: [
10-
// Sample workspace the tests expect
11-
'./client/test/sample',
129
// Bring the file under test into the workspace
1310
'./client/test/sample/events/irm.txt'
1411
]
15-
// workplaceFolder: "D:\Synced\Git\Personal\cwtools-vscode\client\test\sample mod"
1612
}

.vscode/launch.json

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,16 @@
2323
"name": "Extension Tests",
2424
"type": "extensionHost",
2525
"request": "launch",
26-
"runtimeExecutable": "${execPath}",
27-
"args": [
28-
"--extensionDevelopmentPath=${workspaceFolder}/release",
29-
"--extensionTestsPath=${workspaceFolder}/release/bin/client/test/suite/index"
30-
],
31-
"outFiles": [
32-
"${workspaceFolder}/release/bin/client/test/**/*.js"
33-
]
26+
"preLaunchTask": "UpdateBuild",
27+
// "runtimeExecutable": "${execPath}",
28+
"testConfiguration": "${workspaceFolder}/.vscode-test.js",
29+
// "args": [
30+
// "--extensionDevelopmentPath=${workspaceFolder}/release",
31+
// "--extensionTestsPath=${workspaceFolder}/release/bin/client/test/suite/index"
32+
// ],
33+
// "outFiles": [
34+
// "${workspaceFolder}/release/bin/client/test/**/*.js"
35+
// ]
3436
},
3537
{
3638
"preLaunchTask": "UpdateBuildDebug",

CHANGELOG.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,18 @@
1-
### 0.10.27-pre
1+
### 0.10.30
2+
* HOI4: Add country_metadata, music, portraits, and sound folders to cache
3+
4+
### 0.10.29
5+
* Add "integrated_dlc" directory
6+
7+
### 0.10.28
8+
* Add basic support for EU5
9+
* Fix DLC references
10+
* Fix completion replacement range
11+
12+
### 0.10.27
213
* Remove unused config settings
314
* Added chinese localisation for extension setings and actions
15+
* Various performance improvements
416

517
### 0.10.26
618
* Fix stellaris log parsing

CLAUDE.md

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## Project Overview
6+
7+
CWTools is a Visual Studio Code extension that provides language services for Paradox Interactive game modding, supporting games like Stellaris, Hearts of Iron IV, Europa Universalis IV, Crusader Kings II/III, Victoria 2/3, and Imperator: Rome. The extension offers syntax validation, autocomplete, tooltips, localization checking, and visual graph analysis for game scripts.
8+
9+
## Architecture
10+
11+
This is a hybrid .NET/TypeScript VS Code extension with three main components:
12+
13+
### Backend (.NET/F#)
14+
- **Main** (`src/Main/`): Core F# language server providing validation, completion, and analysis
15+
- **LSP** (`src/LSP/`): Language Server Protocol implementation in F#
16+
- **CSharpExtensions** (`src/CSharpExtensions/`): C# helper utilities
17+
- Dependencies: Uses CWTools library via Paket (git submodule in `paket-files/`)
18+
19+
### Frontend (TypeScript)
20+
- **Client Extension** (`client/extension/`): VS Code extension host and commands
21+
- **Webview** (`client/webview/`): Graph visualization using Cytoscape.js
22+
- **Test Suite** (`client/test/`): Extension tests with sample Stellaris mod files
23+
24+
### Build System
25+
- **FAKE build script** (`build/Program.fs`): Cross-platform F# build automation
26+
- **TypeScript compilation**: Uses `tsc` and `rollup` for client bundling
27+
- **Release packaging**: Creates `.vsix` files for VS Code marketplace
28+
29+
## Development Commands
30+
31+
### Building
32+
```bash
33+
# Windows
34+
./build.cmd QuickBuild
35+
36+
# Unix/Linux
37+
./build.sh QuickBuild
38+
39+
# Debug build
40+
./build.cmd QuickBuildDebug
41+
```
42+
43+
### TypeScript Client
44+
```bash
45+
npm install
46+
npm run compile # Compile TypeScript + bundle webview
47+
npm test # Run VS Code extension tests
48+
```
49+
50+
### Available Build Targets
51+
- `QuickBuild`: Build for local development (Release)
52+
- `QuickBuildDebug`: Build for local development (Debug)
53+
- `DryRelease`: Full package build without publishing
54+
- `Release`: Full build + publish to marketplace
55+
56+
### Testing
57+
VS Code extension tests are located in `client/test/suite/` and use the sample Stellaris mod in `client/test/sample/` for validation scenarios.
58+
59+
## Key Files
60+
61+
- `package.json`: Node.js dependencies and scripts for TypeScript client
62+
- `release/package.json`: VS Code extension manifest and configuration
63+
- `fsharp-language-server.sln`: .NET solution with F# projects
64+
- `paket.dependencies`: .NET package management
65+
- Build scripts: `build.cmd` (Windows) / `build.sh` (Unix)
66+
67+
## Development Workflow
68+
69+
1. Use `./build.cmd QuickBuild` for initial setup and F# server compilation
70+
2. Use `npm run compile` for TypeScript changes during development
71+
3. Debug by launching "Launch Extension" configuration in VS Code
72+
4. Test with sample Paradox game mod files in `client/test/sample/`
73+
5. Run tests with `npm test` before committing changes
74+
75+
## CWTools Integration
76+
77+
The extension integrates with the CWTools library (F# game script parser/validator) via git submodule. The build system automatically pulls the latest CWTools when building the language server.

README.md

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,27 @@ This extension is still in preview, it may not work, it may stop working at any
3636
* and a number of other specific validators
3737
* "Code actions" to generate .yml for missing localisation
3838

39+
## Usage
40+
41+
1. Install this extension
42+
2. Open your mod folder directly, which should be within a folder containing the game name:
43+
44+
* `C:\Users\name\Documents\Paradox Interactive\Stellaris\mod\your_mod`
45+
46+
3. Follow the prompts to select your vanilla folder
47+
4. Edit files and watch syntax errors show up when you make mistakes
48+
5. Wait up to a minute for the extension to scan your mod and find errors
49+
50+
### Multiple mods - workspace
51+
52+
If you have multiple mods that need to be loaded at once, use VS Code's [multi-root workspace](https://code.visualstudio.com/docs/editing/workspaces/workspaces#_untitled-multiroot-workspaces) feature.
53+
54+
1. Open your first mod
55+
2. Use "File", "Add folder to workspace" to add your next mod
56+
3. cwtools should reload including both mods and vanilla in context using correct mod load order
57+
58+
If you want to browse vanilla files, you can use the "CWTOOLS LOADED FILES" section in the Explorer tab.
59+
3960
### Completion
4061

4162
![Completion](https://raw.githubusercontent.com/cwtools/cwtools-vscode/refs/heads/main/release/docs/completion.gif)
@@ -64,22 +85,6 @@ This extension is still in preview, it may not work, it may stop working at any
6485

6586
![Find all references](https://raw.githubusercontent.com/cwtools/cwtools-vscode/refs/heads/main/release/docs/findallrefs.png)
6687

67-
## Usage
68-
69-
1. Install this extension
70-
2. If on linux, possibly follow [these instructions](https://code.visualstudio.com/docs/setup/linux#_error-enospc)
71-
3. Either open your mod folder directly
72-
4. or open the Game folder containing your mods. E.g. for Stellaris this can be one of:
73-
* "C:\Users\name\Paradox Interactive\Stellaris"
74-
* "C:\Program Files(x86)\Steam\steamapps\common\Stellaris"
75-
76-
or on linux
77-
* "/home/name/.local/share/Paradox Interactive/Stellars"
78-
* "/home/name/.steam/steam/steamapps/common/Stellaris"
79-
5. Follow the prompts to select your vanilla folder
80-
6. Edit files and watch syntax errors show up when you make mistakes
81-
7. Wait up to a minute for the extension to scan all your mods and find all errors
82-
8388
## Links
8489

8590
* [vic2-config](https://github.com/cwtools/cwtools-vic2-config)

build/Program.fs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,9 @@ let initTargets () =
241241

242242
Target.create "CopyHtml" (fun _ -> !!("client/webview/*.css") |> Shell.copyFiles "release/bin/client/webview")
243243

244+
Target.create "CopyTestSamples" (fun _ ->
245+
Shell.copyDir "release/bin/client/test/sample" "client/test/sample" (fun _ -> true))
246+
244247

245248
Target.create "BuildPackage" (fun _ -> buildPackage "release")
246249

@@ -293,6 +296,7 @@ let buildTargetTree () =
293296
==> "BuildClient"
294297
==> "CopyDocs"
295298
==> "CopyHtml"
299+
==> "CopyTestSamples"
296300
==> "PrepareClient"
297301
==> "PrePackage"
298302
==>! "BuildPackage"

client/extension/extension.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import * as path from 'path';
88
import * as os from 'os';
99
import * as fs from 'fs';
1010
import * as vs from 'vscode';
11-
import { workspace, ExtensionContext, window, Disposable, Position, Uri, WorkspaceEdit, TextEdit, Range, commands, env } from 'vscode';
11+
import { workspace, ExtensionContext, window, Disposable, Uri, WorkspaceEdit, TextEdit, Range, commands, env } from 'vscode';
1212
import { LanguageClient, LanguageClientOptions, ServerOptions, TransportKind, NotificationType, ExecuteCommandRequest, ExecuteCommandParams, RevealOutputChannelOn } from 'vscode-languageclient/node';
1313

1414
import { FileExplorer, FileListItem } from './fileExplorer';
@@ -24,6 +24,7 @@ const irRemote = `https://github.com/cwtools/cwtools-ir-config`;
2424
const vic2Remote = `https://github.com/cwtools/cwtools-vic2-config`;
2525
const vic3Remote = `https://github.com/cwtools/cwtools-vic3-config`;
2626
const ck3Remote = `https://github.com/cwtools/cwtools-ck3-config`;
27+
const eu5Remote = `https://github.com/kaiser-chris/cwtools-eu5-config`;
2728

2829
export let defaultClient: LanguageClient;
2930
let fileList : FileListItem[];
@@ -75,6 +76,7 @@ export async function activate(context: ExtensionContext) {
7576
case "vic2": repoPath = vic2Remote; break;
7677
case "vic3": repoPath = vic3Remote; break;
7778
case "ck3": repoPath = ck3Remote; break;
79+
case "eu5": repoPath = eu5Remote; break;
7880
default: repoPath = stellarisRemote; break;
7981
}
8082
console.log(language + " " + repoPath);
@@ -100,7 +102,7 @@ export async function activate(context: ExtensionContext) {
100102
// Register the server for F# documents
101103
documentSelector: [{ scheme: 'file', language: 'paradox' }, { scheme: 'file', language: 'yaml' }, { scheme: 'file', language: 'stellaris' },
102104
{ scheme: 'file', language: 'hoi4' }, { scheme: 'file', language: 'eu4' }, { scheme: 'file', language: 'ck2' }, { scheme: 'file', language: 'imperator' }
103-
, { scheme: 'file', language: 'vic2' }, { scheme: 'file', language: 'vic3' }, { scheme: 'file', language: 'ck3' }, { scheme: 'file', language: 'paradox'}],
105+
, { scheme: 'file', language: 'vic2' }, { scheme: 'file', language: 'vic3' }, { scheme: 'file', language: 'ck3' }, { scheme: 'file', language: 'eu5' }, { scheme: 'file', language: 'paradox'}],
104106
synchronize: {
105107
// Synchronize the setting section 'languageServerExample' to the server
106108
configurationSection: 'cwtools',
@@ -109,7 +111,7 @@ export async function activate(context: ExtensionContext) {
109111
fileEvents: fileEvents
110112
},
111113
initializationOptions: {
112-
language: language,
114+
language: language === 'eu5' ? 'paradox' : language,
113115
isVanillaFolder: isVanillaFolder,
114116
rulesCache: cacheDir,
115117
rules_version: workspace.getConfiguration('cwtools').get('rules_version'),
@@ -133,7 +135,6 @@ export async function activate(context: ExtensionContext) {
133135
const promptVanillaPath = new NotificationType<string>('promptVanillaPath')
134136
interface DidFocusFile { uri : string }
135137
const didFocusFile = new NotificationType<DidFocusFile>('didFocusFile')
136-
interface GetWordRangeAtPositionParams { position : Position, uri: string }
137138
let status: Disposable;
138139
interface UpdateFileList { fileList: FileListItem[] }
139140
const updateFileList = new NotificationType<UpdateFileList>('updateFileList');
@@ -227,6 +228,7 @@ export async function activate(context: ExtensionContext) {
227228
case "vic2": gameDisplay = "Victoria II"; break;
228229
case "vic3": gameDisplay = "Victoria 3"; break;
229230
case "ck3": gameDisplay = "Crusader Kings III"; break;
231+
case "eu5": gameDisplay = "Europa Universalis V"; break;
230232
}
231233
const result = await window.showInformationMessage("Please select the vanilla installation folder for " + gameDisplay, "Select folder");
232234
if(!result) {
@@ -268,6 +270,10 @@ export async function activate(context: ExtensionContext) {
268270
game = "imperator";
269271
dir = path.join(dir, "game");
270272
break;
273+
case "Europa Universalis V":
274+
game = "eu5";
275+
dir = path.join(dir, "game");
276+
break;
271277
}
272278
console.log(path.join(dir, "common"));
273279
if (game === "" || !(fs.existsSync(path.join(dir, "common")))) {
@@ -366,7 +372,7 @@ export async function activate(context: ExtensionContext) {
366372
}
367373

368374
let languageId : string;
369-
const knownLanguageIds = ["stellaris", "eu4", "hoi4", "ck2", "imperator", "vic2", "vic3", "ck3"];
375+
const knownLanguageIds = ["stellaris", "eu4", "hoi4", "ck2", "imperator", "vic2", "vic3", "ck3", "eu5"];
370376
const getLanguageIdFallback = async function() {
371377
const markerFiles = await workspace.findFiles("**/*.txt", null, 1);
372378
if (markerFiles.length == 1) {
@@ -389,6 +395,7 @@ export async function activate(context: ExtensionContext) {
389395
case "vic2": languageId = "vic2"; break;
390396
case "vic3": languageId = "vic3"; break;
391397
case "ck3": languageId = "ck3"; break;
398+
case "eu5": languageId = "eu5"; break;
392399
default: languageId = "paradox"; break;
393400
}
394401
async function findExeInFiles(gameExeName: string, binariesPrefix = false) {
@@ -422,6 +429,7 @@ export async function activate(context: ExtensionContext) {
422429
{ id: "vic2", exeName: "v2game", binariesPrefix: false },
423430
{ id: "ck3", exeName: "ck3", binariesPrefix: true },
424431
{ id: "vic3", exeName: "victoria3", binariesPrefix: true },
432+
{ id: "eu5", exeName: "eu5", binariesPrefix: true },
425433
];
426434

427435
const promises = games.map(({ exeName, binariesPrefix }) =>

0 commit comments

Comments
 (0)