From 92ba854773af2941ed4f736e54fa2a60e299cd1a Mon Sep 17 00:00:00 2001
From: Chris Wong <lambda.fairy@gmail.com>
Date: Fri, 3 Jun 2016 23:06:39 +1200
Subject: [PATCH] Implement ID shorthand

Closes #35
---
 maud_macros/src/parse.rs   | 44 +++++++++++++++++++++++---------------
 maud_macros/tests/tests.rs | 13 ++++++++---
 2 files changed, 37 insertions(+), 20 deletions(-)

diff --git a/maud_macros/src/parse.rs b/maud_macros/src/parse.rs
index 5da6621..794a286 100644
--- a/maud_macros/src/parse.rs
+++ b/maud_macros/src/parse.rs
@@ -39,6 +39,9 @@ macro_rules! eq {
 macro_rules! not {
     () => (TokenTree::Token(_, Token::Not))
 }
+macro_rules! pound {
+    () => (TokenTree::Token(_, Token::Pound))
+}
 macro_rules! question {
     () => (TokenTree::Token(_, Token::Question))
 }
@@ -462,7 +465,6 @@ impl<'cx, 'i> Parser<'cx, 'i> {
             parse_error!(self, sp, "unexpected element, you silly bumpkin");
         }
         self.render.element_open_start(name);
-        self.class_shorthand()?;
         self.attrs()?;
         self.render.element_open_end();
         if let [slash!(), ..] = self.input {
@@ -474,23 +476,10 @@ impl<'cx, 'i> Parser<'cx, 'i> {
         Ok(())
     }
 
-    /// Parses and renders the attributes of an element.
-    fn class_shorthand(&mut self) -> PResult<()> {
-        let mut classes = Vec::new();
-        while let [dot!(), ident!(_, _), ..] = self.input {
-            self.shift(1);
-            classes.push(self.name()?);
-        }
-        if !classes.is_empty() {
-            self.render.attribute_start("class");
-            self.render.string(&classes.join(" "));
-            self.render.attribute_end();
-        }
-        Ok(())
-    }
-
     /// Parses and renders the attributes of an element.
     fn attrs(&mut self) -> PResult<()> {
+        let mut classes = Vec::new();
+        let mut ids = Vec::new();
         loop {
             let old_input = self.input;
             let maybe_name = self.name();
@@ -528,11 +517,32 @@ impl<'cx, 'i> Parser<'cx, 'i> {
                         self.render.attribute_empty(&name);
                     }
                 },
+                (Err(_), [dot!(), ident!(_, _), ..]) => {
+                    // Class shorthand
+                    self.shift(1);
+                    classes.push(self.name()?);
+                },
+                (Err(_), [pound!(), ident!(_, _), ..]) => {
+                    // ID shorthand
+                    self.shift(1);
+                    ids.push(self.name()?);
+                },
                 _ => {
                     self.input = old_input;
                     break;
                 },
-        }}
+            }
+        }
+        if !classes.is_empty() {
+            self.render.attribute_start("class");
+            self.render.string(&classes.join(" "));
+            self.render.attribute_end();
+        }
+        if !ids.is_empty() {
+            self.render.attribute_start("id");
+            self.render.string(&ids.join(" "));
+            self.render.attribute_end();
+        }
         Ok(())
     }
 
diff --git a/maud_macros/tests/tests.rs b/maud_macros/tests/tests.rs
index b287372..f5f202c 100644
--- a/maud_macros/tests/tests.rs
+++ b/maud_macros/tests/tests.rs
@@ -422,10 +422,17 @@ fn classes_shorthand_with_space() {
 }
 
 #[test]
-fn classes_shorthand_with_attrs() {
+fn ids_shorthand() {
     let mut s = String::new();
-    html!(s, p { "Hi, " span.name.here id="thing" { "Lyra" } "!" }).unwrap();
-    assert_eq!(s, "<p>Hi, <span class=\"name here\" id=\"thing\">Lyra</span>!</p>");
+    html!(s, p { "Hi, " span#thing { "Lyra" } "!" }).unwrap();
+    assert_eq!(s, "<p>Hi, <span id=\"thing\">Lyra</span>!</p>");
+}
+
+#[test]
+fn classes_attrs_ids_mixed_up() {
+    let mut s = String::new();
+    html!(s, p { "Hi, " span.name.here lang="en" #thing { "Lyra" } "!" }).unwrap();
+    assert_eq!(s, "<p>Hi, <span lang=\"en\" class=\"name here\" id=\"thing\">Lyra</span>!</p>");
 }
 
 #[test]