<commit_before>//! This crate contains implementations of built-in macros and other code generating facilities
//! injecting code into the crate before it is lowered to HIR.

#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(bool_to_option)]
#![feature(crate_visibility_modifier)]
#![feature(decl_macro)]
#![feature(nll)]
#![feature(or_patterns)]
#![feature(proc_macro_internals)]
#![feature(proc_macro_quote)]

extern crate proc_macro;

use crate::deriving::*;

use rustc_expand::base::{MacroExpanderFn, ResolverExpand, SyntaxExtension, SyntaxExtensionKind};
use rustc_expand::proc_macro::BangProcMacro;
use rustc_span::edition::Edition;
use rustc_span::symbol::{sym, Ident};

mod asm;
mod assert;
mod cfg;
mod cfg_accessible;
mod compile_error;
mod concat;
mod concat_idents;
mod deriving;
mod env;
mod format;
mod format_foreign;
mod global_allocator;
mod global_asm;
mod llvm_asm;
mod log_syntax;
mod source_util;
mod test;
mod trace_macros;
mod util;

pub mod cmdline_attrs;
pub mod proc_macro_harness;
pub mod standard_library_imports;
pub mod test_harness;

pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand, edition: Edition) {
    let mut register = |name, kind| {
        resolver.register_builtin_macro(
            Ident::with_dummy_span(name),
            SyntaxExtension { builtin_name: Some(name), ..SyntaxExtension::default(kind, edition) },
        )
    };
    macro register_bang($($name:ident: $f:expr,)*) {
        $(register(sym::$name, SyntaxExtensionKind::LegacyBang(Box::new($f as MacroExpanderFn)));)*
    }
    macro register_attr($($name:ident: $f:expr,)*) {
        $(register(sym::$name, SyntaxExtensionKind::LegacyAttr(Box::new($f)));)*
    }
    macro register_derive($($name:ident: $f:expr,)*) {
        $(register(sym::$name, SyntaxExtensionKind::LegacyDerive(Box::new(BuiltinDerive($f))));)*
    }

    register_bang! {
        asm: asm::expand_asm,
        assert: assert::expand_assert,
        cfg: cfg::expand_cfg,
        column: source_util::expand_column,
        compile_error: compile_error::expand_compile_error,
        concat_idents: concat_idents::expand_concat_idents,
        concat: concat::expand_concat,
        env: env::expand_env,
        file: source_util::expand_file,
        format_args_nl: format::expand_format_args_nl,
        format_args: format::expand_format_args,
        global_asm: global_asm::expand_global_asm,
        include_bytes: source_util::expand_include_bytes,
        include_str: source_util::expand_include_str,
        include: source_util::expand_include,
        line: source_util::expand_line,
        llvm_asm: llvm_asm::expand_llvm_asm,
        log_syntax: log_syntax::expand_log_syntax,
        module_path: source_util::expand_mod,
        option_env: env::expand_option_env,
        stringify: source_util::expand_stringify,
        trace_macros: trace_macros::expand_trace_macros,
    }

    register_attr! {
        bench: test::expand_bench,
        cfg_accessible: cfg_accessible::Expander,
        global_allocator: global_allocator::expand,
        test: test::expand_test,
        test_case: test::expand_test_case,
    }

    register_derive! {
        Clone: clone::expand_deriving_clone,
        Copy: bounds::expand_deriving_copy,
        Debug: debug::expand_deriving_debug,
        Default: default::expand_deriving_default,
        Eq: eq::expand_deriving_eq,
        Hash: hash::expand_deriving_hash,
        Ord: ord::expand_deriving_ord,
        PartialEq: partial_eq::expand_deriving_partial_eq,
        PartialOrd: partial_ord::expand_deriving_partial_ord,
        RustcDecodable: decodable::expand_deriving_rustc_decodable,
        RustcEncodable: encodable::expand_deriving_rustc_encodable,
    }

    let client = proc_macro::bridge::client::Client::expand1(proc_macro::quote);
    register(sym::quote, SyntaxExtensionKind::Bang(Box::new(BangProcMacro { client })));
}
<commit_msg>Don't set builtin_name for builtin macro implementations.<commit_after>//! This crate contains implementations of built-in macros and other code generating facilities
//! injecting code into the crate before it is lowered to HIR.

#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(bool_to_option)]
#![feature(crate_visibility_modifier)]
#![feature(decl_macro)]
#![feature(nll)]
#![feature(or_patterns)]
#![feature(proc_macro_internals)]
#![feature(proc_macro_quote)]

extern crate proc_macro;

use crate::deriving::*;

use rustc_expand::base::{MacroExpanderFn, ResolverExpand, SyntaxExtension, SyntaxExtensionKind};
use rustc_expand::proc_macro::BangProcMacro;
use rustc_span::edition::Edition;
use rustc_span::symbol::{sym, Ident};

mod asm;
mod assert;
mod cfg;
mod cfg_accessible;
mod compile_error;
mod concat;
mod concat_idents;
mod deriving;
mod env;
mod format;
mod format_foreign;
mod global_allocator;
mod global_asm;
mod llvm_asm;
mod log_syntax;
mod source_util;
mod test;
mod trace_macros;
mod util;

pub mod cmdline_attrs;
pub mod proc_macro_harness;
pub mod standard_library_imports;
pub mod test_harness;

pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand, edition: Edition) {
    let mut register = |name, kind| {
        resolver.register_builtin_macro(
            Ident::with_dummy_span(name),
            SyntaxExtension::default(kind, edition),
        )
    };
    macro register_bang($($name:ident: $f:expr,)*) {
        $(register(sym::$name, SyntaxExtensionKind::LegacyBang(Box::new($f as MacroExpanderFn)));)*
    }
    macro register_attr($($name:ident: $f:expr,)*) {
        $(register(sym::$name, SyntaxExtensionKind::LegacyAttr(Box::new($f)));)*
    }
    macro register_derive($($name:ident: $f:expr,)*) {
        $(register(sym::$name, SyntaxExtensionKind::LegacyDerive(Box::new(BuiltinDerive($f))));)*
    }

    register_bang! {
        asm: asm::expand_asm,
        assert: assert::expand_assert,
        cfg: cfg::expand_cfg,
        column: source_util::expand_column,
        compile_error: compile_error::expand_compile_error,
        concat_idents: concat_idents::expand_concat_idents,
        concat: concat::expand_concat,
        env: env::expand_env,
        file: source_util::expand_file,
        format_args_nl: format::expand_format_args_nl,
        format_args: format::expand_format_args,
        global_asm: global_asm::expand_global_asm,
        include_bytes: source_util::expand_include_bytes,
        include_str: source_util::expand_include_str,
        include: source_util::expand_include,
        line: source_util::expand_line,
        llvm_asm: llvm_asm::expand_llvm_asm,
        log_syntax: log_syntax::expand_log_syntax,
        module_path: source_util::expand_mod,
        option_env: env::expand_option_env,
        stringify: source_util::expand_stringify,
        trace_macros: trace_macros::expand_trace_macros,
    }

    register_attr! {
        bench: test::expand_bench,
        cfg_accessible: cfg_accessible::Expander,
        global_allocator: global_allocator::expand,
        test: test::expand_test,
        test_case: test::expand_test_case,
    }

    register_derive! {
        Clone: clone::expand_deriving_clone,
        Copy: bounds::expand_deriving_copy,
        Debug: debug::expand_deriving_debug,
        Default: default::expand_deriving_default,
        Eq: eq::expand_deriving_eq,
        Hash: hash::expand_deriving_hash,
        Ord: ord::expand_deriving_ord,
        PartialEq: partial_eq::expand_deriving_partial_eq,
        PartialOrd: partial_ord::expand_deriving_partial_ord,
        RustcDecodable: decodable::expand_deriving_rustc_decodable,
        RustcEncodable: encodable::expand_deriving_rustc_encodable,
    }

    let client = proc_macro::bridge::client::Client::expand1(proc_macro::quote);
    register(sym::quote, SyntaxExtensionKind::Bang(Box::new(BangProcMacro { client })));
}
<|endoftext|>


<commit_before>//  Copyright (C) 2020 Éloïs SANCHEZ.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.

use super::create_subscription;
use crate::*;
use duniter_dbs::databases::cm_v1::{CmV1DbReadable, CurrentBlockEvent, CurrentBlockMetaEvent};

#[derive(Clone, Copy, Default)]
pub struct NewBlocksSubscription;

#[async_graphql::Subscription]
impl NewBlocksSubscription {
    async fn new_blocks_meta(
        &self,
        ctx: &async_graphql::Context<'_>,
    ) -> impl Stream<Item = async_graphql::Result<Vec<BlockMeta>>> {
        create_subscription(
            ctx,
            |dbs| dbs.cm_db.current_block_meta(),
            |events| {
                let mut blocks_meta = Vec::new();
                for event in events.deref() {
                    if let CurrentBlockMetaEvent::Upsert {
                        value: ref block_meta,
                        ..
                    } = event
                    {
                        blocks_meta.push(BlockMeta::from(block_meta));
                    }
                }
                if blocks_meta.is_empty() {
                    futures::future::ready(None)
                } else {
                    futures::future::ready(Some(Ok(blocks_meta)))
                }
            },
        )
        .await
    }
    async fn new_blocks(
        &self,
        ctx: &async_graphql::Context<'_>,
    ) -> impl Stream<Item = async_graphql::Result<Vec<Block>>> {
        create_subscription(
            ctx,
            |dbs| dbs.cm_db.current_block(),
            |events| {
                let mut blocks = Vec::new();
                for event in events.deref() {
                    if let CurrentBlockEvent::Upsert {
                        value: ref block, ..
                    } = event
                    {
                        blocks.push(Block::from(&block.0));
                    }
                }
                if blocks.is_empty() {
                    futures::future::ready(None)
                } else {
                    futures::future::ready(Some(Ok(blocks)))
                }
            },
        )
        .await
    }
}
<commit_msg>[ref] gva: fusion sub newBlockMeta with newBlock<commit_after>//  Copyright (C) 2020 Éloïs SANCHEZ.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.

use super::create_subscription;
use crate::*;
use duniter_dbs::databases::cm_v1::{CmV1DbReadable, CurrentBlockEvent, CurrentBlockMetaEvent};
use futures::future::Either;

#[derive(Clone, Copy, Default)]
pub struct NewBlocksSubscription;

#[async_graphql::Subscription]
impl NewBlocksSubscription {
    async fn new_blocks(
        &self,
        ctx: &async_graphql::Context<'_>,
    ) -> impl Stream<Item = async_graphql::Result<Vec<Block>>> {
        let meta_only = !(ctx.look_ahead().field("identities").exists()
            || ctx.look_ahead().field("joiners").exists()
            || ctx.look_ahead().field("actives").exists()
            || ctx.look_ahead().field("leavers").exists()
            || ctx.look_ahead().field("revoked").exists()
            || ctx.look_ahead().field("excluded").exists()
            || ctx.look_ahead().field("certifications").exists()
            || ctx.look_ahead().field("transactions").exists());
        if meta_only {
            Either::Left(
                create_subscription(
                    ctx,
                    |dbs| dbs.cm_db.current_block_meta(),
                    |events| {
                        let mut blocks = Vec::new();
                        for event in events.deref() {
                            if let CurrentBlockMetaEvent::Upsert {
                                value: ref block_meta,
                                ..
                            } = event
                            {
                                blocks.push(Block::from(block_meta));
                            }
                        }
                        if blocks.is_empty() {
                            futures::future::ready(None)
                        } else {
                            futures::future::ready(Some(Ok(blocks)))
                        }
                    },
                )
                .await,
            )
        } else {
            Either::Right(
                create_subscription(
                    ctx,
                    |dbs| dbs.cm_db.current_block(),
                    |events| {
                        let mut blocks = Vec::new();
                        for event in events.deref() {
                            if let CurrentBlockEvent::Upsert {
                                value: ref block, ..
                            } = event
                            {
                                blocks.push(Block::from(&block.0));
                            }
                        }
                        if blocks.is_empty() {
                            futures::future::ready(None)
                        } else {
                            futures::future::ready(Some(Ok(blocks)))
                        }
                    },
                )
                .await,
            )
        }
    }
}
<|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/. */

//! A windowing implementation using GLUT.

use windowing::{ApplicationMethods, WindowEvent, WindowMethods};
use windowing::{IdleWindowEvent, ResizeWindowEvent, LoadUrlWindowEvent, MouseWindowEventClass};
use windowing::{ScrollWindowEvent, ZoomWindowEvent, NavigationWindowEvent, FinishedWindowEvent};
use windowing::{MouseWindowClickEvent, MouseWindowMouseDownEvent, MouseWindowMouseUpEvent};
use windowing::{Forward, Back};

use alert::{Alert, AlertMethods};
use libc::{c_int, c_uchar};
use std::cell::{Cell, RefCell};
use std::local_data;
use std::rc::Rc;
use geom::point::Point2D;
use geom::size::Size2D;
use servo_msg::compositor_msg::{IdleRenderState, RenderState, RenderingRenderState};
use servo_msg::compositor_msg::{FinishedLoading, Blank, ReadyState};

use glut::glut::{ACTIVE_SHIFT, DOUBLE, WindowHeight};
use glut::glut::WindowWidth;
use glut::glut;

// static THROBBER: [char, ..8] = [ '⣾', '⣽', '⣻', '⢿', '⡿', '⣟', '⣯', '⣷' ];

/// A structure responsible for setting up and tearing down the entire windowing system.
pub struct Application;

impl ApplicationMethods for Application {
    fn new() -> Application {
        glut::init();
        glut::init_display_mode(DOUBLE);
        Application
    }
}

impl Drop for Application {
    fn drop(&mut self) {
        drop_local_window();
    }
}

/// The type of a window.
pub struct Window {
    pub glut_window: glut::Window,

    pub event_queue: RefCell<Vec<WindowEvent>>,

    pub drag_origin: Point2D<c_int>,

    pub mouse_down_button: Cell<c_int>,
    pub mouse_down_point: Cell<Point2D<c_int>>,

    pub ready_state: Cell<ReadyState>,
    pub render_state: Cell<RenderState>,
    pub throbber_frame: Cell<u8>,
}

impl WindowMethods<Application> for Window {
    /// Creates a new window.
    fn new(_: &Application, _: bool) -> Rc<Window> {
        // Create the GLUT window.
        glut::init_window_size(800, 600);
        let glut_window = glut::create_window("Servo".to_owned());

        // Create our window object.
        let window = Window {
            glut_window: glut_window,

            event_queue: RefCell::new(vec!()),

            drag_origin: Point2D(0 as c_int, 0),

            mouse_down_button: Cell::new(0),
            mouse_down_point: Cell::new(Point2D(0 as c_int, 0)),

            ready_state: Cell::new(Blank),
            render_state: Cell::new(IdleRenderState),
            throbber_frame: Cell::new(0),
        };

        // Register event handlers.

        //Added dummy display callback to freeglut. According to freeglut ref, we should register some kind of display callback after freeglut 3.0.

        struct DisplayCallbackState;
        impl glut::DisplayCallback for DisplayCallbackState {
            fn call(&self) {
                debug!("GLUT display func registgered");
            }
        }
        glut::display_func(~DisplayCallbackState);
        struct ReshapeCallbackState;
        impl glut::ReshapeCallback for ReshapeCallbackState {
            fn call(&self, width: c_int, height: c_int) {
                let tmp = local_window();
                tmp.event_queue.borrow_mut().push(ResizeWindowEvent(width as uint, height as uint))
            }
        }
        glut::reshape_func(glut_window, ~ReshapeCallbackState);
        struct KeyboardCallbackState;
        impl glut::KeyboardCallback for KeyboardCallbackState {
            fn call(&self, key: c_uchar, _x: c_int, _y: c_int) {
                let tmp = local_window();
                tmp.handle_key(key)
            }
        }
        glut::keyboard_func(~KeyboardCallbackState);
        struct MouseCallbackState;
        impl glut::MouseCallback for MouseCallbackState {
            fn call(&self, button: c_int, state: c_int, x: c_int, y: c_int) {
                if button < 3 {
                    let tmp = local_window();
                    tmp.handle_mouse(button, state, x, y);
                } else {
                    match button {
                        3 => {
                            let tmp = local_window();
                            tmp.event_queue.borrow_mut().push(ScrollWindowEvent(Point2D(0.0, 5.0 as f32), Point2D(0.0 as i32, 5.0 as i32)));
                        },
                        4 => {
                            let tmp = local_window();
                            tmp.event_queue.borrow_mut().push(ScrollWindowEvent(Point2D(0.0, -5.0 as f32), Point2D(0.0 as i32, -5.0 as i32)));
                        },
                        _ => {}
                    }
                }
            }
        }
        glut::mouse_func(~MouseCallbackState);

        let wrapped_window = Rc::new(window);

        install_local_window(wrapped_window.clone());

        wrapped_window
    }

    /// Returns the size of the window.
    fn size(&self) -> Size2D<f32> {
        Size2D(glut::get(WindowWidth) as f32, glut::get(WindowHeight) as f32)
    }

    /// Presents the window to the screen (perhaps by page flipping).
    fn present(&self) {
        glut::swap_buffers();
    }

    fn recv(&self) -> WindowEvent {
        if !self.event_queue.borrow_mut().is_empty() {
            return self.event_queue.borrow_mut().shift().unwrap();
        }

        glut::check_loop();

        self.event_queue.borrow_mut().shift().unwrap_or(IdleWindowEvent)
    }

    /// Sets the ready state.
    fn set_ready_state(&self, ready_state: ReadyState) {
        self.ready_state.set(ready_state);
        //FIXME: set_window_title causes crash with Android version of freeGLUT. Temporarily blocked.
        //self.update_window_title()
    }

    /// Sets the render state.
    fn set_render_state(&self, render_state: RenderState) {
        if self.ready_state.get() == FinishedLoading &&
            self.render_state.get() == RenderingRenderState &&
            render_state == IdleRenderState {
            // page loaded
            self.event_queue.borrow_mut().push(FinishedWindowEvent);
        }

        self.render_state.set(render_state);
        //FIXME: set_window_title causes crash with Android version of freeGLUT. Temporarily blocked.
        //self.update_window_title()
    }

    fn hidpi_factor(&self) -> f32 {
        //FIXME: Do nothing in GLUT now.
    0f32
    }
}

impl Window {
    /// Helper function to set the window title in accordance with the ready state.
    // fn update_window_title(&self) {
    //     let throbber = THROBBER[self.throbber_frame];
    //     match self.ready_state {
    //         Blank => {
    //             glut::set_window_title(self.glut_window, "Blank")
    //         }
    //         Loading => {
    //             glut::set_window_title(self.glut_window, format!("{:c} Loading . Servo", throbber))
    //         }
    //         PerformingLayout => {
    //             glut::set_window_title(self.glut_window, format!("{:c} Performing Layout . Servo", throbber))
    //         }
    //         FinishedLoading => {
    //             match self.render_state {
    //                 RenderingRenderState => {
    //                     glut::set_window_title(self.glut_window, format!("{:c} Rendering . Servo", throbber))
    //                 }
    //                 IdleRenderState => glut::set_window_title(self.glut_window, "Servo"),
    //             }
    //         }
    //     }
    // }

    /// Helper function to handle keyboard events.
    fn handle_key(&self, key: u8) {
        debug!("got key: {}", key);
        let modifiers = glut::get_modifiers();
        match key {
            42 => self.load_url(),
            43 => self.event_queue.borrow_mut().push(ZoomWindowEvent(1.1)),
            45 => self.event_queue.borrow_mut().push(ZoomWindowEvent(0.909090909)),
            56 => self.event_queue.borrow_mut().push(ScrollWindowEvent(Point2D(0.0, 5.0 as f32), Point2D(0.0 as i32, 5.0 as i32))),
            50 => self.event_queue.borrow_mut().push(ScrollWindowEvent(Point2D(0.0, -5.0 as f32), Point2D(0.0 as i32, -5.0 as i32))),
            127 => {
                if (modifiers & ACTIVE_SHIFT) != 0 {
                    self.event_queue.borrow_mut().push(NavigationWindowEvent(Forward));
                }
                else {
                    self.event_queue.borrow_mut().push(NavigationWindowEvent(Back));
                }
            }
            _ => {}
        }
    }

    /// Helper function to handle a click
    fn handle_mouse(&self, button: c_int, state: c_int, x: c_int, y: c_int) {
        // FIXME(tkuehn): max pixel dist should be based on pixel density
        let max_pixel_dist = 10f32;
        let event = match state {
            glut::MOUSE_DOWN => {
                self.mouse_down_point.set(Point2D(x, y));
                self.mouse_down_button.set(button);
                MouseWindowMouseDownEvent(button as uint, Point2D(x as f32, y as f32))
            }
            glut::MOUSE_UP => {
                if self.mouse_down_button.get() == button {
                    let pixel_dist = self.mouse_down_point.get() - Point2D(x, y);
                    let pixel_dist = ((pixel_dist.x * pixel_dist.x +
                                       pixel_dist.y * pixel_dist.y) as f32).sqrt();
                    if pixel_dist < max_pixel_dist {
                        let click_event = MouseWindowClickEvent(button as uint,
                                                           Point2D(x as f32, y as f32));
                        self.event_queue.borrow_mut().push(MouseWindowEventClass(click_event));
                    }
                }
                MouseWindowMouseUpEvent(button as uint, Point2D(x as f32, y as f32))
            }
            _ => fail!("I cannot recognize the type of mouse action that occured. :-(")
        };
        self.event_queue.borrow_mut().push(MouseWindowEventClass(event));
    }

    /// Helper function to pop up an alert box prompting the user to load a URL.
    fn load_url(&self) {
        let mut alert: Alert = AlertMethods::new("Navigate to:");
        alert.add_prompt();
        alert.run();
        let value = alert.prompt_value();
        if "" == value {    // To avoid crashing on Linux.
            self.event_queue.borrow_mut().push(LoadUrlWindowEvent("http://purple.com/".to_owned()))
        } else {
            self.event_queue.borrow_mut().push(LoadUrlWindowEvent(value.clone()))
        }
    }
}

static TLS_KEY: local_data::Key<Rc<Window>> = &local_data::Key;

fn install_local_window(window: Rc<Window>) {
    local_data::set(TLS_KEY, window);
}

fn drop_local_window() {
    local_data::pop(TLS_KEY);
}

fn local_window() -> Rc<Window> {
    local_data::get(TLS_KEY, |v| v.unwrap().clone())
}
<commit_msg>auto merge of #2377 : aydinkim/servo/hidpi, r=larsbergstrom<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/. */

//! A windowing implementation using GLUT.

use windowing::{ApplicationMethods, WindowEvent, WindowMethods};
use windowing::{IdleWindowEvent, ResizeWindowEvent, LoadUrlWindowEvent, MouseWindowEventClass};
use windowing::{ScrollWindowEvent, ZoomWindowEvent, NavigationWindowEvent, FinishedWindowEvent};
use windowing::{MouseWindowClickEvent, MouseWindowMouseDownEvent, MouseWindowMouseUpEvent};
use windowing::{Forward, Back};

use alert::{Alert, AlertMethods};
use libc::{c_int, c_uchar};
use std::cell::{Cell, RefCell};
use std::local_data;
use std::rc::Rc;
use geom::point::Point2D;
use geom::size::Size2D;
use servo_msg::compositor_msg::{IdleRenderState, RenderState, RenderingRenderState};
use servo_msg::compositor_msg::{FinishedLoading, Blank, ReadyState};

use glut::glut::{ACTIVE_SHIFT, DOUBLE, WindowHeight};
use glut::glut::WindowWidth;
use glut::glut;

// static THROBBER: [char, ..8] = [ '⣾', '⣽', '⣻', '⢿', '⡿', '⣟', '⣯', '⣷' ];

/// A structure responsible for setting up and tearing down the entire windowing system.
pub struct Application;

impl ApplicationMethods for Application {
    fn new() -> Application {
        glut::init();
        glut::init_display_mode(DOUBLE);
        Application
    }
}

impl Drop for Application {
    fn drop(&mut self) {
        drop_local_window();
    }
}

/// The type of a window.
pub struct Window {
    pub glut_window: glut::Window,

    pub event_queue: RefCell<Vec<WindowEvent>>,

    pub drag_origin: Point2D<c_int>,

    pub mouse_down_button: Cell<c_int>,
    pub mouse_down_point: Cell<Point2D<c_int>>,

    pub ready_state: Cell<ReadyState>,
    pub render_state: Cell<RenderState>,
    pub throbber_frame: Cell<u8>,
}

impl WindowMethods<Application> for Window {
    /// Creates a new window.
    fn new(_: &Application, _: bool) -> Rc<Window> {
        // Create the GLUT window.
        glut::init_window_size(800, 600);
        let glut_window = glut::create_window("Servo".to_owned());

        // Create our window object.
        let window = Window {
            glut_window: glut_window,

            event_queue: RefCell::new(vec!()),

            drag_origin: Point2D(0 as c_int, 0),

            mouse_down_button: Cell::new(0),
            mouse_down_point: Cell::new(Point2D(0 as c_int, 0)),

            ready_state: Cell::new(Blank),
            render_state: Cell::new(IdleRenderState),
            throbber_frame: Cell::new(0),
        };

        // Register event handlers.

        //Added dummy display callback to freeglut. According to freeglut ref, we should register some kind of display callback after freeglut 3.0.

        struct DisplayCallbackState;
        impl glut::DisplayCallback for DisplayCallbackState {
            fn call(&self) {
                debug!("GLUT display func registgered");
            }
        }
        glut::display_func(~DisplayCallbackState);
        struct ReshapeCallbackState;
        impl glut::ReshapeCallback for ReshapeCallbackState {
            fn call(&self, width: c_int, height: c_int) {
                let tmp = local_window();
                tmp.event_queue.borrow_mut().push(ResizeWindowEvent(width as uint, height as uint))
            }
        }
        glut::reshape_func(glut_window, ~ReshapeCallbackState);
        struct KeyboardCallbackState;
        impl glut::KeyboardCallback for KeyboardCallbackState {
            fn call(&self, key: c_uchar, _x: c_int, _y: c_int) {
                let tmp = local_window();
                tmp.handle_key(key)
            }
        }
        glut::keyboard_func(~KeyboardCallbackState);
        struct MouseCallbackState;
        impl glut::MouseCallback for MouseCallbackState {
            fn call(&self, button: c_int, state: c_int, x: c_int, y: c_int) {
                if button < 3 {
                    let tmp = local_window();
                    tmp.handle_mouse(button, state, x, y);
                } else {
                    match button {
                        3 => {
                            let tmp = local_window();
                            tmp.event_queue.borrow_mut().push(ScrollWindowEvent(Point2D(0.0, 5.0 as f32), Point2D(0.0 as i32, 5.0 as i32)));
                        },
                        4 => {
                            let tmp = local_window();
                            tmp.event_queue.borrow_mut().push(ScrollWindowEvent(Point2D(0.0, -5.0 as f32), Point2D(0.0 as i32, -5.0 as i32)));
                        },
                        _ => {}
                    }
                }
            }
        }
        glut::mouse_func(~MouseCallbackState);

        let wrapped_window = Rc::new(window);

        install_local_window(wrapped_window.clone());

        wrapped_window
    }

    /// Returns the size of the window.
    fn size(&self) -> Size2D<f32> {
        Size2D(glut::get(WindowWidth) as f32, glut::get(WindowHeight) as f32)
    }

    /// Presents the window to the screen (perhaps by page flipping).
    fn present(&self) {
        glut::swap_buffers();
    }

    fn recv(&self) -> WindowEvent {
        if !self.event_queue.borrow_mut().is_empty() {
            return self.event_queue.borrow_mut().shift().unwrap();
        }

        glut::check_loop();

        self.event_queue.borrow_mut().shift().unwrap_or(IdleWindowEvent)
    }

    /// Sets the ready state.
    fn set_ready_state(&self, ready_state: ReadyState) {
        self.ready_state.set(ready_state);
        //FIXME: set_window_title causes crash with Android version of freeGLUT. Temporarily blocked.
        //self.update_window_title()
    }

    /// Sets the render state.
    fn set_render_state(&self, render_state: RenderState) {
        if self.ready_state.get() == FinishedLoading &&
            self.render_state.get() == RenderingRenderState &&
            render_state == IdleRenderState {
            // page loaded
            self.event_queue.borrow_mut().push(FinishedWindowEvent);
        }

        self.render_state.set(render_state);
        //FIXME: set_window_title causes crash with Android version of freeGLUT. Temporarily blocked.
        //self.update_window_title()
    }

    fn hidpi_factor(&self) -> f32 {
        //FIXME: Do nothing in GLUT now.
    1f32
    }
}

impl Window {
    /// Helper function to set the window title in accordance with the ready state.
    // fn update_window_title(&self) {
    //     let throbber = THROBBER[self.throbber_frame];
    //     match self.ready_state {
    //         Blank => {
    //             glut::set_window_title(self.glut_window, "Blank")
    //         }
    //         Loading => {
    //             glut::set_window_title(self.glut_window, format!("{:c} Loading . Servo", throbber))
    //         }
    //         PerformingLayout => {
    //             glut::set_window_title(self.glut_window, format!("{:c} Performing Layout . Servo", throbber))
    //         }
    //         FinishedLoading => {
    //             match self.render_state {
    //                 RenderingRenderState => {
    //                     glut::set_window_title(self.glut_window, format!("{:c} Rendering . Servo", throbber))
    //                 }
    //                 IdleRenderState => glut::set_window_title(self.glut_window, "Servo"),
    //             }
    //         }
    //     }
    // }

    /// Helper function to handle keyboard events.
    fn handle_key(&self, key: u8) {
        debug!("got key: {}", key);
        let modifiers = glut::get_modifiers();
        match key {
            42 => self.load_url(),
            43 => self.event_queue.borrow_mut().push(ZoomWindowEvent(1.1)),
            45 => self.event_queue.borrow_mut().push(ZoomWindowEvent(0.909090909)),
            56 => self.event_queue.borrow_mut().push(ScrollWindowEvent(Point2D(0.0, 5.0 as f32), Point2D(0.0 as i32, 5.0 as i32))),
            50 => self.event_queue.borrow_mut().push(ScrollWindowEvent(Point2D(0.0, -5.0 as f32), Point2D(0.0 as i32, -5.0 as i32))),
            127 => {
                if (modifiers & ACTIVE_SHIFT) != 0 {
                    self.event_queue.borrow_mut().push(NavigationWindowEvent(Forward));
                }
                else {
                    self.event_queue.borrow_mut().push(NavigationWindowEvent(Back));
                }
            }
            _ => {}
        }
    }

    /// Helper function to handle a click
    fn handle_mouse(&self, button: c_int, state: c_int, x: c_int, y: c_int) {
        // FIXME(tkuehn): max pixel dist should be based on pixel density
        let max_pixel_dist = 10f32;
        let event = match state {
            glut::MOUSE_DOWN => {
                self.mouse_down_point.set(Point2D(x, y));
                self.mouse_down_button.set(button);
                MouseWindowMouseDownEvent(button as uint, Point2D(x as f32, y as f32))
            }
            glut::MOUSE_UP => {
                if self.mouse_down_button.get() == button {
                    let pixel_dist = self.mouse_down_point.get() - Point2D(x, y);
                    let pixel_dist = ((pixel_dist.x * pixel_dist.x +
                                       pixel_dist.y * pixel_dist.y) as f32).sqrt();
                    if pixel_dist < max_pixel_dist {
                        let click_event = MouseWindowClickEvent(button as uint,
                                                           Point2D(x as f32, y as f32));
                        self.event_queue.borrow_mut().push(MouseWindowEventClass(click_event));
                    }
                }
                MouseWindowMouseUpEvent(button as uint, Point2D(x as f32, y as f32))
            }
            _ => fail!("I cannot recognize the type of mouse action that occured. :-(")
        };
        self.event_queue.borrow_mut().push(MouseWindowEventClass(event));
    }

    /// Helper function to pop up an alert box prompting the user to load a URL.
    fn load_url(&self) {
        let mut alert: Alert = AlertMethods::new("Navigate to:");
        alert.add_prompt();
        alert.run();
        let value = alert.prompt_value();
        if "" == value {    // To avoid crashing on Linux.
            self.event_queue.borrow_mut().push(LoadUrlWindowEvent("http://purple.com/".to_owned()))
        } else {
            self.event_queue.borrow_mut().push(LoadUrlWindowEvent(value.clone()))
        }
    }
}

static TLS_KEY: local_data::Key<Rc<Window>> = &local_data::Key;

fn install_local_window(window: Rc<Window>) {
    local_data::set(TLS_KEY, window);
}

fn drop_local_window() {
    local_data::pop(TLS_KEY);
}

fn local_window() -> Rc<Window> {
    local_data::get(TLS_KEY, |v| v.unwrap().clone())
}
<|endoftext|>


<commit_before>// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use namespace::Namespace;
use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
use rustc::hir;
use rustc::hir::itemlikevisit::ItemLikeVisitor;
use rustc::traits::{self, IntercrateMode, FutureCompatOverlapErrorKind};
use rustc::ty::TyCtxt;
use rustc::ty::relate::TraitObjectMode;

use lint;

pub fn crate_inherent_impls_overlap_check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                                    crate_num: CrateNum) {
    assert_eq!(crate_num, LOCAL_CRATE);
    let krate = tcx.hir().krate();
    krate.visit_all_item_likes(&mut InherentOverlapChecker { tcx });
}

struct InherentOverlapChecker<'a, 'tcx: 'a> {
    tcx: TyCtxt<'a, 'tcx, 'tcx>
}

impl<'a, 'tcx> InherentOverlapChecker<'a, 'tcx> {
    fn check_for_common_items_in_impls(
        &self, impl1: DefId, impl2: DefId,
        overlap: traits::OverlapResult,
        used_to_be_allowed: Option<FutureCompatOverlapErrorKind>)
    {

        let name_and_namespace = |def_id| {
            let item = self.tcx.associated_item(def_id);
            (item.ident, Namespace::from(item.kind))
        };

        let impl_items1 = self.tcx.associated_item_def_ids(impl1);
        let impl_items2 = self.tcx.associated_item_def_ids(impl2);

        for &item1 in &impl_items1[..] {
            let (name, namespace) = name_and_namespace(item1);

            for &item2 in &impl_items2[..] {
                if (name, namespace) == name_and_namespace(item2) {
                    let node_id = self.tcx.hir().as_local_node_id(impl1);
                    let mut err = match used_to_be_allowed {
                        Some(kind) if node_id.is_some() => {
                            let lint = match kind {
                                FutureCompatOverlapErrorKind::Issue43355 =>
                                    lint::builtin::INCOHERENT_FUNDAMENTAL_IMPLS,
                                FutureCompatOverlapErrorKind::Issue33140 =>
                                    lint::builtin::ORDER_DEPENDENT_TRAIT_OBJECTS,
                            };
                            self.tcx.struct_span_lint_node(
                                lint,
                                node_id.unwrap(),
                                self.tcx.span_of_impl(item1).unwrap(),
                                &format!("duplicate definitions with name `{}` (E0592)", name)
                            )
                        }
                        _ => {
                            struct_span_err!(self.tcx.sess,
                                             self.tcx.span_of_impl(item1).unwrap(),
                                             E0592,
                                             "duplicate definitions with name `{}`",
                                             name)
                        }
                    };

                    err.span_label(self.tcx.span_of_impl(item1).unwrap(),
                                   format!("duplicate definitions for `{}`", name));
                    err.span_label(self.tcx.span_of_impl(item2).unwrap(),
                                   format!("other definition for `{}`", name));

                    for cause in &overlap.intercrate_ambiguity_causes {
                        cause.add_intercrate_ambiguity_hint(&mut err);
                    }

                    err.emit();
                }
            }
        }
    }

    fn check_for_overlapping_inherent_impls(&self, ty_def_id: DefId) {
        let impls = self.tcx.inherent_impls(ty_def_id);

        for (i, &impl1_def_id) in impls.iter().enumerate() {
            for &impl2_def_id in &impls[(i + 1)..] {
                let mut used_to_be_allowed = traits::overlapping_impls(
                    self.tcx,
                    impl1_def_id,
                    impl2_def_id,
                    IntercrateMode::Issue43355,
                    TraitObjectMode::NoSquash,
                    |overlap| {
                        self.check_for_common_items_in_impls(
                            impl1_def_id,
                            impl2_def_id,
                            overlap,
                            Some(FutureCompatOverlapErrorKind::Issue43355),
                        );
                        false
                    },
                    || true,
                );

                if used_to_be_allowed {
                    used_to_be_allowed = traits::overlapping_impls(
                        self.tcx,
                        impl1_def_id,
                        impl2_def_id,
                        IntercrateMode::Fixed,
                        TraitObjectMode::NoSquash,
                        |overlap| {
                            self.check_for_common_items_in_impls(
                                impl1_def_id,
                                impl2_def_id,
                                overlap,
                                None,
                            );
                            false
                        },
                        || true,
                    );
                }

                if used_to_be_allowed {
                    traits::overlapping_impls(
                        self.tcx,
                        impl1_def_id,
                        impl2_def_id,
                        IntercrateMode::Fixed,
                        TraitObjectMode::SquashAutoTraitsIssue33140,
                        |overlap| {
                            self.check_for_common_items_in_impls(
                                impl1_def_id,
                                impl2_def_id,
                                overlap,
                                Some(FutureCompatOverlapErrorKind::Issue33140),
                            );
                            false
                        },
                        || true,
                    );
                }
            }
        }
    }
}

impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentOverlapChecker<'a, 'tcx> {
    fn visit_item(&mut self, item: &'v hir::Item) {
        match item.node {
            hir::ItemKind::Enum(..) |
            hir::ItemKind::Struct(..) |
            hir::ItemKind::Trait(..) |
            hir::ItemKind::Union(..) => {
                let type_def_id = self.tcx.hir().local_def_id(item.id);
                self.check_for_overlapping_inherent_impls(type_def_id);
            }
            _ => {}
        }
    }

    fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
    }

    fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
    }
}
<commit_msg>fix stupid bug<commit_after>// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use namespace::Namespace;
use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
use rustc::hir;
use rustc::hir::itemlikevisit::ItemLikeVisitor;
use rustc::traits::{self, IntercrateMode, FutureCompatOverlapErrorKind};
use rustc::ty::TyCtxt;
use rustc::ty::relate::TraitObjectMode;

use lint;

pub fn crate_inherent_impls_overlap_check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                                    crate_num: CrateNum) {
    assert_eq!(crate_num, LOCAL_CRATE);
    let krate = tcx.hir().krate();
    krate.visit_all_item_likes(&mut InherentOverlapChecker { tcx });
}

struct InherentOverlapChecker<'a, 'tcx: 'a> {
    tcx: TyCtxt<'a, 'tcx, 'tcx>
}

impl<'a, 'tcx> InherentOverlapChecker<'a, 'tcx> {
    fn check_for_common_items_in_impls(
        &self, impl1: DefId, impl2: DefId,
        overlap: traits::OverlapResult,
        used_to_be_allowed: Option<FutureCompatOverlapErrorKind>)
    {

        let name_and_namespace = |def_id| {
            let item = self.tcx.associated_item(def_id);
            (item.ident, Namespace::from(item.kind))
        };

        let impl_items1 = self.tcx.associated_item_def_ids(impl1);
        let impl_items2 = self.tcx.associated_item_def_ids(impl2);

        for &item1 in &impl_items1[..] {
            let (name, namespace) = name_and_namespace(item1);

            for &item2 in &impl_items2[..] {
                if (name, namespace) == name_and_namespace(item2) {
                    let node_id = self.tcx.hir().as_local_node_id(impl1);
                    let mut err = match used_to_be_allowed {
                        Some(kind) if node_id.is_some() => {
                            let lint = match kind {
                                FutureCompatOverlapErrorKind::Issue43355 =>
                                    lint::builtin::INCOHERENT_FUNDAMENTAL_IMPLS,
                                FutureCompatOverlapErrorKind::Issue33140 =>
                                    lint::builtin::ORDER_DEPENDENT_TRAIT_OBJECTS,
                            };
                            self.tcx.struct_span_lint_node(
                                lint,
                                node_id.unwrap(),
                                self.tcx.span_of_impl(item1).unwrap(),
                                &format!("duplicate definitions with name `{}` (E0592)", name)
                            )
                        }
                        _ => {
                            struct_span_err!(self.tcx.sess,
                                             self.tcx.span_of_impl(item1).unwrap(),
                                             E0592,
                                             "duplicate definitions with name `{}`",
                                             name)
                        }
                    };

                    err.span_label(self.tcx.span_of_impl(item1).unwrap(),
                                   format!("duplicate definitions for `{}`", name));
                    err.span_label(self.tcx.span_of_impl(item2).unwrap(),
                                   format!("other definition for `{}`", name));

                    for cause in &overlap.intercrate_ambiguity_causes {
                        cause.add_intercrate_ambiguity_hint(&mut err);
                    }

                    err.emit();
                }
            }
        }
    }

    fn check_for_overlapping_inherent_impls(&self, ty_def_id: DefId) {
        let impls = self.tcx.inherent_impls(ty_def_id);

        for (i, &impl1_def_id) in impls.iter().enumerate() {
            for &impl2_def_id in &impls[(i + 1)..] {
                // First, check if the impl was forbidden under the
                // old rules. In that case, just have an error.
                let used_to_be_allowed = traits::overlapping_impls(
                    self.tcx,
                    impl1_def_id,
                    impl2_def_id,
                    IntercrateMode::Issue43355,
                    TraitObjectMode::NoSquash,
                    |overlap| {
                        self.check_for_common_items_in_impls(
                            impl1_def_id,
                            impl2_def_id,
                            overlap,
                            None,
                        );
                        false
                    },
                    || true,
                );

                if !used_to_be_allowed {
                    continue;
                }

                // Then, check if the impl was forbidden under only
                // #43355. In that case, emit an #43355 error.
                let used_to_be_allowed = traits::overlapping_impls(
                    self.tcx,
                    impl1_def_id,
                    impl2_def_id,
                    IntercrateMode::Fixed,
                    TraitObjectMode::NoSquash,
                    |overlap| {
                        self.check_for_common_items_in_impls(
                            impl1_def_id,
                            impl2_def_id,
                            overlap,
                            Some(FutureCompatOverlapErrorKind::Issue43355),
                        );
                        false
                    },
                    || true,
                );

                if !used_to_be_allowed {
                    continue;
                }

                // Then, check if the impl was forbidden under
                // #33140. In that case, emit a #33140 error.
                traits::overlapping_impls(
                    self.tcx,
                    impl1_def_id,
                    impl2_def_id,
                    IntercrateMode::Fixed,
                    TraitObjectMode::SquashAutoTraitsIssue33140,
                    |overlap| {
                        self.check_for_common_items_in_impls(
                            impl1_def_id,
                            impl2_def_id,
                            overlap,
                            Some(FutureCompatOverlapErrorKind::Issue33140),
                        );
                        false
                    },
                    || true,
                );
            }
        }
    }
}

impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentOverlapChecker<'a, 'tcx> {
    fn visit_item(&mut self, item: &'v hir::Item) {
        match item.node {
            hir::ItemKind::Enum(..) |
            hir::ItemKind::Struct(..) |
            hir::ItemKind::Trait(..) |
            hir::ItemKind::Union(..) => {
                let type_def_id = self.tcx.hir().local_def_id(item.id);
                self.check_for_overlapping_inherent_impls(type_def_id);
            }
            _ => {}
        }
    }

    fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
    }

    fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
    }
}
<|endoftext|>


<commit_before>// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// ignore-android: FIXME(#10381)

// compile-flags:-g1

// Make sure functions have proper names
// debugger:info functions
// check:static void limited-debuginfo::main();
// check:static void limited-debuginfo::some_function();
// check:static void limited-debuginfo::some_other_function();
// check:static void limited-debuginfo::zzz();

// debugger:rbreak zzz
// debugger:run

// Make sure there is no information about locals
// debugger:finish
// debugger:info locals
// check:No locals.
// debugger:continue

#[allow(unused_variable)];

struct Struct {
    a: i64,
    b: i32
}

fn main() {
    some_function(101, 202);
}

fn zzz() {()}

fn some_function(a: int, b: int) {
    let some_variable = Struct { a: 11, b: 22 };
    let some_other_variable = 23;
    zzz();
}

fn some_other_function(a: int, b: int) -> bool { true }<commit_msg>test: Relax a debuginfo test<commit_after>// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// ignore-android: FIXME(#10381)

// compile-flags:-g1

// Make sure functions have proper names
// debugger:info functions
// check:static void [...]main();
// check:static void [...]some_function();
// check:static void [...]some_other_function();
// check:static void [...]zzz();

// debugger:rbreak zzz
// debugger:run

// Make sure there is no information about locals
// debugger:finish
// debugger:info locals
// check:No locals.
// debugger:continue

#[allow(unused_variable)];

struct Struct {
    a: i64,
    b: i32
}

fn main() {
    some_function(101, 202);
}

fn zzz() {()}

fn some_function(a: int, b: int) {
    let some_variable = Struct { a: 11, b: 22 };
    let some_other_variable = 23;
    zzz();
}

fn some_other_function(a: int, b: int) -> bool { true }
<|endoftext|>


<commit_before>#![cfg_attr(test, allow(dead_code))]
#![cfg_attr(nightly, feature(scoped))]

extern crate unicode_width;

mod args;
mod matching;
mod screen;
mod version;
#[cfg(not(windows))] mod ansi;

use version::*;
use std::collections::HashSet;
use std::process;
use std::io::{stdin, BufRead};
use std::cmp::min;
use screen::Screen;
use screen::Key;
use screen::Key::*;
use self::SearchState::*;
use unicode_width::UnicodeWidthStr;

#[cfg(windows)] const NEWLINE: &'static str = "\r\n";
#[cfg(not(windows))] const NEWLINE: &'static str = "\n";

fn main() {
    let args = match args::parse_args() {
        Some(args) => args,
        None => {
            process::exit(1);
        },
    };

    if args.help { return; }

    if args.version {
        if COMMIT == "" {
            println!("heatseeker {} (built {})", VERSION, TIMESTAMP);
        } else {
            println!("heatseeker {} ({}) (built {})", VERSION, COMMIT, TIMESTAMP);
        }
        return;
    }

    let choices = read_choices();
    let initial_search = args.initial_search.clone();
    let choices = choices.iter().map(|x| &x[..]).collect::<Vec<&str>>();
    if args.use_first {
        let matches = matching::compute_matches(&choices, &initial_search);
        println!("{}", matches.get(0).unwrap_or(&""));
        return;
    } else {
        event_loop(&choices, &initial_search);
    }
}

fn event_loop(choices: &[&str], initial_search: &str) {
    let mut search = Search::new(choices, initial_search.to_string());
    let mut screen = Screen::open_screen();

    loop {
        search.recompute_matches();

        match search.state {
            InProgress => draw_screen(&mut screen, &search),
            _ => break,
        }

        let keys = screen.get_buffered_keys();
        for key in keys.iter() {
            handle_key(&mut search, key, screen.visible_choices);
        }
    }

    screen.move_cursor_to_bottom();
    println!("{}", search.get_selections());
}

fn handle_key(search: &mut Search, key: &Key, visible_choices: u16) {
    match *key {
        Char(x) => search.append(x),
        Backspace => search.backspace(),
        Control('h') => search.backspace(),
        Control('w') => search.delete_word(),
        Control('u') => search.clear_query(),
        Control('c') => search.cancel(),
        Control('g') => search.cancel(),
        Control('p') => search.up(visible_choices),
        Control('t') => { search.toggle_selection(); search.down(visible_choices); },
        Control('n') => search.down(visible_choices),
        Tab => search.down(visible_choices),
        Enter => search.done(),
        _ => {}
    }
}

struct Search<'a> {
    choices: &'a [&'a str],
    query: String,
    matches: Vec<&'a str>,
    stale: bool,
    index: usize,
    state: SearchState,
    selections: HashSet<String>,
}

#[derive(PartialEq, Eq)]
enum SearchState {
    InProgress,
    Done,
    Canceled,
}

impl<'a> Search<'a> {
    fn new(choices: &'a [&'a str], initial_search: String) -> Search<'a> {
        let matches = choices.to_vec();
        Search {
            choices: choices,
            query: initial_search,
            matches: matches,
            stale: true,
            index: 0,
            state: InProgress,
            selections: HashSet::new(),
        }
    }

    fn up(&mut self, visible_choices: u16) {
        let limit = min(visible_choices as usize - 1, self.matches.len() - 1);
        self.index = if self.index == 0 { limit } else { self.index - 1 };
    }

    fn down(&mut self, visible_choices: u16) {
        let limit = min(visible_choices as usize - 1, self.matches.len() - 1);
        self.index = if self.index == limit { 0 } else { self.index + 1 }
    }

    fn backspace(&mut self) {
        self.query.pop();
        self.stale = true;
        self.index = 0;
        self.matches = self.choices.to_vec();
    }

    fn delete_word(&mut self) {
        self.stale = true;
        delete_last_word(&mut self.query);
        self.matches = self.choices.to_vec();
    }

    fn append(&mut self, c: char) {
        self.query.push(c);
        self.stale = true;
        self.index = 0;
    }

    fn clear_query(&mut self) {
        self.query.clear();
        self.matches = self.choices.to_vec();
    }

    fn recompute_matches(&mut self) {
        if self.stale {
            self.matches = matching::compute_matches(&self.matches, &self.query);
            self.stale = false;
        }
    }

    fn toggle_selection(&mut self) {
        self.recompute_matches();
        let selection = self.matches.get(self.index).unwrap_or(&"").to_string();
        if self.selections.contains(&selection) {
            self.selections.remove(&selection);
        } else {
            self.selections.insert(selection);
        }
    }

    fn get_selections(&mut self) -> String {
        let mut ret = String::new();
        if self.state != Canceled {
            self.recompute_matches();
            let selection = self.matches.get(self.index).unwrap_or(&"").to_string();
            self.selections.insert(selection);
        }
        for selection in self.selections.iter() {
            ret.push_str(selection);
            ret.push_str(NEWLINE);
        }
        ret
    }

    fn cancel(&mut self) {
        self.state = Canceled
    }

    fn done(&mut self) {
        self.state = Done
    }
}

fn draw_screen(screen: &mut Screen, search: &Search) {
    screen.hide_cursor();
    screen.blank_screen();
    screen.write(&format!("> {} ({}/{} choices){}", search.query, search.matches.len(), search.choices.len(), NEWLINE));

    print_matches(screen, &search.matches, &search.query, search.index, &search.selections);

    let start = screen.start_line;
    let query_str: &str = &search.query;
    screen.move_cursor(start, 2 + UnicodeWidthStr::width(query_str) as u16);
    screen.show_cursor();
}

fn print_matches(screen: &mut Screen, matches: &[&str], query: &str, index: usize, selections: &HashSet<String>) {
    let mut i = 1;
    for choice in matches.iter() {
        let indices = matching::visual_score(choice, query);
        let max_width = screen.width;
        let mut annotated_choice = choice.to_string();
        if selections.contains(&annotated_choice) {
            annotated_choice.push(' ');
            if cfg!(windows) {
                annotated_choice.push('√');
            } else {
                annotated_choice.push('✓');
            }
        }
        print_match(&annotated_choice, &indices, max_width, &mut |s, highlight| {
            if i == index + 1 {
                if highlight { screen.write_red_inverted(s); } else { screen.write_inverted(s); }
            } else {
                if highlight { screen.write_red(s); } else { screen.write(s); }
            }
        });
        if i >= screen.visible_choices as usize {
            return;
        } else {
            screen.write(NEWLINE);
        }
        i += 1;
    }
}

fn print_match(choice: &str, indices: &[usize], max_width: u16, writer: &mut FnMut(&str, bool)) {
    #[cfg(windows)] const MARGIN: u16 = 1;
    #[cfg(not(windows))] const MARGIN: u16 = 0;
    let max_width = max_width - MARGIN;
    let chars_in_choice = choice.chars().count();
    let chars_to_draw = min(chars_in_choice, max_width as usize);
    let mut last_idx = 0;
    for &idx in indices {
        let idx = min(idx, chars_to_draw);
        if last_idx >= chars_to_draw {
            return;
        }
        writer(&slice_chars(choice, last_idx, idx), false);
        if idx == chars_to_draw { return }
        writer(&slice_chars(choice, idx, idx + 1), true);
        last_idx = idx + 1;
    }
    writer(&slice_chars(choice, last_idx, chars_to_draw), false);
}

fn read_choices() -> Vec<String> {
    let stdin = stdin();
    let mut lines = Vec::new();

    let mut stdin = stdin.lock();
    loop {
        let mut s = String::new();
        stdin.read_line(&mut s).unwrap();
        if s.len() == 0 {
            break;
        } else {
            trim(&mut s);
            lines.push(s);
        }
    }

    lines
}

pub fn trim(s: &mut String) {
    while let Some(x) = s.pop() {
        if x != '\n' && x != '\r' {
            s.push(x);
            return;
        }
    }
}

fn delete_last_word(s: &mut String) {
    let mut deleted_something = false;
    while let Some(x) = s.pop() {
        if x == ' ' {
            if deleted_something {
                s.push(x);
                return;
            }
        } else {
            deleted_something = true;
        }
    }
}

// This is technically a standard library function, but it's plastered with
// stability warnings and therefore only available on the nightly channel.
fn slice_chars(s: &str, begin: usize, end: usize) -> &str {
    assert!(begin <= end);
    let mut count = 0;
    let mut begin_byte = None;
    let mut end_byte = None;

    // This could be even more efficient by not decoding,
    // only finding the char boundaries
    for (idx, _) in s.char_indices() {
        if count == begin { begin_byte = Some(idx); }
        if count == end { end_byte = Some(idx); break; }
        count += 1;
    }
    if begin_byte.is_none() && count == begin { begin_byte = Some(s.len()) }
    if end_byte.is_none() && count == end { end_byte = Some(s.len()) }

    match (begin_byte, end_byte) {
        (None, _) => panic!("slice_chars: `begin` is beyond end of string"),
        (_, None) => panic!("slice_chars: `end` is beyond end of string"),
        (Some(a), Some(b)) => unsafe { s.slice_unchecked(a, b) }
    }
}

#[test]
fn trim_test() {
    fn should_become(before: &str, after: &str) {
        let mut x = before.to_string();
        trim(&mut x);
        assert_eq!(after.to_string(), x);
    }
    should_become("", "");
    should_become("\n", "");
    should_become("\n\n", "");
    should_become("asdf", "asdf");
    should_become("asdf\n", "asdf");
    should_become("asdf\nasdf\n", "asdf\nasdf");
    should_become("asdf\r\n", "asdf");
}

#[test]
fn delete_word_test() {
    fn should_become(before: &str, after: &str) {
        let mut x = before.to_string();
        delete_last_word(&mut x);
        assert_eq!(after.to_string(), x);
    }
    should_become("", "");
    should_become("a", "");
    should_become("asdf", "");
    should_become("asdf asdf asdf", "asdf asdf ");
    should_become("asdf asdf asdf ", "asdf asdf ");
    should_become("asdf asdf asdf  ", "asdf asdf ");
}
<commit_msg>Fix extra newline after making a selection interactively<commit_after>#![cfg_attr(test, allow(dead_code))]
#![cfg_attr(nightly, feature(scoped))]

extern crate unicode_width;

mod args;
mod matching;
mod screen;
mod version;
#[cfg(not(windows))] mod ansi;

use version::*;
use std::collections::HashSet;
use std::process;
use std::io::{stdin, BufRead};
use std::cmp::min;
use screen::Screen;
use screen::Key;
use screen::Key::*;
use self::SearchState::*;
use unicode_width::UnicodeWidthStr;

#[cfg(windows)] const NEWLINE: &'static str = "\r\n";
#[cfg(not(windows))] const NEWLINE: &'static str = "\n";

fn main() {
    let args = match args::parse_args() {
        Some(args) => args,
        None => {
            process::exit(1);
        },
    };

    if args.help { return; }

    if args.version {
        if COMMIT == "" {
            println!("heatseeker {} (built {})", VERSION, TIMESTAMP);
        } else {
            println!("heatseeker {} ({}) (built {})", VERSION, COMMIT, TIMESTAMP);
        }
        return;
    }

    let choices = read_choices();
    let initial_search = args.initial_search.clone();
    let choices = choices.iter().map(|x| &x[..]).collect::<Vec<&str>>();
    if args.use_first {
        let matches = matching::compute_matches(&choices, &initial_search);
        println!("{}", matches.get(0).unwrap_or(&""));
        return;
    } else {
        event_loop(&choices, &initial_search);
    }
}

fn event_loop(choices: &[&str], initial_search: &str) {
    let mut search = Search::new(choices, initial_search.to_string());
    let mut screen = Screen::open_screen();

    loop {
        search.recompute_matches();

        match search.state {
            InProgress => draw_screen(&mut screen, &search),
            _ => break,
        }

        let keys = screen.get_buffered_keys();
        for key in keys.iter() {
            handle_key(&mut search, key, screen.visible_choices);
        }
    }

    screen.move_cursor_to_bottom();
    print!("{}", search.get_selections());
}

fn handle_key(search: &mut Search, key: &Key, visible_choices: u16) {
    match *key {
        Char(x) => search.append(x),
        Backspace => search.backspace(),
        Control('h') => search.backspace(),
        Control('w') => search.delete_word(),
        Control('u') => search.clear_query(),
        Control('c') => search.cancel(),
        Control('g') => search.cancel(),
        Control('p') => search.up(visible_choices),
        Control('t') => { search.toggle_selection(); search.down(visible_choices); },
        Control('n') => search.down(visible_choices),
        Tab => search.down(visible_choices),
        Enter => search.done(),
        _ => {}
    }
}

struct Search<'a> {
    choices: &'a [&'a str],
    query: String,
    matches: Vec<&'a str>,
    stale: bool,
    index: usize,
    state: SearchState,
    selections: HashSet<String>,
}

#[derive(PartialEq, Eq)]
enum SearchState {
    InProgress,
    Done,
    Canceled,
}

impl<'a> Search<'a> {
    fn new(choices: &'a [&'a str], initial_search: String) -> Search<'a> {
        let matches = choices.to_vec();
        Search {
            choices: choices,
            query: initial_search,
            matches: matches,
            stale: true,
            index: 0,
            state: InProgress,
            selections: HashSet::new(),
        }
    }

    fn up(&mut self, visible_choices: u16) {
        let limit = min(visible_choices as usize - 1, self.matches.len() - 1);
        self.index = if self.index == 0 { limit } else { self.index - 1 };
    }

    fn down(&mut self, visible_choices: u16) {
        let limit = min(visible_choices as usize - 1, self.matches.len() - 1);
        self.index = if self.index == limit { 0 } else { self.index + 1 }
    }

    fn backspace(&mut self) {
        self.query.pop();
        self.stale = true;
        self.index = 0;
        self.matches = self.choices.to_vec();
    }

    fn delete_word(&mut self) {
        self.stale = true;
        delete_last_word(&mut self.query);
        self.matches = self.choices.to_vec();
    }

    fn append(&mut self, c: char) {
        self.query.push(c);
        self.stale = true;
        self.index = 0;
    }

    fn clear_query(&mut self) {
        self.query.clear();
        self.matches = self.choices.to_vec();
    }

    fn recompute_matches(&mut self) {
        if self.stale {
            self.matches = matching::compute_matches(&self.matches, &self.query);
            self.stale = false;
        }
    }

    fn toggle_selection(&mut self) {
        self.recompute_matches();
        let selection = self.matches.get(self.index).unwrap_or(&"").to_string();
        if self.selections.contains(&selection) {
            self.selections.remove(&selection);
        } else {
            self.selections.insert(selection);
        }
    }

    fn get_selections(&mut self) -> String {
        let mut ret = String::new();
        if self.state != Canceled {
            self.recompute_matches();
            let selection = self.matches.get(self.index).unwrap_or(&"").to_string();
            self.selections.insert(selection);
        }
        for selection in self.selections.iter() {
            ret.push_str(selection);
            ret.push_str(NEWLINE);
        }
        ret
    }

    fn cancel(&mut self) {
        self.state = Canceled
    }

    fn done(&mut self) {
        self.state = Done
    }
}

fn draw_screen(screen: &mut Screen, search: &Search) {
    screen.hide_cursor();
    screen.blank_screen();
    screen.write(&format!("> {} ({}/{} choices){}", search.query, search.matches.len(), search.choices.len(), NEWLINE));

    print_matches(screen, &search.matches, &search.query, search.index, &search.selections);

    let start = screen.start_line;
    let query_str: &str = &search.query;
    screen.move_cursor(start, 2 + UnicodeWidthStr::width(query_str) as u16);
    screen.show_cursor();
}

fn print_matches(screen: &mut Screen, matches: &[&str], query: &str, index: usize, selections: &HashSet<String>) {
    let mut i = 1;
    for choice in matches.iter() {
        let indices = matching::visual_score(choice, query);
        let max_width = screen.width;
        let mut annotated_choice = choice.to_string();
        if selections.contains(&annotated_choice) {
            annotated_choice.push(' ');
            if cfg!(windows) {
                annotated_choice.push('√');
            } else {
                annotated_choice.push('✓');
            }
        }
        print_match(&annotated_choice, &indices, max_width, &mut |s, highlight| {
            if i == index + 1 {
                if highlight { screen.write_red_inverted(s); } else { screen.write_inverted(s); }
            } else {
                if highlight { screen.write_red(s); } else { screen.write(s); }
            }
        });
        if i >= screen.visible_choices as usize {
            return;
        } else {
            screen.write(NEWLINE);
        }
        i += 1;
    }
}

fn print_match(choice: &str, indices: &[usize], max_width: u16, writer: &mut FnMut(&str, bool)) {
    #[cfg(windows)] const MARGIN: u16 = 1;
    #[cfg(not(windows))] const MARGIN: u16 = 0;
    let max_width = max_width - MARGIN;
    let chars_in_choice = choice.chars().count();
    let chars_to_draw = min(chars_in_choice, max_width as usize);
    let mut last_idx = 0;
    for &idx in indices {
        let idx = min(idx, chars_to_draw);
        if last_idx >= chars_to_draw {
            return;
        }
        writer(&slice_chars(choice, last_idx, idx), false);
        if idx == chars_to_draw { return }
        writer(&slice_chars(choice, idx, idx + 1), true);
        last_idx = idx + 1;
    }
    writer(&slice_chars(choice, last_idx, chars_to_draw), false);
}

fn read_choices() -> Vec<String> {
    let stdin = stdin();
    let mut lines = Vec::new();

    let mut stdin = stdin.lock();
    loop {
        let mut s = String::new();
        stdin.read_line(&mut s).unwrap();
        if s.len() == 0 {
            break;
        } else {
            trim(&mut s);
            lines.push(s);
        }
    }

    lines
}

pub fn trim(s: &mut String) {
    while let Some(x) = s.pop() {
        if x != '\n' && x != '\r' {
            s.push(x);
            return;
        }
    }
}

fn delete_last_word(s: &mut String) {
    let mut deleted_something = false;
    while let Some(x) = s.pop() {
        if x == ' ' {
            if deleted_something {
                s.push(x);
                return;
            }
        } else {
            deleted_something = true;
        }
    }
}

// This is technically a standard library function, but it's plastered with
// stability warnings and therefore only available on the nightly channel.
fn slice_chars(s: &str, begin: usize, end: usize) -> &str {
    assert!(begin <= end);
    let mut count = 0;
    let mut begin_byte = None;
    let mut end_byte = None;

    // This could be even more efficient by not decoding,
    // only finding the char boundaries
    for (idx, _) in s.char_indices() {
        if count == begin { begin_byte = Some(idx); }
        if count == end { end_byte = Some(idx); break; }
        count += 1;
    }
    if begin_byte.is_none() && count == begin { begin_byte = Some(s.len()) }
    if end_byte.is_none() && count == end { end_byte = Some(s.len()) }

    match (begin_byte, end_byte) {
        (None, _) => panic!("slice_chars: `begin` is beyond end of string"),
        (_, None) => panic!("slice_chars: `end` is beyond end of string"),
        (Some(a), Some(b)) => unsafe { s.slice_unchecked(a, b) }
    }
}

#[test]
fn trim_test() {
    fn should_become(before: &str, after: &str) {
        let mut x = before.to_string();
        trim(&mut x);
        assert_eq!(after.to_string(), x);
    }
    should_become("", "");
    should_become("\n", "");
    should_become("\n\n", "");
    should_become("asdf", "asdf");
    should_become("asdf\n", "asdf");
    should_become("asdf\nasdf\n", "asdf\nasdf");
    should_become("asdf\r\n", "asdf");
}

#[test]
fn delete_word_test() {
    fn should_become(before: &str, after: &str) {
        let mut x = before.to_string();
        delete_last_word(&mut x);
        assert_eq!(after.to_string(), x);
    }
    should_become("", "");
    should_become("a", "");
    should_become("asdf", "");
    should_become("asdf asdf asdf", "asdf asdf ");
    should_become("asdf asdf asdf ", "asdf asdf ");
    should_become("asdf asdf asdf  ", "asdf asdf ");
}
<|endoftext|>


<commit_before>use crate::{channels::Channels, Result};
use parking_lot::Mutex;
use std::{
    sync::Arc,
    time::{Duration, Instant},
};

#[derive(Clone)]
pub struct Heartbeat {
    channels: Channels,
    inner: Arc<Mutex<Inner>>,
}

impl Heartbeat {
    pub(crate) fn new(channels: Channels) -> Self {
        let inner = Default::default();
        Self { channels, inner }
    }

    pub(crate) fn set_timeout(&self, timeout: Duration) {
        self.inner.lock().timeout = Some(timeout);
    }

    pub fn poll_timeout(&self) -> Result<Option<Duration>> {
        self.inner.lock().poll_timeout(&self.channels)
    }

    pub(crate) fn update_last_write(&self) {
        self.inner.lock().update_last_write();
    }
}

struct Inner {
    last_write: Instant,
    timeout: Option<Duration>,
}

impl Default for Inner {
    fn default() -> Self {
        Self {
            last_write: Instant::now(),
            timeout: None,
        }
    }
}

impl Inner {
    fn poll_timeout(&mut self, channels: &Channels) -> Result<Option<Duration>> {
        self.timeout
            .map(|timeout| {
                timeout
                    .checked_sub(self.last_write.elapsed())
                    .map(Ok)
                    .unwrap_or_else(|| {
                        // Update last_write so that if we cannot write to the socket yet, we don't enqueue countless heartbeats
                        self.update_last_write();
                        channels.send_heartbeat()?;
                        Ok(timeout)
                    })
            })
            .transpose()
    }

    fn update_last_write(&mut self) {
        self.last_write = Instant::now();
    }
}
<commit_msg>heartbeat: make sure everything needed is in the public API<commit_after>use crate::{channels::Channels, Result};
use parking_lot::Mutex;
use std::{
    sync::Arc,
    time::{Duration, Instant},
};

#[derive(Clone)]
pub struct Heartbeat {
    channels: Channels,
    inner: Arc<Mutex<Inner>>,
}

impl Heartbeat {
    pub(crate) fn new(channels: Channels) -> Self {
        let inner = Default::default();
        Self { channels, inner }
    }

    pub(crate) fn set_timeout(&self, timeout: Duration) {
        self.inner.lock().timeout = Some(timeout);
    }

    pub fn get_heartbeat(&self) -> Option<Duration> {
        self.inner.lock().timeout
    }

    pub fn poll_timeout(&self) -> Result<Option<Duration>> {
        self.inner.lock().poll_timeout(&self.channels)
    }

    pub fn send(&self) -> Result<()> {
        self.channels.send_heartbeat()
    }

    pub(crate) fn update_last_write(&self) {
        self.inner.lock().update_last_write();
    }
}

struct Inner {
    last_write: Instant,
    timeout: Option<Duration>,
}

impl Default for Inner {
    fn default() -> Self {
        Self {
            last_write: Instant::now(),
            timeout: None,
        }
    }
}

impl Inner {
    fn poll_timeout(&mut self, channels: &Channels) -> Result<Option<Duration>> {
        self.timeout
            .map(|timeout| {
                timeout
                    .checked_sub(self.last_write.elapsed())
                    .map(Ok)
                    .unwrap_or_else(|| {
                        // Update last_write so that if we cannot write to the socket yet, we don't enqueue countless heartbeats
                        self.update_last_write();
                        channels.send_heartbeat()?;
                        Ok(timeout)
                    })
            })
            .transpose()
    }

    fn update_last_write(&mut self) {
        self.last_write = Instant::now();
    }
}
<|endoftext|>