Add project documentation and clean up obsolete files
- Add CLAUDE.md with project overview and XScript reference - Remove obsolete ai-commit.sh script - Clean up duplicate .env entry in .gitignore Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
8277be6518
commit
1b3b5ee194
1
.gitignore
vendored
1
.gitignore
vendored
@ -47,4 +47,3 @@ tools/steamcmd/
|
||||
|
||||
# Environment files (API keys)
|
||||
.env
|
||||
app/.env
|
||||
|
||||
185
CLAUDE.md
Normal file
185
CLAUDE.md
Normal file
@ -0,0 +1,185 @@
|
||||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
|
||||
## Build Instructions
|
||||
|
||||
**DO NOT BUILD** - The user will build manually. This project uses Qt 6.10.0 with MSVC 2022 on Windows.
|
||||
|
||||
Build commands (for reference only):
|
||||
```bash
|
||||
qmake XPlor.pro
|
||||
nmake # or jom on Windows
|
||||
```
|
||||
|
||||
## Project Overview
|
||||
|
||||
XPlor is a Qt-based binary file format explorer for video game files. It uses **XScript**, a custom DSL for defining binary file structures, allowing new formats to be added without modifying core code.
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
XPlor/
|
||||
├── app/ # Qt GUI application (MainWindow, previews, settings)
|
||||
├── libs/
|
||||
│ ├── dsl/ # XScript engine (lexer, parser, interpreter, typeregistry)
|
||||
│ ├── core/ # Utilities, logging, syntax highlighters
|
||||
│ ├── compression/ # LZO, zlib, Oodle, xcompress64 support
|
||||
│ └── encryption/ # Salsa20, SHA1 support
|
||||
├── definitions/ # XScript format definitions
|
||||
│ ├── cod/ # Call of Duty formats (60+ files)
|
||||
│ ├── asura/ # Sniper Elite V2 formats
|
||||
│ └── [other engines]
|
||||
└── third_party/ # External SDKs (DevIL, Xbox SDK, zlib)
|
||||
```
|
||||
|
||||
## DSL Engine Flow
|
||||
|
||||
1. `TypeRegistry` loads and merges `.xscript` files from `definitions/`
|
||||
2. `Lexer` tokenizes XScript source
|
||||
3. `Parser` builds AST
|
||||
4. `Interpreter` executes AST against binary streams
|
||||
5. Results stored as `QVariantMap` for UI display
|
||||
|
||||
## XScript Language Reference
|
||||
|
||||
### Type Definition
|
||||
```xscript
|
||||
type typename [root, display="Display Name"] byteorder LE
|
||||
{
|
||||
criteria { require _ext == "ff"; }
|
||||
|
||||
// Parse body
|
||||
magic = ascii(read(4));
|
||||
version = u32;
|
||||
}
|
||||
```
|
||||
|
||||
### Scalar Types
|
||||
`u8`, `i8`, `u16`, `i16`, `u32`, `i32`, `u64`, `i64`, `f32`, `f64`, `bool`
|
||||
|
||||
### Built-in Functions
|
||||
|
||||
**Reading:**
|
||||
- `read(n)` - read n bytes
|
||||
- `cstring()` - read null-terminated string
|
||||
- `wstring()` / `wstring_be()` - read UTF-16 LE/BE string
|
||||
- `skip(n)` - skip n bytes
|
||||
- `align(n)` - align to n-byte boundary
|
||||
- `seek(pos)` - seek to absolute position
|
||||
- `pos()` / `size()` - current position / file size
|
||||
|
||||
**Random Access:**
|
||||
- `u8at(off)`, `u16at(off)`, `u32at(off)`, `u64at(off)`, `i32at(off)` - read at offset without advancing
|
||||
- `bytesat(off, len)` - read bytes at offset
|
||||
- `with_seek(offset, expr)` - evaluate expression at offset, restore position
|
||||
|
||||
**Parsing:**
|
||||
- `parse("typename", bytes)` - parse bytes as type (creates new stream)
|
||||
- `parse_here("typename")` - parse type at current position (same stream, delegation pattern)
|
||||
|
||||
**Context:**
|
||||
- `ctx_set(name, value)` - set global context variable (cross-type communication)
|
||||
- `ctx_get(name)` - get global context variable
|
||||
- `set_name(value)` - set item name for tree display
|
||||
- `set_display(value)` - set display name
|
||||
|
||||
**Decompression:**
|
||||
- `zlib(bytes)` - decompress zlib
|
||||
- `xmem(bytes)` - decompress Xbox xcompress
|
||||
- `deflate(bytes)` - decompress raw deflate
|
||||
|
||||
**Conversion:**
|
||||
- `ascii(bytes)` / `utf8(bytes)` / `utf16le(bytes)` / `utf16be(bytes)` - bytes to string
|
||||
- `hex(value)` - format as hex string
|
||||
|
||||
**Collections:**
|
||||
- `make_list()` / `make_object()` - create empty list/object
|
||||
- `push(listName, value)` - append to list
|
||||
- `get(container, key)` - get from list/object
|
||||
- `set(varName, key, value)` - set in list/object
|
||||
- `len(value)` - length of string/bytes/list
|
||||
|
||||
**String:**
|
||||
- `contains(str, sub)`, `starts_with(str, prefix)`, `ends_with(str, suffix)`
|
||||
- `substr(str, start, len)`, `split(str, delim)`, `replace(str, old, new)`
|
||||
- `trim(str)`, `to_lower(str)`, `clean(str)`, `basename(path)`
|
||||
|
||||
**UI Metadata:**
|
||||
- `ui(varName, displayName)` - mark field for readonly display
|
||||
- `ui_edit(varName, displayName)` - mark field for editable display
|
||||
- `hide(varName)` - hide from UI
|
||||
- `set_viewer("hex"|"text"|"image"|"audio")` - set viewer type
|
||||
- `preview(data)` / `set_preview(filename, data)` - set preview data
|
||||
|
||||
**Control:**
|
||||
- `match(value, case1, result1, case2, result2, ..., default)` - switch expression
|
||||
- `bit(value, bit)` / `bit(value, start, count)` - extract bits
|
||||
- `check_criteria("typename")` - test if type criteria matches current position
|
||||
|
||||
### Control Flow
|
||||
```xscript
|
||||
if (condition) { ... } else { ... }
|
||||
while (condition) { ... }
|
||||
repeat count { ... } // provides _i index
|
||||
for i in start..end { ... }
|
||||
break;
|
||||
|
||||
// Match expression (replaces long if-else chains)
|
||||
match(value) {
|
||||
"pattern1" => { ... }
|
||||
"pattern2" | "pattern3" => { ... } // multiple patterns
|
||||
default => { ... }
|
||||
}
|
||||
```
|
||||
|
||||
### Constants
|
||||
```xscript
|
||||
const PTR_INLINE = -1;
|
||||
const MAGIC_HEADER = 0x12345678;
|
||||
```
|
||||
|
||||
### Inline Declaration (simplifies pointer-to-inline patterns)
|
||||
```xscript
|
||||
// Instead of: if (name_ptr == -1) { name = cstring(); ui("name", "Name"); set_name(name); }
|
||||
inline cstring name when name_ptr [ui="Name", set_name];
|
||||
|
||||
// For complex types:
|
||||
inline material mat when mat_ptr;
|
||||
inline itemkeyhandler handler when handler_ptr;
|
||||
```
|
||||
|
||||
### Array Declaration (simplifies repeat/push patterns)
|
||||
```xscript
|
||||
// Instead of: items = 0; repeat(count) { _x = parse_here("type"); items = push("items", _x); }
|
||||
array[count] items: typename;
|
||||
|
||||
// With pointer condition:
|
||||
array[count] items: typename when items_ptr;
|
||||
```
|
||||
|
||||
### Pipeline Syntax
|
||||
```xscript
|
||||
zone = read(size) | zlib | parse("zone");
|
||||
```
|
||||
|
||||
### File Variables
|
||||
- `_path` - full file path
|
||||
- `_name` - filename
|
||||
- `_basename` - filename without extension
|
||||
- `_ext` - file extension (lowercase)
|
||||
|
||||
## Key Files
|
||||
|
||||
- `libs/dsl/interpreter.cpp` - Runtime execution, all built-in functions
|
||||
- `libs/dsl/parser.cpp` - AST generation
|
||||
- `libs/dsl/typeregistry.cpp` - Type loading and file detection
|
||||
- `app/mainwindow.cpp` - Main UI logic
|
||||
- `definitions/cod/fastfile.xscript` - Primary COD format (good example)
|
||||
|
||||
## Conventions
|
||||
|
||||
- Use `ctx_set()`/`ctx_get()` for cross-type context (not `set_global`/`get_global`)
|
||||
- Use `skip(n)` for padding, not `_padding = read(n)`
|
||||
- Pointer values of `-1` indicate inline data follows
|
||||
- Use `-1` consistently (not `4294967295` or `0xFFFFFFFF`)
|
||||
36
ai-commit.sh
36
ai-commit.sh
@ -1,36 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# 1. Stage everything
|
||||
git add -A
|
||||
|
||||
# 2. Get list of staged files
|
||||
FILES=$(git diff --cached --name-only)
|
||||
|
||||
if [ -z "$FILES" ]; then
|
||||
echo "No changes to commit."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# 3. Loop file by file
|
||||
for FILE in $FILES; do
|
||||
# Get diff for this file
|
||||
DIFF=$(git diff --cached -- "$FILE")
|
||||
|
||||
if [ -z "$DIFF" ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
# Ask Ollama for a commit message describing this file change
|
||||
MSG=$(echo "$DIFF" | ollama run gemma3 \
|
||||
"You are a commit bot. Write a SHORT, clear, concise Git commit message for changes in file: $FILE.
|
||||
Only output the commit message, nothing else.
|
||||
Diff:
|
||||
$DIFF")
|
||||
|
||||
# Commit just this file with its message
|
||||
git commit -m "$MSG" -- "$FILE"
|
||||
|
||||
echo "✅ Committed $FILE with message:"
|
||||
echo "$MSG"
|
||||
done
|
||||
Loading…
x
Reference in New Issue
Block a user