Forráskód Böngészése

Merge pull request #302 from Demonthos/master

tui bugfixes and text modifier elements
Jon Kelley 3 éve
szülő
commit
268cc5bd39

+ 1 - 4
packages/tui/Cargo.toml

@@ -2,7 +2,7 @@
 name = "dioxus-tui"
 version = "0.2.1"
 authors = ["Jonathan Kelley, @dementhos"]
-edition = "2018"
+edition = "2021"
 description = "TUI-based renderer for Dioxus"
 repository = "https://github.com/DioxusLabs/dioxus/"
 homepage = "https://dioxuslabs.com"
@@ -19,9 +19,6 @@ dioxus-html = { path = "../html", version = "^0.2.0" }
 tui = "0.17.0"
 crossterm = "0.23.0"
 anyhow = "1.0.42"
-thiserror = "1.0.24"
-ctrlc = "3.2.1"
-bumpalo = { version = "3.8.0", features = ["boxed"] }
 tokio = { version = "1.15.0", features = ["full"] }
 futures = "0.3.19"
 stretch2 = "0.4.1"

+ 64 - 4
packages/tui/src/attributes.rs

@@ -388,6 +388,15 @@ pub enum UnitSystem {
     Point(f32),
 }
 
+impl Into<Dimension> for UnitSystem {
+    fn into(self) -> Dimension {
+        match self {
+            Self::Percent(v) => Dimension::Percent(v),
+            Self::Point(v) => Dimension::Points(v),
+        }
+    }
+}
+
 fn parse_value(value: &str) -> Option<UnitSystem> {
     if value.ends_with("px") {
         if let Ok(px) = value.trim_end_matches("px").parse::<f32>() {
@@ -505,11 +514,16 @@ fn apply_border(name: &str, value: &str, style: &mut StyleModifer) {
             }
         }
         "border-bottom-style" => {
+            if style.style.border.bottom == Dimension::default() {
+                let v = Dimension::Points(1.0);
+                style.style.border.bottom = v;
+            }
             style.tui_modifier.borders.bottom.style = parse_border_style(value)
         }
         "border-bottom-width" => {
             if let Some(v) = parse_value(value) {
                 style.tui_modifier.borders.bottom.width = v;
+                style.style.border.bottom = v.into();
             }
         }
         "border-collapse" => {}
@@ -547,10 +561,17 @@ fn apply_border(name: &str, value: &str, style: &mut StyleModifer) {
                 style.tui_modifier.borders.left.color = Some(c);
             }
         }
-        "border-left-style" => style.tui_modifier.borders.left.style = parse_border_style(value),
+        "border-left-style" => {
+            if style.style.border.start == Dimension::default() {
+                let v = Dimension::Points(1.0);
+                style.style.border.start = v;
+            }
+            style.tui_modifier.borders.left.style = parse_border_style(value)
+        }
         "border-left-width" => {
             if let Some(v) = parse_value(value) {
                 style.tui_modifier.borders.left.width = v;
+                style.style.border.start = v.into();
             }
         }
         "border-radius" => {
@@ -581,7 +602,11 @@ fn apply_border(name: &str, value: &str, style: &mut StyleModifer) {
                 style.tui_modifier.borders.right.color = Some(c);
             }
         }
-        "border-right-style" => style.tui_modifier.borders.right.style = parse_border_style(value),
+        "border-right-style" => {
+            let v = Dimension::Points(1.0);
+            style.style.border.end = v;
+            style.tui_modifier.borders.right.style = parse_border_style(value)
+        }
         "border-right-width" => {
             if let Some(v) = parse_value(value) {
                 style.tui_modifier.borders.right.width = v;
@@ -590,6 +615,22 @@ fn apply_border(name: &str, value: &str, style: &mut StyleModifer) {
         "border-spacing" => {}
         "border-style" => {
             let values: Vec<_> = value.split(' ').collect();
+            if style.style.border.top == Dimension::default() {
+                let v = Dimension::Points(1.0);
+                style.style.border.top = v;
+            }
+            if style.style.border.bottom == Dimension::default() {
+                let v = Dimension::Points(1.0);
+                style.style.border.bottom = v;
+            }
+            if style.style.border.start == Dimension::default() {
+                let v = Dimension::Points(1.0);
+                style.style.border.start = v;
+            }
+            if style.style.border.end == Dimension::default() {
+                let v = Dimension::Points(1.0);
+                style.style.border.end = v;
+            }
             if values.len() == 1 {
                 let border_style = parse_border_style(values[0]);
                 style
@@ -623,9 +664,16 @@ fn apply_border(name: &str, value: &str, style: &mut StyleModifer) {
                 style.tui_modifier.borders.right.radius = v;
             }
         }
-        "border-top-style" => style.tui_modifier.borders.top.style = parse_border_style(value),
+        "border-top-style" => {
+            if style.style.border.top == Dimension::default() {
+                let v = Dimension::Points(1.0);
+                style.style.border.top = v;
+            }
+            style.tui_modifier.borders.top.style = parse_border_style(value)
+        }
         "border-top-width" => {
             if let Some(v) = parse_value(value) {
+                style.style.border.top = v.into();
                 style.tui_modifier.borders.top.width = v;
             }
         }
@@ -633,6 +681,10 @@ fn apply_border(name: &str, value: &str, style: &mut StyleModifer) {
             let values: Vec<_> = value.split(' ').collect();
             if values.len() == 1 {
                 if let Some(w) = parse_value(values[0]) {
+                    style.style.border.top = w.into();
+                    style.style.border.bottom = w.into();
+                    style.style.border.start = w.into();
+                    style.style.border.end = w.into();
                     style
                         .tui_modifier
                         .borders
@@ -641,11 +693,19 @@ fn apply_border(name: &str, value: &str, style: &mut StyleModifer) {
                         .for_each(|b| b.width = w);
                 }
             } else {
-                for (v, b) in values
+                let border_widths = [
+                    &mut style.style.border.top,
+                    &mut style.style.border.bottom,
+                    &mut style.style.border.start,
+                    &mut style.style.border.end,
+                ];
+                for ((v, b), width) in values
                     .into_iter()
                     .zip(style.tui_modifier.borders.slice().iter_mut())
+                    .zip(border_widths)
                 {
                     if let Some(w) = parse_value(v) {
+                        *width = w.into();
                         b.width = w;
                     }
                 }

+ 140 - 83
packages/tui/src/hooks.rs

@@ -460,26 +460,7 @@ impl RinkInputHandler {
 // translate crossterm events into dioxus events
 fn get_event(evt: TermEvent) -> Option<(&'static str, EventData)> {
     let (name, data): (&str, EventData) = match evt {
-        TermEvent::Key(k) => {
-            let key = translate_key_code(k.code)?;
-            (
-                "keydown",
-                // from https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent
-                EventData::Keyboard(KeyboardData {
-                    char_code: key.raw_code(),
-                    key: format!("{key:?}"),
-                    key_code: key,
-                    alt_key: k.modifiers.contains(KeyModifiers::ALT),
-                    ctrl_key: k.modifiers.contains(KeyModifiers::CONTROL),
-                    meta_key: false,
-                    shift_key: k.modifiers.contains(KeyModifiers::SHIFT),
-                    locale: Default::default(),
-                    location: 0x00,
-                    repeat: Default::default(),
-                    which: Default::default(),
-                }),
-            )
-        }
+        TermEvent::Key(k) => ("keydown", translate_key_event(k)?),
         TermEvent::Mouse(m) => {
             let (x, y) = (m.column.into(), m.row.into());
             let alt = m.modifiers.contains(KeyModifiers::ALT);
@@ -542,69 +523,145 @@ fn get_event(evt: TermEvent) -> Option<(&'static str, EventData)> {
     Some((name, data))
 }
 
-fn translate_key_code(c: TermKeyCode) -> Option<KeyCode> {
-    match c {
-        TermKeyCode::Backspace => Some(KeyCode::Backspace),
-        TermKeyCode::Enter => Some(KeyCode::Enter),
-        TermKeyCode::Left => Some(KeyCode::LeftArrow),
-        TermKeyCode::Right => Some(KeyCode::RightArrow),
-        TermKeyCode::Up => Some(KeyCode::UpArrow),
-        TermKeyCode::Down => Some(KeyCode::DownArrow),
-        TermKeyCode::Home => Some(KeyCode::Home),
-        TermKeyCode::End => Some(KeyCode::End),
-        TermKeyCode::PageUp => Some(KeyCode::PageUp),
-        TermKeyCode::PageDown => Some(KeyCode::PageDown),
-        TermKeyCode::Tab => Some(KeyCode::Tab),
-        TermKeyCode::BackTab => None,
-        TermKeyCode::Delete => Some(KeyCode::Delete),
-        TermKeyCode::Insert => Some(KeyCode::Insert),
-        TermKeyCode::F(fn_num) => match fn_num {
-            1 => Some(KeyCode::F1),
-            2 => Some(KeyCode::F2),
-            3 => Some(KeyCode::F3),
-            4 => Some(KeyCode::F4),
-            5 => Some(KeyCode::F5),
-            6 => Some(KeyCode::F6),
-            7 => Some(KeyCode::F7),
-            8 => Some(KeyCode::F8),
-            9 => Some(KeyCode::F9),
-            10 => Some(KeyCode::F10),
-            11 => Some(KeyCode::F11),
-            12 => Some(KeyCode::F12),
-            _ => None,
-        },
-        TermKeyCode::Char(c) => match c.to_uppercase().next().unwrap() {
-            'A' => Some(KeyCode::A),
-            'B' => Some(KeyCode::B),
-            'C' => Some(KeyCode::C),
-            'D' => Some(KeyCode::D),
-            'E' => Some(KeyCode::E),
-            'F' => Some(KeyCode::F),
-            'G' => Some(KeyCode::G),
-            'H' => Some(KeyCode::H),
-            'I' => Some(KeyCode::I),
-            'J' => Some(KeyCode::J),
-            'K' => Some(KeyCode::K),
-            'L' => Some(KeyCode::L),
-            'M' => Some(KeyCode::M),
-            'N' => Some(KeyCode::N),
-            'O' => Some(KeyCode::O),
-            'P' => Some(KeyCode::P),
-            'Q' => Some(KeyCode::Q),
-            'R' => Some(KeyCode::R),
-            'S' => Some(KeyCode::S),
-            'T' => Some(KeyCode::T),
-            'U' => Some(KeyCode::U),
-            'V' => Some(KeyCode::V),
-            'W' => Some(KeyCode::W),
-            'X' => Some(KeyCode::X),
-            'Y' => Some(KeyCode::Y),
-            'Z' => Some(KeyCode::Z),
-            _ => None,
-        },
-        TermKeyCode::Null => None,
-        TermKeyCode::Esc => Some(KeyCode::Escape),
-    }
+fn translate_key_event(event: crossterm::event::KeyEvent) -> Option<EventData> {
+    let (code, key_str);
+    if let TermKeyCode::Char(c) = event.code {
+        code = match c {
+            'A'..='Z' | 'a'..='z' => match c.to_ascii_uppercase() {
+                'A' => KeyCode::A,
+                'B' => KeyCode::B,
+                'C' => KeyCode::C,
+                'D' => KeyCode::D,
+                'E' => KeyCode::E,
+                'F' => KeyCode::F,
+                'G' => KeyCode::G,
+                'H' => KeyCode::H,
+                'I' => KeyCode::I,
+                'J' => KeyCode::J,
+                'K' => KeyCode::K,
+                'L' => KeyCode::L,
+                'M' => KeyCode::M,
+                'N' => KeyCode::N,
+                'O' => KeyCode::O,
+                'P' => KeyCode::P,
+                'Q' => KeyCode::Q,
+                'R' => KeyCode::R,
+                'S' => KeyCode::S,
+                'T' => KeyCode::T,
+                'U' => KeyCode::U,
+                'V' => KeyCode::V,
+                'W' => KeyCode::W,
+                'X' => KeyCode::X,
+                'Y' => KeyCode::Y,
+                'Z' => KeyCode::Z,
+                _ => return None,
+            },
+            ' ' => KeyCode::Space,
+            '[' => KeyCode::OpenBracket,
+            '{' => KeyCode::OpenBracket,
+            ']' => KeyCode::CloseBraket,
+            '}' => KeyCode::CloseBraket,
+            ';' => KeyCode::Semicolon,
+            ':' => KeyCode::Semicolon,
+            ',' => KeyCode::Comma,
+            '<' => KeyCode::Comma,
+            '.' => KeyCode::Period,
+            '>' => KeyCode::Period,
+            '1' => KeyCode::Num1,
+            '2' => KeyCode::Num2,
+            '3' => KeyCode::Num3,
+            '4' => KeyCode::Num4,
+            '5' => KeyCode::Num5,
+            '6' => KeyCode::Num6,
+            '7' => KeyCode::Num7,
+            '8' => KeyCode::Num8,
+            '9' => KeyCode::Num9,
+            '0' => KeyCode::Num0,
+            '!' => KeyCode::Num1,
+            '@' => KeyCode::Num2,
+            '#' => KeyCode::Num3,
+            '$' => KeyCode::Num4,
+            '%' => KeyCode::Num5,
+            '^' => KeyCode::Num6,
+            '&' => KeyCode::Num7,
+            '*' => KeyCode::Num8,
+            '(' => KeyCode::Num9,
+            ')' => KeyCode::Num0,
+            // numpad charicter are ambiguous to tui
+            // '*' => KeyCode::Multiply,
+            // '/' => KeyCode::Divide,
+            // '-' => KeyCode::Subtract,
+            // '+' => KeyCode::Add,
+            '+' => KeyCode::EqualSign,
+            '-' => KeyCode::Dash,
+            '_' => KeyCode::Dash,
+            '\'' => KeyCode::SingleQuote,
+            '"' => KeyCode::SingleQuote,
+            '\\' => KeyCode::BackSlash,
+            '|' => KeyCode::BackSlash,
+            '/' => KeyCode::ForwardSlash,
+            '?' => KeyCode::ForwardSlash,
+            '=' => KeyCode::EqualSign,
+            '`' => KeyCode::GraveAccent,
+            '~' => KeyCode::GraveAccent,
+            _ => return None,
+        };
+        key_str = c.to_string();
+    } else {
+        code = match event.code {
+            TermKeyCode::Esc => KeyCode::Escape,
+            TermKeyCode::Backspace => KeyCode::Backspace,
+            TermKeyCode::Enter => KeyCode::Enter,
+            TermKeyCode::Left => KeyCode::LeftArrow,
+            TermKeyCode::Right => KeyCode::RightArrow,
+            TermKeyCode::Up => KeyCode::UpArrow,
+            TermKeyCode::Down => KeyCode::DownArrow,
+            TermKeyCode::Home => KeyCode::Home,
+            TermKeyCode::End => KeyCode::End,
+            TermKeyCode::PageUp => KeyCode::PageUp,
+            TermKeyCode::PageDown => KeyCode::PageDown,
+            TermKeyCode::Tab => KeyCode::Tab,
+            TermKeyCode::Delete => KeyCode::Delete,
+            TermKeyCode::Insert => KeyCode::Insert,
+            TermKeyCode::F(fn_num) => match fn_num {
+                1 => KeyCode::F1,
+                2 => KeyCode::F2,
+                3 => KeyCode::F3,
+                4 => KeyCode::F4,
+                5 => KeyCode::F5,
+                6 => KeyCode::F6,
+                7 => KeyCode::F7,
+                8 => KeyCode::F8,
+                9 => KeyCode::F9,
+                10 => KeyCode::F10,
+                11 => KeyCode::F11,
+                12 => KeyCode::F12,
+                _ => return None,
+            },
+            TermKeyCode::BackTab => return None,
+            TermKeyCode::Null => return None,
+            _ => return None,
+        };
+        key_str = if let KeyCode::BackSlash = code {
+            "\\".to_string()
+        } else {
+            format!("{code:?}")
+        }
+    };
+    // from https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent
+    Some(EventData::Keyboard(KeyboardData {
+        char_code: code.raw_code(),
+        key: key_str.to_string(),
+        key_code: code,
+        alt_key: event.modifiers.contains(KeyModifiers::ALT),
+        ctrl_key: event.modifiers.contains(KeyModifiers::CONTROL),
+        meta_key: false,
+        shift_key: event.modifiers.contains(KeyModifiers::SHIFT),
+        locale: Default::default(),
+        location: 0x00,
+        repeat: Default::default(),
+        which: Default::default(),
+    }))
 }
 
 fn clone_mouse_data(m: &MouseData) -> MouseData {

+ 19 - 0
packages/tui/src/layout.rs

@@ -55,6 +55,25 @@ pub fn collect_layout<'a>(
                 tui_modifier: TuiModifier::default(),
             };
 
+            // handle text modifier elements
+            if el.namespace.is_none() {
+                match el.tag {
+                    "b" => apply_attributes("font-weight", "bold", &mut modifier),
+                    "strong" => apply_attributes("font-weight", "bold", &mut modifier),
+                    "u" => apply_attributes("text-decoration", "underline", &mut modifier),
+                    "ins" => apply_attributes("text-decoration", "underline", &mut modifier),
+                    "del" => apply_attributes("text-decoration", "line-through", &mut modifier),
+                    "i" => apply_attributes("font-style", "italic", &mut modifier),
+                    "em" => apply_attributes("font-style", "italic", &mut modifier),
+                    "mark" => apply_attributes(
+                        "background-color",
+                        "rgba(241, 231, 64, 50%)",
+                        &mut modifier,
+                    ),
+                    _ => (),
+                }
+            }
+
             for &Attribute { name, value, .. } in el.attributes {
                 apply_attributes(name, value, &mut modifier);
             }

+ 1 - 1
packages/tui/src/lib.rs

@@ -172,7 +172,7 @@ pub fn render_vdom(
                             match evt.as_ref().unwrap() {
                                 InputEvent::UserInput(event) => match event {
                                     TermEvent::Key(key) => {
-                                        if matches!(key.code, KeyCode::Char('c'))
+                                        if matches!(key.code, KeyCode::Char('C' | 'c'))
                                             && key.modifiers.contains(KeyModifiers::CONTROL)
                                         {
                                             break;