Skip to content

Commit

Permalink
Revert to single comma for description barrier
Browse files Browse the repository at this point in the history
This PR reverts the use of a double comma to indicate the start of the
description, a breaking change introduced in Hamster 3.0, back to the
previous use of a single comma, as discussed in projecthamster#657. Likewise, the
double comma needed before tags, in the case of descriptions containing
the #hash pattern, is also reverted to the use of a single comma.

This change requires two restrictions to the parsing rules. Firstly,
no comma is allowed in the activity name (projecthamster#270). Secondly, tags
may not be separated by a comma when entered on the commandline
(ie. just use `#tag1 #tag2`, not `#tag1, #tag2`).
  • Loading branch information
GeraldJansen authored and matthijskooijman committed Apr 29, 2023
1 parent 01944e1 commit b183b0d
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 31 deletions.
18 changes: 9 additions & 9 deletions help/C/input.page
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,18 @@
To start tracking, press the <gui style="button">+</gui> button,
type in the activity name in the entry,
and hit the <key>Enter</key> key.
To specify more detail on the fly, use this syntax:
`time_info activity name @category,, some description #tag #other tag with spaces`.
To specify more detail on the fly, use this syntax:
`time_info activity name@category, some description #tag #other tag with spaces`.
</p>

<steps>
<item><p>Specify specific times as `13:10-13:45`, and "started 5 minutes ago" as `-5`.</p></item>
<item><p>Next comes the activity name</p></item>
<item><p>Place the category after the activity name, and start it with an at sign `@`, e.g. `@garden`</p></item>
<item><p>If you want to add a description, add a double comma `,,`.</p></item>
<item><p>The description is just freeform text immediately after the double comma, and runs until the end of the string or until the beginning of tags.</p></item>
<item><p>If you want to add a description, add a comma `,`.</p></item>
<item><p>The description is just freeform text immediately after the comma, and runs until the end of the string or until the beginning of tags.</p></item>
<item><p>Place tags at the end, and start each tag with a hash mark `#`.</p></item>
<item><p>A double comma `,,` can also be placed to indicate the beginning of tags. Otherwise any `#` in the activity, category or description would be interpreted as a starting a tag.</p></item>
<item><p>A comma `,` can also be placed to indicate the beginning of tags. Otherwise any `#` in the activity, category or description would be interpreted as a starting a tag.</p></item>
</steps>

<p>
Expand All @@ -33,14 +33,14 @@
<p>Forgot to note the important act of watering flowers over lunch.</p>
</example>
<example>
<code>tomatoes@garden,, digging holes</code>
<code>tomatoes@garden, digging holes</code>
<p>
Need more tomatoes in the garden. Digging holes is purely informational,
so added it as a description.
</p>
</example>
<example>
<code>-7 existentialism,, thinking about the vastness of the universe</code>
<code>-7 existentialism, thinking about the vastness of the universe</code>
<p>
Corrected information by informing application that I've been
doing something else for the last seven minutes.
Expand All @@ -52,14 +52,14 @@
<list>
<item>
<p>Relative times work both for <var>start</var> and <var>end</var>,
provided they are preceded by an explicit sign,
provided they are preceded by an explicit sign,
and <em>separated by a space</em>.</p>
<p><code>-30 -10</code> means started 30 minutes ago and stopped 10 minutes ago.</p>
<p><code>-5 +30</code> means started 5 minutes ago and will stop in 30 minutes
(duration of 35 minutes).</p>
</item>
<item>
<p>Duration can be given instead of <var>end</var>,
<p>Duration can be given instead of <var>end</var>,
as 1, 2 or 3 digits without any sign.</p>
<p><code>-50 30</code> means started 50 minutes ago and lasted 30 minutes
(so it ended 20 minutes ago).</p>
Expand Down
4 changes: 2 additions & 2 deletions src/hamster/lib/fact.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,15 +186,15 @@ def serialized_name(self):
res += "@%s" % self.category

if self.description:
res += ',, '
res += ', '
res += self.description

if ('#' in self.activity
or '#' in self.category
or '#' in self.description
):
# need a tag barrier
res += ",, "
res += ", "

if self.tags:
# double comma is a left barrier for tags,
Expand Down
8 changes: 4 additions & 4 deletions src/hamster/lib/parsing.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def parse_fact(text, range_pos="head", default_day=None, ref="now"):
Returns found fields as a dict.
Tentative syntax (not accurate):
start [- end_time] activity[@category][,, description][,,]{ #tag}
start [- end_time] activity[@category][, description][,]{ #tag}
According to the legacy tests, # were allowed in the description
"""

Expand All @@ -64,7 +64,7 @@ def parse_fact(text, range_pos="head", default_day=None, ref="now"):
# especially the tags barrier
m = re.search(tags_separator, remaining_text)
remaining_text = remaining_text[:m.start()]
if m.group(1) == ",,":
if m.group(1) == ",":
# tags barrier found
break

Expand All @@ -83,8 +83,8 @@ def parse_fact(text, range_pos="head", default_day=None, ref="now"):
res["tags"] = list(reversed(tags))

# description
# first look for double comma (description hard left boundary)
head, sep, description = remaining_text.partition(",,")
# first look for comma (description hard left boundary)
head, sep, description = remaining_text.partition(",")
res["description"] = description.strip()
remaining_text = head.strip()

Expand Down
32 changes: 16 additions & 16 deletions tests/test_stuff.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ def test_category(self):

def test_description(self):
# plain activity name
activity = Fact.parse("case,, with added descriptiön")
activity = Fact.parse("case, with added descriptiön")
self.assertEqual(activity.activity, "case")
self.assertEqual(activity.description, "with added descriptiön")
assert not activity.category
Expand All @@ -95,7 +95,7 @@ def test_description(self):

def test_tags(self):
# plain activity name
activity = Fact.parse("#case,, description with #hash,, #and, #some #tägs")
activity = Fact.parse("#case, description with #hash, #and #some #tägs")
self.assertEqual(activity.activity, "#case")
self.assertEqual(activity.description, "description with #hash")
self.assertEqual(set(activity.tags), set(["and", "some", "tägs"]))
Expand All @@ -105,16 +105,17 @@ def test_tags(self):

def test_full(self):
# plain activity name
activity = Fact.parse("1225-1325 case@cat,, description #ta non-tag,, #tag #bäg")
activity = Fact.parse(
"1225-1325 case@cat, description #hash non-tag, #tag #bäg")
self.assertEqual(activity.start_time.strftime("%H:%M"), "12:25")
self.assertEqual(activity.end_time.strftime("%H:%M"), "13:25")
self.assertEqual(activity.activity, "case")
self.assertEqual(activity.category, "cat")
self.assertEqual(activity.description, "description #ta non-tag")
self.assertEqual(activity.description, "description #hash non-tag")
self.assertEqual(set(activity.tags), set(["bäg", "tag"]))

def test_copy(self):
fact1 = Fact.parse("12:25-13:25 case@cat,, description #tag #bäg")
fact1 = Fact.parse("12:25-13:25 case@cat, description #tag #bäg")
fact2 = fact1.copy()
self.assertEqual(fact1.start_time, fact2.start_time)
self.assertEqual(fact1.end_time, fact2.end_time)
Expand All @@ -132,7 +133,7 @@ def test_copy(self):
self.assertEqual(fact3.tags, ["changed"])

def test_comparison(self):
fact1 = Fact.parse("12:25-13:25 case@cat,, description #tag #bäg")
fact1 = Fact.parse("12:25-13:25 case@cat, description #tag #bäg")
fact2 = fact1.copy()
self.assertEqual(fact1, fact2)
fact2 = fact1.copy()
Expand Down Expand Up @@ -161,12 +162,12 @@ def test_comparison(self):

def test_decimal_in_activity(self):
# cf. issue #270
fact = Fact.parse("12:25-13:25 10.0@ABC,, Two Words #tag #bäg")
fact = Fact.parse("12:25-13:25 10.0@ABC, Two Words #tag #bäg")
self.assertEqual(fact.activity, "10.0")
self.assertEqual(fact.category, "ABC")
self.assertEqual(fact.description, "Two Words")
# should not pick up a time here
fact = Fact.parse("10.00@ABC,, Two Words #tag #bäg")
fact = Fact.parse("10.00@ABC, Two Words #tag #bäg")
self.assertEqual(fact.activity, "10.00")
self.assertEqual(fact.category, "ABC")
self.assertEqual(fact.description, "Two Words")
Expand All @@ -186,18 +187,18 @@ def test_spaces(self):
self.assertEqual(fact3.serialized(), "")

def test_commas(self):
fact = Fact.parse("11:00 12:00 activity, with comma@category,, description, with comma")
self.assertEqual(fact.activity, "activity, with comma")
fact = Fact.parse("11:00 12:00 activity@category, description, with comma")
self.assertEqual(fact.activity, "activity")
self.assertEqual(fact.category, "category")
self.assertEqual(fact.description, "description, with comma")
self.assertEqual(fact.tags, [])
fact = Fact.parse("11:00 12:00 activity, with comma@category,, description, with comma, #tag1, #tag2")
self.assertEqual(fact.activity, "activity, with comma")
fact = Fact.parse("11:00 12:00 activity@category, description, with comma, #tag1 #tag2")
self.assertEqual(fact.activity, "activity")
self.assertEqual(fact.category, "category")
self.assertEqual(fact.description, "description, with comma")
self.assertEqual(fact.tags, ["tag1", "tag2"])
fact = Fact.parse("11:00 12:00 activity, with comma@category,, description, with comma and #hash,, #tag1, #tag2")
self.assertEqual(fact.activity, "activity, with comma")
fact = Fact.parse("11:00 12:00 activity@category, description, with comma and #hash, #tag1 #tag2")
self.assertEqual(fact.activity, "activity")
self.assertEqual(fact.category, "category")
self.assertEqual(fact.description, "description, with comma and #hash")
self.assertEqual(fact.tags, ["tag1", "tag2"])
Expand All @@ -215,7 +216,6 @@ def test_roundtrips(self):
for activity in (
"activity",
"#123 with two #hash",
"activity, with comma",
"17.00 tea",
):
for category in (
Expand Down Expand Up @@ -453,7 +453,7 @@ def test_timedelta(self):

class TestDBus(unittest.TestCase):
def test_round_trip(self):
fact = Fact.parse("11:00 12:00 activity, with comma@category,, description, with comma #and #tags")
fact = Fact.parse("11:00 12:00 activity@category, description, with comma #and #tags")
dbus_fact = to_dbus_fact_json(fact)
return_fact = from_dbus_fact_json(dbus_fact)
self.assertEqual(return_fact, fact)
Expand Down

0 comments on commit b183b0d

Please sign in to comment.