Skip to content

Commit

Permalink
Org-habit-style min/max ranges in repeaters are not parsed correctly (#…
Browse files Browse the repository at this point in the history
…17)

Fixes #16

---------

Co-authored-by: Aaron Madlon-Kay <aaron@madlon-kay.com>
  • Loading branch information
bgro and amake authored Jan 6, 2025
1 parent f9e5214 commit 7315578
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 6 deletions.
43 changes: 37 additions & 6 deletions lib/src/org/grammar.dart
Original file line number Diff line number Diff line change
Expand Up @@ -551,7 +551,7 @@ class OrgContentGrammarDefinition extends GrammarDefinition {
(active ? char('<') : char('[')) &
ref0(date) &
ref0(time).trim().optional() &
ref0(repeaterOrDelay).trim().repeat(0, 2) &
ref0(repeaterOrDelays) &
(active ? char('>') : char(']'));

Parser timestampRange(bool active) =>
Expand All @@ -561,7 +561,7 @@ class OrgContentGrammarDefinition extends GrammarDefinition {
(active ? char('<') : char('[')) &
ref0(date) &
(ref0(time) & char('-') & ref0(time)).trim() &
ref0(repeaterOrDelay).trim().repeat(0, 2) &
ref0(repeaterOrDelays) &
(active ? char('>') : char(']'));

Parser timestampDateRange(bool active) =>
Expand Down Expand Up @@ -593,15 +593,46 @@ class OrgContentGrammarDefinition extends GrammarDefinition {

Parser minutes() => digit().timesString(2, 'Expected minutes');

// TODO(aaron): Figure out if the spec is actually more restrictive than this.
//
// Namely, it appears that the only valid use cases are:
//
// - None
// - One of Repeater, Min/max Repeater, or Delay
// - Repeater followed by Delay
//
// We can be lenient here for the time being because we are not trying to
// validate the content.
Parser repeaterOrDelays() => ref0(repeaterOrDelay).trim().repeat(0, 2);

Parser repeaterOrDelay() =>
ref0(minMaxRepeater) | ref0(repeater) | ref0(delay);

Parser minMaxRepeater() =>
ref0(repeaterMark) &
digit().plusString('Expected number') &
ref0(repeaterUnit);
ref0(minMaxRepeatUnit) &
char('/') &
digit().plusString('Expected number') &
ref0(minMaxRepeatUnit);

Parser minMaxRepeatUnit() => anyOf('dwmy');

Parser repeater() =>
ref0(repeaterMark) &
digit().plusString('Expected number') &
ref0(repeatOrDelayUnit);

Parser repeaterMark() => string('++') | string('.+') | char('+');

Parser delay() =>
ref0(delayMark) &
digit().plusString('Expected number') &
ref0(repeatOrDelayUnit);

Parser repeaterMark() =>
string('++') | string('.+') | string('--') | anyOf('+-');
Parser delayMark() => string('--') | char('-');

Parser repeaterUnit() => anyOf('hdwmy');
Parser repeatOrDelayUnit() => anyOf('hdwmy');

Parser keyword() => ref0(_keyword).flatten('Expected keyword');

Expand Down
20 changes: 20 additions & 0 deletions test/org/grammar/timestamp_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,18 @@ void main() {
'>'
]);
});
test('with repeater (min/max)', () {
final result = parser.parse('''<2020-03-12 Wed 8:34 +1w/2w>''');
expect(result.value, [
'<',
['2020', '-', '03', '-', '12', 'Wed'],
['8', ':', '34'],
[
['+', '1', 'w', '/', '2', 'w'],
],
'>'
]);
});
test('with multiple repeaters', () {
final result = parser.parse('''<2020-03-12 Wed 8:34 +1w --2d>''');
expect(result.value, [
Expand Down Expand Up @@ -146,5 +158,13 @@ void main() {
final result = parser.parse('''[2020-03-11 Wed 18:34:56 .+1w --12d]''');
expect(result, isA<Failure>(), reason: 'Seconds not supported');
});
test('min/max with hour', () {
final result = parser.parse('''[2020-03-11 Wed 18:34:56 .+1h/2h]''');
expect(result, isA<Failure>(), reason: 'Hours not supported for min/max');
});
test('min/max delay', () {
final result = parser.parse('''[2020-03-11 Wed 18:34:56 -1d/2d]''');
expect(result, isA<Failure>(), reason: 'Min/max not supported on delay');
});
});
}
9 changes: 9 additions & 0 deletions test/org/model/timestamp_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,15 @@ void main() {
expect(result.contains('あ'), isFalse);
expect(result.toMarkup(), markup);
});
test('with repeater (min/max)', () {
final markup = '<2020-03-12 Wed 8:34 +1w/2w>';
final result = parser.parse(markup).value as OrgSimpleTimestamp;
expect(result.contains('2020'), isTrue);
expect(result.contains('Wed'), isTrue);
expect(result.contains('+1w/2w'), isTrue);
expect(result.contains('あ'), isFalse);
expect(result.toMarkup(), markup);
});
test('with multiple repeaters', () {
final markup = '<2020-03-12 Wed 8:34 +1w --2d>';
final result = parser.parse(markup).value as OrgSimpleTimestamp;
Expand Down

0 comments on commit 7315578

Please sign in to comment.