Contributing to Owlkettle

A short introduction to owlkettle's internals can be found here.

Documentation

When adding a new widget or modifying an existing widget, you will need to update the widget documentation. Since it is automatically generated from the owlkettle/widgets.nim module, running the following command from the project folder will update the documentation to reflect any changes you made to the widgets.

make -C docs
# Alternatively
nimble genDocs

Note: Please do never change the docs/widgets.md file manually. Any changes you make will be removed once it is generated the next time.

Examples

You can add examples for how to use a widget by using the example widget property:

renderable MyWidget:
  text: string

  example:
    MyWidget:
      text = "Hello, world!"

All examples you add to widgets in this way will also be included in the widget documentation the next time you regenerate it.

Images

When adding any images to the nimibook documentation, try to account for light and dark-modes. You can do so easily by first making sure your image looks good in nimibooks light mode, and then adding a text block containing a css rule like this to your .md or .nim file:

<style>
.coal img.invertable-image,
.navy img.invertable-image,
.ayu img.invertable-image {
  filter: invert(100%);
  background-color:white;
}
</style>

Style Guide

This style guide is supposed to provide some guidelines for developing owlkettle. It is currently still under construction and should therefore not be viewed as a strict set of rules to follow.

Identifiers

Owlkettle uses camelCase for identifiers. The names of types and widgets are in PascalCase.

Constructors

The names of constructor procedures for ref object types should start with the prefix new while constructor procedures for object types should start with the prefix init. For example the constructor for a type named MyType would be called newMyType if it is a ref object and initMyType if it is an object.

Procedures which load data from disk should start with the prefix load and take a path as their first argument. A procedure which loads MyType from disk may for example have the signature proc loadMyType(path: string): MyType.

Procedure Calls

Since there are multiple ways to call procedures in nim, it is necessary to have some guidelines on when to use which syntax. Please note that these are general guidelines and there are exceptions for some specific cases.

Generally myObject.doSomething(argument1, ...) and doSomething(argument1, ...) are preferred over myObject.doSomething argument1, ... and doSomething argument1, ....

There are however a few exceptions to this rule:

  • Echo: The echo procedure should always be called using command syntax (Example: echo "Hello, world!")
  • Getters: If the called procedure does not have any parameters and is so simple that it may be identified as a getter for a field, it may be called without parentheses.
  • Type Conversions: Type conversions may be called without parentheses (Example: myInt.float).
  • Imported Procedures: Procedures imported from C code using {.importc.} should always be called using myProc(argument0, ...).
  • Macros/Templates: Since the preferred way to call a macro heavily depends on the macro itself, macros may be called using any possible syntax.