Skip to content

Commit 206859d

Browse files
added .tkproj creation
1 parent 63a36a3 commit 206859d

3 files changed

Lines changed: 81 additions & 22 deletions

File tree

src/archiveFsCommands.ts

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -648,11 +648,20 @@ export function registerArchiveFileCommands(context: vscode.ExtensionContext): v
648648
if (!entry?.resourceUri || !isDiskMutableItem(entry)) {
649649
return;
650650
}
651+
if (entry.entryName.toLowerCase().endsWith('.tkproj')) {
652+
void vscode.window.showErrorMessage('Project files must be named exactly ".tkproj" and cannot be renamed.');
653+
return;
654+
}
651655
const newName = await vscode.window.showInputBox({
652656
prompt: 'New name',
653657
value: entry.entryName,
654-
validateInput: (value) =>
655-
value.trim() ? undefined : 'Name cannot be empty',
658+
validateInput: (value) => {
659+
if (!value.trim()) return 'Name cannot be empty';
660+
if (value.toLowerCase().endsWith('.tkproj') && value.toLowerCase() !== '.tkproj') {
661+
return 'Project file must be named exactly ".tkproj"';
662+
}
663+
return undefined;
664+
}
656665
});
657666
if (!newName || newName === entry.entryName) {
658667
return;
@@ -709,8 +718,13 @@ export function registerArchiveFileCommands(context: vscode.ExtensionContext): v
709718
}
710719
const name = await vscode.window.showInputBox({
711720
prompt: 'New file name',
712-
validateInput: (value) =>
713-
value.trim() ? undefined : 'Name cannot be empty',
721+
validateInput: (value) => {
722+
if (!value.trim()) return 'Name cannot be empty';
723+
if (value.toLowerCase().endsWith('.tkproj') && value.toLowerCase() !== '.tkproj') {
724+
return 'Project file must be named exactly ".tkproj"';
725+
}
726+
return undefined;
727+
}
714728
});
715729
if (!name) {
716730
return;
@@ -732,7 +746,7 @@ export function registerArchiveFileCommands(context: vscode.ExtensionContext): v
732746
},
733747
});
734748
refreshArchives();
735-
await vscode.window.showTextDocument(target);
749+
await vscode.commands.executeCommand('vscode.open', target);
736750
} catch (error) {
737751
const message = error instanceof Error ? error.message : String(error);
738752
void vscode.window.showErrorMessage(`Create file failed: ${message}`);

src/extension.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -514,7 +514,7 @@ class SarcProvider implements vscode.FileSystemProvider {
514514

515515
const cached = this.fileContentCache.get(uri.toString());
516516
if (cached instanceof Uint8Array && cached.length === content.length && Buffer.compare(cached, content) === 0) {
517-
logger.info(`Skipping write for unchanged binary file: ${fsPath}`);
517+
logger.info(`Skipping write for unchanged file: ${fsPath}`);
518518
return;
519519
}
520520
await fs.promises.writeFile(fsPath, content);
@@ -562,7 +562,7 @@ class SarcProvider implements vscode.FileSystemProvider {
562562
} else {
563563
const cached = this.fileContentCache.get(uri.toString());
564564
if (cached instanceof Uint8Array && cached.length === content.length && Buffer.compare(cached, content) === 0) {
565-
logger.info(`Skipping write and canonical sync for unchanged binary file inside archive: ${fsPath}`);
565+
logger.info(`Skipping write and canonical sync for unchanged file inside archive: ${fsPath}`);
566566
return;
567567
}
568568

src/tkprojEditor.ts

Lines changed: 60 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,33 @@ export class TkprojEditorProvider implements vscode.CustomTextEditorProvider {
3939
): Promise<void> {
4040
webviewPanel.webview.options = { enableScripts: true };
4141

42+
if (document.getText().trim() === '') {
43+
const defaultData: TkprojData = {
44+
Mod: {
45+
Name: "New Project",
46+
Author: "Unknown",
47+
Version: "1.0.0",
48+
Description: "",
49+
Id: generateUlidNumber(),
50+
Contributors: [],
51+
Dependencies: []
52+
},
53+
Flags: {
54+
TrackRemovedRsDbEntries: false
55+
}
56+
};
57+
const edit = new vscode.WorkspaceEdit();
58+
edit.insert(document.uri, new vscode.Position(0, 0), JSON.stringify(defaultData, null, 2));
59+
await vscode.workspace.applyEdit(edit);
60+
await document.save();
61+
}
62+
63+
let isUpdatingFromWebview = false;
64+
4265
const update = () => {
66+
if (isUpdatingFromWebview) {
67+
return;
68+
}
4369
try {
4470
const data = JSON.parse(document.getText()) as TkprojData;
4571
webviewPanel.webview.html = buildHtml(data);
@@ -64,14 +90,22 @@ export class TkprojEditorProvider implements vscode.CustomTextEditorProvider {
6490
if (msg.type === 'update' && msg.field && msg.value !== undefined) {
6591
const data = JSON.parse(document.getText()) as TkprojData;
6692
applyField(data, msg.field, msg.value as string);
67-
await writeBack(document, data);
68-
}
69-
if (msg.type === 'updateContributors' && msg.contributors) {
93+
isUpdatingFromWebview = true;
94+
try {
95+
await writeBack(document, data);
96+
} finally {
97+
isUpdatingFromWebview = false;
98+
}
99+
} else if (msg.type === 'updateContributors' && msg.contributors) {
70100
const data = JSON.parse(document.getText()) as TkprojData;
71101
data.Mod.Contributors = msg.contributors;
72-
await writeBack(document, data);
73-
}
74-
if (msg.type === 'browseThumbnail') {
102+
isUpdatingFromWebview = true;
103+
try {
104+
await writeBack(document, data);
105+
} finally {
106+
isUpdatingFromWebview = false;
107+
}
108+
} else if (msg.type === 'browseThumbnail') {
75109
const result = await vscode.window.showOpenDialog({
76110
canSelectMany: false,
77111
filters: { Images: ['png', 'jpg', 'jpeg', 'webp'] },
@@ -128,16 +162,27 @@ function escHtml(s: string): string {
128162
return s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
129163
}
130164

165+
function generateUlidNumber(): string {
166+
let id = '';
167+
for (let i = 0; i < 26; i++) {
168+
id += Math.floor(Math.random() * 10).toString();
169+
}
170+
if (id === '00000000000000000000000001') {
171+
return generateUlidNumber();
172+
}
173+
return id;
174+
}
175+
131176
function buildContributorRows(contributors: TkprojContributor[]): string {
132177
if (!contributors.length) {
133178
return '';
134179
}
135180
return contributors.map((c, i) => /* html */`
136181
<div class="contrib-row" data-idx="${i}">
137182
<input type="text" class="contrib-name" placeholder="Name" value="${escHtml(c.Author ?? '')}"
138-
onchange="updateContrib()" />
183+
oninput="updateContrib()" />
139184
<input type="text" class="contrib-work" placeholder="Contribution (e.g. Models; Textures)"
140-
value="${escHtml(c.Contribution ?? '')}" onchange="updateContrib()" />
185+
value="${escHtml(c.Contribution ?? '')}" oninput="updateContrib()" />
141186
<button class="btn btn-sm btn-danger" onclick="removeContrib(${i})">-</button>
142187
</div>`).join('');
143188
}
@@ -255,22 +300,22 @@ function buildHtml(data: TkprojData): string {
255300
<div class="field">
256301
<label>Name</label>
257302
<input type="text" id="name" value="${escHtml(mod.Name ?? '')}"
258-
onchange="send('name', this.value)" />
303+
oninput="send('name', this.value)" />
259304
</div>
260305
<div class="field">
261306
<label>Author</label>
262307
<input type="text" id="author" value="${escHtml(mod.Author ?? '')}"
263-
onchange="send('author', this.value)" />
308+
oninput="send('author', this.value)" />
264309
</div>
265310
<div class="field">
266311
<label>Version</label>
267312
<input type="text" id="version" value="${escHtml(mod.Version ?? '')}"
268-
onchange="send('version', this.value)" />
313+
oninput="send('version', this.value)" />
269314
</div>
270315
<div class="field">
271316
<label>Description (Markdown supported)</label>
272317
<textarea id="description"
273-
onchange="send('description', this.value)">${escHtml(mod.Description ?? '')}</textarea>
318+
oninput="send('description', this.value)">${escHtml(mod.Description ?? '')}</textarea>
274319
</div>
275320
</div>
276321
</div>
@@ -294,7 +339,7 @@ function buildHtml(data: TkprojData): string {
294339
<label>Thumbnail Path</label>
295340
<div class="thumb-row">
296341
<input type="text" id="thumbnailPath" value="${escHtml(thumbPath)}"
297-
onchange="send('thumbnailPath', this.value)" />
342+
oninput="send('thumbnailPath', this.value)" />
298343
<button class="btn" onclick="browse()">Browse...</button>
299344
</div>
300345
</div>
@@ -336,8 +381,8 @@ function buildHtml(data: TkprojData): string {
336381
div.className = 'contrib-row';
337382
div.dataset.idx = idx;
338383
div.innerHTML =
339-
'<input type="text" class="contrib-name" placeholder="Name" onchange="updateContrib()" />' +
340-
'<input type="text" class="contrib-work" placeholder="Contribution (e.g. Models; Textures)" onchange="updateContrib()" />' +
384+
'<input type="text" class="contrib-name" placeholder="Name" oninput="updateContrib()" />' +
385+
'<input type="text" class="contrib-work" placeholder="Contribution (e.g. Models; Textures)" oninput="updateContrib()" />' +
341386
'<button class="btn btn-sm btn-danger" onclick="removeContrib(' + idx + ')">-</button>';
342387
list.appendChild(div);
343388
}

0 commit comments

Comments
 (0)