Skip to content

Conversation

@Yahm3
Copy link
Contributor

@Yahm3 Yahm3 commented Nov 15, 2025

This commit hopefully accomplishes the todo that was made to use the system object to get the current working directory

Summary by CodeRabbit

Release Notes

  • New Features

    • Graphics drawing system with primitives (lines, rectangles, ovals, text, images)
    • Image creation, loading, and resizing capabilities
    • Metal brush filter for artistic effects
    • Settings dialogs for editor and project configuration
    • Dark and light theme support for the UI
    • Enhanced dynamic plugin loading system
  • Chores

    • Updated dependencies and build tools
    • Added testing infrastructure

Yahm3 and others added 30 commits August 6, 2025 07:14
The word was previously mispelled as 'araound'
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
hexaredecimal and others added 18 commits October 10, 2025 07:06
Bumps [org.apache.maven.plugins:maven-jar-plugin](https://github.com/apache/maven-jar-plugin) from 3.2.0 to 3.4.2.
- [Release notes](https://github.com/apache/maven-jar-plugin/releases)
- [Commits](apache/maven-jar-plugin@maven-jar-plugin-3.2.0...maven-jar-plugin-3.4.2)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-jar-plugin
  dependency-version: 3.4.2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Bumps [org.apache.maven.plugins:maven-enforcer-plugin](https://github.com/apache/maven-enforcer) from 3.5.0 to 3.6.1.
- [Release notes](https://github.com/apache/maven-enforcer/releases)
- [Commits](apache/maven-enforcer@enforcer-3.5.0...enforcer-3.6.1)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-enforcer-plugin
  dependency-version: 3.6.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Bumps [org.junit:junit-bom](https://github.com/junit-team/junit-framework) from 5.12.2 to 5.13.4.
- [Release notes](https://github.com/junit-team/junit-framework/releases)
- [Commits](junit-team/junit-framework@r5.12.2...r5.13.4)

---
updated-dependencies:
- dependency-name: org.junit:junit-bom
  dependency-version: 5.13.4
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Bumps [org.apache.maven.plugins:maven-assembly-plugin](https://github.com/apache/maven-assembly-plugin) from 2.4.1 to 3.7.1.
- [Release notes](https://github.com/apache/maven-assembly-plugin/releases)
- [Commits](apache/maven-assembly-plugin@maven-assembly-plugin-2.4.1...maven-assembly-plugin-3.7.1)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-assembly-plugin
  dependency-version: 3.7.1
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Bumps [org.bidib.jbidib.com.vldocking:vldocking](https://github.com/akuhtz/vldocking) from 3.0.10 to 3.0.11.
- [Release notes](https://github.com/akuhtz/vldocking/releases)
- [Changelog](https://github.com/akuhtz/vldocking/blob/master/CHANGELOG.md)
- [Commits](akuhtz/vldocking@bidib-3.0.10...bidib-3.0.11)

---
updated-dependencies:
- dependency-name: org.bidib.jbidib.com.vldocking:vldocking
  dependency-version: 3.0.11
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Bumps [org.antlr:antlr4-runtime](https://github.com/antlr/antlr4) from 4.9.3 to 4.13.2.
- [Release notes](https://github.com/antlr/antlr4/releases)
- [Changelog](https://github.com/antlr/antlr4/blob/dev/CHANGES.txt)
- [Commits](antlr/antlr4@4.9.3...4.13.2)

---
updated-dependencies:
- dependency-name: org.antlr:antlr4-runtime
  dependency-version: 4.13.2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Bumps [org.graalvm.buildtools:native-maven-plugin](https://github.com/graalvm/native-build-tools) from 0.10.0 to 0.11.0.
- [Release notes](https://github.com/graalvm/native-build-tools/releases)
- [Commits](graalvm/native-build-tools@0.10.0...0.11.0)

---
updated-dependencies:
- dependency-name: org.graalvm.buildtools:native-maven-plugin
  dependency-version: 0.11.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Bumps [com.formdev:flatlaf](https://github.com/JFormDesigner/FlatLaf) from 3.6 to 3.6.1.
- [Release notes](https://github.com/JFormDesigner/FlatLaf/releases)
- [Changelog](https://github.com/JFormDesigner/FlatLaf/blob/main/CHANGELOG.md)
- [Commits](JFormDesigner/FlatLaf@3.6...3.6.1)

---
updated-dependencies:
- dependency-name: com.formdev:flatlaf
  dependency-version: 3.6.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Bumps [org.graalvm.buildtools:native-maven-plugin](https://github.com/graalvm/native-build-tools) from 0.11.0 to 0.11.1.
- [Release notes](https://github.com/graalvm/native-build-tools/releases)
- [Commits](graalvm/native-build-tools@0.11.0...0.11.1)

---
updated-dependencies:
- dependency-name: org.graalvm.buildtools:native-maven-plugin
  dependency-version: 0.11.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Bumps [org.junit:junit-bom](https://github.com/junit-team/junit-framework) from 5.13.4 to 6.0.0.
- [Release notes](https://github.com/junit-team/junit-framework/releases)
- [Commits](junit-team/junit-framework@r5.13.4...r6.0.0)

---
updated-dependencies:
- dependency-name: org.junit:junit-bom
  dependency-version: 6.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Bumps [org.apache.maven.plugins:maven-enforcer-plugin](https://github.com/apache/maven-enforcer) from 3.6.1 to 3.6.2.
- [Release notes](https://github.com/apache/maven-enforcer/releases)
- [Commits](apache/maven-enforcer@enforcer-3.6.1...enforcer-3.6.2)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-enforcer-plugin
  dependency-version: 3.6.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
This commit hopefully accomplishes the todo that was made to use the system object to get the current working directory
@Yahm3 Yahm3 requested a review from hexaredecimal November 15, 2025 13:46
@Yahm3 Yahm3 added the enhancement New feature or request label Nov 15, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 15, 2025

Walkthrough

This PR integrates graphics rendering capabilities into the Piccode language with corresponding Java native implementations, introduces theme management and settings dialogs, enhances the plugin system with dynamic loading, adds comprehensive README validation tests, and updates build configuration. Multiple new Piccode modules provide bindings for drawing operations, image handling, and filter effects.

Changes

Cohort / File(s) Summary
Build & Configuration
.github/dependabot.yml, .gitignore, pom.xml, pytest.ini, requirements-test.txt
Added Dependabot configuration for weekly Maven updates; added JAR file ignore rule; updated dependency versions (antlr4-runtime 4.9.3→4.13.2, flatlaf 3.6→3.6.1, junit-bom 5.12.2→6.0.0); bumped Maven plugin versions (jar, assembly, enforcer, GraalVM native build tool); added Python test dependencies and pytest configuration.
Documentation
README.md
Corrected spelling "Piccaso"→"Picasso"; contains unresolved merge conflict markers and duplicated sections across About, Download, Building, Inspired by, References, and License sections with competing content versions.
Piccode Language Modules
piccode/context/ctx.pics, piccode/image/image.pics, piccode/filters/filter.pics, piccode/filters/metal/brushMetal.pics, piccode/pen/draw.pics, piccode/render/context.pics
Added graphics API modules: Context (fromRect, from, drop), Image (new, newWithType, getContext, fromPath, resize with Type constants RGB/ARGB/ARGB\_PRE/BGR), Filter (apply), BrushMetal (new, radius, amount, shine), Pen (drawLine, drawRect, drawRoundRect, drawOval, drawImage, drawText), Render (getContext).
Example
examples/starrect.pics
New drawing example demonstrating composition of Pen and Render modules with functions drawStar, drawRect, drawDepth, drawBackLines, and main pipeline.
Java Graphics & Rendering
src/main/java/org/editor/nativemods/PiccodeGfxModule.java, src/main/java/org/editor/nativemods/PiccodePenModule.java, src/main/java/org/editor/nativemods/PiccodeImageModule.java, src/main/java/org/editor/nativemods/PiccodeFilterModule.java, src/main/java/org/editor/nativemods/PiccodeBrushedMetalFilterModule.java
Implemented native function modules for graphics operations: graphics context management (get, create from rect, dispose), pen drawing operations (line, rect, oval, image, text), image creation/loading/resizing, filter application, and brushed metal filter parameter setters.
Java Canvas & Editor Updates
src/main/java/org/editor/CanvasFrame.java, src/main/java/org/editor/CodeEditor.java, src/main/java/org/editor/EditorWindow.java
Introduced render pipeline with buffered image in CanvasFrame; added compile(Supplier) method replacing direct compilation; CodeEditor now supports runtime theme switching via setThemeMode; EditorWindow integrated ThemeManager for coordinated theming across editors and plugins.
Java UI Dialogs
src/main/java/org/editor/dialogs/EditorSettingsDialog.form, src/main/java/org/editor/dialogs/EditorSettingsDialog.java, src/main/java/org/editor/dialogs/GeneralSettingsDialog.form, src/main/java/org/editor/dialogs/GeneralSettingsDialog.java, src/main/java/org/editor/dialogs/NewProjectDialog.form, src/main/java/org/editor/dialogs/NewProjectDialog.java, src/main/java/org/editor/dialogs/SettingsDialog.form, src/main/java/org/editor/dialogs/SettingsDialog.java
Added four settings/project dialog classes with NetBeans form definitions: EditorSettingsDialog (font, line numbers, syntax highlight, bookmarks), GeneralSettingsDialog (working directory, project name, entry file, arguments), NewProjectDialog (project metadata, location, git initialization), SettingsDialog (tabbed dialog container).
Java Theme Management
src/main/java/org/editor/theme/ThemeManager.java
New centralized theme manager exposing color constants (RENDER\_BG, RENDER\_FG, RENDER\_TXT2, RENDER\_GRID) and registering editors/plugins for coordinated dark/light mode updates via FlatLaf.
Java Event & Plugin Integration
src/main/java/org/editor/events/AccessEvents.java, src/main/java/org/editor/events/MenuEvents.java, src/main/java/org/editor/panels/AboutPanel.java, src/main/java/org/editor/panels/PluginsPanel.java, src/main/java/org/piccode/piccode/Piccode.java
Refactored AccessEvents to use CanvasFrame.compile() hook; MenuEvents adjusted directory handling and formatting; AboutPanel updated attribution text; PluginsPanel implements dynamic JAR-based plugin discovery and loading with URLClassLoader lifecycle; Piccode initializes native modules via initializeNativeAppModules().
Python Test Infrastructure
run_readme_tests.py, tests/test_readme_validation.py
Added test runner script and comprehensive README validation suite covering structure (sections, headings), content (project name variants, build instructions, external links), code blocks, HTML integrity, and formatting compliance.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant EditorWindow as EditorWindow<br/>(Theme Mgr)
    participant CanvasFrame
    participant PiccodeRuntime as Piccode<br/>Runtime
    participant NativeGfx as Native<br/>Modules

    User->>EditorWindow: set theme (dark/light)
    EditorWindow->>EditorWindow: updateThemes(dark)
    EditorWindow->>CanvasFrame: propagate theme
    EditorWindow->>EditorWindow: setFlatLaf(dark)

    User->>EditorWindow: compile code
    EditorWindow->>CanvasFrame: compile(Supplier)
    CanvasFrame->>PiccodeRuntime: invoke Supplier<br/>(Compiler.compile)
    PiccodeRuntime->>NativeGfx: Render::getContext()
    NativeGfx-->>PiccodeRuntime: Graphics2D ref
    PiccodeRuntime->>NativeGfx: Pen::drawLine(...)<br/>Pen::drawRect(...)
    NativeGfx->>CanvasFrame: render to buffer
    CanvasFrame->>CanvasFrame: paintComponent()<br/>draw render buffer
    CanvasFrame-->>User: display result
Loading
sequenceDiagram
    participant PluginsPanel
    participant PluginDisco as Plugin<br/>Discovery
    participant URLClassLoader as ClassLoader
    participant PluginJar as JAR
    participant PluginImpl as Plugin<br/>Implementation
    participant ThemeManager

    PluginsPanel->>PluginsPanel: constructor
    PluginsPanel->>PluginDisco: loadPlugins()
    PluginDisco->>PluginDisco: walk ./etc/plugins/
    PluginDisco->>PluginDisco: find *.jar files

    loop for each JAR
        PluginDisco->>URLClassLoader: scanJar(jarFile)
        URLClassLoader->>PluginJar: open JAR stream
        PluginJar-->>URLClassLoader: class entries
        URLClassLoader->>URLClassLoader: filter by base<br/>(PiccodePluginPanel)
        URLClassLoader->>PluginImpl: Class.forName<br/>or jar-loader
        URLClassLoader->>PluginDisco: loadPlugin(class)
    end

    PluginDisco->>PluginImpl: instantiate
    PluginImpl->>ThemeManager: register plugin
    PluginImpl->>PluginsPanel: add to UI
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

  • README.md merge conflicts: Unresolved conflict markers across multiple sections require careful manual resolution and validation.
  • Native module implementations: Five new Java native modules with type checking, context management, and Graphics2D operations require careful validation of type safety and memory management.
  • Plugin system with ClassLoader lifecycle: Dynamic loading with URLClassLoader instances requires scrutiny for resource leaks and class loader hierarchy issues.
  • Theme manager integration: Coordinates multiple components (EditorWindow, editors, plugins) with state mutations; verify all registration/removal paths are correct.
  • Heterogeneous changes: Mix of Piccode language bindings, Java graphics/UI code, Python tests, and configuration—each requires different verification logic.
  • Public API surface expansion: Many new public classes, methods, and modules introduced; verify signatures align with use sites.

Possibly related PRs

Poem

🐰 Brushing pixels, drawing dreams with Pen,
Themes that dance 'tween dark and light again,
Plugins hop in, filters bloom and shine,
Graphics pipeline—a work sublime!
Context, Canvas, rendering divine! 🎨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 45.92% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The PR title 'Innocent' is vague and generic, providing no meaningful information about the changeset's purpose or content. Replace with a descriptive title that summarizes the main change, such as 'Use system object to retrieve current working directory in file chooser initialization' or similar.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch Innocent

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 17

🧹 Nitpick comments (22)
src/main/java/org/editor/dialogs/NewProjectDialog.java (4)

4-7: Remove unused imports.

The imports java.io.FileWriter and java.util.logging.Logger are never used in this class.

Apply this diff:

 package org.editor.dialogs;
 
 import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.util.logging.Level;
-import java.util.logging.Logger;
 import javax.swing.JFileChooser;

10-14: Replace boilerplate license header.

This is a generic NetBeans template comment. Consider replacing it with your project's actual license or removing it.


31-32: Address initialization concerns.

Line 31 sets hasError = false, but this field (declared at line 351) is never checked or meaningfully used. Line 32 contains commented-out code that duplicates line 67.

Apply this diff:

     public NewProjectDialog() {
         initComponents();
         this.setResizable(false);
         this.setTitle("Create a new project");
-        this.hasError = false;
-        //this.setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
     }

351-351: Unused field hasError.

The hasError field is initialized in the constructor (line 31) but never read or meaningfully updated. Consider removing it or implementing proper error tracking.

src/main/java/org/editor/events/MenuEvents.java (2)

85-98: openFile now uses current working directory but overrides file filter

Using new JFileChooser(System.getProperty("user.dir")) aligns with the PR objective to base the dialog on the current working directory and is a reasonable default.

However, calling setFileFilter twice means the second call (FileFilter.picsFilter) overrides the first (FileFilter.mdFilter), so only one filter is actually active. If you intend to offer both filters, consider:

var fileChooser = new JFileChooser(System.getProperty("user.dir"));
fileChooser.addChoosableFileFilter(FileFilter.mdFilter);
fileChooser.addChoosableFileFilter(FileFilter.picsFilter);
fileChooser.setFileFilter(FileFilter.picsFilter); // default, if desired

135-138: newFile TODO is acceptable

newFile simply forwards to EditorWindow.addTab(e) and keeps a TODO about using a dedicated file‑creator dialog later. That’s a reasonable incremental step; no changes requested.

In a follow‑up, you might want to capture a brief issue/ticket for the “file creator dialog” TODO so it doesn’t get lost.

pom.xml (1)

19-25: Consider the implications of updatePolicy=always for snapshot dependencies.

Setting updatePolicy to always means Maven will check for updates on every build, which can lead to non-reproducible builds and potential build instability if upstream snapshots change unexpectedly. This is particularly risky when combined with main-SNAPSHOT dependencies.

Consider using daily instead of always to balance freshness with build stability:

 <snapshots>
   <enabled>true</enabled>
-  <updatePolicy>always</updatePolicy>
+  <updatePolicy>daily</updatePolicy>
 </snapshots>
 <releases>
-  <updatePolicy>always</updatePolicy>
+  <updatePolicy>daily</updatePolicy>
 </releases>
piccode/render/context.pics (1)

1-16: LGTM with minor documentation fix.

The Render module provides a clean abstraction for obtaining the graphics context. The implementation correctly delegates to the native function registered by PiccodeGfxModule.

Minor typo in the documentation comment on Line 12:

-  //   - (Reference) a handler to the Graphics2D. 
+  //   - (Reference) a handle to the Graphics2D.
src/main/java/org/editor/CodeEditor.java (1)

302-311: Improve error handling in theme loading.

The comment "Never happens" for IOException is misleading—resource loading can fail if the theme file is missing or corrupted. Using printStackTrace() is not ideal for production code and provides poor user feedback.

Consider logging the error properly or providing user feedback:

 public void setThemeMode(boolean dark) {
   var themeName = dark ? "monokai" : "vs";
   try {
     Theme theme = Theme.load(getClass().getResourceAsStream(
                     "/org/fife/ui/rsyntaxtextarea/themes/" + themeName +".xml"));
     theme.apply(textArea);
-  } catch (IOException ioe) { // Never happens
-    ioe.printStackTrace();
+  } catch (IOException ioe) {
+    Logger.getLogger(CodeEditor.class.getName()).log(Level.WARNING, 
+      "Failed to load theme: " + themeName, ioe);
+    // Optionally notify user or fall back to default theme
   }
 }
piccode/filters/filter.pics (1)

1-5: Add documentation for the Filter module.

The module lacks documentation explaining its purpose, parameter types, and return values. This would help developers understand how to use the filter system.

Consider adding documentation:

+// Module: Filter
+// Functions for applying image filters
 Filter :: module {
+  // Function: apply
+  // Applies a filter to an image
+  //
+  // Parameters:
+  //   - filter: (Reference) A BufferedImageOp filter instance
+  //   - image: (Reference) A BufferedImage to filter
+  //
+  // Returns:
+  //   - (Reference) The filtered BufferedImage
   apply :: (filter, image) = pic_nat_filter_apply(filter, image)
 }
src/main/java/org/piccode/piccode/Piccode.java (1)

27-33: LGTM! Clean centralized module initialization.

The new initializeNativeAppModules() method provides a clean, centralized way to register native modules before the editor window starts. The use of method references keeps the code concise and maintainable.

Consider adding error handling if module registration could fail:

 private static void initializeNativeAppModules() {
+  try {
     Compiler.addNativeFunctions(PiccodeGfxModule::addFunctions);
     Compiler.addNativeFunctions(PiccodePenModule::addFunctions);
     Compiler.addNativeFunctions(PiccodeBrushedMetalFilterModule::addFunctions);
     Compiler.addNativeFunctions(PiccodeFilterModule::addFunctions);
     Compiler.addNativeFunctions(PiccodeImageModule::addFunctions);
+  } catch (Exception e) {
+    System.err.println("Failed to initialize native modules: " + e.getMessage());
+    System.exit(1);
+  }
 }

However, this is only necessary if addNativeFunctions or the module initialization methods can throw exceptions.

piccode/filters/metal/brushMetal.pics (1)

3-7: BrushMetal wrapper signatures look fine; consider clarifying parameter names

The thin wrappers around the native brush metal functions are consistent and simple. For readability, you might consider renaming the second parameter of amount and shine from radius to something like value or amount/shine to better reflect the underlying meaning.

src/main/java/org/editor/nativemods/PiccodePenModule.java (2)

28-204: Consider extracting shared helpers for ctx resolution and numeric conversion

Each drawing function repeats the same patterns (resolve Context, get caller, verify types, deref Graphics2D, convert PiccodeNumber to int). This is correct but quite duplicated; extracting small helpers (e.g., resolveGraphics2D(caller, _ctx) and a numeric conversion helper) would reduce boilerplate and keep behavior consistent if you tweak validation later.


205-232: Verify how PiccodeString is converted before drawing text

Here _text is validated as Type.STRING, but the draw call uses:

gfx.drawString(_text.toString(), _x, _y);

Since PiccodeString is imported but not used, this may end up drawing the wrapper’s toString() (e.g., a debug representation) instead of the underlying string, depending on PiccodeString’s implementation. It might be safer to cast to PiccodeString and use its underlying value accessor instead of toString(), if one exists.

src/main/java/org/editor/panels/PluginsPanel.java (1)

30-46: Plugin loading works; consider tightening path/error handling

The plugin scanning logic is sound overall, but a few small tweaks could improve robustness:

  • Before Files.walk(pluginsDir), consider checking Files.isDirectory(pluginsDir) and returning early to avoid treating a missing plugins directory as an error.
  • Relying on "./etc/plugins/" ties behavior to the process working directory; if you ever run from different CWDs, you might want a central “app root” or configuration-based path instead.
  • In scanJar, you already catch per-class failures; you might also want more structured logging (or at least include the jar path) instead of plain System.out to make diagnosing plugin issues easier.

Also applies to: 69-99

tests/test_readme_validation.py (1)

30-35: Project-name spelling tests are very brittle to future cleanup

These assertions hard‑code both Piccaso Code and Piccasso code and later assert both variants exist. That will break as soon as the README is standardized to a single, correct spelling.

Consider relaxing these checks (e.g., allow either variant, or assert only the canonical name) so README cleanup doesn’t require test rewrites every time the title changes.

src/main/java/org/editor/theme/ThemeManager.java (2)

17-23: Use generics and diamond operator on the editor/plugin lists

To avoid unchecked operations and make the intent explicit, you can give the lists concrete generic types and use the diamond operator:

-    private static List<CodeEditor> editors = new ArrayList();
-    private static List<PiccodePluginInterface> plugins = new ArrayList();
+    private static final List<CodeEditor> editors = new ArrayList<>();
+    private static final List<PiccodePluginInterface> plugins = new ArrayList<>();

Marking them final also documents that the list references themselves don’t change.


54-66: Consider calling FlatLaf.updateUI() instead of subclass-specific updateUI()

updateUI() is defined on the FlatLaf base class; calling it via FlatDarkLaf / FlatLightLaf works but is slightly non‑idiomatic. For clarity you could centralize the update:

-            if (dark) {
-                FlatDarkLaf.setup();
-                FlatDarkLaf.updateUI();
-            } else {
-                FlatLightLaf.setup();
-                FlatLightLaf.updateUI();
-            }
+            if (dark) {
+                FlatDarkLaf.setup();
+            } else {
+                FlatLightLaf.setup();
+            }
+            com.formdev.flatlaf.FlatLaf.updateUI();

Optional, but it better reflects the FlatLaf API design.

piccode/pen/draw.pics (1)

48-65: Fix drawOval docstring and consider documenting drawImage/drawText

The implementation of drawOval is correct, but the comment still says “Draws a rect”, which is misleading. Also, drawImage and drawText are undocumented while the other functions are nicely described.

You could align the docs like this:

-  // Function: drawOval
-  // Draws a rect inside the specified context, based on the provided coordinates
+  // Function: drawOval
+  // Draws an oval inside the specified context, based on the provided coordinates
@@
-  drawOval :: (ctx, x, y, w, h) = pic_nat_draw_oval(ctx, x, y, w, h)
+  drawOval :: (ctx, x, y, w, h) = pic_nat_draw_oval(ctx, x, y, w, h)
+
+  // Function: drawImage
+  // Draws an image at the specified position in the given context
+  drawImage :: (ctx, image, x, y) = pic_nat_draw_image(ctx, image, x, y)
+  
+  // Function: drawText
+  // Draws text at the specified position in the given context
+  drawText :: (ctx, text, x, y) = pic_nat_draw_text(ctx, text, x, y)
-
-  drawImage :: (ctx, image, x, y) = pic_nat_draw_image(ctx, image, x, y)
-  
-  drawText :: (ctx, text, x, y) = pic_nat_draw_text(ctx, text, x, y)
src/main/java/org/editor/nativemods/PiccodeGfxModule.java (1)

25-104: GFX native bindings look consistent; consider a small guard for null gfx

The overall module (context resolution, type checks, Graphics2D validation, and disposal via gfx_drop) looks consistent and correct for the Piccode runtime.

One minor defensive improvement you might consider:

  • In get_gfx, if CanvasFrame.gfx can ever be null (e.g., before the first successful CanvasFrame.compile(...)), you may want to throw a PiccodeException with a clear message instead of returning a PiccodeReference wrapping null. That would keep error reporting aligned with the other functions that validate their inputs.

This is non-blocking and can be deferred.

src/main/java/org/editor/CanvasFrame.java (1)

249-301: compile() ctor call is likely a no-op; verify expectations for CanvasFrame.gfx initialization

compile(Supplier<PiccodeValue> fx) correctly sets up an ARGB buffer, clears it via AlphaComposite.Clear, then switches back to SrcOver and invokes the supplier. drawGrid() now uses ThemeManager colors and disposes the grid Graphics2D, which is good resource hygiene.

One behavioral nuance:

  • When compile(() -> null); is invoked from the constructor, getWidth() / getHeight() are typically 0, so compile() returns early without initializing render or CanvasFrame.gfx.
  • This means CanvasFrame.gfx will remain null until some later explicit call to compile(...) when the component has a non-zero size.

If the rest of the system assumes get_gfx (from the native module) is only used after an explicit compile, this is fine. If not, you may want to:

  • Either defer the initial compile until the component is realized (or until the first explicit render), or
  • Add a guard/error path wherever get_gfx is used to clearly indicate that compilation hasn’t run yet.

This is more of a lifecycle gotcha than a bug, but worth double-checking.

Also applies to: 303-324

src/main/java/org/editor/EditorWindow.java (1)

46-47: ThemeManager integration and dark-mode wiring look coherent

Exposing dark as a single static flag and routing LaF + editor theme updates through ThemeManager (constructor, addTab, addTab(Path, Void), and removal via ThemeManager.removeEditor) provides a clear centralization for theming.

There is a small redundancy where ThemeManager.setFlatLaf(dark) is called explicitly in the constructor and again from ThemeManager.updateThemes(dark), but this is harmless and can be cleaned up later if desired.

Also applies to: 76-79, 92-93, 230-231, 254-256, 276-277

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between dd4bf20 and f99bbb7.

📒 Files selected for processing (37)
  • .github/dependabot.yml (1 hunks)
  • .gitignore (1 hunks)
  • README.md (3 hunks)
  • examples/starrect.pics (1 hunks)
  • piccode/context/ctx.pics (1 hunks)
  • piccode/filters/filter.pics (1 hunks)
  • piccode/filters/metal/brushMetal.pics (1 hunks)
  • piccode/image/image.pics (1 hunks)
  • piccode/pen/draw.pics (1 hunks)
  • piccode/render/context.pics (1 hunks)
  • pom.xml (9 hunks)
  • pytest.ini (1 hunks)
  • requirements-test.txt (1 hunks)
  • run_readme_tests.py (1 hunks)
  • src/main/java/org/editor/CanvasFrame.java (9 hunks)
  • src/main/java/org/editor/CodeEditor.java (2 hunks)
  • src/main/java/org/editor/EditorWindow.java (10 hunks)
  • src/main/java/org/editor/dialogs/EditorSettingsDialog.form (1 hunks)
  • src/main/java/org/editor/dialogs/EditorSettingsDialog.java (1 hunks)
  • src/main/java/org/editor/dialogs/GeneralSettingsDialog.form (1 hunks)
  • src/main/java/org/editor/dialogs/GeneralSettingsDialog.java (1 hunks)
  • src/main/java/org/editor/dialogs/NewProjectDialog.form (1 hunks)
  • src/main/java/org/editor/dialogs/NewProjectDialog.java (1 hunks)
  • src/main/java/org/editor/dialogs/SettingsDialog.form (1 hunks)
  • src/main/java/org/editor/dialogs/SettingsDialog.java (1 hunks)
  • src/main/java/org/editor/events/AccessEvents.java (1 hunks)
  • src/main/java/org/editor/events/MenuEvents.java (1 hunks)
  • src/main/java/org/editor/nativemods/PiccodeBrushedMetalFilterModule.java (1 hunks)
  • src/main/java/org/editor/nativemods/PiccodeFilterModule.java (1 hunks)
  • src/main/java/org/editor/nativemods/PiccodeGfxModule.java (1 hunks)
  • src/main/java/org/editor/nativemods/PiccodeImageModule.java (1 hunks)
  • src/main/java/org/editor/nativemods/PiccodePenModule.java (1 hunks)
  • src/main/java/org/editor/panels/AboutPanel.java (1 hunks)
  • src/main/java/org/editor/panels/PluginsPanel.java (1 hunks)
  • src/main/java/org/editor/theme/ThemeManager.java (1 hunks)
  • src/main/java/org/piccode/piccode/Piccode.java (2 hunks)
  • tests/test_readme_validation.py (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (11)
src/main/java/org/editor/panels/PluginsPanel.java (2)
src/main/java/org/editor/EditorWindow.java (1)
  • EditorWindow (62-567)
src/main/java/org/editor/theme/ThemeManager.java (1)
  • ThemeManager (15-67)
src/main/java/org/editor/nativemods/PiccodeGfxModule.java (1)
src/main/java/org/editor/CanvasFrame.java (1)
  • CanvasFrame (44-349)
src/main/java/org/editor/nativemods/PiccodeImageModule.java (1)
src/main/java/org/editor/icons/ImageLoader.java (1)
  • ImageLoader (16-92)
src/main/java/org/editor/nativemods/PiccodePenModule.java (1)
src/main/java/org/editor/CanvasFrame.java (1)
  • CanvasFrame (44-349)
tests/test_readme_validation.py (1)
run_readme_tests.py (1)
  • main (11-33)
src/main/java/org/editor/theme/ThemeManager.java (1)
src/main/java/org/editor/CodeEditor.java (1)
  • CodeEditor (43-312)
src/main/java/org/piccode/piccode/Piccode.java (5)
src/main/java/org/editor/nativemods/PiccodeBrushedMetalFilterModule.java (1)
  • PiccodeBrushedMetalFilterModule (24-112)
src/main/java/org/editor/nativemods/PiccodeFilterModule.java (1)
  • PiccodeFilterModule (17-57)
src/main/java/org/editor/nativemods/PiccodeGfxModule.java (1)
  • PiccodeGfxModule (23-106)
src/main/java/org/editor/nativemods/PiccodeImageModule.java (1)
  • PiccodeImageModule (29-148)
src/main/java/org/editor/nativemods/PiccodePenModule.java (1)
  • PiccodePenModule (24-235)
src/main/java/org/editor/CanvasFrame.java (1)
src/main/java/org/editor/theme/ThemeManager.java (1)
  • ThemeManager (15-67)
src/main/java/org/editor/events/AccessEvents.java (2)
src/main/java/org/editor/AccessFrame.java (1)
  • AccessFrame (40-279)
src/main/java/org/editor/CanvasFrame.java (1)
  • CanvasFrame (44-349)
src/main/java/org/editor/events/MenuEvents.java (2)
src/main/java/org/editor/EditorWindow.java (1)
  • EditorWindow (62-567)
src/main/java/org/editor/fs/FileFilter.java (1)
  • FileFilter (9-12)
src/main/java/org/editor/EditorWindow.java (1)
src/main/java/org/editor/theme/ThemeManager.java (1)
  • ThemeManager (15-67)
🪛 LanguageTool
README.md

[style] ~89-~89: You have already used ‘tries to’ in nearby sentences. Consider using one of the replacements to let your writing stand out.
Context: ...CAD](https://openscad.org/) program and tries to mimic its functionality ======= Picasso...

(REP_TRY)


[style] ~91-~91: You have already used ‘tries to’ in nearby sentences. Consider using one of the replacements to let your writing stand out.
Context: ...CAD](https://openscad.org/) program and tries to mimic its functionality >>>>>>> 455b066...

(REP_TRY)

🪛 markdownlint-cli2 (0.18.1)
README.md

17-17: Heading style
Expected: atx; Actual: setext

(MD003, heading-style)


24-24: Emphasis style
Expected: asterisk; Actual: underscore

(MD049, emphasis-style)


24-24: Emphasis style
Expected: asterisk; Actual: underscore

(MD049, emphasis-style)


28-28: Heading style
Expected: atx; Actual: setext

(MD003, heading-style)


29-29: Emphasis style
Expected: asterisk; Actual: underscore

(MD049, emphasis-style)


29-29: Emphasis style
Expected: asterisk; Actual: underscore

(MD049, emphasis-style)


66-66: Multiple headings with the same content

(MD024, no-duplicate-heading)


73-73: Multiple headings with the same content

(MD024, no-duplicate-heading)


80-80: Heading style
Expected: atx; Actual: setext

(MD003, heading-style)


89-89: Heading style
Expected: atx; Actual: setext

(MD003, heading-style)

🪛 Ruff (0.14.4)
run_readme_tests.py

1-1: Shebang is present but file is not executable

(EXE001)


19-19: subprocess call: check for execution of untrusted input

(S603)


25-25: Consider moving this statement to an else block

(TRY300)


31-31: Do not catch blind exception: Exception

(BLE001)

🔇 Additional comments (24)
.gitignore (2)

1-5: Inconsistency detected between PR objectives and provided changes.

The PR objectives reference a TODO about using the system object to obtain the current working directory, and the AI summary describes extensive graphics rendering, plugin system, and theme management features. However, the only file provided contains .gitignore changes (adding *.jar and adjusting docs/.obsidian).

These are valid build artifact exclusion rules, but they don't align with the stated PR objectives. Please verify that the correct files are included in this review.


4-5: Ignore rules are appropriate for a Java project.

The additions to .gitignore are sound:

  • Line 5: *.jar correctly excludes compiled JAR artifacts from version control.
  • Line 4: docs/.obsidian preserves IDE-specific configuration exclusion.

Both changes follow standard best practices for Java projects.

src/main/java/org/editor/dialogs/NewProjectDialog.java (1)

1-377: Inconsistency: PR description does not match file contents.

The PR description states this implements a TODO to use the system object to obtain the current working directory. However, these files implement a GUI dialog for creating new projects with no reference to any TODO or current working directory retrieval. Please verify that the correct files were included in this PR.

src/main/java/org/editor/dialogs/NewProjectDialog.form (1)

1-376: NetBeans auto-generated form file.

This is an auto-generated NetBeans Form Editor XML file. It should only be modified through the NetBeans visual form designer, not manually. The form definition appears consistent with the corresponding Java file.

src/main/java/org/editor/dialogs/GeneralSettingsDialog.form (1)

1-197: Form structure looks good.

The form defines a clear two-panel layout for General and Runtime settings with appropriate labels and input fields. The default entry file value "./main.pics" is reasonable, and the note about space-separated arguments provides helpful guidance.

src/main/java/org/editor/dialogs/GeneralSettingsDialog.java (1)

90-90: Verify the default entry file path convention.

The entry file defaults to "./main.pics". Ensure this filename convention and relative path are consistent with the project's runtime expectations and documentation.

src/main/java/org/editor/dialogs/EditorSettingsDialog.form (1)

1-224: Form structure is well-organized.

The form provides a clean three-section layout (Font, General, LookAndFeel) with appropriate UI controls for editor configuration. The checkbox labels and combo box options are clear and user-friendly.

.github/dependabot.yml (1)

2-7: Dependabot Maven configuration looks good

Minimal v2 config for weekly Maven updates at the repo root is valid and should work as intended. No changes requested.

requirements-test.txt (1)

1-4: Test requirements are reasonable

The chosen versions for pytest, pytest-mock, requests, and conditional pathlib2 support look sane for a standalone test requirements file.

src/main/java/org/editor/events/MenuEvents.java (5)

26-53: gotoLine handler looks correct but relies on initialized dialogs

The gotoLineEvent implementation cleanly hides the find/replace dialogs, opens GoToDialog, and positions the caret correctly with proper bounds checking and error feedback.

It assumes EditorWindow.findDialog and EditorWindow.replaceDialog are non‑null; if there’s any path where these dialogs aren’t initialized before this handler runs, you may want null‑checks to avoid NPEs.


55-71: find/replace event handlers behave as expected

The replaceEvent and findEvent methods correctly ensure only one of the dialogs is visible at a time by toggling visibility between findDialog and replaceDialog. This matches typical editor UX.


73-83: About/close-all handlers are straightforward

aboutDialog instantiates the AboutDialog with the main window, and closeAllTabs delegates to EditorWindow.removeAllTabs(). Both are thin wrappers with clear behavior and no obvious issues.


100-109: saveFile handler is fine

The saveFile method correctly no‑ops when there are no tabs or no selected editor and otherwise delegates to ed.saveFile(). This is straightforward and safe.


122-133: Bulk save and quit behavior

saveAllFiles delegating to EditorWindow.saveAll() and quit calling closeAllTabs(e) before System.exit(0) is consistent with expected editor behavior, assuming removeAllTabs() already handles dirty‑file prompts.

No issues from what’s visible here.

Please confirm that EditorWindow.removeAllTabs() handles unsaved changes as expected before System.exit(0) is called.

src/main/java/org/editor/events/AccessEvents.java (1)

32-34: LGTM! Cleaner compilation flow.

The refactoring to use CanvasFrame.the().compile(() -> ...) with a lambda is cleaner than the previous flag-based approach. Clearing messages before compilation provides good user feedback.

run_readme_tests.py (2)

11-16: LGTM! This accomplishes the PR objective.

This code successfully implements the TODO mentioned in the PR description: "use the system object to obtain the current working directory." The script uses os.path.dirname(os.path.abspath(__file__)) to get the repository root and os.chdir() to change to that directory, ensuring tests run from the correct location.


19-23: Consider security implications of subprocess usage.

While the static analysis tool flags subprocess.run for potential security risks, in this context the command is constructed from trusted sources (sys.executable and hardcoded arguments), so this is a false positive.

pom.xml (2)

78-91: All SNAPSHOT dependencies confirmed accessible.

Verification shows all three JitPack dependencies (PiccodeScript, JHLabs, PiccodePlugin) are currently available. While SNAPSHOT versions do carry inherent stability risks if upstream branches change, this is an accepted trade-off of the current build approach, and no immediate accessibility issues prevent the build from proceeding.


100-100: JUnit 6.0.0 is a valid, released version and is available on Maven Central.

JUnit BOM version 6.0.0 exists and release artifacts are available on Maven Central. The latest stable is 6.0.1 (published Oct 31, 2025), so if you prefer the absolute latest patch release, consider updating to that instead.

piccode/context/ctx.pics (1)

4-38: Context wrappers look consistent and minimal

The three functions are clean, direct wrappers around the native gfx APIs with matching parameter lists and documentation; no issues from this file alone.

src/main/java/org/editor/nativemods/PiccodeFilterModule.java (1)

19-52: filter_apply binding is straightforward and defensively typed

Argument type checks, dereferencing, and instanceof validation for BufferedImageOp and BufferedImage are consistent and make error cases explicit. The returned PiccodeReference for the new image matches expected semantics.

src/main/java/org/editor/nativemods/PiccodeBrushedMetalFilterModule.java (1)

26-110: BrushedMetalFilter native bindings look correct and defensive

Argument type checks, dereferencing, and object-type validation before calling setRadius, setAmount, and setShine are consistent and should prevent misuse. Returning a new PiccodeReference to the same underlying BrushedMetalFilter object keeps semantics clear.

No functional issues stand out here.

piccode/image/image.pics (1)

2-16: Image module wrappers look coherent and minimal

The Image module cleanly exposes creation (new, newWithType, fromPath), context access, resizing, and a simple Type enum-like submodule. The API surface is cohesive and aligns well with typical image operations.

src/main/java/org/editor/CanvasFrame.java (1)

5-5: Render buffer + static gfx integration looks good

The additions of the render buffer, the layered draw in paintComponent, and the shared static gfx (for consumption by native modules) are wired coherently. Drawing render after the grid preserves the intended background and avoids interfering with selection/crosshair rendering.

Also applies to: 52-55, 79-80, 117-119

Comment on lines +14 to +20
drawRect :: (ctx, x, y, w, h) =
ctx
|> Pen::drawLine(x, y, x + w, y)
|> Pen::drawLine(x, y + h, x + w, y + h)
|> Pen::drawLine(x, y, x, y + w)
|> Pen::drawLine(x + w, y, x + w, y + h)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Bug in drawRect: using w instead of h for the left edge height

The left vertical edge is using the width as its vertical extent:

   |> Pen::drawLine(x, y, x, y + w)

This should use h to match the other sides and produce a proper rectangle.

-   |> Pen::drawLine(x, y, x, y + w)
+   |> Pen::drawLine(x, y, x, y + h)
🤖 Prompt for AI Agents
In examples/starrect.pics around lines 14 to 20, the drawRect function
mistakenly uses w for the left edge Y extent (x, y + w) causing a malformed
rectangle; change that call to use h (x, y + h) so the left vertical line
matches the rectangle height, ensuring all four edges use h for vertical extents
and w for horizontal extents.

Comment on lines +1 to +10
[tool:pytest]
testpaths = tests
python_files = test_*.py
python_classes = Test*
python_functions = test_*
addopts = -v --tb=short --strict-markers
markers =
slow: marks tests as slow (deselect with '-m "not slow"')
integration: marks tests as integration tests
unit: marks tests as unit tests No newline at end of file
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

❓ Verification inconclusive

pytest.ini section header is likely wrong and will be ignored

For a pytest.ini file, pytest expects the section header [pytest]. Using [tool:pytest] here is non‑standard and will likely cause pytest to ignore the entire configuration (testpaths, addopts, markers, etc.), so your settings may not take effect.

Recommend changing the header to:

[pytest]

and keeping the rest of the options as‑is.

Please run pytest locally after changing the header to [pytest] to confirm that the options (e.g., --strict-markers, markers, and discovery patterns) are picked up as expected.


pytest.ini section header is incorrect and will be ignored

For pytest.ini files, pytest requires the section header [pytest]. The [tool:pytest] header is used only for setup.cfg files. Using the wrong header in your pytest.ini will cause pytest to ignore the entire configuration.

Change the header to:

[pytest]

Keep the rest of the options as-is.

🤖 Prompt for AI Agents
In pytest.ini around lines 1 to 10, the section header is currently
"[tool:pytest]" which pytest ignores in a pytest.ini file; change the section
header to "[pytest]" and keep all other keys and values (testpaths,
python_files, python_classes, python_functions, addopts, markers) unchanged so
pytest will load the configuration.

Comment on lines 16 to 97
## About
<<<<<<< HEAD
<<<<<<< HEAD
Picasso code is an image editor that uses code to create/edit an image. This allows powerful designs to be created with ease and
automation. The editor uses *PiccodeScript* as the scripting language for writing the image editing code.
=======

Piccasso code is an image editor that uses code to create/edit an image. This allows powerful designs to be created with ease and
automation. The editor uses _glimr_ as the scripting language for writing the image editing code.
>>>>>>> 0064ac3 (fix: corrected a spelling error in the readme file)
=======

Piccasso code is an image editor that uses code to create/edit an image. This allows powerful designs to be created with ease and
automation. The editor uses *glimr* as the scripting language for writing the image editing code.
automation. The editor uses _glimr_ as the scripting language for writing the image editing code.
=======
Picasso code is an image editor that uses code to create/edit an image. This allows powerful designs to be created with ease and
automation. The editor uses *PiccodeScript* as the scripting language for writing the image editing code.
>>>>>>> 455b066 (README: Fixed mistakes in the README)
>>>>>>> 955b7fb (README: Fixed mistakes in the README)
## Download
>> Coming soon

> > Coming soon
## Building

```sh
$ git clone git@github.com:hexaredecimal/Piccode.git
$ cd Piccode
<<<<<<< HEAD
<<<<<<< HEAD
$ git clone https://github.com/Glimmr-Lang/PicassoCode.git
$ cd PicassoCode
$ mvn package
```
### Test your build
```sh
$ java -jar target/Piccode-1.0-SNAPSHOT-jar-with-dependencies.jar
=======
git clone git@github.com:hexaredecimal/Piccode.git
cd Piccode
mvn package
>>>>>>> 0064ac3 (fix: corrected a spelling error in the readme file)
=======
git clone git@github.com:hexaredecimal/Piccode.git
cd Piccode
mvn package
=======
$ git clone https://github.com/Glimmr-Lang/PicassoCode.git
$ cd PicassoCode
$ mvn package
```
### Test your build
```sh
$ java -jar target/Piccode-1.0-SNAPSHOT-jar-with-dependencies.jar
>>>>>>> 455b066 (README: Fixed mistakes in the README)
>>>>>>> 955b7fb (README: Fixed mistakes in the README)
```

### Test your build

```sh
java -jar target/Piccode-1.0-SNAPSHOT-jar-with-dependencies.jar
```

## Inspired by
<<<<<<< HEAD
<<<<<<< HEAD
PicassoCode is heavily inspired by the [OpenSCAD](https://openscad.org/) program and tries to mimic its functionality
=======

Piccassocode is heavily inspired by the [OpenSCAD](https://openscad.org/) program and tries to mimic its functionality
>>>>>>> 0064ac3 (fix: corrected a spelling error in the readme file)
=======

Piccassocode is heavily inspired by the [OpenSCAD](https://openscad.org/) program and tries to mimic its functionality
=======
PicassoCode is heavily inspired by the [OpenSCAD](https://openscad.org/) program and tries to mimic its functionality
>>>>>>> 455b066 (README: Fixed mistakes in the README)
>>>>>>> 955b7fb (README: Fixed mistakes in the README)
as much as it can while still being an image editor. I was stoked when I tried OpenSCAD for the first time and ended up
challenging myself to start a new project based araound the idea. A friend suggested something that has to do with graphics
and my first though was OpenSCAD, but 2D. The idea quickly grew and the small program became an image editor.
challenging myself to start a new project based around the idea. A friend suggested something that has to do with graphics
and my first though was OpenSCAD, but 2D. The idea quickly grew and the small program became an image editor.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Unresolved merge conflicts and duplicated content in README

The README currently contains unresolved merge‑conflict markers (<<<<<<<, =======, >>>>>>>), duplicated/contradictory sections (e.g., multiple “About”, “Building”, and “Test your build” variants), and inconsistent naming (“Picasso code”, “Piccasso code”, “Piccassocode”, _glimr_ vs *PiccodeScript*).

This makes the documentation hard to read and will likely break any automated README validation or linting you have.

Please fully resolve the conflicts by:

  • Removing all conflict markers.
  • Choosing a single, consistent project name and scripting language reference.
  • Consolidating the build and “Test your build” instructions into one canonical version.
🧰 Tools
🪛 LanguageTool

[style] ~89-~89: You have already used ‘tries to’ in nearby sentences. Consider using one of the replacements to let your writing stand out.
Context: ...CAD](https://openscad.org/) program and tries to mimic its functionality ======= Picasso...

(REP_TRY)


[style] ~91-~91: You have already used ‘tries to’ in nearby sentences. Consider using one of the replacements to let your writing stand out.
Context: ...CAD](https://openscad.org/) program and tries to mimic its functionality >>>>>>> 455b066...

(REP_TRY)

🪛 markdownlint-cli2 (0.18.1)

17-17: Heading style
Expected: atx; Actual: setext

(MD003, heading-style)


24-24: Emphasis style
Expected: asterisk; Actual: underscore

(MD049, emphasis-style)


24-24: Emphasis style
Expected: asterisk; Actual: underscore

(MD049, emphasis-style)


28-28: Heading style
Expected: atx; Actual: setext

(MD003, heading-style)


29-29: Emphasis style
Expected: asterisk; Actual: underscore

(MD049, emphasis-style)


29-29: Emphasis style
Expected: asterisk; Actual: underscore

(MD049, emphasis-style)


66-66: Multiple headings with the same content

(MD024, no-duplicate-heading)


73-73: Multiple headings with the same content

(MD024, no-duplicate-heading)


80-80: Heading style
Expected: atx; Actual: setext

(MD003, heading-style)


89-89: Heading style
Expected: atx; Actual: setext

(MD003, heading-style)

🤖 Prompt for AI Agents
README.md lines 16-97: the file contains unresolved Git conflict markers and
duplicated/contradictory sections; remove all conflict markers, choose one
consistent project name (e.g., "PicassoCode") and one scripting language name
(e.g., "PiccodeScript" or "_glimr_") across the document, and consolidate the
duplicated "Building" and "Test your build" blocks into a single canonical
clone/build/test sequence (keep only one repository URL, one mvn package
instruction, and one java -jar test command), then proofread to ensure no
leftover markers or duplicate paragraphs remain.

@@ -0,0 +1,36 @@
#!/usr/bin/env python3
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Make the script executable.

The shebang is present, but the file is not marked as executable.

Run the following command to fix:

#!/bin/bash
chmod +x run_readme_tests.py
🧰 Tools
🪛 Ruff (0.14.4)

1-1: Shebang is present but file is not executable

(EXE001)

🤖 Prompt for AI Agents
In run_readme_tests.py around lines 1 to 1 the file contains a shebang but is
not marked executable; make the script executable by setting the executable
permission (e.g. run chmod +x run_readme_tests.py from the repository root) and
verify the file has the executable bit (ls -l) so the shebang will be honored
when invoked directly.

Comment on lines +16 to +18
public EditorSettingsDialog() {
initComponents();
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

UI scaffolding requires event handlers and persistence logic.

The constructor initializes the UI components but there's no logic to load current settings, handle user interactions, or save changes. Essential next steps include:

  • Wire event handlers for the "Pick Font" button
  • Add listeners for checkboxes and combo box to enable/apply settings
  • Implement logic to load and persist editor preferences

Would you like me to generate example event handler code for these components?

🤖 Prompt for AI Agents
In src/main/java/org/editor/dialogs/EditorSettingsDialog.java around lines 16 to
18, the constructor only calls initComponents() but does not load existing
preferences, wire UI event handlers, or persist changes; update the constructor
to call a loadSettings() method that reads stored editor preferences (e.g.,
java.util.prefs.Preferences) and sets initial states for checkboxes, combo box
and font display, add an ActionListener for the "Pick Font" button to open a
font chooser dialog and update the preview and a temporary settings model, add
ItemListeners/ActionListeners on checkboxes and combo box to enable/disable
related UI and update the model, and implement saveSettings() invoked from the
OK/Apply actions (and optionally on change) to persist values to Preferences and
notify the editor of changes.

Comment on lines +111 to +120
static void saveFileAs(ActionEvent e) {
if (EditorWindow.tabsCount() == 1) {
return;
}
var ed = EditorWindow.getSelectedEditor();
if (ed == null) {
return;
}
ed.saveFileAs();
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

saveFileAs tab-count check appears inverted

The guard:

if (EditorWindow.tabsCount() == 1) {
  return;
}

prevents “Save As” when there is exactly one tab open, which is a common case where you’d want Save As to work. Conversely, it allows Save As when there are multiple tabs.

This condition likely intended to prevent Save As only when there are no tabs:

if (EditorWindow.tabsCount() == 0) {
  return;
}

Otherwise users with a single open file cannot use “Save As”.

🤖 Prompt for AI Agents
In src/main/java/org/editor/events/MenuEvents.java around lines 111 to 120, the
tab-count guard for saveFileAs is inverted: it returns when tabsCount() == 1,
preventing "Save As" for the common single-tab case. Change the guard to return
only when there are no tabs (tabsCount() == 0) so Save As is allowed when one or
more tabs exist; update the conditional accordingly and keep the remaining logic
(getting selected editor and calling saveFileAs) unchanged.

Comment on lines +74 to +91
NativeFunctionFactory.create("image_new_from_path", List.of("path"), (args, namedArgs, frame) -> {
var path = namedArgs.get("path");

var ctx = frame == null ?
Context.top
: Context.getContextAt(frame);
var caller = ctx.getTopFrame().caller;

PiccodeValue.verifyType(caller, path, Type.STRING);

try {
BufferedImage image = ImageIO.read(new File(path.raw().toString()));
return new PiccodeReference(image);
} catch (IOException ex) {
var def = (BufferedImage) ImageLoader.getImage(-1);
return new PiccodeReference(def);
}
}, null);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Handle ImageIO.read returning null in image_new_from_path

image_new_from_path handles IOException and falls back to a default image, which is good. One additional edge case:

  • ImageIO.read(File) can return null when no appropriate reader is found, without throwing an exception. In that case, you currently wrap null in PiccodeReference, which may later cause confusing failures when the script expects a BufferedImage.

Consider treating null like a load failure and using the same default image fallback:

-        try {
-            BufferedImage image = ImageIO.read(new File(path.raw().toString()));
-            return new PiccodeReference(image);
-        } catch (IOException ex) {
-            var def = (BufferedImage) ImageLoader.getImage(-1);
-            return new PiccodeReference(def);
-        }
+        try {
+            BufferedImage image = ImageIO.read(new File(path.raw().toString()));
+            if (image == null) {
+                var def = (BufferedImage) ImageLoader.getImage(-1);
+                return new PiccodeReference(def);
+            }
+            return new PiccodeReference(image);
+        } catch (IOException ex) {
+            var def = (BufferedImage) ImageLoader.getImage(-1);
+            return new PiccodeReference(def);
+        }

This keeps the behavior consistent between silent read failures and IO failures.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
NativeFunctionFactory.create("image_new_from_path", List.of("path"), (args, namedArgs, frame) -> {
var path = namedArgs.get("path");
var ctx = frame == null ?
Context.top
: Context.getContextAt(frame);
var caller = ctx.getTopFrame().caller;
PiccodeValue.verifyType(caller, path, Type.STRING);
try {
BufferedImage image = ImageIO.read(new File(path.raw().toString()));
return new PiccodeReference(image);
} catch (IOException ex) {
var def = (BufferedImage) ImageLoader.getImage(-1);
return new PiccodeReference(def);
}
}, null);
NativeFunctionFactory.create("image_new_from_path", List.of("path"), (args, namedArgs, frame) -> {
var path = namedArgs.get("path");
var ctx = frame == null ?
Context.top
: Context.getContextAt(frame);
var caller = ctx.getTopFrame().caller;
PiccodeValue.verifyType(caller, path, Type.STRING);
try {
BufferedImage image = ImageIO.read(new File(path.raw().toString()));
if (image == null) {
var def = (BufferedImage) ImageLoader.getImage(-1);
return new PiccodeReference(def);
}
return new PiccodeReference(image);
} catch (IOException ex) {
var def = (BufferedImage) ImageLoader.getImage(-1);
return new PiccodeReference(def);
}
}, null);
🤖 Prompt for AI Agents
In src/main/java/org/editor/nativemods/PiccodeImageModule.java around lines 74
to 91, image_new_from_path currently only catches IOExceptions but does not
handle ImageIO.read returning null; update the try block to check if the
BufferedImage returned is null and, in that case, use the existing default image
fallback (e.g., via ImageLoader.getImage(-1)) and return a PiccodeReference to
that default instead of wrapping null; keep the same behavior for IOException
and ensure the method always returns a non-null PiccodeReference.

Comment on lines +93 to +123
NativeFunctionFactory.create("image_resize", List.of("img" ,"w", "h"), (args, namedArgs, frame) -> {
var img = namedArgs.get("img");
var w = namedArgs.get("w");
var h = namedArgs.get("h");

var ctx = frame == null ?
Context.top
: Context.getContextAt(frame);
var caller = ctx.getTopFrame().caller;

PiccodeValue.verifyType(caller, img, Type.REFERENCE);
PiccodeValue.verifyType(caller, w, Type.NUMBER);
PiccodeValue.verifyType(caller, h, Type.NUMBER);

var _buffered_image = ((PiccodeReference)img).deref();

if (!(_buffered_image instanceof BufferedImage)) {
throw new PiccodeException(caller.file, caller.line, caller.column, "Expected a buffer image. Found " + _buffered_image);
}

var bufferedmage = (BufferedImage) _buffered_image;

var _w = (int) (double) ((PiccodeNumber) w).raw();
var _h = (int) (double) ((PiccodeNumber) h).raw();

Image resultingImage = bufferedmage.getScaledInstance(_w, _h, Image.SCALE_DEFAULT);
BufferedImage outputImage = new BufferedImage(_w, _h, BufferedImage.TYPE_INT_RGB);
outputImage.getGraphics().drawImage(resultingImage, 0, 0, null);

return new PiccodeReference(outputImage);
}, null);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

image_resize drops alpha and leaks a Graphics instance

The resize implementation is mostly correct but has two issues:

  1. Alpha is lost

    • You create the target as BufferedImage.TYPE_INT_RGB, which strips any alpha channel even if the source image is ARGB (e.g., created via image_new). This can break rendering where transparency is expected.
  2. Graphics from outputImage is never disposed

    • outputImage.getGraphics() allocates a Graphics instance that should be dispose()d after use to avoid leaking resources.

Suggested fix:

-        Image resultingImage = bufferedmage.getScaledInstance(_w, _h, Image.SCALE_DEFAULT);
-        BufferedImage outputImage = new BufferedImage(_w, _h, BufferedImage.TYPE_INT_RGB);
-        outputImage.getGraphics().drawImage(resultingImage, 0, 0, null);
+        Image resultingImage = bufferedmage.getScaledInstance(_w, _h, Image.SCALE_DEFAULT);
+        // Preserve alpha if the source has it; default to ARGB for safety.
+        int type = bufferedmage.getColorModel().hasAlpha()
+                ? BufferedImage.TYPE_INT_ARGB
+                : BufferedImage.TYPE_INT_RGB;
+        BufferedImage outputImage = new BufferedImage(_w, _h, type);
+        var g = outputImage.createGraphics();
+        try {
+            g.drawImage(resultingImage, 0, 0, null);
+        } finally {
+            g.dispose();
+        }

This preserves transparency when present and cleans up the interim Graphics.

Comment on lines +41 to +45
jLabel4.setText("Brought to you by Solaris Studio developers");

jTextPane1.setEditable(false);
jTextPane1.setBackground(new java.awt.Color(255, 255, 255));
jTextPane1.setText("\ndrawString(\"\n+--------------------------------------------+\n | ▄▖▘ ▌ |\n | ▙▌▌▛▘▀▌▛▘▛▘▛▌▛▘▛▌▛▌█▌ |\n | ▌ ▌▙▖█▌▄▌▄▌▙▌▙▖▙▌▙▌▙▖ |\n | Creativity + Logic + Math |\n+---------------------------------------------+\n\", 0, 0)\n\nBrought to you by glimmr developers\n\nLead developer: Gama Sibusiso Vincent\nAI and Plugin intergration: TODO\nDocumenentation: TODO\n\nCreated 100% in java using java swing, antlr4 and flatlaf. \nIcons pack dowloaded from icons8");
jTextPane1.setText("\nPen::drawText(\"\n+--------------------------------------------+\n | ▄▖▘ ▌ |\n | ▙▌▌▛▘▀▌▛▘▛▘▛▌▛▘▛▌▛▌█▌ |\n | ▌ ▌▙▖█▌▄▌▄▌▙▌▙▖▙▌▙▌▙▖ |\n | Creativity + Logic + Math |\n+---------------------------------------------+\n\", 0, 0)\n\nBrought to you by glimmr developers\n\nLead developer: Gama Sibusiso Vincent\nAI and Plugin intergration: TODO\nDocumenentation: TODO\n\nCreated 100% in java using java swing, antlr4 and flatlaf. \nIcons pack dowloaded from icons8");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Inconsistent branding in About panel.

Line 41 updates the label to reference "Solaris Studio developers", but Line 45's text content still contains "Brought to you by glimmr developers" (note lowercase "glimmr"). This creates confusion about the project's identity.

Apply this diff to make the branding consistent:

-jTextPane1.setText("\nPen::drawText(\"\n+--------------------------------------------+\n |  ▄▖▘                                     ▌        |\n |  ▙▌▌▛▘▀▌▛▘▛▘▛▌▛▘▛▌▛▌█▌   |\n |  ▌  ▌▙▖█▌▄▌▄▌▙▌▙▖▙▌▙▌▙▖   |\n |        Creativity + Logic + Math        |\n+---------------------------------------------+\n\", 0, 0)\n\nBrought to you by glimmr developers\n\nLead developer: Gama Sibusiso Vincent\nAI and Plugin intergration: TODO\nDocumenentation: TODO\n\nCreated 100% in java using java swing, antlr4 and flatlaf. \nIcons pack dowloaded from icons8");
+jTextPane1.setText("\nPen::drawText(\"\n+--------------------------------------------+\n |  ▄▖▘                                     ▌        |\n |  ▙▌▌▛▘▀▌▛▘▛▘▛▌▛▘▛▌▛▌█▌   |\n |  ▌  ▌▙▖█▌▄▌▄▌▙▌▙▖▙▌▙▌▙▖   |\n |        Creativity + Logic + Math        |\n+---------------------------------------------+\n\", 0, 0)\n\nBrought to you by Solaris Studio developers\n\nLead developer: Gama Sibusiso Vincent\nAI and Plugin integration: TODO\nDocumentation: TODO\n\nCreated 100% in java using java swing, antlr4 and flatlaf. \nIcons pack downloaded from icons8");

Note: This also fixes typos "intergration" → "integration" and "Documenentation" → "Documentation" and "dowloaded" → "downloaded".

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
jLabel4.setText("Brought to you by Solaris Studio developers");
jTextPane1.setEditable(false);
jTextPane1.setBackground(new java.awt.Color(255, 255, 255));
jTextPane1.setText("\ndrawString(\"\n+--------------------------------------------+\n | ▄▖▘ ▌ |\n | ▙▌▌▛▘▀▌▛▘▛▘▛▌▛▘▛▌▛▌█▌ |\n | ▌ ▌▙▖█▌▄▌▄▌▙▌▙▖▙▌▙▌▙▖ |\n | Creativity + Logic + Math |\n+---------------------------------------------+\n\", 0, 0)\n\nBrought to you by glimmr developers\n\nLead developer: Gama Sibusiso Vincent\nAI and Plugin intergration: TODO\nDocumenentation: TODO\n\nCreated 100% in java using java swing, antlr4 and flatlaf. \nIcons pack dowloaded from icons8");
jTextPane1.setText("\nPen::drawText(\"\n+--------------------------------------------+\n | ▄▖▘ ▌ |\n | ▙▌▌▛▘▀▌▛▘▛▘▛▌▛▘▛▌▛▌█▌ |\n | ▌ ▌▙▖█▌▄▌▄▌▙▌▙▖▙▌▙▌▙▖ |\n | Creativity + Logic + Math |\n+---------------------------------------------+\n\", 0, 0)\n\nBrought to you by glimmr developers\n\nLead developer: Gama Sibusiso Vincent\nAI and Plugin intergration: TODO\nDocumenentation: TODO\n\nCreated 100% in java using java swing, antlr4 and flatlaf. \nIcons pack dowloaded from icons8");
jLabel4.setText("Brought to you by Solaris Studio developers");
jTextPane1.setEditable(false);
jTextPane1.setBackground(new java.awt.Color(255, 255, 255));
jTextPane1.setText("\nPen::drawText(\"\n+--------------------------------------------+\n | ▄▖▘ ▌ |\n | ▙▌▌▛▘▀▌▛▘▛▘▛▌▛▘▛▌▛▌█▌ |\n | ▌ ▌▙▖█▌▄▌▄▌▙▌▙▖▙▌▙▌▙▖ |\n | Creativity + Logic + Math |\n+---------------------------------------------+\n\", 0, 0)\n\nBrought to you by Solaris Studio developers\n\nLead developer: Gama Sibusiso Vincent\nAI and Plugin integration: TODO\nDocumentation: TODO\n\nCreated 100% in java using java swing, antlr4 and flatlaf. \nIcons pack downloaded from icons8");
🤖 Prompt for AI Agents
In src/main/java/org/editor/panels/AboutPanel.java around lines 41 to 45, the
label text and the large jTextPane1 content have inconsistent branding and
several typos; update the jTextPane1 string to match "Solaris Studio developers"
(capitalize consistently), replace the "Brought to you by glimmr developers"
line with "Brought to you by Solaris Studio developers", and fix typos: change
"intergration" to "integration", "Documenentation" to "Documentation", and
"dowloaded" to "downloaded"; ensure the surrounding punctuation and spacing
remain valid for the Java string literal.

Comment on lines +220 to +237
def test_file_encoding_and_format(self):
"""Test that README file has proper encoding and line endings."""
readme_path = Path("README.md")
if readme_path.exists():
# Test that file can be read as UTF-8
try:
content = readme_path.read_text(encoding='utf-8')
assert len(content) > 0, "File should be readable as UTF-8"
except UnicodeDecodeError:
pytest.fail("README.md should be encoded in UTF-8")

# Test for reasonable line lengths (soft limit)
lines = content.split('\n')
long_lines = [i for i, line in enumerate(lines, 1) if len(line) > 120]
# This is a soft warning rather than hard failure
if len(long_lines) > 3:
pytest.warn(f"Many lines exceed 120 characters: lines {long_lines[:5]}")

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

pytest.warn will fail at runtime; use warnings.warn instead

pytest has warns (context manager) but no warn function, so pytest.warn(...) will raise an AttributeError and break the suite. For a soft warning, use the standard warnings module.

A minimal fix:

-import pytest
+import pytest
+import warnings
@@
-            long_lines = [i for i, line in enumerate(lines, 1) if len(line) > 120]
-            # This is a soft warning rather than hard failure
-            if len(long_lines) > 3:
-                pytest.warn(f"Many lines exceed 120 characters: lines {long_lines[:5]}")
+            long_lines = [i for i, line in enumerate(lines, 1) if len(line) > 120]
+            # This is a soft warning rather than hard failure
+            if len(long_lines) > 3:
+                warnings.warn(
+                    f"Many lines in README.md exceed 120 characters: lines {long_lines[:5]}",
+                    stacklevel=2,
+                )

🏁 Script executed:

#!/bin/bash
# Check if file exists and examine lines 220-237
if [ -f "tests/test_readme_validation.py" ]; then
  echo "=== File found. Examining lines 220-237 ==="
  sed -n '220,237p' tests/test_readme_validation.py
  echo ""
  echo "=== Checking imports at top of file ==="
  head -20 tests/test_readme_validation.py
else
  echo "File not found at tests/test_readme_validation.py"
fi

Length of output: 1555


🏁 Script executed:

#!/bin/bash
# Search for pytest.warn usage in the codebase
echo "=== Searching for pytest.warn usage ==="
rg -n "pytest\.warn\(" --type py

Length of output: 164


🏁 Script executed:

#!/bin/bash
# Verify pytest module capabilities
python3 << 'EOF'
import pytest
# Check if warn method exists on pytest
if hasattr(pytest, 'warn'):
    print("pytest.warn exists")
else:
    print("pytest.warn does NOT exist")

# Check what warn-related methods pytest has
warn_methods = [attr for attr in dir(pytest) if 'warn' in attr.lower()]
print(f"pytest has these warn-related attributes: {warn_methods}")
EOF

Length of output: 486


pytest.warn() does not exist and will cause runtime failure; use warnings.warn() instead

Line 236 calls pytest.warn() which is not a valid pytest function (pytest only has warns as a context manager, not a warn function). This will raise AttributeError when the test runs. Use the standard warnings module instead.

Required fix:

 import pytest
 import re
 import requests
+import warnings
 from pathlib import Path
             long_lines = [i for i, line in enumerate(lines, 1) if len(line) > 120]
             # This is a soft warning rather than hard failure
             if len(long_lines) > 3:
-                pytest.warn(f"Many lines exceed 120 characters: lines {long_lines[:5]}")
+                warnings.warn(
+                    f"Many lines in README.md exceed 120 characters: lines {long_lines[:5]}",
+                    stacklevel=2,
+                )

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In tests/test_readme_validation.py around lines 220 to 237, the test uses
pytest.warn(...) which does not exist and will raise an AttributeError at
runtime; replace the call with warnings.warn(<message>, category=UserWarning,
stacklevel=2) and ensure you import the warnings module at the top of the file
(import warnings) so the test emits a soft warning instead of failing.

@Yahm3 Yahm3 closed this Nov 15, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants