Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 5 additions & 66 deletions extensions.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ are 5 modifiers:
- `@` **Recipe**. References another recipe by it's name.
```cooklang
Add @@tomato sauce{200%ml}.
```
```
- `&` **Reference**. References another ingredient with the same name. If a
quantity is given, the amount can be added. The ingredient must be defined
before. If there are multiple definitions, use the last one.
Expand All @@ -21,7 +21,7 @@ are 5 modifiers:
```cooklang
Now you can add @?thyme.
```
- `+` **New**. Forces to create a new ingredient. This works with the
- `+` **New**. Forces to create a new ingredient. This works with the
[modes](#modes) extension.

This also works (except recipe) for cookware.
Expand All @@ -47,18 +47,7 @@ There are more syntax variations:
Only past steps from the current section can be referenced. It can only be
combined with the optional (`?`) modifier. Text steps can't be referenced. In
relative references, text steps are ignored. Enabling this extension
automatically enables the [modifiers](#modifiers) extension.

## Component note
Simple, add small notes to ingredients. The notes in between parenthesis.

```coklang
@flour{}(all purpose)
@flour(all purpose) -- can omit the close brackets
@flour{} (all purpose) -- ❌ no space between the ingredient and the note
```

This also works for cookware.
automatically enables the [modifiers](#modifiers) extension.

## Component alias
Add an alias to an ingredient to display a different name.
Expand All @@ -78,43 +67,6 @@ Add more @&tipo zero flour|flour{}

This also works for cookware.

## Sections
Divide the steps. Sections can have a name or not.

```cooklang
= Cooking -- this
== Cooking == -- many before and after is also supported
==== -- without name
```

To add images to steps inside a section, add another index to the image name:
```txt
Recipe.0.jpeg -- First section, first step
Recipe.0.0.jpeg -- The same
Recipe.1.0.jpeg -- Second section, first, step
```

## Multiline steps
In regular cooklang each line is a step. With this extension, the recipe is
divided into blocks by a blank line in between, so:
```cooklang
A step,
the same step.

A different step.
```

## Text blocks
Some people like to write a couple of paragraphs in the recipe that don't are steps.

It can also be used as notes that are not instructions.

```cooklang
> Text block.

Regular step.
```

## Advanced units
Maybe confusing name. Tweaks a little bit the parsing and behaviour of units
inside quantities.
Expand Down Expand Up @@ -205,29 +157,16 @@ Just an extra rule that makes timers like `~name` invalid.
[^2]: Currently this is done in the analysis pass. So in the AST there is no
concept of inline quantities.

## Special metadata
This extension enables extra parsing for some special metadata keys. These are:

- `tags`. Comma separated list of tags.
- `emoji`. Emoji or emoji shortcode, checked that it's an actual emoji.
- `author`. Name, URL or [both](#Name-with-URL) with the format `name <URL>`.
- `source`. Same as `author`.
- `time`. Time string with unit support. Like `2 hour 30 min`. This overrides past `prep_time`/`cook_time`.
- `prep_time`. Same format as `time`. Overrides past `time` but not `prep_time`.
- `cook_time`. Same format as `time`. Overrides past `time` but not `cook_time`.

_(`servings` is always parsed)_

### Name with URL

Example: `Mom's Cookbook <https://moms-cookbook.url>` -> name: `Mom's Cookbook` url: `https://moms-cookbook.url/`

The interpretations of the key value will be:
The interpretations of the key value will be:

- `name <valid url>` -> as `name` & `url`
- `name <invalid url>` -> as `name`
- `name` -> as `name`
- `invalid url` -> as `name`
- `<invalid url>` -> as `name`
- `valid url` -> as `url`
- `<valid url>` -> as `url`
- `<valid url>` -> as `url`
4 changes: 1 addition & 3 deletions playground/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ <h1>cooklang-rs playground</h1>
<input type="checkbox" name="loadUnits" id="loadUnits">
<label for="loadUnits">Load units</label>
</div>

<fieldset>
<legend>Extensions</legend>
<div id="extensions-container"></div>
Expand Down Expand Up @@ -331,9 +331,7 @@ <h1>cooklang-rs playground</h1>
const extensionsContainer = document.getElementById("extensions-container");
const extensions = [
"COMPONENT_MODIFIERS",
"COMPONENT_NOTE",
"COMPONENT_ALIAS",
"SECTIONS",
"ADVANCED_UNITS",
"MODES",
"TEMPERATURE",
Expand Down
7 changes: 0 additions & 7 deletions src/analysis/event_consumer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -288,13 +288,6 @@ impl<'i, 'c> RecipeCollector<'i, 'c> {

// check if it's a special key
if let Ok(sp_key) = SpecialKey::from_str(&key_t) {
// always parse servings
if sp_key != SpecialKey::Servings
&& !self.extensions.contains(Extensions::SPECIAL_METADATA)
{
return;
}

// try to insert it
let res =
self.content
Expand Down
8 changes: 1 addition & 7 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,12 +113,8 @@ bitflags! {
pub struct Extensions: u32 {
/// Enables the [`Modifiers`](crate::ast::Modifiers)
const COMPONENT_MODIFIERS = 1 << 1;
/// Notes with `@igr(note)`
const COMPONENT_NOTE = 1 << 2;
/// Alias with `@igr|alias{}`
const COMPONENT_ALIAS = 1 << 3;
/// Sections with `== Section ==` or `= Section`
const SECTIONS = 1 << 4;
/// Enable extra checks with units and allows to omit the `%` in simple
/// cases like `@igr{10 kg}`
const ADVANCED_UNITS = 1 << 5;
Expand All @@ -144,9 +140,7 @@ bitflags! {
///
/// **ADDITIONS TO THE EXTENSIONS THIS ENABLES WILL NOT BE CONSIDERED A BREAKING CHANGE**
const COMPAT = Self::COMPONENT_MODIFIERS.bits()
| Self::COMPONENT_NOTE.bits()
| Self::COMPONENT_ALIAS.bits()
| Self::SECTIONS.bits()
| Self::ADVANCED_UNITS.bits()
| Self::MODES.bits()
| Self::TEMPERATURE.bits()
Expand Down Expand Up @@ -257,7 +251,7 @@ impl CooklangParser {
analysis::parse_events(
meta_events,
input,
Extensions::SPECIAL_METADATA & self.extensions,
self.extensions,
&self.converter,
options,
)
Expand Down
4 changes: 0 additions & 4 deletions src/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,6 @@ use crate::{
/// The raw key/value pairs from the recipe are in the `map` field. Many methods
/// on this struct are the parsed values with some special meaning. They return
/// `None` if the key is missing or the value failed to parse.
///
/// Also, most of these values will not have been parsed if the
/// [`SPECIAL_METADATA`](crate::Extensions::SPECIAL_METADATA) extension is not
/// enabled.
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone, Default)]
pub struct Metadata {
special: HashMap<SpecialKey, SpecialValue>,
Expand Down
6 changes: 1 addition & 5 deletions src/parser/section.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
use crate::{error::label, lexer::T, Extensions};
use crate::{error::label, lexer::T};

use super::{tokens_span, warning, BlockParser, Event};

pub(crate) fn section<'i>(block: &mut BlockParser<'_, 'i>) -> Option<Event<'i>> {
if !block.extension(Extensions::SECTIONS) {
return None;
}

block.consume(T![=])?;
block.consume_while(|t| t == T![=]);
let name_pos = block.current_offset();
Expand Down
21 changes: 7 additions & 14 deletions src/parser/step.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,17 +116,13 @@ fn modifiers<'t>(bp: &mut BlockParser<'t, '_>) -> &'t [Token] {
}

fn note<'i>(bp: &mut BlockParser<'_, 'i>) -> Option<Text<'i>> {
bp.extension(Extensions::COMPONENT_NOTE)
.then(|| {
bp.with_recover(|line| {
line.consume(T!['('])?;
let offset = line.current_offset();
let note = line.until(|t| t == T![')'])?;
line.bump(T![')']);
Some(line.text(offset, note))
})
})
.flatten()
bp.with_recover(|line| {
line.consume(T!['('])?;
let offset = line.current_offset();
let note = line.until(|t| t == T![')'])?;
line.bump(T![')']);
Some(line.text(offset, note))
})
}

struct ParsedModifiers {
Expand Down Expand Up @@ -577,9 +573,6 @@ fn check_alias(bp: &mut BlockParser, name_tokens: &[Token], container: &'static
fn check_note(bp: &mut BlockParser, container: &'static str) {
assert_ne!(container, INGREDIENT);
assert_ne!(container, COOKWARE);
if !bp.extension(Extensions::COMPONENT_NOTE) {
return;
}

assert!(bp
.with_recover(|bp| {
Expand Down