summaryrefslogtreecommitdiff
path: root/src/syntax/func/keys.rs
blob: 116cd4e6da8841a7e127881ffacc79d6bd6731b5 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
use crate::layout::prelude::*;
use super::values::AlignmentValue::{self, *};
use super::*;

use self::AxisKey::*;
use self::PaddingKey::*;



pub trait Key {
    type Output: Eq;

    fn parse(key: Spanned<&str>) -> Option<Self::Output>;
}

impl<K: Key> Key for Spanned<K> {
    type Output = Spanned<K::Output>;

    fn parse(key: Spanned<&str>) -> Option<Self::Output> {
        K::parse(key).map(|v| Spanned { v, span: key.span })
    }
}

macro_rules! key {
    ($type:ty, $output:ty, $($($p:pat)|* => $r:expr),* $(,)?) => {
        impl Key for $type {
            type Output = $output;

            fn parse(key: Spanned<&str>) -> Option<Self::Output> {
                match key.v {
                    $($($p)|* => Some($r)),*,
                    _ => None,
                }
            }
        }
    };
}

/// An argument key which identifies a layouting axis.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum AxisKey {
    Generic(GenericAxis),
    Specific(SpecificAxis),
}

impl AxisKey {
    /// The generic version of this axis key in the given system of axes.
    pub fn to_generic(self, axes: LayoutAxes) -> GenericAxis {
        match self {
            Generic(axis) => axis,
            Specific(axis) => axis.to_generic(axes),
        }
    }

    /// The specific version of this axis key in the given system of axes.
    pub fn to_specific(self, axes: LayoutAxes) -> SpecificAxis {
        match self {
            Generic(axis) => axis.to_specific(axes),
            Specific(axis) => axis,
        }
    }
}

key!(AxisKey, Self,
    "horizontal" | "h" => Specific(Horizontal),
    "vertical"   | "v" => Specific(Vertical),
    "primary"    | "p" => Generic(Primary),
    "secondary"  | "s" => Generic(Secondary),
);

pub struct ExtentKey;

key!(ExtentKey, AxisKey,
    "width"          | "w"  => Specific(Horizontal),
    "height"         | "h"  => Specific(Vertical),
    "primary-size"   | "ps" => Generic(Primary),
    "secondary-size" | "ss" => Generic(Secondary),
);

/// An argument key which identifies an axis, but allows for positional
/// arguments with unspecified axes.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum PosAxisKey {
    /// The first positional argument.
    First,
    /// The second positional argument.
    Second,
    /// An axis keyword argument.
    Keyword(AxisKey),
}

/// An argument key which identifies a margin or padding target.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum PaddingKey<Axis> {
    /// All four sides should have the specified padding.
    All,
    /// Both sides of the given axis should have the specified padding.
    Both(Axis),
    /// Only the given side of the given axis should have the specified padding.
    Side(Axis, AlignmentValue),
}

key!(PaddingKey<AxisKey>, Self,
    "horizontal" | "h" => Both(Specific(Horizontal)),
    "vertical"   | "v" => Both(Specific(Vertical)),
    "primary"    | "p" => Both(Generic(Primary)),
    "secondary"  | "s" => Both(Generic(Secondary)),

    "left"   => Side(Specific(Horizontal), Left),
    "right"  => Side(Specific(Horizontal), Right),
    "top"    => Side(Specific(Vertical),   Top),
    "bottom" => Side(Specific(Vertical),   Bottom),

    "primary-origin"    => Side(Generic(Primary),     Align(Origin)),
    "primary-end"       => Side(Generic(Primary),     Align(End)),
    "secondary-origin"  => Side(Generic(Secondary),   Align(Origin)),
    "secondary-end"     => Side(Generic(Secondary),   Align(End)),
    "horizontal-origin" => Side(Specific(Horizontal), Align(Origin)),
    "horizontal-end"    => Side(Specific(Horizontal), Align(End)),
    "vertical-origin"   => Side(Specific(Vertical),   Align(Origin)),
    "vertical-end"      => Side(Specific(Vertical),   Align(End)),
);