commit 13f0869f58bf5e33d59b48795f35abbe51c43d5f
parent e1facb08b722bfef09ccf8ccd2acfb09adf11742
Author: Demonstrandum <moi@knutsen.co>
Date: Thu, 2 Jul 2020 22:17:34 +0100
Working (but naïve) CSS generation.
Diffstat:
3 files changed, 75 insertions(+), 6 deletions(-)
diff --git a/samples/css-concept.sex b/samples/css-concept.sex
@@ -13,7 +13,7 @@
;p #para-id {
; width: calc(3em + 6px);
; color: green;
-; margin: 3px, auto, 4px, 2px;
+; margin: 3px auto 4px 2px;
; position: absolute;
;}
diff --git a/src/assemble/css.rs b/src/assemble/css.rs
@@ -17,11 +17,78 @@ impl CSSFormatter {
pub const DEFAULT : &str = "\n";
+/// All CSS functions, I might have missed a few.
+const CSS_FUNCTIONS : [&str; 52] = [
+ "attr", "blur", "brightness", "calc", "circle", "contrast",
+ "counter", "counters", "cubic-bezier", "drop-shadow", "ellipse",
+ "grayscale", "hsl", "hsla", "hue-rotate", "hwb", "image", "inset",
+ "invert", "linear-gradient", "matrix", "matrix3d", "opacity",
+ "perspective", "polygon", "radial-gradient", "repeating-linear-gradient",
+ "repeating-radial-gradient", "rgb", "rgba", "rotate", "rotate3d",
+ "rotateX", "rotateY", "rotateZ", "saturate", "sepia", "scale", "scale3d",
+ "scaleX", "scaleY", "scaleZ", "skew", "skewX", "skewY", "symbols",
+ "translate", "translate3d", "translateX", "translateY", "translateZ",
+ "url",
+];
+
+/// The only four math operations supported by CSS calc(...),
+/// or at least I think.
+const BINARY_OPERATORS : [&str; 4] = ["+", "-", "*", "/"];
+
+fn convert_value(node : &ParseNode) -> Result<String, GenerationError> {
+ match node {
+ ParseNode::List(list) => {
+ let list = parser::strip(list, false);
+ let result = match list.as_slice() {
+ [head, tail@..] => {
+ let head = convert_value(head)?;
+
+ let mut tail_tmp = vec![String::new(); tail.len()];
+ for (i, e) in tail.iter().enumerate() {
+ tail_tmp[i] = convert_value(e)?
+ }
+ let tail = tail_tmp.as_slice();
+
+ let args = tail.iter()
+ .fold(String::new(), |acc, s| acc + " " + &s);
+ let args = args.trim();
+ if CSS_FUNCTIONS.contains(&head.as_str()) {
+ format!("{}({})", head, args)
+ } else if BINARY_OPERATORS.contains(&head.as_str()) {
+ let args = tail
+ .join(&format!(" {} ", head));
+ format!("({})", args)
+ } else {
+ format!("{} {}", head, args)
+ }
+ },
+ _ => String::from("")
+ };
+ Ok(result)
+ },
+ ParseNode::Number(node)
+ | ParseNode::Symbol(node)
+ | ParseNode::String(node) =>
+ Ok(if node.value.chars().any(|c| c.is_whitespace()) {
+ format!("\"{}\"", node.value)
+ } else {
+ node.value.to_owned()
+ }),
+ ParseNode::Attribute(_) => Err(GenerationError::new("CSS-value",
+ "Incompatible structure (attribute) found in CSS \
+ property value.",
+ &node.site()))
+ }
+}
+
/// Function responsible for translating a CSS value (i.e.
/// a value of a CSS property) from some s-expression into
/// a valid CSS value.
-pub fn css_value(property : &str, node : &ParseNode) -> String {
- String::from("x")
+pub fn css_value(_property : &str, node : &ParseNode)
+-> Result<String, GenerationError> {
+ // Naïve way (in future consider the type of property,
+ // and take care of special cases):
+ convert_value(node)
}
impl MarkupDisplay for CSSFormatter {
@@ -69,7 +136,7 @@ impl MarkupDisplay for CSSFormatter {
let value = &property.node;
writeln!(f, " {}: {};",
&property.keyword,
- css_value(&property.keyword, value))?;
+ css_value(&property.keyword, value)?)?;
} else {
return Err(GenerationError::new("CSS",
"CSS property-value pairs must be in the \
diff --git a/test-css.sex b/test-css.sex
@@ -1,6 +1,8 @@
-(a b c
+(a 2b c2
+ :background-image (url dog.png)
+ :background-position ((calc (- 100% 50px)) (calc (- 100% 20px)))
:width 2
:heigh 3)
(x #y .z
- :color (rgb 2 (calc (+ 3 1)) 4))
+ :color (rgb 2 (calc (+ 3 (* 7 3) 1)) 4))