Configuring a project with ubproject.toml

The ubproject.toml file is a TOML configuration file that allows you to specify the settings for your project.

You can find the schema at https://ubcode.useblocks.com/ubproject.schema.json, and it is recommended that you add this to the top of your file for use with the taplo toolkit:

"$schema" = "https://ubcode.useblocks.com/ubproject.schema.json"

Please also see the detailed ubproject.toml schema reference.

For a complete example, see the Sphinx-Needs Demo project.

Configuration file discovery

Hierarchical configuration is supported, such that the “closest” config file in the directory hierarchy is used for every individual file, with all paths in the config file being resolved relative to the directory containing that config file.

For example, given the following directory structure:

project/
├── docs1/
│   ├── doc1.rst
│   └── ubproject.toml
├── docs2/
│   └── doc2.rst
└── ubproject.toml

The configuration for doc1.rst will be read from project/docs1/ubproject.toml, whereas for doc2.rst it will be read from project/ubproject.toml.

See also the source configuration below for how file-discovery works for reStructuredText source files.

Sharing configuration

To share configuration between multiple projects, you can use the extend option to reference another ubproject.toml file.

# Extend the `ubproject.toml` file in the parent directory...
extend = "../ubproject.toml"

[needs]
# ...but use a different ID regex.
id_regex = "^[a-zA-Z0-9_]{5,}"

Configuration options

Top-level options

# Extend another configuration file
extend = "path/to/ubproject.toml"
# Virtual configurations do not correspond to an actual project.
# They are used for providing shared configuration defaults.
virtual = true

needs

This provides configuration for ubCode to identify and extract needs in the source files.

[needs]
# whether an non-autogenerated ID is required for each need
id_required = true
# regex pattern to validate the ID against
id_regex = "^[A-Z0-9_]{5,}"
# options for auto-generating IDs
id_length = 5
# Base auto-generated IDs on the title.
id_from_title = false
# If True, a title is optional.
title_optional = false
# Base auto-generated titles on the content.
title_from_content = false
# If given, only the defined statuses are allowed.
statuses = [{name="open"}, {name="closed"}]
# If given, only the defined tags are allowed.
tags = [{name="tag1"}, {name="tag2"}]
# Mapping of keys that can be used as needimport arguments and replaced by the values
import_keys = {key1="/path/to/needs.json"}

# list of need types
[[needs.types]]
directive = "my-req"
title = "My Requirement"
prefix = "M_"
color = "#000000"
style = "node"

# list of link types
[[needs.extra_links]]
option = "tests"
incoming = "is tested by"
outgoing = "tests"
copy = true
style = "#00AA00"
style_part = "dotted,#00AA00"

# list of extra options
extra_options = ["tests"]

# default options for all needs
[needs.global_options]
status = {default="open"}

needs_json

This provides configuration for the Needs Index tree view

[needs_json]
# Path to the needs.json file
path = "relative/path/to/needs.json"
# Optional path to resolve source locations against
src = "."

parse

This provides configuration for parsing of source files.

[parse]
# A list of directive names that will not emit a warning if they are unknown.
ignore_directives = []

# A map of directive names to extend the built-in directives with.
# Note that all fields are optional, see below for an example.
[parse.extend_directives.example]
argument = true  # Whether the directive can have an argument
options = true  # Whether the directive can have options
content = true  # Whether the directive can have content
content_required = true  # Whether a warning should be emitted if the directive has no content
parse_content = true  # Whether the directive content should be parsed as reStructuredText
description = "A directive"  # A description of the directive
extension = "other"  # The extension that provides the directive
named_options.class = { description = "space-delimited classes" }  # A map of named options for the directive

# A map of role names to extend the built-in roles with.
# Note that all fields are optional, see below for an example.
[parse.extend_roles.other]
description = "A role"  # A description of the role
extension = "other"  # The extension that provides the role

project

This provides configuration for the project.

[project]
# Project name
name = "My Project"
# Project version
version = "1.0.0"
# Project description
description = "My project description"
# A directory, used for resolving paths in certain directives (defaults to config directory).
srcdir = "src"

lint

This provides configuration for linting of projects.

[lint]
# List of linting codes to ignore
ignore = ["block.title_line"]
# A list of linting codes to select in LSP file diagnostics
# This overrides the ignore list.
lsp_select = ["block.title_line"]

source

This provides configuration for discovery of source files.

[source]
# Whether to automatically exclude files that are ignored by `.ignore`, `.gitignore`, `.git/info/exclude`, and global gitignore files.
respect_gitignore = true
# A list of glob patterns to extend the exclude list with.
extend_exclude = []
# A list of glob patterns to extend the include list with.
extend_include = []

scripts

This key can be used to register custom scripts to run. In VS Code they can be accessed via the command palette (Ctrl+Shift+P) by selecting “ubCode: Run Script in Terminal”.

Each key is a script, and each value is the configuration for that script. Normally the value is an object with different keys with the most important key being cmd which holds the command to execute. However if only cmd is set, then the object is optional.

[scripts]
sphinx1 = "sphinx-build -b html . _build/html {{filepath}}"
sphinx2 = { cmd = "sphinx-build -b html . _build/html {{filepath}}", env = { SPHINXOPTS = "-W" }, terminal = "name", jinja = true }

Additionally, the chain key can be used in place of cmd to run multiple commands in sequence:

[scripts]
rm_build = "rm -rf _build"
sphinx = "sphinx-build -b html . _build/html {{filepath}}"
"sphinx:clean" = { chain = ["rm_build", "sphinx"] }

The following keys are possible for a script:

  • cmd: The command to execute.

  • chain: A list of scripts to execute in sequence.

  • env: A map of environment variables to set.

  • terminal: What to name the terminal in VS Code. If not set, the terminal will be named after the script key. Terminal names are unique, so if a terminal with the same name already exists, it will be reused.

  • jinja: If True (the default), the command is treated as a jinja template, which can take the following variables:

    • {{ confdir }}: The directory containing the configuration file.

    • {{ filepath }}: The currently active file in VS Code

The current working directory for the script is set as the directory containing the configuration file.

server

This provides configuration for the language server.

[server]
# Whether to run background indexing of the project every time a source document is saved.
index_on_save = true

format_rst

This provides configuration for the reStructuredText formatter.

[format_rst]
fail_on_warning = []
validate = true
blockquote_indent = 2
definition_list_indent = 2
directive_indent = 3
enum_list_auto = "preserve"
enum_list_style = "preserve"
field_list_align_body = false
field_list_body_on_new_line = 20
field_list_indent = 2
literal_indent = 2
paragraph_line_length = 70
paragraph_semantic_wrap = false
simple_table_space = 2
substitution_indent = 3
transition_char = "-"
transition_length = 10
fail_on_warning

A list of linting codes that should fail the formatting of a document.

validate

If True, the formatter will validate that the document structure has not been changed before writing any changes.

blockquote_indent

The number of spaces to indent blockquotes (default: 2)

definition_list_indent

The number of spaces to indent definitions in definition lists (default: 2), e.g.

term
  and the second line is indented two spaces.
directive_indent

The number of spaces to indent directive body (default: 3), e.g.

.. directive::
   :option: value
   :option2: value2

   The body is indented three spaces.
enum_list_auto

The behaviour of enumerated lists when using auto # markers:

  • preserve: Preserve the auto markers from the original document (default).

  • always: Always use auto markers for subsequent items.

  • never: Never use auto markers for subsequent items.

enum_list_style

The style of enumerated lists:

  • preserve: Preserve the original style (default).

  • period: Use a period after the enumerator, e.g. 1..

  • rparen: Use a parenthesis after the enumerator, e.g. 1).

  • parens: Use parentheses around the enumerator, e.g. (1).

field_list_body_on_new_line

The field length after which the first line of the body should start on a new line (default: 20), e.g.

:this is a really really long field:
  So the body starts on a new line.
field_list_indent

The number of spaces to indent the content of field lists (default: 2), e.g.

:field: This is the body
  and the second line is indented two spaces.
field_list_align_body

Whether to align the body of field lists with the with its first line (default: false), e.g.

:field: This is the body
        and the second line is a aligned.
literal_indent

The number of spaces to indent literal blocks, after paragraphs (default: 2), e.g.

This is a paragraph::

  This is a literal block, indented two spaces.
paragraph_line_length

A target width for paragraphs (default: unset). Unless paragraph_semantic_wrap is set, this replaces all new lines in the plain text with spaces, then wraps the paragraph at the target width, at any single-space boundary, e.g.

This is a paragraph, *with a line-break in emphasis*, **and a line-break in strong**, ``and a
line-break in literal``, and another line.

Then for paragraph_line_length = 10`, this would be formatted as:

This is a paragraph,
*with a
line-break in emphasis*,
**and a
line-break in strong**,
``and a
line-break in literal``,
and another line.

Note

this is not a hard limit, but a target length, and it will also not wrap paragraphs that are in table cells.

paragraph_semantic_wrap

Wrap paragraphs at semantic boundaries; this replaces all new lines in the plain text with spaces, then always wraps at [.!?] [A-Z] sentence boundaries then, if paragraph_line_length is set, it may also wrap at [,;] clause boundaries, e.g.

This is
a sentence. Then another with an e.g. ``literal . element``!
Then, well lets do, another that has; a really long line? Then something else...

Then for paragraph_semantic_wrap = true and paragraph_line_length = 10`, this would be formatted as:

This is a sentence.
Then another with an e.g. ``literal . element``!
Then, well lets do,
another that has;
a really long line?
Then something else...