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
76 changes: 66 additions & 10 deletions README.org
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ A Parser, Formatter, and Editor for jbeam Files

This project is a command-line tool designed to work with jbeam files (the structured, JSON-like format used in BeamNG to define vehicles, physics, and structures). Initially implemented in Haskell as a fast and robust demo, it has grown into a comprehensive utility for manipulating jbeam data.

** Features
** Features at a glance

*** Complete File Parsing
- Parses entire =.jbeam= files, including comments.
Expand All @@ -18,8 +18,8 @@ This project is a command-line tool designed to work with jbeam files (the struc
- Sorts and sequentially renames all nodes (e.g., =["bf1", ...]= becomes =["bf0", "bf1", "bf2"]=).
- Updates all references to renamed nodes throughout the file to prevent inconsistencies.

*** Configurable Formatting Rules Powered by JBFL
=jbeam_edit= supports user-defined rule files in JBFL (JBeam Formatting Language), a declarative mini-language for specifying formatting behavior.
*** Configurable Formatting Rules, Powered by JBFL
=jbeam-edit= supports user-defined rule files in JBFL (JBeam Formatting Language), a declarative mini-language for specifying formatting behavior.

**** Example rule file (rules.jbfl)

Expand All @@ -39,6 +39,49 @@ This project is a command-line tool designed to work with jbeam files (the struc
- Control indentation, spacing, padding, and decimal precision.
- As a maintainer, enforce customized formatting rules to fit your preference.

** Configuration

When using =jbeam-edit= for the first time, you should generate a default formatting configuration file.

Run one of the following:

#+BEGIN_SRC bash
jbeam-edit -cminimal # Generates a simple, clean formatting config
jbeam-edit -ccomplex # Generates a more detailed and explicit config
#+END_SRC

This will create a file named =rules.jbfl= in your XDG config directory:

- On **Linux/macOS**: =$HOME/.config/jbeam-edit/rules.jbfl=
- On **Windows**: =%APPDATA%\jbeam-edit\rules.jbfl=

This configuration will be used automatically when formatting files, unless a local =.jbeam_edit.jbfl= file is present in the current working directory.

*** Project-Specific Configuration

You can override the global configuration on a per-project basis by placing a .jbeam_edit.jbfl= file in the root of your project.
After creating the user configuration with =jbeam-edit -cminimal= or =jbeam-edit -ccomplex=, you can copy that to your project if you want to apply specific rules on a per-project basis.

#+BEGIN_SRC bash
cp ~/.config/jbeam-edit/rules.jbfl ./.jbeam_edit.jbfl
#+END_SRC

On Windows:

#+BEGIN_SRC powershell
copy "%APPDATA%\jbeam-edit\rules.jbfl" .\.jbeam_edit.jbfl
#+END_SRC

The presence of this file takes precedence over the global configuration and allows for project-specific formatting preferences.

** Examples

For detailed example files and usage instructions, please see the dedicated examples documentation:

[[examples/README.org][Examples Directory README]]

This contains sample =.jbeam= files and formatting rules to help you explore and test jbeam-edit’s features

** Planned Features / TODO

- Integration with editors via Language Server Protocol (LSP)
Expand Down Expand Up @@ -73,33 +116,46 @@ For now, the project remains a Haskell-based tool, but the idea of a C/C++ port

*** Prerequisites

- Haskell Compiler: GHC (https://www.haskell.org/ghc/)
- Haskell Compiler: GHC (https://www.haskell.org/ghc/)
- Build Tool: Stack (https://docs.haskellstack.org)

*** Installation

Clone the repository and build the project using your preferred Haskell build tool:

git clone https://github.com/webdevred/jbeam-tool.git
cd jbeam-tool
#+BEGIN_SRC bash
git clone https://github.com/webdevred/jbeam-tool.git
cd jbeam-tool
stack build
#+END_SRC

*** Usage

Run the tool from the command line as follows:

#+begin_src
#+BEGIN_SRC bash
stack exec jbeam-tool -- [options] <input-file>
#+end_src
#+END_SRC

The tool will:

- Parse the provided jbeam file.
- Format it according to the default or user-defined rules.
- Parse the provided jbeam file.
- Format it according to the default or user-defined rules.
- Automatically sort nodes, rename them sequentially, and update all related references.
- By default, write the formatted output back to the file and create a backup file named <input-file>.bak.
- Use the `-i` or `--in-place` option to modify files directly **without** creating a backup.

Example:

#+BEGIN_SRC bash
jbeam-edit -i example.jbeam
#+END_SRC

This will update `example.jbeam` in place, skipping the backup creation step.

For full usage details and configuration options, please refer to [[EXPLANATION_OF_SOURCE_CODE.org][EXPLANATION_OF_SOURCE_CODE.org]]


*** Contributing

Contributions, bug reports, and feature requests are welcome!
Expand Down
29 changes: 22 additions & 7 deletions app/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -2,39 +2,54 @@ module Main (
main,
) where

import CommandLineOptions
import Control.Monad (unless)
import Core.Node (Node)
import Core.NodeCursor (newCursor)
import Data.Text.Lazy.Encoding (encodeUtf8)
import Formatting (RuleSet, formatNode)
import Formatting.Config
import IOUtils
import Parsing.Jbeam (parseNodes)
import System.Directory (copyFile)
import System.Environment (getArgs)
import Transformation (transform)

import Data.ByteString.Lazy qualified as BL (
toStrict,
writeFile,
)
import Data.List qualified as L (uncons)
import Data.Text.IO qualified as TIO (putStrLn)
import Data.Text.Lazy qualified as TL (fromStrict)

main :: IO ()
main = do
args <- getArgs
opts <- parseOptions args
case opts of
Options {optCopyJbflConfig = Just configType} -> copyToConfigDir configType
_ -> editFile opts

getWritabaleFilename :: FilePath -> Options -> IO FilePath
getWritabaleFilename filename opts =
unless (optInPlace opts) (copyFile filename (filename <> ".bak"))
>> pure filename

editFile :: Options -> IO ()
editFile opts = do
formattingConfig <- readFormattingConfig
case L.uncons args of
Just (filename, _) -> do
case optInputFile opts of
Just filename -> do
outFilename <- getWritabaleFilename filename opts
contents <- tryReadFile [] filename
case contents >>= parseNodes . BL.toStrict of
Right ns -> processNodes ns formattingConfig
Right ns -> processNodes outFilename ns formattingConfig
Left err -> TIO.putStrLn err
Nothing -> TIO.putStrLn "missing arg filename"

processNodes :: Node -> RuleSet -> IO ()
processNodes nodes formattingConfig =
BL.writeFile "hewwu.jbeam"
processNodes :: FilePath -> Node -> RuleSet -> IO ()
processNodes outFile nodes formattingConfig =
BL.writeFile outFile
. encodeUtf8
. TL.fromStrict
. formatNode formattingConfig newCursor
Expand Down
55 changes: 55 additions & 0 deletions examples/README.org
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
* Examples Directory

This file guides you through example files and formatting rules to help you learn and test jbeam-edit’s features hands-on. It includes example JBeam files and JBFL rule files to explore the tool’s capabilities.

** Example JBeam Files

- =minimal.jbeam=
- A simple, clean example JBeam file demonstrating basic parsing and formatting. Running jbeam-edit on this file will:
- Parse the entire structure including comments
- Format the file with consistent indentation and spacing
- Automatically sort and rename nodes sequentially (e.g., "bf1" becomes "bf0", etc.)
- Update all references accordingly
- Automatically move vertices into their correct groups (e.g., LeftTree, MiddleTree, RightTree) to maintain proper structure

** JBFL Configuration Files

- =minimal.jbfl=
Defines a minimal set of formatting rules, focusing on basic indentation and spacing. Ideal for quick, clean formatting without much customization.

- =complex.jbfl=
Contains detailed rules demonstrating advanced formatting capabilities such as controlling padding, decimal precision, and line breaks using JBFL patterns.

** How JBFL Affects Formatting

JBFL (JBeam Formatting Language) is a declarative mini-language that lets you specify how different parts of the JBeam file should be formatted:

- Match sections of the data tree with wildcard patterns
- Control padding amounts, decimal precision, and newline behavior
- Customize formatting to fit your preferences or project standards

By swapping between the minimal and complex JBFL configs, you can see how formatting behavior changes, making the tool flexible for different workflows.

** Using These Examples

To format an example file with the minimal configuration:

#+BEGIN_SRC bash
jbeam-edit -cminimal
stack exec jbeam-edit -- examples/jbeam/minimal.jbeam
#+END_SRC

To try the complex configuration, generate it first and run:

#+BEGIN_SRC bash
jbeam-edit -ccomplex
stack exec jbeam-edit -- examples/jbeam/complex.jbeam
#+END_SRC

Feel free to modify these examples or create your own to better suit your projects.

These examples provide a practical way to understand and customize how jbeam-edit handles your JBeam files.

For complete documentation and usage, please refer to the root [[file:README.org][README.org]].

There is also [[file:JBFL_DOCS.org][JBFL_DOCS.org]] for detailed information on the JBFL formatting language.
18 changes: 18 additions & 0 deletions examples/ast/jbfl/complex.hs
Original file line number Diff line number Diff line change
@@ -1,6 +1,24 @@
RuleSet
( fromList
[
( NodePattern
( fromList
[ AnyObjectKey
, Selector
( ObjectKey "nodes" )
, Selector
( ArrayIndex 0 )
, AnyArrayIndex
]
)
, fromList
[
( SomeKey PadAmount
, SomeProperty PadAmount 0
)
]
)
,
( NodePattern
( fromList
[ AnyObjectKey
Expand Down
36 changes: 14 additions & 22 deletions examples/jbfl/complex.jbfl
Original file line number Diff line number Diff line change
@@ -1,35 +1,27 @@
// Apply default padding and decimal formatting to all node elements
.*.nodes[*][*] {
// Show numbers with exactly 3 decimal places (e.g., 1.000)
PadDecimals: 3;
// Disable padding for header row (column names)
.*.nodes[0][*] {
PadAmount: 0; // no padding here
// This row has string headers, so no numeric formatting needed
}

// Pad numeric values to 6 characters wide for alignment
PadAmount: 6;
/* Default formatting for all numeric node values */
.*.nodes[*][*] {
PadDecimals: 3; // Show 3 decimal places for uniformity
PadAmount: 6; // Align numeric columns
}

// Special padding for the first element in each node list (vertex names)
// Padding for vertex names (first element in nodes Array)
.*.nodes[*][0] {
/*
Vertex names can be up to 8 characters long,
so we pad them to width 8 for neat column alignment.
This improves readability by lining up numeric columns.
*/
PadAmount: 8;
// Wider for typical vertex IDs
}

.*.nodes[*] {
/*
Prevent inserting newlines inside node elements with complex children.
Disable complex newlines here to keep nested structures inline.
This avoids cluttering the output with unnecessary line breaks,
making it easier to scan.
*/
NoComplexNewLine: true;
// Keep nodes inline for easier reading
}

// Flexbodies typically contain nested lists representing grouped geometry or materials
// Keep complex nested content inline rather than breaking into multiple lines
// This makes output more compact and easier to scan given typical data patterns
// Flexbodies usually contain nested data structures
.*.flexbodies[*] {
NoComplexNewLine: true;
NoComplexNewLine: true; /* compact formatting for flexbodies */
}
1 change: 1 addition & 0 deletions jbeam-edit.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ flag dump-ast

library
exposed-modules:
CommandLineOptions
Core.Node
Core.NodeCursor
Core.NodePath
Expand Down
Loading