Code Monkey home page Code Monkey logo

openscad_docsgen's Introduction

OpenSCAD Documentation Generator

This package generates wiki-ready GitHub flavored markdown documentation pages from in-line source code comments. This is similar to Doxygen or JavaDoc, but designed for use with OpenSCAD code. Example images can be generated automatically from short example scripts.

Documentation about how to add documentation comments to OpenSCAD code can be found at https://github.com/revarbat/openscad_docsgen/blob/main/WRITING_DOCS.md

Installing openscad-docsgen

The easiest way to install this is to use pip:

% pip3 install openscad_docsgen

To install directly from these sources, you can instead do:

% python3 setup.py build install

Using openscad-docsgen

The simplest way to generate documentation is:

% openscad-docsgen -m *.scad

Which will read all of .scad files in the current directory, and writes out documentation for each .scad file to the ./docs/ dir. To write out to a different directory, use the -D argument:

% openscad-docsgen -D wikidir -m *.scad

To write out an alphabetical function/module index markdown file, use the -i flag:

% openscad-docsgen -i *.scad

To write out a Table of Contents markdown file, use the -t flag:

% openscad-docsgen -t *.scad

To write out a CheatSheet markdown file, use the -c flag. In addition, you can specify the project name shown in the CheatSheet with the -P PROJECTNAME argument:

% openscad-docsgen -c -P "My Foobar Library" *.scad

A Topics index file can be generated by passing the -I flag:

% openscad-docsgen -I *.scad

You can just test for script errors more quickly with the -T flag (for test-only):

% openscad-docsgen -m -T *.scad

By default, the target output profile is to generate documentation for a GitHub Wiki. You can output for a more generic Wiki with -p wiki:

% openscad-docsgen -ticmI -p wiki *.scad

Docsgen Configuration File

You can also make more persistent configurations by putting a .openscad_docsgen_rc file in the directory you will be running openscad-docsgen from. It can look something like this:

DocsDirectory: WikiDir/
TargetProfile: githubwiki
ProjectName: The Foobar Project
GeneratedDocs: Files, ToC, Index, Topics, CheatSheet
SidebarHeader:
  ## Indices
  .
SidebarMiddle:
  [Tutorials](Tutorials)
IgnoreFiles:
  foo.scad
  std.scad
  version.scad
  tmp_*.scad
PrioritizeFiles:
  First.scad
  Second.scad
  Third.scad
  Fourth.scad
DefineHeader(BulletList): Side Effects
DefineHeader(Table;Headers=Anchor Name|Position): Extra Anchors

For an explanation of the syntax and the specific headers, see: https://github.com/revarbat/openscad_docsgen/blob/main/WRITING_DOCS.md

Using openscad-mdimggen

If you have MarkDown based files that you would like to generate images for, you can use the openscad_mdimggen command. It can take the following arguments:

-h, --help            Show help message and exit
-D DOCS_DIR, --docs-dir DOCS_DIR
                      The directory to put generated documentation in.
-P FILE_PREFIX, --file-prefix FILE_PREFIX
                      The prefix to put in front of each output markdown file.
-T, --test-only       If given, don't generate images, but do try executing the scripts.
-I IMAGE_ROOT, --image_root IMAGE_ROOT
                      The directory to put generated images in.
-f, --force           If given, force regeneration of images.
-a, --png-animation   If given, animations are created using animated PNGs instead of GIFs.

What openscad-mdimggen will do is read the input MarkDown file and look for fenced scripts of OpenSCAD code, that starts with a line of the form:

```openscad-METADATA

It will copy all non-script lines to the output markdown file, and run OpenSCAD for each of the found fenced scripts, inserting the generated image into the output MarkDown file after the script block. The METADATA for each script will define the viewpoint and other info for the given generated image. This METADATA takes the form of a set of semi-colon separated options that can be any of the following:

  • NORENDER: Don't generate an image for this example, but show the example text.
  • ImgOnly: Generate and show the image, but hide the text of the script.
  • Hide: Generate, but don't show script or image. This can be used to generate images to be manually displayed in markdown text blocks.
  • 2D: Orient camera in a top-down view for showing 2D objects.
  • 3D: Orient camera in an oblique view for showing 3D objects.
  • VPT=[10,20,30] Force the viewpoint translation $vpt to [10,20,30].
  • VPR=[55,0,600] Force the viewpoint rotation $vpr to [55,0,60].
  • VPD=440: Force viewpoint distance $vpd to 440.
  • VPF=22.5: Force field of view angle $vpf to 22.5.
  • Spin: Animate camera orbit around the [0,1,1] axis to display all sides of an object.
  • FlatSpin: Animate camera orbit around the Z axis, above the XY plane.
  • Anim: Make an animation where $t varies from 0.0 to almost 1.0.
  • FrameMS=250: Sets the number of milliseconds per frame for spins and animation.
  • FPS=8: Sets the number of frames per second for spins and animation.
  • Frames=36: Number of animation frames to make.
  • Small: Make the image small sized.
  • Med: Make the image medium sized.
  • Big: Make the image big sized.
  • Huge: Make the image huge sized.
  • Size=880x640: Make the image 880 by 640 pixels in size.
  • Render: Force full rendering from OpenSCAD, instead of the normal preview.
  • Edges: Highlight face edges.
  • NoAxes: Hides the axes and scales.
  • NoScales: Hides the scale numbers along the axes.
  • ColorScheme: Generate the image using a specific color scheme - Usage: ColorScheme=<color scheme name> (e.g. ColorScheme=BeforeDawn) - Default color scheme: Cornfield - Predefined color schemes: Cornfield, Metallic, Sunset, Starnight, BeforeDawn, Nature, DeepOcean, Solarized, Tomorrow, Tomorrow Night, Monotone - Color schemes defined as a [Read-only Resource](https://github.com/openscad/openscad/wiki/Path-locations#read-only-resources) or [User Resource](https://github.com/openscad/openscad/wiki/Path-locations#user-resources) are also supported.

For example:

```openscad-FlatSpin;VPD=500
prismoid([60,40], [40,20], h=40, offset=[10,10]);
```

Will generate an animated flat spin of the prismoid at a viewing distance of 500. While:

```openscad-3D;Big
prismoid([60,40], [40,20], h=40, offset=[10,10]);
```

Will generate a still image of the same prismoid, but at a bigger image size.

MDImgGen Configuration File

You can store defaults for openscad_mdimggen in the .openscad_mdimggen_rc file like this:

docs_dir: "BOSL2.wiki"
image_root: "images/tutorials"
file_prefix: "Tutorial-"
source_files: "tutorials/*.md"
png_animations: true

External Calling

Here's an example of how to use this library, to get the parsed documentation data:

import openscad_docsgen as docsgen
from glob import glob
from pprint import pprint
dgp = docsgen.DocsGenParser(quiet=True)
dgp.parse_files(glob("*.scad"))
for name in dgp.get_indexed_names():
    data = dgp.get_indexed_data(name)
    pprint(name)
    pprint(data["description"])

The data for an OpenSCAD function, module, or constant generally looks like:

{
    'name': 'Function&Module',  // Could also be 'Function', 'Module', or 'Constant'
    'subtitle': 'line_of()',
    'body': [],
    'file': 'distributors.scad',
    'line': 43,
    'aliases': ['linear_spread()'],
    'topics': ['Distributors'],
    'usages': [
        {
            'subtitle': 'Spread `n` copies by a given spacing',
            'body': ['line_of(spacing, <n>, <p1=>) ...']
        },
        {
            'subtitle': 'Spread copies every given spacing along the line',
            'body': ['line_of(spacing, <l=>, <p1=>) ...']
        },
        {
            'subtitle': 'Spread `n` copies along the length of the line',
            'body': ['line_of(<n=>, <l=>, <p1=>) ...']
        },
        {
            'subtitle': 'Spread `n` copies along the line from `p1` to `p2`',
            'body': ['line_of(<n=>, <p1=>, <p2=>) ...']
        },
        {
            'subtitle': 'Spread copies every given spacing, centered along the line from `p1` to `p2`',
            'body': ['line_of(<spacing>, <p1=>, <p2=>) ...']
        },
        {
            'subtitle': 'As a function',
            'body': [
                'pts = line_of(<spacing>, <n>, <p1=>);',
                'pts = line_of(<spacing>, <l=>, <p1=>);',
                'pts = line_of(<n=>, <l=>, <p1=>);',
                'pts = line_of(<n=>, <p1=>, <p2=>);',
                'pts = line_of(<spacing>, <p1=>, <p2=>);'
            ]
        }
    ],
    'description': [
        'When called as a function, returns a list of points at evenly spread positions along a line.',
        'When called as a module, copies `children()` at one or more evenly spread positions along a line.',
        'By default, the line will be centered at the origin, unless the starting point `p1` is given.',
        'The line will be pointed towards `RIGHT` (X+) unless otherwise given as a vector in `l`,',
        '`spacing`, or `p1`/`p2`.',
    ],
    'arguments': [
        'spacing = The vector giving both the direction and spacing distance between each set of copies.',
        'n = Number of copies to distribute along the line. (Default: 2)',
        '---',
        'l = Either the scalar length of the line, or a vector giving both the direction and length of the line.',
        'p1 = If given, specifies the starting point of the line.',
        'p2 = If given with `p1`, specifies the ending point of line, and indirectly calculates the line length.'
    ],
    'see_also': ['xcopies()', 'ycopies()'],
    'examples': [
        ['line_of(10) sphere(d=1);'],
        ['line_of(10, n=5) sphere(d=1);'],
        ['line_of([10,5], n=5) sphere(d=1);'],
        ['line_of(spacing=10, n=6) sphere(d=1);'],
        ['line_of(spacing=[10,5], n=6) sphere(d=1);'],
        ['line_of(spacing=10, l=50) sphere(d=1);'],
        ['line_of(spacing=10, l=[50,30]) sphere(d=1);'],
        ['line_of(spacing=[10,5], l=50) sphere(d=1);'],
        ['line_of(l=50, n=4) sphere(d=1);'],
        ['line_of(l=[50,-30], n=4) sphere(d=1);'],
        [
            'line_of(p1=[0,0,0], p2=[5,5,20], n=6) '
            'cube(size=[3,2,1],center=true);'
        ],
        [
            'line_of(p1=[0,0,0], p2=[5,5,20], spacing=6) '
            'cube(size=[3,2,1],center=true);'
        ],
        [
            'line_of(l=20, n=3) {',
            '    cube(size=[1,3,1],center=true);',
            '    cube(size=[3,1,1],center=true);',
            '}'
        ],
        [
            'pts = line_of([10,5],n=5);',
            'move_copies(pts) circle(d=2);'
        ]
    ],
    'children': [
        {
            'name': 'Side Effects',
            'subtitle': '',
            'body': [
                '`$pos` is set to the relative centerpoint of each child copy.',
                '`$idx` is set to the index number of each child being copied.'
            ],
            'file': 'distributors.scad',
            'line': 88
        }
    ]
}

openscad_docsgen's People

Contributors

revarbat avatar julianstirling avatar rwb27 avatar andrewtasso avatar ramilewski avatar

Stargazers

Rafael Bedia avatar Olivier avatar  avatar Minseok Song avatar Simon Hobbs avatar  avatar Mendy Berger avatar Dylan Koji-Cheslin avatar  avatar Kaspar Emanuel avatar Vincent Paeder avatar  avatar

Watchers

 avatar  avatar James Cloos avatar  avatar  avatar

openscad_docsgen's Issues

Integration/output for SCA2D

This may take some discussion. I am writing SCA2D which is a linter or static code analyser for OpenSCAD.

One thing I want to do is warn when people have not documented their functions and modules. Sort of like PyLint does for python. I was about to define my own doc string format when I cam across openscad_docsgen. It make sense for sca2d to use your standard as it already exists, and creates great documentation.

As SCA2D is also in python, I think that the most sensible way for SCA2D to check docstrings would be to run openscad_docsgen. This way I know exactly what documentation openscad_docsgen has found without having to reimplement anything.

To do this I would probably need a function that returns all of the block information as something like a dictionary, but that also returns the line numbers the blocks were read from. With this information I should be able to check that the function is documented directly before implementation and that the arguments match, etc.

I am not proposing that you do these changes. I am just checking that you would be happy for me to put the time in to make them?

Confusing/inconsistent behavior in enforcing requirement for File/LibFile block at file start.

Summary

Currently, the docs state that all files must have a File: or LibFile: block at the start of the file
. However, the parser does not explicitly enforce this. Instead, if either of those blocks have not been previously encountered, it'll automatically inject a LibFile block upon first encountering one of a handful of other blocks (e.g. Section, Includes, etc.).

This issue is further compounded when a File/LibFile block is inadvertently added after one of the blocks which results in an automatically generated LibFile block. This causes an error to be displayed without a clear indication that one had automatically been generated.

I ran into this issue when I accidentally created a File block after a FileGroup block and couldn't understand how to resolve the issue until I reviewed the source to determine how the application was behaving behind the scenes.

Steps to reproduce

  1. Create a file, test.scad, with the following content
// FileGroup: Test Library
// File: test.scad
  1. Execute
openscad-docsgen <path to test.scad>

Expected behavior

Either

  • Explicitly provide an error when a File/LibFile block is not the first block of a file. (To be consistent with the docs)
    • Effectively strict by default

or

  • Print a warning to console to indicate that a File block has been auto-generated in the absence of one
  • Ignore subsequent File blocks or overwrite existing File block in the parser if they're encountered (providing a warning when doing so)

Actual behavior

The application displays an error indicating that a File/LibFile block has already been specified, when it has not.

Output:

Parsing...
  test.scad
!! ERROR at test.scad:2: File/Libfile block already specified, while declaring block: "File"

Output from "Failed OpenSCAD script" doesn't include specific error messages.

I've created a simple file to test this issue, it must be specific to my machine but there's not enough error information to track it down.

My test.scad file includes:

// File: test.scad 

// Module: cube()
// Example(2D):
//   cube(1);
cube(1);

I'm running

openscad-docsgen -m test.scad

And I get the following output:

Parsing...
  test.scad
Writing docs\test.scad.md...
  cube.png...
!! ERROR at test.scad:4: Failed OpenSCAD script:
     Image: cube.png
     cmd-line = openscad -o tmp_cube.png --imgsize=640,480 --view=axes,scales --camera 0,0,0,0,0,0,444 --projection=o --autocenter --viewall --preview  --hardwarnings tmp_cube_png.scad

     Usage: openscad [options] file.scad
     Allowed options:
       --export-format arg          overrides format of exported scad file when
                                    using option '-o', arg can be any of its
                                    supported file extensions.  For ascii stl
                                    export, specify 'asciistl', and for binary stl
                                    export, specify 'binstl'.  Ascii export is the
                                    current stl default, but binary stl is planned
                                    as the future default so asciistl should be
                                    explicitly specified in scripts when needed.

(OpenSCAD help continues, no output from stderr)

     Return code = 1
     -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
     cube(1);
     =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
WARNING: Errors encountered.

I'm running Windows 11 and Python 3.8.0

Consider renaming Index.md

When generating for a website that isn't a wiki Index.md will become Index.html. The root page of the website must be index.md which is only a different by the case of the filename. I would be possible to have both index.html and Index.html, this is a bit confusing and this would fail on operating systems where filenames are case independent.

openscad-mdimggen wishlist

There appears to be no mdimggen-specific documentation. It seems to work similarly to docsgen Example & Figures blocks, but not exactly.

The following changes would make writing BOSL2 Tutorials easier:

  • VPD, VPT, and VPR entries in the metadata list are added as visible scad lines in the rendered code. They should be invisible.
  • VPD overrides 2D and forces a 3D image.
  • Lines in the example script that begin with -- throw an error rather than the Example block behavior of executing but not appearing in the rendered scripts.
  • NoScales is not listed in the Example Block directives list, but it does suppress the axis scales in the image.
  • The Figures Block directives list includes an FPS directive that does not appear in the Example Block directives list and does not work in mdimggen.

The remainder of the directives in the Example Block directives list appear to work in openscad-mdimggen.

Documentation of what appears in Cheat Sheet

I generate an empty cheat sheet at the moment. From the docs I can't see what should go into the cheat sheet. I think, looking at the code, it is only functions from prioritized files? Is this correct? Can the explanation be added to the documentation?

distutils removed from Python3.12

openscad-docsgen requires distutils which has been removed from Python3.12

Workaround: pip3 install setuptools

setuptools includes the deprecated distutils.

openscad-mdimggen: NameError: name 'platform' not defined?

When I try to run openscad-mdimggen on my local BOSL2 tutorials it fails with a NameError:

Traceback (most recent call last):
File "/usr/local/bin/openscad-mdimggen", line 8, in
sys.exit(mdimggen_main())
File "/usr/local/lib/python3.9/site-packages/openscad_docsgen/mdimggen.py", line 163, in mdimggen_main
elif platform.system() == 'Windows':
NameError: name 'platform' is not defined

openscad_mdimggen_rc is unmodified.

Running Python 3.9.1 on MacOS 10.14.6

Subdirectory in docs fails to be created

If you document a file inside a directory for example

libs/utilities.scad

it will try to make the output be

docs/libs/utilities.scad.md

This will then fail as docs/ is created but docs/libs is not

*.scad file not recognize

% openscad-docsgen -m *.scad
image

this command doesn't seem to work for me as the error given is "*.scad does not exist". I try out different way like removing the * or just try changing it to "*scad" and it still giving me the same error. My current directory does have .scad file and I even double check using mydir command and it does exist .

image

openscad-mdimggen fails with AttributeError: module 'PIL.Image' has no attribute 'ANTIALIAS'

Apparently ANTIALIAS was removed in PILLOW 10.0.0

Attempting to process BOSL2 Tutorials locally....

RAM@Maxwell BOSL2 % openscad-mdimggen
BOSL2.wiki/Tutorial-Shapes2d.md
  Shapes2d_1.png... Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.11/bin/openscad-mdimggen", line 8, in <module>
    sys.exit(mdimggen_main())
             ^^^^^^^^^^^^^^^
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/openscad_docsgen/mdimggen.py", line 173, in mdimggen_main
    mdimggen.processFiles(args.srcfiles)
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/openscad_docsgen/mdimggen.py", line 121, in processFiles
    image_manager.process_requests(test_only=opts.test_only)
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/openscad_docsgen/imagemanager.py", line 173, in process_requests
    self.process_request(req)
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/openscad_docsgen/imagemanager.py", line 221, in process_request
    osc.run()
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/openscad_runner/__init__.py", line 306, in run
    im.thumbnail(self.imgsize, Image.ANTIALIAS)
                               ^^^^^^^^^^^^^^^
AttributeError: module 'PIL.Image' has no attribute 'ANTIALIAS'

Enable less strict requirements on including sections

It would be really helpful to be able to generate documentation for simple files and not to have a warning about a lack of section, or the fact the lack of a file block. Would it be possible to warn rather than error?

Directory mode set as hexadecimal not octal

When creating directories

mode=0x744

can cause some strange issues. As the mode should be octal

mode=0o744

Also is there a reason mode is being set in the first place. It seems like something that should be a flagged option if needed. I would not expect a documentation program to override my default file system modes.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.