[california] Specify location and time w/ at-sign in Quick Add: Bug #732033



commit d35ba37e3f48521b147c3d39dc38088c26b125e0
Author: Jim Nelson <jim yorba org>
Date:   Fri Aug 15 11:47:25 2014 -0700

    Specify location and time w/ at-sign in Quick Add: Bug #732033
    
    In addition, if the at-sign is used for location, the location won't
    be added to the summary.

 src/component/component-details-parser.vala |   80 +++++++++++++++++++++++----
 src/tests/tests-quick-add.vala              |   34 +++++++++++
 2 files changed, 103 insertions(+), 11 deletions(-)
---
diff --git a/src/component/component-details-parser.vala b/src/component/component-details-parser.vala
index 3f6b854..10b42e1 100644
--- a/src/component/component-details-parser.vala
+++ b/src/component/component-details-parser.vala
@@ -19,13 +19,56 @@ namespace California.Component {
  */
 
 public class DetailsParser : BaseObject {
+    /**
+     * Recognized "special" symbols.
+     */
+    private enum Shorthand {
+        NONE,
+        /**
+         * { link Shorthand} for TIME or LOCATION.
+         */
+        ATSIGN;
+        
+        /**
+         * Converts a string to a recognized { link Shorthand}.
+         */
+        public static Shorthand parse(string str) {
+            switch (str) {
+                case "@":
+                    return ATSIGN;
+                
+                default:
+                    return NONE;
+            }
+        }
+    }
+    
     private class Token : BaseObject, Gee.Hashable<Token> {
+        /**
+         * Original token.
+         */
         public string original;
+        
+        /*
+         * Casefolded and punctuation removed.
+         */
         public string casefolded;
         
+        /**
+         * { link Shorthand} parsed from { link original}.
+         */
+        public Shorthand shorthand;
+        
         public Token(string token) {
             original = token;
-            casefolded = from_string(token.casefold()).filter(c => !c.ispunct()).to_string(c => 
c.to_string()) ?? "";
+            casefolded = from_string(token.casefold())
+                .filter(c => !c.ispunct())
+                .to_string(c => c.to_string()) ?? "";
+            shorthand = Shorthand.parse(original);
+        }
+        
+        public bool is_empty() {
+            return String.is_empty(casefolded) && shorthand == Shorthand.NONE;
         }
         
         public bool equal_to(Token other) {
@@ -64,6 +107,7 @@ public class DetailsParser : BaseObject {
     private Calendar.Date? end_date = null;
     private Calendar.Duration? duration = null;
     private bool adding_location = false;
+    private bool adding_summary = true;
     private RecurrenceRule? rrule = null;
     
     /**
@@ -131,8 +175,8 @@ public class DetailsParser : BaseObject {
                 break;
             
             // because whitespace and punctuation is stripped from the original token, it's possible
-            // for the casefolded token to be empty
-            if (String.is_empty(token.casefolded)) {
+            // for the casefolded token to be empty (and an unrecognized Shorthand)
+            if (token.is_empty()) {
                 add_text(token);
                 
                 continue;
@@ -155,6 +199,12 @@ public class DetailsParser : BaseObject {
                 continue;
             stack.restore();
             
+            // The ATSIGN is also recognized as a TIME preposition
+            stack.mark();
+            if (token.shorthand == Shorthand.ATSIGN && parse_time(stack.pop(), false))
+                continue;
+            stack.restore();
+            
             // A duration preposition suggests a specific amount of positive time is being described
             // by the next two tokens.
             stack.mark();
@@ -176,16 +226,25 @@ public class DetailsParser : BaseObject {
                 continue;
             stack.restore();
             
-            // only look for location prepositions if not already adding text to the location field
-            if (!adding_location && token.casefolded in LOCATION_PREPOSITIONS) {
+            // only look for LOCATION prepositions if not already adding text to the location field
+            // (ATSIGN is considered a LOCATION preposition)
+            if (!adding_location
+                && (token.casefolded in LOCATION_PREPOSITIONS || token.shorthand == Shorthand.ATSIGN)) {
                 // add current token (the preposition) to summary but not location (because location
                 // tokens are added to summary, i.e. "dinner at John's" yields "John's" for location
-                // and "dinner at John's" for summary)
-                add_text(token);
+                // and "dinner at John's" for summary) ... note that ATSIGN does not add to summary
+                // to allow for more concise summaries
+                if (token.shorthand != Shorthand.ATSIGN)
+                    add_text(token);
                 
                 // now adding to both summary and location
                 adding_location = true;
                 
+                // ...unless at-sign used, which has the side-effect of not adding to summary
+                // (see above)
+                if (token.shorthand == Shorthand.ATSIGN)
+                    adding_summary = false;
+                
                 continue;
             }
             
@@ -727,12 +786,11 @@ public class DetailsParser : BaseObject {
         return true;
     }
     
-    // Adds the text to the summary and location field, if adding_location is set
+    // Adds the text to the summary and location field, if adding_location/summary is set
     private void add_text(Token token) {
-        // always add to summary
-        add_to_builder(summary, token);
+        if (adding_summary)
+            add_to_builder(summary, token);
         
-        // add to location if in that mode
         if (adding_location)
             add_to_builder(location, token);
     }
diff --git a/src/tests/tests-quick-add.vala b/src/tests/tests-quick-add.vala
index c902c37..371cd66 100644
--- a/src/tests/tests-quick-add.vala
+++ b/src/tests/tests-quick-add.vala
@@ -53,6 +53,8 @@ private class QuickAdd : UnitTest.Harness {
         add_case("time-range-one-meridiem", time_range_one_meridiem);
         add_case("time-range-24hr", time_range_24hr);
         add_case("time-range-no-meridiem", time_range_no_meridiem);
+        add_case("atsign-location", atsign_location);
+        add_case("atsign-time", atsign_time);
     }
     
     protected override void setup() throws Error {
@@ -598,6 +600,38 @@ private class QuickAdd : UnitTest.Harness {
         return parser.event.summary == "6-9 Opus Affair"
             && !parser.event.is_valid(false);
     }
+    
+    private bool atsign_location(out string? dump) throws Error {
+        Component.DetailsParser parser = new Component.DetailsParser(
+            "Dinner @ Tadich Grill 7pm", null);
+        
+        dump = parser.event.source;
+        
+        return parser.event.summary == "Dinner"
+            && parser.event.location == "Tadich Grill"
+            && !parser.event.is_all_day
+            && parser.event.exact_time_span.start_exact_time.hour == 19
+            && parser.event.exact_time_span.start_exact_time.minute == 0
+            && parser.event.exact_time_span.end_exact_time.hour == 20
+            && parser.event.exact_time_span.end_exact_time.minute == 0
+            && parser.event.exact_time_span.get_date_span().equal_to(Calendar.System.today.to_date_span());
+    }
+    
+    private bool atsign_time(out string? dump) throws Error {
+        Component.DetailsParser parser = new Component.DetailsParser(
+            "Dinner @ 7pm", null);
+        
+        dump = parser.event.source;
+        
+        return parser.event.summary == "Dinner"
+            && parser.event.location == null
+            && !parser.event.is_all_day
+            && parser.event.exact_time_span.start_exact_time.hour == 19
+            && parser.event.exact_time_span.start_exact_time.minute == 0
+            && parser.event.exact_time_span.end_exact_time.hour == 20
+            && parser.event.exact_time_span.end_exact_time.minute == 0
+            && parser.event.exact_time_span.get_date_span().equal_to(Calendar.System.today.to_date_span());
+    }
 }
 
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]