<commit_before>use std::collections::HashSet;

use orbtk::prelude::*;

#[derive(Debug, Copy, Clone)]
enum Action {
    AddItem,
    ClearText,
    EntryActivated(Entity),
    EntryChanged(Entity),
    ValueChanged(Entity),
    IncrementCounter,
    RemoveItem,
}

#[derive(AsAny)]
pub struct MainViewState {
    action: Option<Action>,
}

impl Default for MainViewState {
    fn default() -> Self {
        MainViewState { action: None }
    }
}

impl MainViewState {
    fn action(&mut self, action: impl Into<Option<Action>>) {
        self.action = action.into();
    }
}

impl State for MainViewState {
    fn update(&mut self, _: &mut Registry, ctx: &mut Context) {
        if let Some(action) = self.action {
            match action {
                Action::AddItem => {
                    let len = main_view(ctx.widget()).list().len();

                    if len < 5 {
                        main_view(ctx.widget())
                            .list_mut()
                            .push(format!("Item {}", len + 1));
                            ctx.child("items").set::<usize>("count", len + 1);
                        items_widget(ctx.child("items")).set_count(len + 1);
                        button(ctx.child("remove-item-button")).set_enabled(true);

                        if len == 4 {
                            button(ctx.child("add-item-button")).set_enabled(false);
                        }
                    }
                }
                Action::RemoveItem => {
                    let len = main_view(ctx.widget()).list().len();
                    if len > 0 {
                        main_view(ctx.widget()).list_mut().remove(len - 1);
                        items_widget(ctx.child("items")).set_count(len - 1);
                        button(ctx.child("add-item-button")).set_enabled(true);

                        if len == 1 {
                            button(ctx.child("remove-item-button")).set_enabled(false);
                        }
                    }
                }
                Action::IncrementCounter => {
                    *main_view(ctx.widget()).counter_mut() += 1;

                    let counter = *main_view(ctx.widget()).counter();

                    main_view(ctx.widget())
                        .set_result(String16::from(format!("Button count: {}", counter)));
                }
                Action::ClearText => {
                    main_view(ctx.widget()).set_text_one(String16::default());
                    main_view(ctx.widget()).set_text_two(String16::default());
                }
                Action::EntryActivated(entity) => {
                    let mut text_box = text_box(ctx.get_widget(entity));
                    let text = text_box.text_mut();
                    println!("submitting {}", text);
                    text.clear();
                }
                Action::EntryChanged(entity) => {
                    println!("entry changed: {}", text_box(ctx.get_widget(entity)).text());
                }
                Action::ValueChanged(entity) => {
                    let val = ((slider(ctx.get_widget(entity)).val()).floor() as i32).to_string();

                    text_block(ctx.child("value_text")).set_text(String16::from(val));
                }
            }

            self.action = None;
        }
    }

    fn update_post_layout(&mut self, _: &mut Registry, ctx: &mut Context) {
        let mut selection_string = "Selected:".to_string();

        for index in &main_view(ctx.widget()).selected_indices().0 {
            selection_string = format!("{} {}", selection_string, index);
        }

        text_block(ctx.child("selection")).set_text(selection_string);
    }
}

fn create_header(ctx: &mut BuildContext, text: &str) -> Entity {
    TextBlock::new()
        .text(text)
        .element("text-block")
        .class("h1")
        .build(ctx)
}

type List = Vec<String>;

widget!(
    MainView<MainViewState> {
        selected_indices: SelectedIndices,
        counter: usize,
        list_count: usize,
        combo_box_list_count: usize,
        list: List,
        selection_list: List,
        combo_box_list: List,
        selection_list_count: usize,
        text_one: String16,
        text_two: String16,
        result: String16
    }
);

impl Template for MainView {
    fn template(self, id: Entity, ctx: &mut BuildContext) -> Self {
        self.name("MainView")
            .result("Button count: 0")
            .counter(0)
            .selected_indices(HashSet::new())
            .list(vec![
                "Item 1".to_string(),
                "Item 2".to_string(),
                "Item 3".to_string(),
            ])
            .list_count(3)
            .selection_list(vec![
                "Item 1".to_string(),
                "Item 2".to_string(),
                "Item 3".to_string(),
                "Item 4".to_string(),
                "Item 5".to_string(),
                "Item 6".to_string(),
                "Item 7".to_string(),
                "Item 8".to_string(),
                "Item 9".to_string(),
                "Item 10".to_string(),
            ])
            .combo_box_list(vec![
                "CB 1".to_string(),
                "CB 2".to_string(),
                "CB 3".to_string(),
                "CB 4".to_string(),
                "CB 5".to_string(),
                "CB 6".to_string(),
                "CB 7".to_string(),
                "CB 8".to_string(),
                "CB 9".to_string(),
                "CB 10".to_string(),
            ])
            .selection_list_count(10)
            .combo_box_list_count(10)
            .child(
                Grid::new()
                    .margin(8.)
                    .columns(
                        Columns::new()
                            .add(132.)
                            .add(16.)
                            .add(132.)
                            .add(16.)
                            .add(132.),
                    )
                    .child(
                        Stack::new()
                            .attach(Grid::column(0))
                            // Column 0
                            .child(create_header(ctx, "Buttons"))
                            .child(
                                Button::new()
                                    .text("Button")
                                    .margin((0., 8., 0., 0.))
                                    .icon(material_font_icons::CHECK_FONT_ICON)
                                    .attach(Grid::column(0))
                                    .attach(Grid::row(1))
                                    .on_click(move |states, _| {
                                        state(id, states).action(Action::IncrementCounter);
                                        true
                                    })
                                    .build(ctx),
                            )
                            .child(
                                Button::new()
                                    .text("Primary")
                                    .element("button")
                                    .class("primary")
                                    .margin((0., 8., 0., 0.))
                                    .icon(material_font_icons::CHECK_FONT_ICON)
                                    .attach(Grid::column(0))
                                    .attach(Grid::row(2))
                                    .build(ctx),
                            )
                            .child(
                                ToggleButton::new()
                                    .class("single_content")
                                    .text("ToggleButton")
                                    .margin((0., 8., 0., 0.))
                                    .attach(Grid::column(0))
                                    .attach(Grid::row(3))
                                    .build(ctx),
                            )
                            .child(
                                CheckBox::new()
                                    .text("CheckBox")
                                    .margin((0., 8., 0., 0.))
                                    .attach(Grid::column(0))
                                    .attach(Grid::row(4))
                                    .build(ctx),
                            )
                            .child(
                                Switch::new()
                                    .margin((0., 8., 0., 0.))
                                    .attach(Grid::column(0))
                                    .attach(Grid::row(5))
                                    .build(ctx),
                            )
                            .child(
                                TextBlock::new()
                                    .margin((0., 8., 0., 0.))
                                    .element("h1")
                                    .id("value_text")
                                    .text("0")
                                    .h_align("center")
                                    .build(ctx),
                            )
                            .child(
                                Slider::new()
                                    .on_changed(move |states, entity| {
                                        state(id, states).action(Action::ValueChanged(entity));
                                    })
                                    .build(ctx),
                            )
                            .build(ctx),
                    )
                    .child(
                        Stack::new()
                            .attach(Grid::column(2))
                            .child(create_header(ctx, "Text"))
                            .child(
                                TextBlock::new()
                                    .class("body")
                                    .text(("result", id))
                                    .margin((0., 8., 0., 0.))
                                    .attach(Grid::column(2))
                                    .attach(Grid::row(1))
                                    .build(ctx),
                            )
                            .child(
                                TextBox::new()
                                    .water_mark("TextBox...")
                                    .text(("text_one", id))
                                    .margin((0., 8., 0., 0.))
                                    .attach(Grid::column(2))
                                    .attach(Grid::row(2))
                                    .on_activate(move |states, entity| {
                                        state(id, states).action(Action::EntryActivated(entity));
                                    })
                                    .on_changed(move |states, entity| {
                                        state(id, states).action(Action::EntryChanged(entity));
                                    })
                                    .build(ctx),
                            )
                            .child(
                                TextBox::new()
                                    .water_mark("TextBox...")
                                    .text(("text_two", id))
                                    .margin((0., 8., 0., 0.))
                                    .attach(Grid::column(2))
                                    .attach(Grid::row(2))
                                    .on_activate(move |states, entity| {
                                        state(id, states).action(Action::EntryActivated(entity));
                                    })
                                    .on_changed(move |states, entity| {
                                        state(id, states).action(Action::EntryChanged(entity));
                                    })
                                    .build(ctx),
                            )
                            .child(
                                Button::new()
                                    .margin((0., 8., 0., 0.))
                                    .class("single_content")
                                    .text("clear text")
                                    .on_click(move |states, _| {
                                        state(id, states).action(Action::ClearText);
                                        true
                                    })
                                    .build(ctx),
                            )
                            .child(
                                NumericBox::new()
                                    .margin((-0., 8., 0., 0.))
                                    .max(123.)
                                    .step(0.123)
                                    .val(0.123)
                                    .build(ctx),
                            )
                            .build(ctx),
                    )
                    .child(
                        Grid::new()
                            .rows(
                                Rows::new()
                                    .add("auto")
                                    .add(32.)
                                    .add(16.)
                                    .add(204.)
                                    .add("auto")
                                    .add(192.)
                                    .add("auto"),
                            )
                            .columns(Columns::new().add("*").add(4.).add("*"))
                            .attach(Grid::column(4))
                            .child(
                                TextBlock::new()
                                    .text("Items")
                                    .element("text-block")
                                    .class("h1")
                                    .attach(Grid::column(0))
                                    .attach(Grid::column_span(3))
                                    .attach(Grid::row(0))
                                    .build(ctx),
                            )
                            .child(
                                ComboBox::new()
                                    .items_builder(move |bc, index| {
                                        let text = bc
                                            .get_widget(id)
                                            .get::<Vec<String>>("combo_box_list")[index]
                                            .clone();
                                        TextBlock::new()
                                            .margin((0., 0., 0., 2.))
                                            .v_align("center")
                                            .text(text)
                                            .build(bc)
                                    })
                                    .selected_index(0)
                                    .attach(Grid::column(0))
                                    .attach(Grid::column_span(3))
                                    .attach(Grid::row(1))
                                    .margin((0., 8., 0., 0.))
                                    .count(("combo_box_list_count", id))
                                    .build(ctx),
                            )
                            .child(
                                ItemsWidget::new()
                                    .element("items-widget")
                                    .id("items")
                                    .padding((4., 4., 4., 2.))
                                    .attach(Grid::column(0))
                                    .attach(Grid::column_span(3))
                                    .attach(Grid::row(3))
                                    .margin((0., 0., 0., 8.))
                                    .items_builder(move |bc, index| {
                                        let text = bc.get_widget(id).get::<Vec<String>>("list")
                                            [index]
                                            .clone();

                                        Button::new()
                                            .margin((0., 0., 0., 2.))
                                            .text(text)
                                            .build(bc)
                                    })
                                    .count(("list_count", id))
                                    .build(ctx),
                            )
                            .child(
                                Button::new()
                                    .element("button")
                                    .class("single_content")
                                    .id("remove-item-button")
                                    .icon(material_font_icons::MINUS_FONT_ICON)
                                    .on_click(move |states, _| {
                                        state(id, states).action(Action::RemoveItem);
                                        true
                                    })
                                    .min_width(0.)
                                    .attach(Grid::column(0))
                                    .attach(Grid::row(4))
                                    .build(ctx),
                            )
                            .child(
                                Button::new()
                                    .element("button")
                                    .class("single_content")
                                    .id("add-item-button")
                                    .icon(material_font_icons::ADD_FONT_ICON)
                                    .on_click(move |states, _| {
                                        state(id, states).action(Action::AddItem);
                                        true
                                    })
                                    .min_width(0.)
                                    .attach(Grid::column(2))
                                    .attach(Grid::row(4))
                                    .build(ctx),
                            )
                            .child(
                                ListView::new()
                                    .attach(Grid::column(0))
                                    .attach(Grid::column_span(3))
                                    .attach(Grid::row(5))
                                    .selected_indices(id)
                                    .margin((0., 16., 0., 8.))
                                    .items_builder(move |bc, index| {
                                        let text = bc
                                            .get_widget(id)
                                            .get::<Vec<String>>("selection_list")[index]
                                            .clone();
                                        TextBlock::new()
                                            .margin((0., 0., 0., 2.))
                                            .v_align("center")
                                            .text(text)
                                            .build(bc)
                                    })
                                    .count(("selection_list_count", id))
                                    .build(ctx),
                            )
                            .child(
                                // todo: wrong text width????
                                TextBlock::new()
                                    .element("text-block")
                                    .id("selection")
                                    .max_width(120.)
                                    .attach(Grid::column(0))
                                    .attach(Grid::column_span(3))
                                    .attach(Grid::row(6))
                                    .text("Selected:")
                                    .build(ctx),
                            )
                            .build(ctx),
                    )
                    .build(ctx),
            )
    }
}

fn main() {
    // use this only if you want to run it as web application.
    orbtk::initialize();

    Application::new()
        .window(|ctx| {
            Window::new()
                .title("OrbTk - widgets example")
                .position((100., 100.))
                .size(468., 730.)
                .resizeable(true)
                .child(MainView::new().build(ctx))
                .build(ctx)
        })
        .run();
}

// helper to request MainViewState
fn state<'a>(id: Entity, states: &'a mut StatesContext) -> &'a mut MainViewState {
    states.get_mut(id)
}
<commit_msg>examples: widgets bug fix<commit_after>use std::collections::HashSet;

use orbtk::prelude::*;

#[derive(Debug, Copy, Clone)]
enum Action {
    AddItem,
    ClearText,
    EntryActivated(Entity),
    EntryChanged(Entity),
    ValueChanged(Entity),
    IncrementCounter,
    RemoveItem,
}

#[derive(AsAny)]
pub struct MainViewState {
    action: Option<Action>,
}

impl Default for MainViewState {
    fn default() -> Self {
        MainViewState { action: None }
    }
}

impl MainViewState {
    fn action(&mut self, action: impl Into<Option<Action>>) {
        self.action = action.into();
    }
}

impl State for MainViewState {
    fn update(&mut self, _: &mut Registry, ctx: &mut Context) {
        if let Some(action) = self.action {
            match action {
                Action::AddItem => {
                    let len = main_view(ctx.widget()).list().len();

                    if len < 5 {
                        main_view(ctx.widget())
                            .list_mut()
                            .push(format!("Item {}", len + 1));
                        ctx.child("items").clone_or_default::<usize>("Item");
                        items_widget(ctx.child("items")).set_count(len + 1);
                        button(ctx.child("remove-item-button")).set_enabled(true);
                        button(ctx.child("remove-item-button")).set_visibility(Visibility::Visible);

                        if len == 4 {
                            button(ctx.child("add-item-button")).set_enabled(false);
                            button(ctx.child("add-item-button")).set_visibility(Visibility::Collapsed);
                        }
                    }
                }
                Action::RemoveItem => {
                    let len = main_view(ctx.widget()).list().len();
                    if len > 0 {
                        main_view(ctx.widget()).list_mut().remove(len - 1);
                        items_widget(ctx.child("items")).set_count(len - 1);
                        button(ctx.child("add-item-button")).set_enabled(true);
                        button(ctx.child("add-item-button")).set_visibility(Visibility::Visible);

                        if len == 1 {
                            button(ctx.child("remove-item-button")).set_enabled(false);
                            button(ctx.child("remove-item-button")).set_visibility(Visibility::Collapsed);
                        }
                    }
                }
                Action::IncrementCounter => {
                    *main_view(ctx.widget()).counter_mut() += 1;

                    let counter = *main_view(ctx.widget()).counter();

                    main_view(ctx.widget())
                        .set_result(String16::from(format!("Button count: {}", counter)));
                }
                Action::ClearText => {
                    main_view(ctx.widget()).set_text_one(String16::default());
                    main_view(ctx.widget()).set_text_two(String16::default());
                }
                Action::EntryActivated(entity) => {
                    let mut text_box = text_box(ctx.get_widget(entity));
                    let text = text_box.text_mut();
                    println!("submitting {}", text);
                    text.clear();
                }
                Action::EntryChanged(entity) => {
                    println!("entry changed: {}", text_box(ctx.get_widget(entity)).text());
                }
                Action::ValueChanged(entity) => {
                    let val = ((slider(ctx.get_widget(entity)).val()).floor() as i32).to_string();

                    text_block(ctx.child("value_text")).set_text(String16::from(val));
                }
            }

            self.action = None;
        }
    }

    fn update_post_layout(&mut self, _: &mut Registry, ctx: &mut Context) {
        let mut selection_string = "Selected:".to_string();

        for index in &main_view(ctx.widget()).selected_indices().0 {
            selection_string = format!("{} {}", selection_string, index);
        }

        text_block(ctx.child("selection")).set_text(selection_string);
    }
}

fn create_header(ctx: &mut BuildContext, text: &str) -> Entity {
    TextBlock::new()
        .text(text)
        .element("text-block")
        .class("h1")
        .build(ctx)
}

type List = Vec<String>;

widget!(
    MainView<MainViewState> {
        selected_indices: SelectedIndices,
        counter: usize,
        list_count: usize,
        combo_box_list_count: usize,
        list: List,
        selection_list: List,
        combo_box_list: List,
        selection_list_count: usize,
        text_one: String16,
        text_two: String16,
        result: String16
    }
);

impl Template for MainView {
    fn template(self, id: Entity, ctx: &mut BuildContext) -> Self {
        self.name("MainView")
            .result("Button count: 0")
            .counter(0)
            .selected_indices(HashSet::new())
            .list(vec![
                "Item 1".to_string(),
                "Item 2".to_string(),
                "Item 3".to_string(),
            ])
            .list_count(3)
            .selection_list(vec![
                "Select Item 1".to_string(),
                "Select Item 2".to_string(),
                "Select Item 3".to_string(),
                "Select Item 4".to_string(),
                "Select Item 5".to_string(),
                "Select Item 6".to_string(),
                "Select Item 7".to_string(),
                "Select Item 8".to_string(),
                "Select Item 9".to_string(),
                "Select Item 10".to_string(),
            ])
            .combo_box_list(vec![
                "CB 1".to_string(),
                "CB 2".to_string(),
                "CB 3".to_string(),
                "CB 4".to_string(),
                "CB 5".to_string(),
                "CB 6".to_string(),
                "CB 7".to_string(),
                "CB 8".to_string(),
                "CB 9".to_string(),
                "CB 10".to_string(),
            ])
            .selection_list_count(10)
            .combo_box_list_count(10)
            .child(
                Grid::new()
                    .margin(8.)
                    .columns(
                        Columns::new()
                            .add(132.)
                            .add(16.)
                            .add(132.)
                            .add(16.)
                            .add(132.),
                    )
                    .child(
                        Stack::new()
                            .attach(Grid::column(0))
                            // Column 0
                            .child(create_header(ctx, "Buttons"))
                            .child(
                                Button::new()
                                    .text("Button")
                                    .margin((0., 8., 0., 0.))
                                    .icon(material_font_icons::CHECK_FONT_ICON)
                                    .attach(Grid::column(0))
                                    .attach(Grid::row(1))
                                    .on_click(move |states, _| {
                                        state(id, states).action(Action::IncrementCounter);
                                        true
                                    })
                                    .build(ctx),
                            )
                            .child(
                                Button::new()
                                    .text("Primary")
                                    .element("button")
                                    .class("primary")
                                    .margin((0., 8., 0., 0.))
                                    .icon(material_font_icons::CHECK_FONT_ICON)
                                    .attach(Grid::column(0))
                                    .attach(Grid::row(2))
                                    .build(ctx),
                            )
                            .child(
                                ToggleButton::new()
                                    .class("single_content")
                                    .text("ToggleButton")
                                    .margin((0., 8., 0., 0.))
                                    .attach(Grid::column(0))
                                    .attach(Grid::row(3))
                                    .build(ctx),
                            )
                            .child(
                                CheckBox::new()
                                    .text("CheckBox")
                                    .margin((0., 8., 0., 0.))
                                    .attach(Grid::column(0))
                                    .attach(Grid::row(4))
                                    .build(ctx),
                            )
                            .child(
                                Switch::new()
                                    .margin((0., 8., 0., 0.))
                                    .attach(Grid::column(0))
                                    .attach(Grid::row(5))
                                    .build(ctx),
                            )
                            .child(
                                TextBlock::new()
                                    .margin((0., 8., 0., 0.))
                                    .element("h1")
                                    .id("value_text")
                                    .text("0")
                                    .h_align("center")
                                    .build(ctx),
                            )
                            .child(
                                Slider::new()
                                    .on_changed(move |states, entity| {
                                        state(id, states).action(Action::ValueChanged(entity));
                                    })
                                    .build(ctx),
                            )
                            .build(ctx),
                    )
                    .child(
                        Stack::new()
                            .attach(Grid::column(2))
                            .child(create_header(ctx, "Text"))
                            .child(
                                TextBlock::new()
                                    .class("body")
                                    .text(("result", id))
                                    .margin((0., 8., 0., 0.))
                                    .attach(Grid::column(2))
                                    .attach(Grid::row(1))
                                    .build(ctx),
                            )
                            .child(
                                TextBox::new()
                                    .water_mark("TextBox...")
                                    .text(("text_one", id))
                                    .margin((0., 8., 0., 0.))
                                    .attach(Grid::column(2))
                                    .attach(Grid::row(2))
                                    .on_activate(move |states, entity| {
                                        state(id, states).action(Action::EntryActivated(entity));
                                    })
                                    .on_changed(move |states, entity| {
                                        state(id, states).action(Action::EntryChanged(entity));
                                    })
                                    .build(ctx),
                            )
                            .child(
                                TextBox::new()
                                    .water_mark("TextBox...")
                                    .text(("text_two", id))
                                    .margin((0., 8., 0., 0.))
                                    .attach(Grid::column(2))
                                    .attach(Grid::row(2))
                                    .on_activate(move |states, entity| {
                                        state(id, states).action(Action::EntryActivated(entity));
                                    })
                                    .on_changed(move |states, entity| {
                                        state(id, states).action(Action::EntryChanged(entity));
                                    })
                                    .build(ctx),
                            )
                            .child(
                                Button::new()
                                    .margin((0., 8., 0., 0.))
                                    .class("single_content")
                                    .text("clear text")
                                    .on_click(move |states, _| {
                                        state(id, states).action(Action::ClearText);
                                        true
                                    })
                                    .build(ctx),
                            )
                            .child(
                                NumericBox::new()
                                    .margin((-0., 8., 0., 0.))
                                    .max(123.)
                                    .step(0.123)
                                    .val(0.123)
                                    .build(ctx),
                            )
                            .build(ctx),
                    )
                    .child(
                        Grid::new()
                            .rows(
                                Rows::new()
                                    .add("auto")
                                    .add(32.)
                                    .add(16.)
                                    .add(204.)
                                    .add("auto")
                                    .add(192.)
                                    .add("auto"),
                            )
                            .columns(Columns::new().add("*").add(4.).add("*"))
                            .attach(Grid::column(4))
                            .child(
                                TextBlock::new()
                                    .text("Items")
                                    .element("text-block")
                                    .class("h1")
                                    .attach(Grid::column(0))
                                    .attach(Grid::column_span(3))
                                    .attach(Grid::row(0))
                                    .build(ctx),
                            )
                            .child(
                                ComboBox::new()
                                    .items_builder(move |bc, index| {
                                        let text = bc
                                            .get_widget(id)
                                            .get::<Vec<String>>("combo_box_list")[index]
                                            .clone();
                                        TextBlock::new()
                                            .margin((0., 0., 0., 2.))
                                            .v_align("center")
                                            .text(text)
                                            .build(bc)
                                    })
                                    .selected_index(0)
                                    .attach(Grid::column(0))
                                    .attach(Grid::column_span(3))
                                    .attach(Grid::row(1))
                                    .margin((0., 8., 0., 0.))
                                    .count(("combo_box_list_count", id))
                                    .build(ctx),
                            )
                            .child(
                                ItemsWidget::new()
                                    .element("items-widget")
                                    .id("items")
                                    .padding((4., 4., 4., 2.))
                                    .attach(Grid::column(0))
                                    .attach(Grid::column_span(3))
                                    .attach(Grid::row(3))
                                    .margin((0., 0., 0., 8.))
                                    // bc = build-context
                                    .items_builder(move |bc, index| {
                                        let text = bc.get_widget(id).get::<Vec<String>>("list")
                                            [index]
                                            .clone();

                                        Button::new()
                                            .margin((0., 0., 0., 2.))
                                            .text(text)
                                            .build(bc)
                                    })
                                    .count(("list_count", id))
                                    .build(ctx),
                            )
                            .child(
                                Button::new()
                                    .element("button")
                                    .class("single_content")
                                    .id("remove-item-button")
                                    .icon(material_font_icons::MINUS_FONT_ICON)
                                    .on_click(move |states, _| {
                                        state(id, states).action(Action::RemoveItem);
                                        true
                                    })
                                    .min_width(0.)
                                    .attach(Grid::column(0))
                                    .attach(Grid::row(4))
                                    .build(ctx),
                            )
                            .child(
                                Button::new()
                                    .element("button")
                                    .class("single_content")
                                    .id("add-item-button")
                                    .icon(material_font_icons::ADD_FONT_ICON)
                                    .on_click(move |states, _| {
                                        state(id, states).action(Action::AddItem);
                                        true
                                    })
                                    .min_width(0.)
                                    .attach(Grid::column(2))
                                    .attach(Grid::row(4))
                                    .build(ctx),
                            )
                            .child(
                                ListView::new()
                                    .attach(Grid::column(0))
                                    .attach(Grid::column_span(3))
                                    .attach(Grid::row(5))
                                    .selected_indices(id)
                                    .margin((0., 16., 0., 8.))
                                    .items_builder(move |bc, index| {
                                        let text = bc
                                            .get_widget(id)
                                            .get::<Vec<String>>("selection_list")[index]
                                            .clone();
                                        TextBlock::new()
                                            .margin((0., 0., 0., 2.))
                                            .v_align("center")
                                            .text(text)
                                            .build(bc)
                                    })
                                    .count(("selection_list_count", id))
                                    .build(ctx),
                            )
                            .child(
                                // todo: wrong text width????
                                TextBlock::new()
                                    .element("text-block")
                                    .id("selection")
                                    .max_width(120.)
                                    .attach(Grid::column(0))
                                    .attach(Grid::column_span(3))
                                    .attach(Grid::row(6))
                                    .text("Selected:")
                                    .build(ctx),
                            )
                            .build(ctx),
                    )
                    .build(ctx),
            )
    }
}

fn main() {
    // use this only if you want to run it as web application.
    orbtk::initialize();

    Application::new()
        .window(|ctx| {
            Window::new()
                .title("OrbTk - widgets example")
                .position((100., 100.))
                .size(468., 730.)
                .resizeable(true)
                .child(MainView::new().build(ctx))
                .build(ctx)
        })
        .run();
}

// helper to request MainViewState
fn state<'a>(id: Entity, states: &'a mut StatesContext) -> &'a mut MainViewState {
    states.get_mut(id)
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use attr::CaseSensitivity;
use bloom::BloomFilter;
use nth_index_cache::NthIndexCache;

/// What kind of selector matching mode we should use.
///
/// There are two modes of selector matching. The difference is only noticeable
/// in presence of pseudo-elements.
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum MatchingMode {
    /// Don't ignore any pseudo-element selectors.
    Normal,

    /// Ignores any stateless pseudo-element selectors in the rightmost sequence
    /// of simple selectors.
    ///
    /// This is useful, for example, to match against ::before when you aren't a
    /// pseudo-element yourself.
    ///
    /// For example, in presence of `::before:hover`, it would never match, but
    /// `::before` would be ignored as in "matching".
    ///
    /// It's required for all the selectors you match using this mode to have a
    /// pseudo-element.
    ForStatelessPseudoElement,
}

/// The mode to use when matching unvisited and visited links.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum VisitedHandlingMode {
    /// All links are matched as if they are unvisted.
    AllLinksUnvisited,
    /// All links are matched as if they are visited and unvisited (both :link
    /// and :visited match).
    ///
    /// This is intended to be used from invalidation code, to be conservative
    /// about whether we need to restyle a link.
    AllLinksVisitedAndUnvisited,
    /// A element's "relevant link" is the element being matched if it is a link
    /// or the nearest ancestor link. The relevant link is matched as though it
    /// is visited, and all other links are matched as if they are unvisited.
    RelevantLinkVisited,
}

/// Which quirks mode is this document in.
///
/// See: https://quirks.spec.whatwg.org/
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum QuirksMode {
    /// Quirks mode.
    Quirks,
    /// Limited quirks mode.
    LimitedQuirks,
    /// No quirks mode.
    NoQuirks,
}

impl QuirksMode {
    #[inline]
    pub fn classes_and_ids_case_sensitivity(self) -> CaseSensitivity {
        match self {
            QuirksMode::NoQuirks |
            QuirksMode::LimitedQuirks => CaseSensitivity::CaseSensitive,
            QuirksMode::Quirks => CaseSensitivity::AsciiCaseInsensitive,
        }
    }
}

/// Data associated with the matching process for a element.  This context is
/// used across many selectors for an element, so it's not appropriate for
/// transient data that applies to only a single selector.
pub struct MatchingContext<'a> {
    /// Input with the matching mode we should use when matching selectors.
    pub matching_mode: MatchingMode,
    /// Input with the bloom filter used to fast-reject selectors.
    pub bloom_filter: Option<&'a BloomFilter>,
    /// An optional cache to speed up nth-index-like selectors.
    pub nth_index_cache: Option<&'a mut NthIndexCache>,
    /// Input that controls how matching for links is handled.
    pub visited_handling: VisitedHandlingMode,
    /// Output that records whether we encountered a "relevant link" while
    /// matching _any_ selector for this element. (This differs from
    /// `RelevantLinkStatus` which tracks the status for the _current_ selector
    /// only.)
    pub relevant_link_found: bool,

    quirks_mode: QuirksMode,
    classes_and_ids_case_sensitivity: CaseSensitivity,
}

impl<'a> MatchingContext<'a> {
    /// Constructs a new `MatchingContext`.
    pub fn new(matching_mode: MatchingMode,
               bloom_filter: Option<&'a BloomFilter>,
               nth_index_cache: Option<&'a mut NthIndexCache>,
               quirks_mode: QuirksMode)
               -> Self
    {
        Self {
            matching_mode: matching_mode,
            bloom_filter: bloom_filter,
            nth_index_cache: nth_index_cache,
            visited_handling: VisitedHandlingMode::AllLinksUnvisited,
            relevant_link_found: false,
            quirks_mode: quirks_mode,
            classes_and_ids_case_sensitivity: quirks_mode.classes_and_ids_case_sensitivity(),
        }
    }

    /// Constructs a new `MatchingContext` for use in visited matching.
    pub fn new_for_visited(matching_mode: MatchingMode,
                           bloom_filter: Option<&'a BloomFilter>,
                           nth_index_cache: Option<&'a mut NthIndexCache>,
                           visited_handling: VisitedHandlingMode,
                           quirks_mode: QuirksMode)
                           -> Self
    {
        Self {
            matching_mode: matching_mode,
            bloom_filter: bloom_filter,
            visited_handling: visited_handling,
            relevant_link_found: false,
            nth_index_cache: nth_index_cache,
            quirks_mode: quirks_mode,
            classes_and_ids_case_sensitivity: quirks_mode.classes_and_ids_case_sensitivity(),
        }
    }

    /// The quirks mode of the document.
    #[inline]
    pub fn quirks_mode(&self) -> QuirksMode {
        self.quirks_mode
    }

    /// The case-sensitivity for class and ID selectors
    #[inline]
    pub fn classes_and_ids_case_sensitivity(&self) -> CaseSensitivity {
        self.classes_and_ids_case_sensitivity
    }
}
<commit_msg>style: Cleanup MatchingContext construction.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use attr::CaseSensitivity;
use bloom::BloomFilter;
use nth_index_cache::NthIndexCache;

/// What kind of selector matching mode we should use.
///
/// There are two modes of selector matching. The difference is only noticeable
/// in presence of pseudo-elements.
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum MatchingMode {
    /// Don't ignore any pseudo-element selectors.
    Normal,

    /// Ignores any stateless pseudo-element selectors in the rightmost sequence
    /// of simple selectors.
    ///
    /// This is useful, for example, to match against ::before when you aren't a
    /// pseudo-element yourself.
    ///
    /// For example, in presence of `::before:hover`, it would never match, but
    /// `::before` would be ignored as in "matching".
    ///
    /// It's required for all the selectors you match using this mode to have a
    /// pseudo-element.
    ForStatelessPseudoElement,
}

/// The mode to use when matching unvisited and visited links.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum VisitedHandlingMode {
    /// All links are matched as if they are unvisted.
    AllLinksUnvisited,
    /// All links are matched as if they are visited and unvisited (both :link
    /// and :visited match).
    ///
    /// This is intended to be used from invalidation code, to be conservative
    /// about whether we need to restyle a link.
    AllLinksVisitedAndUnvisited,
    /// A element's "relevant link" is the element being matched if it is a link
    /// or the nearest ancestor link. The relevant link is matched as though it
    /// is visited, and all other links are matched as if they are unvisited.
    RelevantLinkVisited,
}

/// Which quirks mode is this document in.
///
/// See: https://quirks.spec.whatwg.org/
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum QuirksMode {
    /// Quirks mode.
    Quirks,
    /// Limited quirks mode.
    LimitedQuirks,
    /// No quirks mode.
    NoQuirks,
}

impl QuirksMode {
    #[inline]
    pub fn classes_and_ids_case_sensitivity(self) -> CaseSensitivity {
        match self {
            QuirksMode::NoQuirks |
            QuirksMode::LimitedQuirks => CaseSensitivity::CaseSensitive,
            QuirksMode::Quirks => CaseSensitivity::AsciiCaseInsensitive,
        }
    }
}

/// Data associated with the matching process for a element.  This context is
/// used across many selectors for an element, so it's not appropriate for
/// transient data that applies to only a single selector.
pub struct MatchingContext<'a> {
    /// Input with the matching mode we should use when matching selectors.
    pub matching_mode: MatchingMode,
    /// Input with the bloom filter used to fast-reject selectors.
    pub bloom_filter: Option<&'a BloomFilter>,
    /// An optional cache to speed up nth-index-like selectors.
    pub nth_index_cache: Option<&'a mut NthIndexCache>,
    /// Input that controls how matching for links is handled.
    pub visited_handling: VisitedHandlingMode,
    /// Output that records whether we encountered a "relevant link" while
    /// matching _any_ selector for this element. (This differs from
    /// `RelevantLinkStatus` which tracks the status for the _current_ selector
    /// only.)
    pub relevant_link_found: bool,

    quirks_mode: QuirksMode,
    classes_and_ids_case_sensitivity: CaseSensitivity,
}

impl<'a> MatchingContext<'a> {
    /// Constructs a new `MatchingContext`.
    pub fn new(
        matching_mode: MatchingMode,
        bloom_filter: Option<&'a BloomFilter>,
        nth_index_cache: Option<&'a mut NthIndexCache>,
        quirks_mode: QuirksMode,
    ) -> Self {
        Self::new_for_visited(
            matching_mode,
            bloom_filter,
            nth_index_cache,
            VisitedHandlingMode::AllLinksUnvisited,
            quirks_mode
        )
    }

    /// Constructs a new `MatchingContext` for use in visited matching.
    pub fn new_for_visited(
        matching_mode: MatchingMode,
        bloom_filter: Option<&'a BloomFilter>,
        nth_index_cache: Option<&'a mut NthIndexCache>,
        visited_handling: VisitedHandlingMode,
        quirks_mode: QuirksMode,
    ) -> Self {
        Self {
            matching_mode,
            bloom_filter,
            visited_handling,
            nth_index_cache,
            quirks_mode,
            relevant_link_found: false,
            classes_and_ids_case_sensitivity: quirks_mode.classes_and_ids_case_sensitivity(),
        }
    }

    /// The quirks mode of the document.
    #[inline]
    pub fn quirks_mode(&self) -> QuirksMode {
        self.quirks_mode
    }

    /// The case-sensitivity for class and ID selectors
    #[inline]
    pub fn classes_and_ids_case_sensitivity(&self) -> CaseSensitivity {
        self.classes_and_ids_case_sensitivity
    }
}
<|endoftext|>


<commit_before>use std::io::{Read, Write};
use rand;
use rand::Rng;
use bincode::{self, serde};
use content::TerrainType;
use area;
use field::Field;
use spatial::Spatial;
use flags::Flags;
use components;
use stats;

Ecs! {
    desc: components::Desc,
    map_memory: components::MapMemory,
    health: components::Health,
    brain: components::Brain,
    item: components::Item,
    composite_stats: components::CompositeStats,
    stats: stats::Stats,
}

/// Toplevel game state object.
#[derive(Serialize, Deserialize)]
pub struct World {
    /// Entity component system.
    pub ecs: Ecs,
    /// Terrain data.
    pub terrain: Field<TerrainType>,
    /// Spatial index for game entities.
    pub spatial: Spatial,
    /// Global gamestate flags.
    pub flags: Flags,
}

impl<'a> World {
    pub fn new(seed: Option<u32>) -> World {
        let seed = match seed {
            // Some RNGs don't like 0 as seed, work around this.
            Some(0) => 1,
            Some(s) => s,
            // Use system rng for seed if the user didn't provide one.
            None => rand::thread_rng().gen(),
        };

        let mut ret = World {
            ecs: Ecs::new(),
            terrain: Field::new(TerrainType::Tree),
            spatial: Spatial::new(),
            flags: Flags::new(seed),
        };

        area::start_level(&mut ret, 1);
        ret
    }

    pub fn load<R: Read>(reader: &mut R) -> serde::DeserializeResult<World> {
        serde::deserialize_from(reader, bincode::SizeLimit::Infinite)
    }

    pub fn save<W: Write>(&self, writer: &mut W) -> serde::SerializeResult<()> {
        serde::serialize_into(writer, self, bincode::SizeLimit::Infinite)
    }
}

#[cfg(test)]
mod test {
    use super::World;

    #[test]
    fn test_serialize() {
        use bincode::{serde, SizeLimit};

        let w1 = World::new(Some(123));
        let saved = serde::serialize(&w1, SizeLimit::Infinite).expect("Serialization failed");
        let w2: World = serde::deserialize(&saved).expect("Deserialization failed")
        assert!(w1.flags.seed == w2.flags.seed);
    }
}
<commit_msg>Fixup<commit_after>use std::io::{Read, Write};
use rand;
use rand::Rng;
use bincode::{self, serde};
use content::TerrainType;
use area;
use field::Field;
use spatial::Spatial;
use flags::Flags;
use components;
use stats;

Ecs! {
    desc: components::Desc,
    map_memory: components::MapMemory,
    health: components::Health,
    brain: components::Brain,
    item: components::Item,
    composite_stats: components::CompositeStats,
    stats: stats::Stats,
}

/// Toplevel game state object.
#[derive(Serialize, Deserialize)]
pub struct World {
    /// Entity component system.
    pub ecs: Ecs,
    /// Terrain data.
    pub terrain: Field<TerrainType>,
    /// Spatial index for game entities.
    pub spatial: Spatial,
    /// Global gamestate flags.
    pub flags: Flags,
}

impl<'a> World {
    pub fn new(seed: Option<u32>) -> World {
        let seed = match seed {
            // Some RNGs don't like 0 as seed, work around this.
            Some(0) => 1,
            Some(s) => s,
            // Use system rng for seed if the user didn't provide one.
            None => rand::thread_rng().gen(),
        };

        let mut ret = World {
            ecs: Ecs::new(),
            terrain: Field::new(TerrainType::Tree),
            spatial: Spatial::new(),
            flags: Flags::new(seed),
        };

        area::start_level(&mut ret, 1);
        ret
    }

    pub fn load<R: Read>(reader: &mut R) -> serde::DeserializeResult<World> {
        serde::deserialize_from(reader, bincode::SizeLimit::Infinite)
    }

    pub fn save<W: Write>(&self, writer: &mut W) -> serde::SerializeResult<()> {
        serde::serialize_into(writer, self, bincode::SizeLimit::Infinite)
    }
}

#[cfg(test)]
mod test {
    use super::World;

    #[test]
    fn test_serialize() {
        use bincode::{serde, SizeLimit};

        let w1 = World::new(Some(123));
        let saved = serde::serialize(&w1, SizeLimit::Infinite).expect("Serialization failed");
        let w2: World = serde::deserialize(&saved).expect("Deserialization failed");
        assert!(w1.flags.seed == w2.flags.seed);
    }
}
<|endoftext|>


<commit_before>extern crate clap;
#[macro_use] extern crate log;
extern crate semver;
extern crate toml;
#[macro_use] extern crate version;

extern crate libimagstore;
extern crate libimagrt;
extern crate libimagentrytag;
extern crate libimagutil;

use std::process::exit;

use libimagrt::runtime::Runtime;
use libimagentrytag::tagable::Tagable;
use libimagstore::storeid::build_entry_path;

mod ui;

use ui::build_ui;

use libimagutil::trace::trace_error;

fn main() {
    let name = "imag-store";
    let version = &version!()[..];
    let about = "Direct interface to the store. Use with great care!";
    let ui = build_ui(Runtime::get_default_cli_builder(name, version, about));
    let rt = {
        let rt = Runtime::new(ui);
        if rt.is_ok() {
            rt.unwrap()
        } else {
            println!("Could not set up Runtime");
            println!("{:?}", rt.unwrap_err());
            exit(1);
        }
    };

    let id = rt.cli().value_of("id").unwrap(); // enforced by clap
    rt.cli()
        .subcommand_name()
        .map_or_else(
            || {
                let add = rt.cli().value_of("add");
                let rem = rt.cli().value_of("remove");
                let set = rt.cli().value_of("set");

                alter(&rt, id, add, rem, set);
            },
            |name| {
                debug!("Call: {}", name);
                match name {
                    "list" => list(id, &rt),
                    _ => {
                        warn!("Unknown command");
                        // More error handling
                    },
                };
            });
}

fn alter(rt: &Runtime, id: &str, add: Option<&str>, rem: Option<&str>, set: Option<&str>) {
    let path = {
        match build_entry_path(rt.store(), id) {
            Err(e) => {
                trace_error(&e);
                exit(1);
            },
            Ok(s) => s,
        }
    };
    debug!("path = {:?}", path);

    rt.store()
        // "id" must be present, enforced via clap spec
        .retrieve(path)
        .map(|mut e| {
            add.map(|tags| {
                for tag in tags.split(',') {
                    info!("Adding tag '{}'", tag);
                    if let Err(e) = e.add_tag(String::from(tag)) {
                        trace_error(&e);
                    }
                }
            });

            rem.map(|tags| {
                for tag in tags.split(',') {
                    info!("Removing tag '{}'", tag);
                    if let Err(e) = e.remove_tag(String::from(tag)) {
                        trace_error(&e);
                    }
                }
            });

            set.map(|tags| {
                info!("Setting tags '{}'", tags);
                let tags = tags.split(',').map(String::from).collect();
                if let Err(e) = e.set_tags(tags) {
                    trace_error(&e);
                }
            });
        })
        .map_err(|e| {
            info!("No entry.");
            trace_error(&e);
        })
        .ok();
}

fn list(id: &str, rt: &Runtime) {
    let path = {
        match build_entry_path(rt.store(), id) {
            Err(e) => {
                trace_error(&e);
                exit(1);
            },
            Ok(s) => s,
        }
    };
    debug!("path = {:?}", path);

    let entry = rt.store().retrieve(path.clone());
    if entry.is_err() {
        debug!("Could not retrieve '{:?}' => {:?}", id, path);
        warn!("Could not retrieve entry '{}'", id);
        trace_error(&entry.unwrap_err());
        exit(1);
    }
    let entry = entry.unwrap();

    let scmd = rt.cli().subcommand_matches("list").unwrap(); // safe, we checked in main()

    let json_out = scmd.is_present("json");
    let line_out = scmd.is_present("linewise");
    let sepp_out = scmd.is_present("sep");
    let mut comm_out = scmd.is_present("commasep");

    if !vec![json_out, line_out, comm_out, sepp_out].iter().any(|v| *v) {
        // None of the flags passed, go to default
        comm_out = true;
    }

    let tags = entry.get_tags();
    if tags.is_err() {
        trace_error(&tags.unwrap_err());
        exit(1);
    }
    let tags = tags.unwrap();

    if json_out {
        unimplemented!()
    }

    if line_out {
        for tag in &tags {
            println!("{}", tag);
        }
    }

    if sepp_out {
        let sepp = scmd.value_of("sep").unwrap(); // we checked before
        println!("{}", tags.join(sepp));
    }

    if comm_out {
        println!("{}", tags.join(", "));
    }
}

<commit_msg>fixed type inference on FromIterator call<commit_after>extern crate clap;
#[macro_use] extern crate log;
extern crate semver;
extern crate toml;
#[macro_use] extern crate version;

extern crate libimagstore;
extern crate libimagrt;
extern crate libimagentrytag;
extern crate libimagutil;

use std::process::exit;

use libimagrt::runtime::Runtime;
use libimagentrytag::tagable::Tagable;
use libimagstore::storeid::build_entry_path;

mod ui;

use ui::build_ui;

use libimagutil::trace::trace_error;

fn main() {
    let name = "imag-store";
    let version = &version!()[..];
    let about = "Direct interface to the store. Use with great care!";
    let ui = build_ui(Runtime::get_default_cli_builder(name, version, about));
    let rt = {
        let rt = Runtime::new(ui);
        if rt.is_ok() {
            rt.unwrap()
        } else {
            println!("Could not set up Runtime");
            println!("{:?}", rt.unwrap_err());
            exit(1);
        }
    };

    let id = rt.cli().value_of("id").unwrap(); // enforced by clap
    rt.cli()
        .subcommand_name()
        .map_or_else(
            || {
                let add = rt.cli().value_of("add");
                let rem = rt.cli().value_of("remove");
                let set = rt.cli().value_of("set");

                alter(&rt, id, add, rem, set);
            },
            |name| {
                debug!("Call: {}", name);
                match name {
                    "list" => list(id, &rt),
                    _ => {
                        warn!("Unknown command");
                        // More error handling
                    },
                };
            });
}

fn alter(rt: &Runtime, id: &str, add: Option<&str>, rem: Option<&str>, set: Option<&str>) {
    let path = {
        match build_entry_path(rt.store(), id) {
            Err(e) => {
                trace_error(&e);
                exit(1);
            },
            Ok(s) => s,
        }
    };
    debug!("path = {:?}", path);

    rt.store()
        // "id" must be present, enforced via clap spec
        .retrieve(path)
        .map(|mut e| {
            add.map(|tags| {
                for tag in tags.split(',') {
                    info!("Adding tag '{}'", tag);
                    if let Err(e) = e.add_tag(String::from(tag)) {
                        trace_error(&e);
                    }
                }
            });

            rem.map(|tags| {
                for tag in tags.split(',') {
                    info!("Removing tag '{}'", tag);
                    if let Err(e) = e.remove_tag(String::from(tag)) {
                        trace_error(&e);
                    }
                }
            });

            set.map(|tags| {
                info!("Setting tags '{}'", tags);
                let tags : Vec<_> = tags.split(',').map(String::from).collect();
                if let Err(e) = e.set_tags(&tags) {
                    trace_error(&e);
                }
            });
        })
        .map_err(|e| {
            info!("No entry.");
            trace_error(&e);
        })
        .ok();
}

fn list(id: &str, rt: &Runtime) {
    let path = {
        match build_entry_path(rt.store(), id) {
            Err(e) => {
                trace_error(&e);
                exit(1);
            },
            Ok(s) => s,
        }
    };
    debug!("path = {:?}", path);

    let entry = rt.store().retrieve(path.clone());
    if entry.is_err() {
        debug!("Could not retrieve '{:?}' => {:?}", id, path);
        warn!("Could not retrieve entry '{}'", id);
        trace_error(&entry.unwrap_err());
        exit(1);
    }
    let entry = entry.unwrap();

    let scmd = rt.cli().subcommand_matches("list").unwrap(); // safe, we checked in main()

    let json_out = scmd.is_present("json");
    let line_out = scmd.is_present("linewise");
    let sepp_out = scmd.is_present("sep");
    let mut comm_out = scmd.is_present("commasep");

    if !vec![json_out, line_out, comm_out, sepp_out].iter().any(|v| *v) {
        // None of the flags passed, go to default
        comm_out = true;
    }

    let tags = entry.get_tags();
    if tags.is_err() {
        trace_error(&tags.unwrap_err());
        exit(1);
    }
    let tags = tags.unwrap();

    if json_out {
        unimplemented!()
    }

    if line_out {
        for tag in &tags {
            println!("{}", tag);
        }
    }

    if sepp_out {
        let sepp = scmd.value_of("sep").unwrap(); // we checked before
        println!("{}", tags.join(sepp));
    }

    if comm_out {
        println!("{}", tags.join(", "));
    }
}

<|endoftext|>


<commit_before>use rustc::hir::*;
use rustc::lint::*;
use rustc::ty;
use syntax::ast::LitKind;
use syntax_pos::Span;
use utils::paths;
use utils::{in_macro, is_expn_of, last_path_segment, match_def_path, match_type, opt_def_id, resolve_node, snippet, span_lint_and_then, walk_ptrs_ty};

/// **What it does:** Checks for the use of `format!("string literal with no
/// argument")` and `format!("{}", foo)` where `foo` is a string.
///
/// **Why is this bad?** There is no point of doing that. `format!("too")` can
/// be replaced by `"foo".to_owned()` if you really need a `String`. The even
/// worse `&format!("foo")` is often encountered in the wild. `format!("{}",
/// foo)` can be replaced by `foo.clone()` if `foo: String` or `foo.to_owned()`
/// if `foo: &str`.
///
/// **Known problems:** None.
///
/// **Examples:**
/// ```rust
/// format!("foo")
/// format!("{}", foo)
/// ```
declare_clippy_lint! {
    pub USELESS_FORMAT,
    complexity,
    "useless use of `format!`"
}

#[derive(Copy, Clone, Debug)]
pub struct Pass;

impl LintPass for Pass {
    fn get_lints(&self) -> LintArray {
        lint_array![USELESS_FORMAT]
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
        if let Some(span) = is_expn_of(expr.span, "format") {
            if in_macro(span) {
                return;
            }
            match expr.node {

                // `format!("{}", foo)` expansion
                ExprCall(ref fun, ref args) => {
                    if_chain! {
                        if let ExprPath(ref qpath) = fun.node;
                        if args.len() == 3;
                        if let Some(fun_def_id) = opt_def_id(resolve_node(cx, qpath, fun.hir_id));
                        if match_def_path(cx.tcx, fun_def_id, &paths::FMT_ARGUMENTS_NEWV1FORMATTED);
                        if check_single_piece(&args[0]);
                        if let Some(format_arg) = get_single_string_arg(cx, &args[1]);
                        if check_unformatted(&args[2]);
                        then {
                            let sugg = format!("{}.to_string()", snippet(cx, format_arg, "<arg>").into_owned());
                            span_lint_and_then(cx, USELESS_FORMAT, span, "useless use of `format!`", |db| {
                                db.span_suggestion(expr.span, "consider using .to_string()", sugg);
                            });
                        }
                    }
                },
                // `format!("foo")` expansion contains `match () { () => [], }`
                ExprMatch(ref matchee, _, _) => if let ExprTup(ref tup) = matchee.node {
                    if tup.is_empty() {
                        let sugg = format!("{}.to_string()", snippet(cx, expr.span, "<expr>").into_owned());
                        span_lint_and_then(cx, USELESS_FORMAT, span, "useless use of `format!`", |db| {
                            db.span_suggestion(span, "consider using .to_string()", sugg);
                        });
                    }
                },
                _ => (),
            }
        }
    }
}

/// Checks if the expressions matches `&[""]`
fn check_single_piece(expr: &Expr) -> bool {
    if_chain! {
        if let ExprAddrOf(_, ref expr) = expr.node; // &[""]
        if let ExprArray(ref exprs) = expr.node; // [""]
        if exprs.len() == 1;
        if let ExprLit(ref lit) = exprs[0].node;
        if let LitKind::Str(ref lit, _) = lit.node;
        then {
            return lit.as_str().is_empty();
        }
    }

    false
}

/// Checks if the expressions matches
/// ```rust,ignore
/// &match (&"arg",) {
/// (__arg0,) => [::std::fmt::ArgumentV1::new(__arg0,
/// ::std::fmt::Display::fmt)],
/// }
/// ```
/// and that type of `__arg0` is `&str` or `String`
/// then returns the span of first element of the matched tuple
fn get_single_string_arg(cx: &LateContext, expr: &Expr) -> Option<Span> {
    if_chain! {
        if let ExprAddrOf(_, ref expr) = expr.node;
        if let ExprMatch(ref match_expr, ref arms, _) = expr.node;
        if arms.len() == 1;
        if arms[0].pats.len() == 1;
        if let PatKind::Tuple(ref pat, None) = arms[0].pats[0].node;
        if pat.len() == 1;
        if let ExprArray(ref exprs) = arms[0].body.node;
        if exprs.len() == 1;
        if let ExprCall(_, ref args) = exprs[0].node;
        if args.len() == 2;
        if let ExprPath(ref qpath) = args[1].node;
        if let Some(fun_def_id) = opt_def_id(resolve_node(cx, qpath, args[1].hir_id));
        if match_def_path(cx.tcx, fun_def_id, &paths::DISPLAY_FMT_METHOD);
        then {
            let ty = walk_ptrs_ty(cx.tables.pat_ty(&pat[0]));
            if ty.sty == ty::TyStr || match_type(cx, ty, &paths::STRING) {
                if let ExprTup(ref values) = match_expr.node {
                    return Some(values[0].span);
                }
            }
        }
    }

    None
}

/// Checks if the expression matches
/// ```rust,ignore
/// &[_ {
///    format: _ {
///         width: _::Implied,
///         ...
///    },
///    ...,
/// }]
/// ```
fn check_unformatted(expr: &Expr) -> bool {
    if_chain! {
        if let ExprAddrOf(_, ref expr) = expr.node;
        if let ExprArray(ref exprs) = expr.node;
        if exprs.len() == 1;
        if let ExprStruct(_, ref fields, _) = exprs[0].node;
        if let Some(format_field) = fields.iter().filter(|f| f.name.node == "format").next();
        if let ExprStruct(_, ref fields, _) = format_field.expr.node;
        if let Some(align_field) = fields.iter().filter(|f| f.name.node == "width").next();
        if let ExprPath(ref qpath) = align_field.expr.node;
        if last_path_segment(qpath).name == "Implied";
        then {
            return true;
        }
    }

    false
}
<commit_msg>Fix clippy warnings<commit_after>use rustc::hir::*;
use rustc::lint::*;
use rustc::ty;
use syntax::ast::LitKind;
use syntax_pos::Span;
use utils::paths;
use utils::{in_macro, is_expn_of, last_path_segment, match_def_path, match_type, opt_def_id, resolve_node, snippet, span_lint_and_then, walk_ptrs_ty};

/// **What it does:** Checks for the use of `format!("string literal with no
/// argument")` and `format!("{}", foo)` where `foo` is a string.
///
/// **Why is this bad?** There is no point of doing that. `format!("too")` can
/// be replaced by `"foo".to_owned()` if you really need a `String`. The even
/// worse `&format!("foo")` is often encountered in the wild. `format!("{}",
/// foo)` can be replaced by `foo.clone()` if `foo: String` or `foo.to_owned()`
/// if `foo: &str`.
///
/// **Known problems:** None.
///
/// **Examples:**
/// ```rust
/// format!("foo")
/// format!("{}", foo)
/// ```
declare_clippy_lint! {
    pub USELESS_FORMAT,
    complexity,
    "useless use of `format!`"
}

#[derive(Copy, Clone, Debug)]
pub struct Pass;

impl LintPass for Pass {
    fn get_lints(&self) -> LintArray {
        lint_array![USELESS_FORMAT]
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
        if let Some(span) = is_expn_of(expr.span, "format") {
            if in_macro(span) {
                return;
            }
            match expr.node {

                // `format!("{}", foo)` expansion
                ExprCall(ref fun, ref args) => {
                    if_chain! {
                        if let ExprPath(ref qpath) = fun.node;
                        if args.len() == 3;
                        if let Some(fun_def_id) = opt_def_id(resolve_node(cx, qpath, fun.hir_id));
                        if match_def_path(cx.tcx, fun_def_id, &paths::FMT_ARGUMENTS_NEWV1FORMATTED);
                        if check_single_piece(&args[0]);
                        if let Some(format_arg) = get_single_string_arg(cx, &args[1]);
                        if check_unformatted(&args[2]);
                        then {
                            let sugg = format!("{}.to_string()", snippet(cx, format_arg, "<arg>").into_owned());
                            span_lint_and_then(cx, USELESS_FORMAT, span, "useless use of `format!`", |db| {
                                db.span_suggestion(expr.span, "consider using .to_string()", sugg);
                            });
                        }
                    }
                },
                // `format!("foo")` expansion contains `match () { () => [], }`
                ExprMatch(ref matchee, _, _) => if let ExprTup(ref tup) = matchee.node {
                    if tup.is_empty() {
                        let sugg = format!("{}.to_string()", snippet(cx, expr.span, "<expr>").into_owned());
                        span_lint_and_then(cx, USELESS_FORMAT, span, "useless use of `format!`", |db| {
                            db.span_suggestion(span, "consider using .to_string()", sugg);
                        });
                    }
                },
                _ => (),
            }
        }
    }
}

/// Checks if the expressions matches `&[""]`
fn check_single_piece(expr: &Expr) -> bool {
    if_chain! {
        if let ExprAddrOf(_, ref expr) = expr.node; // &[""]
        if let ExprArray(ref exprs) = expr.node; // [""]
        if exprs.len() == 1;
        if let ExprLit(ref lit) = exprs[0].node;
        if let LitKind::Str(ref lit, _) = lit.node;
        then {
            return lit.as_str().is_empty();
        }
    }

    false
}

/// Checks if the expressions matches
/// ```rust,ignore
/// &match (&"arg",) {
/// (__arg0,) => [::std::fmt::ArgumentV1::new(__arg0,
/// ::std::fmt::Display::fmt)],
/// }
/// ```
/// and that type of `__arg0` is `&str` or `String`
/// then returns the span of first element of the matched tuple
fn get_single_string_arg(cx: &LateContext, expr: &Expr) -> Option<Span> {
    if_chain! {
        if let ExprAddrOf(_, ref expr) = expr.node;
        if let ExprMatch(ref match_expr, ref arms, _) = expr.node;
        if arms.len() == 1;
        if arms[0].pats.len() == 1;
        if let PatKind::Tuple(ref pat, None) = arms[0].pats[0].node;
        if pat.len() == 1;
        if let ExprArray(ref exprs) = arms[0].body.node;
        if exprs.len() == 1;
        if let ExprCall(_, ref args) = exprs[0].node;
        if args.len() == 2;
        if let ExprPath(ref qpath) = args[1].node;
        if let Some(fun_def_id) = opt_def_id(resolve_node(cx, qpath, args[1].hir_id));
        if match_def_path(cx.tcx, fun_def_id, &paths::DISPLAY_FMT_METHOD);
        then {
            let ty = walk_ptrs_ty(cx.tables.pat_ty(&pat[0]));
            if ty.sty == ty::TyStr || match_type(cx, ty, &paths::STRING) {
                if let ExprTup(ref values) = match_expr.node {
                    return Some(values[0].span);
                }
            }
        }
    }

    None
}

/// Checks if the expression matches
/// ```rust,ignore
/// &[_ {
///    format: _ {
///         width: _::Implied,
///         ...
///    },
///    ...,
/// }]
/// ```
fn check_unformatted(expr: &Expr) -> bool {
    if_chain! {
        if let ExprAddrOf(_, ref expr) = expr.node;
        if let ExprArray(ref exprs) = expr.node;
        if exprs.len() == 1;
        if let ExprStruct(_, ref fields, _) = exprs[0].node;
        if let Some(format_field) = fields.iter().find(|f| f.name.node == "format");
        if let ExprStruct(_, ref fields, _) = format_field.expr.node;
        if let Some(align_field) = fields.iter().find(|f| f.name.node == "width");
        if let ExprPath(ref qpath) = align_field.expr.node;
        if last_path_segment(qpath).name == "Implied";
        then {
            return true;
        }
    }

    false
}
<|endoftext|>