<commit_before>//! The interface for interacting with TMUX sessions. All the commands that are
/// built up during the parsing phase get matched to functions here. The
/// functions in this module all build up strings the get passed to a private
/// call. The private call converts them to CStrings and makes an "unsafe" system
/// call. All functions go through this `call` function as a common gateway to
/// system calls and can all be easily logged there.

pub mod config;

use libc::system;
use std::ffi::CString;
use std::process::{Command, ExitStatus, Output};
use std::io;

/// The program to call commands on.
static TMUX_NAME: &'static str = "tmux";

/// The gateway to calling any functions on tmux. Most public functions in this
/// module will be fed through this `call` function. This safely creates a new
/// thread to execute the command on. We say "Most" public functions will use
/// this as `attach` specificaly does not use it.
///
/// args: The command we will send to tmux on the host system for execution.
///
/// # Examples
///
/// ```
/// let _ = call(&["new-window", "-t", "muxed", "-c", "~/Projects/muxed/"]);
/// ```
fn call(args: &[&str]) -> Result<Output, io::Error> {
    //println!("{:?}", &args);
    Command::new(TMUX_NAME).args(args).output()
}

/// Attach is called as the last function in a set of commands. After the tmux
/// env has been setup by all previous commands this attaches the user to their
/// daemonized tmux session.
///
/// # Examples
///
/// ```
/// let session_name = "muxed".to_string();
/// tmux::attach(muxed);
/// ```
/// session_name: The active tmux session name.
pub fn attach(session_name: &String) -> () {
    let line = format!("{} attach -t {} {}", TMUX_NAME, session_name, ">/dev/null");
    let system_call = CString::new(line.clone()).unwrap();
    //println!("{}", line.clone());
    unsafe { system(system_call.as_ptr()); };
}

/// New session is the first call made in any sequence of commands. It initiates
/// a new tmux session with a default first window name.
/// *Why a randomized first window name?*
///   This is because the `new-session` tmux command does not support the `-c`
/// flag as `new-window` and `split-window` do. So if the first window requires
/// being changed to a default directory `send-keys` must be used after the
/// session and first window are opened. This means the first window is treated in
/// a different code path than any other window that is opened.
/// Instead I've opted to open the session with a randomized (no conflicts)
/// named window, and we close this window out before attaching the user. This
/// allows for us to treat all user defined windows the same.
///
/// session_name: The name of the session being created.
/// tmp_name: The named first window that we will close out.
///
/// # Examples
///
/// ```
/// use rand::random;
///
/// let session_name = "muxed".to_string();
/// let tmp_window_name = random::<u16>().to_string();
/// tmux::new_session(session_name, tmp_window_name);
/// ```
///
/// session_name: The active tmux session name.
/// tmp_name: The name for the temp initial window that is created with a new
/// session.
pub fn new_session(session_name: &String, window_name: &String) -> () {
    let _ = call(&["new", "-d", "-s", session_name, "-n", window_name]);
}

/// Split window acts as the command to target named windows in a session to
/// send a make separate a single pane into two panes. Split window should target
/// a specific pane even if only a single pane exists.
///
/// # Examples
///
/// ```
/// let target = "muxed:cargo.0".to_string();
/// tmux::split_window(target, None);
/// ```
///
/// target: A string represented by the {named_session}:{named_window}.{pane}
/// root: An `Option<String>` passed to the -c argument to change the current
/// directory.
pub fn split_window(target: &String) -> () {
    let _ = call(&["split-window", "-t", target]);
}

/// New window opens a new window in the named session with the provided window
/// name.
///
/// # Examples
///
/// ```
/// tmux::new_window("muxed".to_string(), "vim".to_string(), None);
/// ```
///
/// session_name: The active tmux session name.
/// window_name: The desired window name for the new window.
/// root: An `Option<String>` passed to the -c argument to change the current
/// directory.
pub fn new_window(session_name: &String, window_name: &String) -> () {
    let _ = call(&["new-window", "-t", session_name, "-n", window_name]);
}

/// The layout function will adjust the layout of a tmux window that already has
/// multiple panes. Currently it will only accept standard tmux layout types.
///
/// Possible layout options: even-horizontal, even-vertical, main-horizontal,
/// main-vertical, or tiled.
///
/// # Examples
///
/// ```
/// tmux::layout("muxed:cargo.0".to_string(), "main-vertical".to_string(), None);
/// ```
///
/// target: A string represented by the {named_session}:{named_window}.{pane}
/// layout: The predefined tmux named layout.
pub fn layout(target: &String, layout: &String) -> () {
    let _ = call(&["select-layout", "-t", target, layout]);
}

/// Send Keys executes literal key commands in specified target windows. This is
/// the execution method to perform actions like tailing logs, starting servers,
/// or opening editors.
///
/// `KPEnter` represent the keyboard press of the "Enter" key. So the execution
/// is a user input command followed by "enter"
///
/// # Examples
///
/// ```
/// tmux::send_keys("muxed:cargo.0".to_string(), "vim .".to_string());
/// ```
///
/// target: A string represented by the {named_session}:{named_window}.{pane}
/// exec: The system command to be executed in a particular pane.
pub fn send_keys(target: &String, exec: &String) -> () {
    let _ = call(&["send-keys", "-t", target, exec, "KPEnter"]);
}

/// This is used to re-select the first window before
/// attaching to the session.
///
/// # Examples
///
/// ```
/// tmux::select_window("muxed:cargo.0".to_string());
/// ```
///
/// target: A string represented by the {named_session}:{named_window}.{pane}
pub fn select_window(target: &String) -> () {
    let _ = call(&["select-window", "-t", target]);
}

/// This is used to re-select the top pane in the first window before
/// attaching to the session.
///
/// # Examples
///
/// ```
/// tmux::select_pane("muxed:cargo.top".to_string());
/// ```
///
/// target: A string represented by the {named_session}:{named_window}.{pane}
pub fn select_pane(target: &String) -> () {
    let _ = call(&["select-pane", "-t", target]);
}

/// List Windows is used firgure out if a named session is already running.
///
/// # Examples
///
/// ```
/// tmux::has_session("muxed".to_string());
/// => ExitStatus
/// ```
///
/// target: A string represented by the {named_session}
pub fn has_session(target: &String) -> ExitStatus {
    let output = call(&["has-session", "-t", target]).expect("failed to see if the session existed");
    output.status
}

/// Read the tmux config and return a config object
///
/// # Examples
///
/// ```
/// tmux::get_config();
/// => "some-option false\npane-base-index 0"
/// ```
pub fn get_config() -> String {
    let output = call(&["start-server", ";", "show-options", "-g"]).expect("couldn't get tmux options");
    String::from_utf8_lossy(&output.stdout).to_string()
}
<commit_msg>fix(Attach): Attach to named sessions with spaces<commit_after>//! The interface for interacting with TMUX sessions. All the commands that are
/// built up during the parsing phase get matched to functions here. The
/// functions in this module all build up strings the get passed to a private
/// call. The private call converts them to CStrings and makes an "unsafe" system
/// call. All functions go through this `call` function as a common gateway to
/// system calls and can all be easily logged there.

pub mod config;

use libc::system;
use std::ffi::CString;
use std::process::{Command, ExitStatus, Output};
use std::io;

/// The program to call commands on.
static TMUX_NAME: &'static str = "tmux";

/// The gateway to calling any functions on tmux. Most public functions in this
/// module will be fed through this `call` function. This safely creates a new
/// thread to execute the command on. We say "Most" public functions will use
/// this as `attach` specificaly does not use it.
///
/// args: The command we will send to tmux on the host system for execution.
///
/// # Examples
///
/// ```
/// let _ = call(&["new-window", "-t", "muxed", "-c", "~/Projects/muxed/"]);
/// ```
fn call(args: &[&str]) -> Result<Output, io::Error> {
    //println!("{:?}", &args);
    Command::new(TMUX_NAME).args(args).output()
}

/// Attach is called as the last function in a set of commands. After the tmux
/// env has been setup by all previous commands this attaches the user to their
/// daemonized tmux session.
///
/// # Examples
///
/// ```
/// let session_name = "muxed".to_string();
/// tmux::attach(muxed);
/// ```
/// session_name: The active tmux session name.
pub fn attach(session_name: &String) -> () {
    let line = format!("{} attach -t '{}' {}", TMUX_NAME, session_name, ">/dev/null");
    let system_call = CString::new(line.clone()).unwrap();
    //println!("{}", line.clone());
    unsafe { system(system_call.as_ptr()); };
}

/// New session is the first call made in any sequence of commands. It initiates
/// a new tmux session with a default first window name.
/// *Why a randomized first window name?*
///   This is because the `new-session` tmux command does not support the `-c`
/// flag as `new-window` and `split-window` do. So if the first window requires
/// being changed to a default directory `send-keys` must be used after the
/// session and first window are opened. This means the first window is treated in
/// a different code path than any other window that is opened.
/// Instead I've opted to open the session with a randomized (no conflicts)
/// named window, and we close this window out before attaching the user. This
/// allows for us to treat all user defined windows the same.
///
/// session_name: The name of the session being created.
/// tmp_name: The named first window that we will close out.
///
/// # Examples
///
/// ```
/// use rand::random;
///
/// let session_name = "muxed".to_string();
/// let tmp_window_name = random::<u16>().to_string();
/// tmux::new_session(session_name, tmp_window_name);
/// ```
///
/// session_name: The active tmux session name.
/// tmp_name: The name for the temp initial window that is created with a new
/// session.
pub fn new_session(session_name: &String, window_name: &String) -> () {
    let _ = call(&["new", "-d", "-s", session_name, "-n", window_name]);
}

/// Split window acts as the command to target named windows in a session to
/// send a make separate a single pane into two panes. Split window should target
/// a specific pane even if only a single pane exists.
///
/// # Examples
///
/// ```
/// let target = "muxed:cargo.0".to_string();
/// tmux::split_window(target, None);
/// ```
///
/// target: A string represented by the {named_session}:{named_window}.{pane}
/// root: An `Option<String>` passed to the -c argument to change the current
/// directory.
pub fn split_window(target: &String) -> () {
    let _ = call(&["split-window", "-t", target]);
}

/// New window opens a new window in the named session with the provided window
/// name.
///
/// # Examples
///
/// ```
/// tmux::new_window("muxed".to_string(), "vim".to_string(), None);
/// ```
///
/// session_name: The active tmux session name.
/// window_name: The desired window name for the new window.
/// root: An `Option<String>` passed to the -c argument to change the current
/// directory.
pub fn new_window(session_name: &String, window_name: &String) -> () {
    let _ = call(&["new-window", "-t", session_name, "-n", window_name]);
}

/// The layout function will adjust the layout of a tmux window that already has
/// multiple panes. Currently it will only accept standard tmux layout types.
///
/// Possible layout options: even-horizontal, even-vertical, main-horizontal,
/// main-vertical, or tiled.
///
/// # Examples
///
/// ```
/// tmux::layout("muxed:cargo.0".to_string(), "main-vertical".to_string(), None);
/// ```
///
/// target: A string represented by the {named_session}:{named_window}.{pane}
/// layout: The predefined tmux named layout.
pub fn layout(target: &String, layout: &String) -> () {
    let _ = call(&["select-layout", "-t", target, layout]);
}

/// Send Keys executes literal key commands in specified target windows. This is
/// the execution method to perform actions like tailing logs, starting servers,
/// or opening editors.
///
/// `KPEnter` represent the keyboard press of the "Enter" key. So the execution
/// is a user input command followed by "enter"
///
/// # Examples
///
/// ```
/// tmux::send_keys("muxed:cargo.0".to_string(), "vim .".to_string());
/// ```
///
/// target: A string represented by the {named_session}:{named_window}.{pane}
/// exec: The system command to be executed in a particular pane.
pub fn send_keys(target: &String, exec: &String) -> () {
    let _ = call(&["send-keys", "-t", target, exec, "KPEnter"]);
}

/// This is used to re-select the first window before
/// attaching to the session.
///
/// # Examples
///
/// ```
/// tmux::select_window("muxed:cargo.0".to_string());
/// ```
///
/// target: A string represented by the {named_session}:{named_window}.{pane}
pub fn select_window(target: &String) -> () {
    let _ = call(&["select-window", "-t", target]);
}

/// This is used to re-select the top pane in the first window before
/// attaching to the session.
///
/// # Examples
///
/// ```
/// tmux::select_pane("muxed:cargo.top".to_string());
/// ```
///
/// target: A string represented by the {named_session}:{named_window}.{pane}
pub fn select_pane(target: &String) -> () {
    let _ = call(&["select-pane", "-t", target]);
}

/// List Windows is used firgure out if a named session is already running.
///
/// # Examples
///
/// ```
/// tmux::has_session("muxed".to_string());
/// => ExitStatus
/// ```
///
/// target: A string represented by the {named_session}
pub fn has_session(target: &String) -> ExitStatus {
    let output = call(&["has-session", "-t", target]).expect("failed to see if the session existed");
    output.status
}

/// Read the tmux config and return a config object
///
/// # Examples
///
/// ```
/// tmux::get_config();
/// => "some-option false\npane-base-index 0"
/// ```
pub fn get_config() -> String {
    let output = call(&["start-server", ";", "show-options", "-g"]).expect("couldn't get tmux options");
    String::from_utf8_lossy(&output.stdout).to_string()
}
<|endoftext|>


<commit_before>//! The interface for interacting with TMUX sessions. All the commands that are
/// built up during the parsing phase get matched to functions here. The
/// functions in this module all build up strings the get passed to a private
/// call. The private call converts them to CStrings and makes an "unsafe" system
/// call. All functions go through this `call` function as a common gateway to
/// system calls and can all be easily logged there.

pub mod config;

use libc::system;
use std::ffi::CString;
use std::process::{Command, ExitStatus, Output};
use std::io;

/// The program to call commands on.
static TMUX_NAME: &'static str = "tmux";

/// The gateway to calling any functions on tmux. Most public functions in this
/// module will be fed through this `call` function. This safely creates a new
/// thread to execute the command on. We say "Most" public functions will use
/// this as `attach` specificaly does not use it.
///
/// args: The command we will send to tmux on the host system for execution.
///
/// # Examples
///
/// ```
/// call(&["new-window", "-t", "muxed", "-c", "~/Projects/muxed/"]);
/// ```
fn call1(args: &[&str]) -> Result<Output, io::Error> {
    //println!("{}", line.clone());
    Command::new(TMUX_NAME).args(args).output()
}

/// Attach is called as the last function in a set of commands. After the tmux
/// env has been setup by all previous commands this attaches the user to their
/// daemonized tmux session.
///
/// # Examples
///
/// ```
/// let session_name = "muxed".to_string();
/// tmux::attach(muxed);
/// ```
/// session_name: The active tmux session name.
pub fn attach(session_name: &String) -> () {
    let line = format!("{} attach -t {} {}", TMUX_NAME, session_name, ">/dev/null");
    let system_call = CString::new(line.clone()).unwrap();
    //println!("{}", line.clone());
    unsafe { system(system_call.as_ptr()); };
}

/// New session is the first call made in any sequence of commands. It initiates
/// a new tmux session with a default first window name.
/// *Why a randomized first window name?*
///   This is because the `new-session` tmux command does not support the `-c`
/// flag as `new-window` and `split-window` do. So if the first window requires
/// being changed to a default directory `send-keys` must be used after the
/// session and first window are opened. This means the first window is treated in
/// a different code path than any other window that is opened.
/// Instead I've opted to open the session with a randomized (no conflicts)
/// named window, and we close this window out before attaching the user. This
/// allows for us to treat all user defined windows the same.
///
/// session_name: The name of the session being created.
/// tmp_name: The named first window that we will close out.
///
/// # Examples
///
/// ```
/// use rand::random;
///
/// let session_name = "muxed".to_string();
/// let tmp_window_name = random::<u16>().to_string();
/// tmux::new_session(session_name, tmp_window_name);
/// ```
///
/// session_name: The active tmux session name.
/// tmp_name: The name for the temp initial window that is created with a new
/// session.
pub fn new_session(session_name: &String, window_name: &String) -> () {
    //call(format!("new -d -s {} -n {}", session_name, window_name));
    call1(&["new", "-d", "-s", session_name, "-n", window_name]);
}

/// Split window acts as the command to target named windows in a session to
/// send a make separate a single pane into two panes. Split window should target
/// a specific pane even if only a single pane exists.
///
/// # Examples
///
/// ```
/// let target = "muxed:cargo.0".to_string();
/// tmux::split_window(target, None);
/// ```
///
/// target: A string represented by the {named_session}:{named_window}.{pane}
/// root: An `Option<String>` passed to the -c argument to change the current
/// directory.
pub fn split_window(target: &String) -> () {
    //call(format!("split-window -t {}", target));
    call1(&["split-window", "-t", target]);
}

/// New window opens a new window in the named session with the provided window
/// name.
///
/// # Examples
///
/// ```
/// tmux::new_window("muxed".to_string(), "vim".to_string(), None);
/// ```
///
/// session_name: The active tmux session name.
/// window_name: The desired window name for the new window.
/// root: An `Option<String>` passed to the -c argument to change the current
/// directory.
pub fn new_window(session_name: &String, window_name: &String) -> () {
    //call(format!("new-window -t {} -n {}", session_name, window_name));
    call1(&["new-window", "-t", session_name, "-n", window_name]);
}

/// The layout function will adjust the layout of a tmux window that already has
/// multiple panes. Currently it will only accept standard tmux layout types.
///
/// Possible layout options: even-horizontal, even-vertical, main-horizontal,
/// main-vertical, or tiled.
///
/// # Examples
///
/// ```
/// tmux::layout("muxed:cargo.0".to_string(), "main-vertical".to_string(), None);
/// ```
///
/// target: A string represented by the {named_session}:{named_window}.{pane}
/// layout: The predefined tmux named layout.
pub fn layout(target: &String, layout: &String) -> () {
    //call(format!("select-layout -t {} {}", target, layout));
    call1(&["select-layout", "-t", target, layout]);
}

/// Send Keys executes literal key commands in specified target windows. This is
/// the execution method to perform actions like tailing logs, starting servers,
/// or opening editors.
///
/// `KPEnter` represent the keyboard press of the "Enter" key. So the execution
/// is a user input command followed by "enter"
///
/// # Examples
///
/// ```
/// tmux::send_keys("muxed:cargo.0".to_string(), "vim .".to_string());
/// ```
///
/// target: A string represented by the {named_session}:{named_window}.{pane}
/// exec: The system command to be executed in a particular pane.
pub fn send_keys(target: &String, exec: &String) -> () {
    //call(format!("send-keys -t {} '{}' KPEnter", target, exec));
    call1(&["send-keys", "-t", target, exec, "KPEnter"]);
}

/// This is used to re-select the first window before
/// attaching to the session.
///
/// # Examples
///
/// ```
/// tmux::select_window("muxed:cargo.0".to_string());
/// ```
///
/// target: A string represented by the {named_session}:{named_window}.{pane}
pub fn select_window(target: &String) -> () {
    //call(format!("select-window -t {}", target));
    call1(&["select-window", "-t", target]);
}

/// This is used to re-select the top pane in the first window before
/// attaching to the session.
///
/// # Examples
///
/// ```
/// tmux::select_pane("muxed:cargo.top".to_string());
/// ```
///
/// target: A string represented by the {named_session}:{named_window}.{pane}
pub fn select_pane(target: &String) -> () {
    //call(format!("select-pane -t {}", target));
    call1(&["select-pane", "-t", target]);
}

/// List Windows is used firgure out if a named session is already running.
///
/// # Examples
///
/// ```
/// tmux::has_session("muxed".to_string());
/// => ExitStatus
/// ```
///
/// target: A string represented by the {named_session}
pub fn has_session(target: &String) -> ExitStatus {
    let output = Command::new(TMUX_NAME)
                     .arg("has-session")
                     .arg("-t")
                     .arg(target)
                     .output()
                     .unwrap_or_else(|e| { panic!("failed to execute process: {}", e) });

    output.status
}

/// Read the tmux config and return a config object
///
/// # Examples
///
/// ```
/// tmux::get_config();
/// => "some-option false\npane-base-index 0"
/// ```
pub fn get_config() -> String {
    let output = Command::new(TMUX_NAME)
                     .args(&["start-server", ";", "show-options", "-g"])
                     .output()
                     .unwrap_or_else(|e| { panic!("couldn't get tmux options: {}", e) });

    String::from_utf8_lossy(&output.stdout).to_string()
}
<commit_msg>refactor(tmux/mod.rs): Use new call for output<commit_after>//! The interface for interacting with TMUX sessions. All the commands that are
/// built up during the parsing phase get matched to functions here. The
/// functions in this module all build up strings the get passed to a private
/// call. The private call converts them to CStrings and makes an "unsafe" system
/// call. All functions go through this `call` function as a common gateway to
/// system calls and can all be easily logged there.

pub mod config;

use libc::system;
use std::ffi::CString;
use std::process::{Command, ExitStatus, Output};
use std::io;

/// The program to call commands on.
static TMUX_NAME: &'static str = "tmux";

/// The gateway to calling any functions on tmux. Most public functions in this
/// module will be fed through this `call` function. This safely creates a new
/// thread to execute the command on. We say "Most" public functions will use
/// this as `attach` specificaly does not use it.
///
/// args: The command we will send to tmux on the host system for execution.
///
/// # Examples
///
/// ```
/// let _ = call(&["new-window", "-t", "muxed", "-c", "~/Projects/muxed/"]);
/// ```
fn call(args: &[&str]) -> Result<Output, io::Error> {
    println!("{:?}", &args);
    Command::new(TMUX_NAME).args(args).output()
}

/// Attach is called as the last function in a set of commands. After the tmux
/// env has been setup by all previous commands this attaches the user to their
/// daemonized tmux session.
///
/// # Examples
///
/// ```
/// let session_name = "muxed".to_string();
/// tmux::attach(muxed);
/// ```
/// session_name: The active tmux session name.
pub fn attach(session_name: &String) -> () {
    let line = format!("{} attach -t {} {}", TMUX_NAME, session_name, ">/dev/null");
    let system_call = CString::new(line.clone()).unwrap();
    //println!("{}", line.clone());
    unsafe { system(system_call.as_ptr()); };
}

/// New session is the first call made in any sequence of commands. It initiates
/// a new tmux session with a default first window name.
/// *Why a randomized first window name?*
///   This is because the `new-session` tmux command does not support the `-c`
/// flag as `new-window` and `split-window` do. So if the first window requires
/// being changed to a default directory `send-keys` must be used after the
/// session and first window are opened. This means the first window is treated in
/// a different code path than any other window that is opened.
/// Instead I've opted to open the session with a randomized (no conflicts)
/// named window, and we close this window out before attaching the user. This
/// allows for us to treat all user defined windows the same.
///
/// session_name: The name of the session being created.
/// tmp_name: The named first window that we will close out.
///
/// # Examples
///
/// ```
/// use rand::random;
///
/// let session_name = "muxed".to_string();
/// let tmp_window_name = random::<u16>().to_string();
/// tmux::new_session(session_name, tmp_window_name);
/// ```
///
/// session_name: The active tmux session name.
/// tmp_name: The name for the temp initial window that is created with a new
/// session.
pub fn new_session(session_name: &String, window_name: &String) -> () {
    let _ = call(&["new", "-d", "-s", session_name, "-n", window_name]);
}

/// Split window acts as the command to target named windows in a session to
/// send a make separate a single pane into two panes. Split window should target
/// a specific pane even if only a single pane exists.
///
/// # Examples
///
/// ```
/// let target = "muxed:cargo.0".to_string();
/// tmux::split_window(target, None);
/// ```
///
/// target: A string represented by the {named_session}:{named_window}.{pane}
/// root: An `Option<String>` passed to the -c argument to change the current
/// directory.
pub fn split_window(target: &String) -> () {
    let _ = call(&["split-window", "-t", target]);
}

/// New window opens a new window in the named session with the provided window
/// name.
///
/// # Examples
///
/// ```
/// tmux::new_window("muxed".to_string(), "vim".to_string(), None);
/// ```
///
/// session_name: The active tmux session name.
/// window_name: The desired window name for the new window.
/// root: An `Option<String>` passed to the -c argument to change the current
/// directory.
pub fn new_window(session_name: &String, window_name: &String) -> () {
    let _ = call(&["new-window", "-t", session_name, "-n", window_name]);
}

/// The layout function will adjust the layout of a tmux window that already has
/// multiple panes. Currently it will only accept standard tmux layout types.
///
/// Possible layout options: even-horizontal, even-vertical, main-horizontal,
/// main-vertical, or tiled.
///
/// # Examples
///
/// ```
/// tmux::layout("muxed:cargo.0".to_string(), "main-vertical".to_string(), None);
/// ```
///
/// target: A string represented by the {named_session}:{named_window}.{pane}
/// layout: The predefined tmux named layout.
pub fn layout(target: &String, layout: &String) -> () {
    let _ = call(&["select-layout", "-t", target, layout]);
}

/// Send Keys executes literal key commands in specified target windows. This is
/// the execution method to perform actions like tailing logs, starting servers,
/// or opening editors.
///
/// `KPEnter` represent the keyboard press of the "Enter" key. So the execution
/// is a user input command followed by "enter"
///
/// # Examples
///
/// ```
/// tmux::send_keys("muxed:cargo.0".to_string(), "vim .".to_string());
/// ```
///
/// target: A string represented by the {named_session}:{named_window}.{pane}
/// exec: The system command to be executed in a particular pane.
pub fn send_keys(target: &String, exec: &String) -> () {
    let _ = call(&["send-keys", "-t", target, exec, "KPEnter"]);
}

/// This is used to re-select the first window before
/// attaching to the session.
///
/// # Examples
///
/// ```
/// tmux::select_window("muxed:cargo.0".to_string());
/// ```
///
/// target: A string represented by the {named_session}:{named_window}.{pane}
pub fn select_window(target: &String) -> () {
    let _ = call(&["select-window", "-t", target]);
}

/// This is used to re-select the top pane in the first window before
/// attaching to the session.
///
/// # Examples
///
/// ```
/// tmux::select_pane("muxed:cargo.top".to_string());
/// ```
///
/// target: A string represented by the {named_session}:{named_window}.{pane}
pub fn select_pane(target: &String) -> () {
    let _ = call(&["select-pane", "-t", target]);
}

/// List Windows is used firgure out if a named session is already running.
///
/// # Examples
///
/// ```
/// tmux::has_session("muxed".to_string());
/// => ExitStatus
/// ```
///
/// target: A string represented by the {named_session}
pub fn has_session(target: &String) -> ExitStatus {
    let output = Command::new(TMUX_NAME)
                     .arg("has-session")
                     .arg("-t")
                     .arg(target)
                     .output()
                     .unwrap_or_else(|e| { panic!("failed to execute process: {}", e) });

    output.status
}

/// Read the tmux config and return a config object
///
/// # Examples
///
/// ```
/// tmux::get_config();
/// => "some-option false\npane-base-index 0"
/// ```
pub fn get_config() -> String {
    let output = Command::new(TMUX_NAME)
                     .args(&["start-server", ";", "show-options", "-g"])
                     .output()
                     .unwrap_or_else(|e| { panic!("couldn't get tmux options: {}", e) });

    String::from_utf8_lossy(&output.stdout).to_string()
}
<|endoftext|>


<commit_before>use bincode::{serialize, deserialize, Infinite};

use leveldb::database::Database;
use leveldb::kv::KV;
use leveldb::iterator::Iterable;
use leveldb::options::{Options,WriteOptions,ReadOptions};

use std::path::Path;

#[derive(Serialize, Deserialize)]
pub struct ShapeshiftDeposit {
    pub status: String,
    pub address: String,              // recipient new wallet address
    pub deposit: String,              //[altcoin deposit address],
    pub withdrawal: String,           //[withdrawal (RELAY) address],
    pub withdrawalAmount: String,     //[amount to be relayed],
    pub depositAmount: String,        //[amount deposited],
    pub depositType: String,          //[coin type of deposit],
    pub transaction: Option<String>,  //[transaction id of coin sent to withdrawal address],
    pub orderId: String,
    pub expiration: usize,
    pub id: usize,
}

#[derive(Serialize, Deserialize)]
pub struct RegisteredToken {
    pub token_address: String,
    pub crowdsale_address: String,
    pub name: String,
    pub symbol: String,
    pub decimal: u8,
    pub tok_type: String,
    pub icon: String,
    pub url: String,
    pub blerb: String,
    pub date_changed: usize,
    pub changed_by: String,
    pub change_reason: String,
}

pub struct TokenDB {
  db: Database<i32>
}

impl TokenDB {
  pub fn new(path: &Path) -> TokenDB {
      let mut options = Options::new();
      options.create_if_missing = true;
      let db = match Database::open(path, options) {
        Ok(db) => { db },
        Err(e) => { panic!("failed to open database: {:?}", e) }
      };
      TokenDB {
        db: db,
      }
  }

  pub fn write_deposit(&self, deposit: &ShapeshiftDeposit) -> () {
      let write_opts = WriteOptions::new();
      // turn into buffer
      let bytes: Vec<u8> = serialize(deposit, Infinite).unwrap();
      match self.db.put(write_opts, deposit.id as i32, &bytes) {
          Ok(_) => { () },
          Err(e) => { panic!("failed to write to database: {:?}", e) }
      };
  }

  pub fn read_deposit(&self, key: i32) -> Option<Vec<u8>> {
      let read_opts = ReadOptions::new();
      let res = self.db.get(read_opts, key);
      let data = match res {
        Ok(data) => { data },
        Err(e) => { panic!("failed reading data: {:?}", e) }
      };
      data
  }

  pub fn delete_deposit(&self, key: i32) -> () {
      let write_opts = WriteOptions::new();
      let res = self.db.delete(write_opts, key);
      match res {
        Ok(_) => { () },
        Err(e) => { panic!("failed deleting data: {:?}", e) }
      };
  }

  pub fn dump(&self) -> Vec<Vec<u8>> {
      let read_opts = ReadOptions::new();
      let mut iter = self.db.value_iter(read_opts);
      let mut data = vec![];
      loop {
          match iter.next() {
              Some(d) => {
                  data.push(d);
                },
                _ => { break; }
          };
      };
      data
  }

  pub fn dump_addrs(&self) -> Vec<String> {
      let read_opts = ReadOptions::new();
      let mut iter = self.db.value_iter(read_opts);
      let mut data = vec![];
      loop {
          match iter.next() {
              Some(d) => {
                  data.push(deserialize::<ShapeshiftDeposit>(&d).unwrap().deposit);
                },
                _ => { break; }
          };
      };
      data
  }

}
<commit_msg>clone<commit_after>use bincode::{serialize, deserialize, Infinite};

use leveldb::database::Database;
use leveldb::kv::KV;
use leveldb::iterator::Iterable;
use leveldb::options::{Options,WriteOptions,ReadOptions};

use std::path::Path;

#[derive(Serialize, Deserialize, Clone)]
pub struct ShapeshiftDeposit {
    pub status: String,
    pub address: String,              // recipient new wallet address
    pub deposit: String,              //[altcoin deposit address],
    pub withdrawal: String,           //[withdrawal (RELAY) address],
    pub withdrawalAmount: String,     //[amount to be relayed],
    pub depositAmount: String,        //[amount deposited],
    pub depositType: String,          //[coin type of deposit],
    pub transaction: Option<String>,  //[transaction id of coin sent to withdrawal address],
    pub orderId: String,
    pub expiration: usize,
    pub id: usize,
}

#[derive(Serialize, Deserialize)]
pub struct RegisteredToken {
    pub token_address: String,
    pub crowdsale_address: String,
    pub name: String,
    pub symbol: String,
    pub decimal: u8,
    pub tok_type: String,
    pub icon: String,
    pub url: String,
    pub blerb: String,
    pub date_changed: usize,
    pub changed_by: String,
    pub change_reason: String,
}

pub struct TokenDB {
  db: Database<i32>
}

impl TokenDB {
  pub fn new(path: &Path) -> TokenDB {
      let mut options = Options::new();
      options.create_if_missing = true;
      let db = match Database::open(path, options) {
        Ok(db) => { db },
        Err(e) => { panic!("failed to open database: {:?}", e) }
      };
      TokenDB {
        db: db,
      }
  }

  pub fn write_deposit(&self, deposit: &ShapeshiftDeposit) -> () {
      let write_opts = WriteOptions::new();
      // turn into buffer
      let bytes: Vec<u8> = serialize(deposit, Infinite).unwrap();
      match self.db.put(write_opts, deposit.id as i32, &bytes) {
          Ok(_) => { () },
          Err(e) => { panic!("failed to write to database: {:?}", e) }
      };
  }

  pub fn read_deposit(&self, key: i32) -> Option<Vec<u8>> {
      let read_opts = ReadOptions::new();
      let res = self.db.get(read_opts, key);
      let data = match res {
        Ok(data) => { data },
        Err(e) => { panic!("failed reading data: {:?}", e) }
      };
      data
  }

  pub fn delete_deposit(&self, key: i32) -> () {
      let write_opts = WriteOptions::new();
      let res = self.db.delete(write_opts, key);
      match res {
        Ok(_) => { () },
        Err(e) => { panic!("failed deleting data: {:?}", e) }
      };
  }

  pub fn dump(&self) -> Vec<Vec<u8>> {
      let read_opts = ReadOptions::new();
      let mut iter = self.db.value_iter(read_opts);
      let mut data = vec![];
      loop {
          match iter.next() {
              Some(d) => {
                  data.push(d);
                },
                _ => { break; }
          };
      };
      data
  }

  pub fn dump_addrs(&self) -> Vec<String> {
      let read_opts = ReadOptions::new();
      let mut iter = self.db.value_iter(read_opts);
      let mut data = vec![];
      loop {
          match iter.next() {
              Some(d) => {
                  data.push(deserialize::<ShapeshiftDeposit>(&d).unwrap().deposit);
                },
                _ => { break; }
          };
      };
      data
  }

}
<|endoftext|>


<commit_before>use nanovg::{Alignment, Color, TextOptions};
use proto;
use sha3::{Digest, Sha3_256};

use input::{InputString, KeyAction, KeyCode, KeyMod};
use render::{Fonts, RenderContext};

use std::cell::RefCell;
use std::time::{Duration, Instant};

pub struct MainLoadingView<'a> {
    pub cur_load_task: &'a RefCell<String>,
}

impl<'a> super::View for MainLoadingView<'a> {
    fn present(&mut self, ctx: &RenderContext) {
        let (w, h) = ctx.size();
        ctx.frame(|f| {
            f.path(
                |p| {
                    let radius = 30.0;
                    p.circle((w / 2.0, h / 2.0), radius);
                    p.fill(Color::from_rgb(200, 100, 0), Default::default());
                },
                Default::default(),
            );
            // Chorus Studio
            {
                let size = 60.0;
                let text = "Chorus Studio";
                let font = ctx.font(Fonts::Moderno);
                let (_, bounds) = f.text_bounds(
                    font,
                    (0.0, 0.0),
                    text,
                    TextOptions {
                        size: size,
                        ..Default::default()
                    },
                );
                let (width, height) = (bounds.max_x, bounds.max_y);
                f.text(
                    font,
                    ((w - width) / 2.0, (h - height) / 8.0),
                    text,
                    TextOptions {
                        size: size,
                        color: Color::from_rgb(255, 255, 255),
                        ..Default::default()
                    },
                );
            }
            // loading
            {
                let size = 28.0;
                let font = ctx.font(Fonts::Vga8);
                let (_, bounds) = f.text_bounds(
                    font,
                    (0.0, 0.0),
                    &*self.cur_load_task.borrow(),
                    TextOptions {
                        size: size,
                        ..Default::default()
                    },
                );
                let (width, height) = (bounds.max_x, bounds.max_y);
                f.text(
                    font,
                    ((w - width) / 2.0, (h - height) / 4.0),
                    &*self.cur_load_task.borrow(),
                    TextOptions {
                        size: size,
                        color: Color::from_rgb(200, 200, 200),
                        ..Default::default()
                    },
                );
            }
        });
    }
}

pub struct MainView<'a> {
    pub user_list: &'a RefCell<Vec<proto::User>>,
}

impl<'a> super::View for MainView<'a> {
    fn present(&mut self, ctx: &RenderContext) {
        ctx.frame(|f| {
            let mut cur_y = 50.0;
            let size = 24.0;

            f.text(
                ctx.font(Fonts::Moderno),
                (5.0, 5.0),
                "Chorus Studio",
                TextOptions {
                    size: 40.0,
                    color: Color::from_rgb(255, 255, 255),
                    ..Default::default()
                },
            );

            for user in self.user_list.borrow().iter() {
                f.text(
                    ctx.font(Fonts::Vga8),
                    (10.0, cur_y),
                    &user.name,
                    TextOptions {
                        size: size,
                        color: Color::from_rgb(255, 255, 255),
                        ..Default::default()
                    },
                );
                f.text(
                    ctx.font(Fonts::Inter),
                    (200.0, cur_y + 7.0),
                    match user.status {
                        proto::UserStatus::Avail => "online",
                        proto::UserStatus::Away => "away",
                        proto::UserStatus::Offline => "offline",
                    },
                    TextOptions {
                        size: 14.0,
                        color: Color::from_rgb(155, 155, 155),
                        ..Default::default()
                    },
                );
                f.text(
                    ctx.font(Fonts::Inter),
                    (250.0, cur_y + 7.0),
                    &if let Some(ref project) = user.in_project {
                        format!("In project '{}'", project)
                    } else {
                        "Chatting".to_owned()
                    },
                    TextOptions {
                        size: 14.0,
                        color: Color::from_rgb(155, 155, 155),
                        ..Default::default()
                    },
                );
                cur_y += size;
            }
        });
    }
}

pub struct LoginView<'a> {
    username_input: InputString,
    password_input: InputString,
    username_cursor: usize,
    password_cursor: usize,
    active_input: LoginViewActiveInput,
    on_submit: Box<FnMut(&str, &[u8]) + 'a>,
    invalid_timer_start: Option<Instant>,
    invalid_attempts: usize,
}

#[derive(PartialEq, Eq, Copy, Clone)]
enum LoginViewActiveInput {
    Username,
    Password,
}

impl<'a> LoginView<'a> {
    pub fn new(on_submit: Box<FnMut(&str, &[u8]) + 'a>) -> Self {
        LoginView {
            username_input: InputString::new(),
            password_input: InputString::new(),
            username_cursor: 0,
            password_cursor: 0,
            active_input: LoginViewActiveInput::Username,
            on_submit,
            invalid_timer_start: None,
            invalid_attempts: 0,
        }
    }

    pub fn invalid_login(&mut self) {
        self.invalid_timer_start = Some(Instant::now());
        self.invalid_attempts += 1;
    }

    fn active_input_data(&mut self) -> (&mut InputString, &mut usize) {
        match self.active_input {
            LoginViewActiveInput::Username => (&mut self.username_input, &mut self.username_cursor),
            LoginViewActiveInput::Password => (&mut self.password_input, &mut self.password_cursor),
        }
    }
}

impl<'a> super::View for LoginView<'a> {
    fn present(&mut self, ctx: &RenderContext) {
        if let Some(inst) = self.invalid_timer_start.clone() {
            if inst.elapsed() > Duration::from_secs(3) {
                self.invalid_timer_start = None;
            }
        }

        let (w, h) = ctx.size();
        ctx.frame(|f| {
            // "Login"
            f.text(
                ctx.font(Fonts::Moderno),
                (w / 2.0, h / 4.0),
                "Login",
                TextOptions {
                    align: Alignment::new().center().middle(),
                    size: 60.0,
                    color: Color::from_rgb(255, 255, 255),
                    ..Default::default()
                },
            );

            // Button shapes
            let input_width = w / 3.0;
            let input_height = 40f32;
            let input_vert_dist = 20f32;
            f.path(
                |p| {
                    p.rounded_rect(
                        (w / 3.0, h / 2.0 - input_height - input_vert_dist / 2.0),
                        (input_width, input_height),
                        5.0,
                    );
                    p.rounded_rect(
                        (w / 3.0, h / 2.0 + input_vert_dist / 2.0),
                        (input_width, input_height),
                        5.0,
                    );
                    p.fill(Color::from_rgb(128, 30, 80), Default::default());
                },
                Default::default(),
            );

            // Invalid credentials text

            if self.invalid_attempts > 0 {
                f.text(
                    ctx.font(Fonts::Inter),
                    (w / 2.0, h / 2.0 + 100.0),
                    "Your username and / or password is wrong. Please double check.",
                    TextOptions {
                        align: Alignment::new().center().middle(),
                        size: 14.0,
                        color: Color::from_rgb(255, 150, 150),
                        ..Default::default()
                    },
                )
            }

            // Button contents

            let (placeholder_color, content_color) = {
                if self.invalid_timer_start.is_some() {
                    (
                        Color::from_rgb(255, 150, 150),
                        Color::from_rgb(255, 150, 150),
                    )
                } else {
                    (
                        Color::from_rgb(128, 128, 128),
                        Color::from_rgb(255, 255, 255),
                    )
                }
            };

            // Username content
            f.text(
                ctx.font(Fonts::Inter),
                (
                    w / 3.0 + 4.0,
                    h / 2.0 - input_height / 2.0 - input_vert_dist / 2.0,
                ),
                if self.username_input.is_empty() {
                    "Username"
                } else {
                    &self.username_input
                },
                TextOptions {
                    align: Alignment::new().left().middle(),
                    size: input_height - 4.0,
                    color: if self.username_input.is_empty() {
                        placeholder_color
                    } else {
                        content_color
                    },
                    ..Default::default()
                },
            );

            // Password content
            f.text(
                ctx.font(Fonts::Inter),
                (
                    w / 3.0 + 4.0,
                    h / 2.0 + input_height / 2.0 + input_vert_dist / 2.0,
                ),
                if self.password_input.is_empty() {
                    "Password"
                } else {
                    &self.password_input
                },
                TextOptions {
                    align: Alignment::new().left().middle(),
                    size: input_height - 4.0,
                    color: if self.password_input.is_empty() {
                        placeholder_color
                    } else {
                        content_color
                    },
                    ..Default::default()
                },
            );

            // Input cursor
            {
                let origin = match self.active_input {
                    LoginViewActiveInput::Username => {
                        (w / 3.0, h / 2.0 - input_height - input_vert_dist / 2.0)
                    }
                    LoginViewActiveInput::Password => (w / 3.0, h / 2.0 + input_vert_dist / 2.0),
                };

                let (string, cursor) = self.active_input_data();
                let (adv, _bounds) = f.text_bounds(
                    ctx.font(Fonts::Inter),
                    origin,
                    &string[0..*cursor],
                    TextOptions {
                        align: Alignment::new().left().middle(),
                        size: input_height - 4.0,
                        ..Default::default()
                    },
                );
                f.path(
                    |p| {
                        p.rect((origin.0 + adv, origin.1 + 2.0), (2.0, input_height - 4.0));
                        p.fill(Color::from_rgb(255, 0, 0), Default::default());
                    },
                    Default::default(),
                );
            }
        });
    }

    fn on_char_input(&mut self, c: char) {
        if !c.is_control() {
            let (string, cursor) = self.active_input_data();
            string.insert(*cursor, c);
            *cursor += 1;
        }
    }

    fn on_key_input(&mut self, key: KeyAction) {
        if key.was_pressed(KeyCode::Backspace) {
            let (string, cursor) = self.active_input_data();
            if *cursor > 0 {
                string.remove(*cursor - 1);
                *cursor -= 1;
            }
        } else if key.was_pressed(KeyCode::Delete) {
            let (string, cursor) = self.active_input_data();
            if *cursor < string.len() {
                string.remove(*cursor);
            }
        } else if key.was_pressed_once(KeyCode::Return) {
            if self.active_input == LoginViewActiveInput::Username {
                self.active_input = LoginViewActiveInput::Password;
            } else if self.active_input == LoginViewActiveInput::Password {
                (self.on_submit)(
                    &self.username_input.as_str(),
                    Sha3_256::digest(self.password_input.as_str().as_bytes()).as_slice(),
                );
            }
        } else if key.was_pressed_once(KeyCode::Tab) && key.with_modifier(KeyMod::Shift) {
            if self.active_input == LoginViewActiveInput::Password {
                self.active_input = LoginViewActiveInput::Username;
            }
        } else if key.was_pressed_once(KeyCode::Tab) {
            if self.active_input == LoginViewActiveInput::Username {
                self.active_input = LoginViewActiveInput::Password;
            }
        } else if key.was_pressed(KeyCode::Left) {
            let (_string, cursor) = self.active_input_data();
            if *cursor > 0 {
                *cursor -= 1;
            }
        } else if key.was_pressed(KeyCode::Right) {
            let (string, cursor) = self.active_input_data();
            if *cursor < string.len() {
                *cursor += 1;
            }
        } else if key.was_pressed(KeyCode::Home) {
            let (_, cursor) = self.active_input_data();
            *cursor = 0;
        } else if key.was_pressed(KeyCode::End) {
            let (string, cursor) = self.active_input_data();
            *cursor = string.len();
        }
    }
}
<commit_msg>Display stars for password<commit_after>use nanovg::{Alignment, Color, TextOptions};
use proto;
use sha3::{Digest, Sha3_256};

use input::{InputString, KeyAction, KeyCode, KeyMod};
use render::{Fonts, RenderContext};

use std::cell::RefCell;
use std::time::{Duration, Instant};

pub struct MainLoadingView<'a> {
    pub cur_load_task: &'a RefCell<String>,
}

impl<'a> super::View for MainLoadingView<'a> {
    fn present(&mut self, ctx: &RenderContext) {
        let (w, h) = ctx.size();
        ctx.frame(|f| {
            f.path(
                |p| {
                    let radius = 30.0;
                    p.circle((w / 2.0, h / 2.0), radius);
                    p.fill(Color::from_rgb(200, 100, 0), Default::default());
                },
                Default::default(),
            );
            // Chorus Studio
            {
                let size = 60.0;
                let text = "Chorus Studio";
                let font = ctx.font(Fonts::Moderno);
                let (_, bounds) = f.text_bounds(
                    font,
                    (0.0, 0.0),
                    text,
                    TextOptions {
                        size: size,
                        ..Default::default()
                    },
                );
                let (width, height) = (bounds.max_x, bounds.max_y);
                f.text(
                    font,
                    ((w - width) / 2.0, (h - height) / 8.0),
                    text,
                    TextOptions {
                        size: size,
                        color: Color::from_rgb(255, 255, 255),
                        ..Default::default()
                    },
                );
            }
            // loading
            {
                let size = 28.0;
                let font = ctx.font(Fonts::Vga8);
                let (_, bounds) = f.text_bounds(
                    font,
                    (0.0, 0.0),
                    &*self.cur_load_task.borrow(),
                    TextOptions {
                        size: size,
                        ..Default::default()
                    },
                );
                let (width, height) = (bounds.max_x, bounds.max_y);
                f.text(
                    font,
                    ((w - width) / 2.0, (h - height) / 4.0),
                    &*self.cur_load_task.borrow(),
                    TextOptions {
                        size: size,
                        color: Color::from_rgb(200, 200, 200),
                        ..Default::default()
                    },
                );
            }
        });
    }
}

pub struct MainView<'a> {
    pub user_list: &'a RefCell<Vec<proto::User>>,
}

impl<'a> super::View for MainView<'a> {
    fn present(&mut self, ctx: &RenderContext) {
        ctx.frame(|f| {
            let mut cur_y = 50.0;
            let size = 24.0;

            f.text(
                ctx.font(Fonts::Moderno),
                (5.0, 5.0),
                "Chorus Studio",
                TextOptions {
                    size: 40.0,
                    color: Color::from_rgb(255, 255, 255),
                    ..Default::default()
                },
            );

            for user in self.user_list.borrow().iter() {
                f.text(
                    ctx.font(Fonts::Vga8),
                    (10.0, cur_y),
                    &user.name,
                    TextOptions {
                        size: size,
                        color: Color::from_rgb(255, 255, 255),
                        ..Default::default()
                    },
                );
                f.text(
                    ctx.font(Fonts::Inter),
                    (200.0, cur_y + 7.0),
                    match user.status {
                        proto::UserStatus::Avail => "online",
                        proto::UserStatus::Away => "away",
                        proto::UserStatus::Offline => "offline",
                    },
                    TextOptions {
                        size: 14.0,
                        color: Color::from_rgb(155, 155, 155),
                        ..Default::default()
                    },
                );
                f.text(
                    ctx.font(Fonts::Inter),
                    (250.0, cur_y + 7.0),
                    &if let Some(ref project) = user.in_project {
                        format!("In project '{}'", project)
                    } else {
                        "Chatting".to_owned()
                    },
                    TextOptions {
                        size: 14.0,
                        color: Color::from_rgb(155, 155, 155),
                        ..Default::default()
                    },
                );
                cur_y += size;
            }
        });
    }
}

pub struct LoginView<'a> {
    username_input: InputString,
    password_input: InputString,
    username_cursor: usize,
    password_cursor: usize,
    active_input: LoginViewActiveInput,
    on_submit: Box<FnMut(&str, &[u8]) + 'a>,
    invalid_timer_start: Option<Instant>,
    invalid_attempts: usize,
}

#[derive(PartialEq, Eq, Copy, Clone)]
enum LoginViewActiveInput {
    Username,
    Password,
}

impl<'a> LoginView<'a> {
    pub fn new(on_submit: Box<FnMut(&str, &[u8]) + 'a>) -> Self {
        LoginView {
            username_input: InputString::new(),
            password_input: InputString::new(),
            username_cursor: 0,
            password_cursor: 0,
            active_input: LoginViewActiveInput::Username,
            on_submit,
            invalid_timer_start: None,
            invalid_attempts: 0,
        }
    }

    pub fn invalid_login(&mut self) {
        self.invalid_timer_start = Some(Instant::now());
        self.invalid_attempts += 1;
    }

    fn active_input_data(&mut self) -> (&mut InputString, &mut usize) {
        match self.active_input {
            LoginViewActiveInput::Username => (&mut self.username_input, &mut self.username_cursor),
            LoginViewActiveInput::Password => (&mut self.password_input, &mut self.password_cursor),
        }
    }

    fn active_input_str(&self) -> (&str, usize) {
        match self.active_input {
            LoginViewActiveInput::Username => (&self.username_input.as_str(), self.username_cursor),
            LoginViewActiveInput::Password => (self.password_stars(), self.password_cursor),
        }
    }

    fn password_stars(&self) -> &str {
        const STARS: &str =
            "*************************************************************************************";
        &STARS[0..self.password_input.len().min(STARS.len())]
    }
}

impl<'a> super::View for LoginView<'a> {
    fn present(&mut self, ctx: &RenderContext) {
        if let Some(inst) = self.invalid_timer_start.clone() {
            if inst.elapsed() > Duration::from_secs(3) {
                self.invalid_timer_start = None;
            }
        }

        let (w, h) = ctx.size();
        ctx.frame(|f| {
            // "Login"
            f.text(
                ctx.font(Fonts::Moderno),
                (w / 2.0, h / 4.0),
                "Login",
                TextOptions {
                    align: Alignment::new().center().middle(),
                    size: 60.0,
                    color: Color::from_rgb(255, 255, 255),
                    ..Default::default()
                },
            );

            // Button shapes
            let input_width = w / 3.0;
            let input_height = 40f32;
            let input_vert_dist = 20f32;
            f.path(
                |p| {
                    p.rounded_rect(
                        (w / 3.0, h / 2.0 - input_height - input_vert_dist / 2.0),
                        (input_width, input_height),
                        5.0,
                    );
                    p.rounded_rect(
                        (w / 3.0, h / 2.0 + input_vert_dist / 2.0),
                        (input_width, input_height),
                        5.0,
                    );
                    p.fill(Color::from_rgb(128, 30, 80), Default::default());
                },
                Default::default(),
            );

            // Invalid credentials text

            if self.invalid_attempts > 0 {
                f.text(
                    ctx.font(Fonts::Inter),
                    (w / 2.0, h / 2.0 + 100.0),
                    "Your username and / or password is wrong. Please double check.",
                    TextOptions {
                        align: Alignment::new().center().middle(),
                        size: 14.0,
                        color: Color::from_rgb(255, 150, 150),
                        ..Default::default()
                    },
                )
            }

            // Button contents

            let (placeholder_color, content_color) = {
                if self.invalid_timer_start.is_some() {
                    (
                        Color::from_rgb(255, 150, 150),
                        Color::from_rgb(255, 150, 150),
                    )
                } else {
                    (
                        Color::from_rgb(128, 128, 128),
                        Color::from_rgb(255, 255, 255),
                    )
                }
            };

            // Username content
            f.text(
                ctx.font(Fonts::Inter),
                (
                    w / 3.0 + 4.0,
                    h / 2.0 - input_height / 2.0 - input_vert_dist / 2.0,
                ),
                if self.username_input.is_empty() {
                    "Username"
                } else {
                    &self.username_input
                },
                TextOptions {
                    align: Alignment::new().left().middle(),
                    size: input_height - 4.0,
                    color: if self.username_input.is_empty() {
                        placeholder_color
                    } else {
                        content_color
                    },
                    ..Default::default()
                },
            );

            // Password content
            f.text(
                ctx.font(Fonts::Inter),
                (
                    w / 3.0 + 4.0,
                    h / 2.0 + input_height / 2.0 + input_vert_dist / 2.0,
                ),
                if self.password_input.is_empty() {
                    "Password"
                } else {
                    self.password_stars()
                },
                TextOptions {
                    align: Alignment::new().left().middle(),
                    size: input_height - 4.0,
                    color: if self.password_input.is_empty() {
                        placeholder_color
                    } else {
                        content_color
                    },
                    ..Default::default()
                },
            );

            // Input cursor
            {
                let origin = match self.active_input {
                    LoginViewActiveInput::Username => {
                        (w / 3.0, h / 2.0 - input_height - input_vert_dist / 2.0)
                    }
                    LoginViewActiveInput::Password => (w / 3.0, h / 2.0 + input_vert_dist / 2.0),
                };

                let (string, cursor) = self.active_input_str();
                let (adv, _bounds) = f.text_bounds(
                    ctx.font(Fonts::Inter),
                    origin,
                    &string[0..cursor],
                    TextOptions {
                        align: Alignment::new().left().middle(),
                        size: input_height - 4.0,
                        ..Default::default()
                    },
                );
                f.path(
                    |p| {
                        p.rect((origin.0 + adv, origin.1 + 2.0), (2.0, input_height - 4.0));
                        p.fill(Color::from_rgb(255, 0, 0), Default::default());
                    },
                    Default::default(),
                );
            }
        });
    }

    fn on_char_input(&mut self, c: char) {
        if !c.is_control() {
            let (string, cursor) = self.active_input_data();
            string.insert(*cursor, c);
            *cursor += 1;
        }
    }

    fn on_key_input(&mut self, key: KeyAction) {
        if key.was_pressed(KeyCode::Backspace) {
            let (string, cursor) = self.active_input_data();
            if *cursor > 0 {
                string.remove(*cursor - 1);
                *cursor -= 1;
            }
        } else if key.was_pressed(KeyCode::Delete) {
            let (string, cursor) = self.active_input_data();
            if *cursor < string.len() {
                string.remove(*cursor);
            }
        } else if key.was_pressed_once(KeyCode::Return) {
            if self.active_input == LoginViewActiveInput::Username {
                self.active_input = LoginViewActiveInput::Password;
            } else if self.active_input == LoginViewActiveInput::Password {
                (self.on_submit)(
                    &self.username_input.as_str(),
                    Sha3_256::digest(self.password_input.as_str().as_bytes()).as_slice(),
                );
            }
        } else if key.was_pressed_once(KeyCode::Tab) && key.with_modifier(KeyMod::Shift) {
            if self.active_input == LoginViewActiveInput::Password {
                self.active_input = LoginViewActiveInput::Username;
            }
        } else if key.was_pressed_once(KeyCode::Tab) {
            if self.active_input == LoginViewActiveInput::Username {
                self.active_input = LoginViewActiveInput::Password;
            }
        } else if key.was_pressed(KeyCode::Left) {
            let (_string, cursor) = self.active_input_data();
            if *cursor > 0 {
                *cursor -= 1;
            }
        } else if key.was_pressed(KeyCode::Right) {
            let (string, cursor) = self.active_input_data();
            if *cursor < string.len() {
                *cursor += 1;
            }
        } else if key.was_pressed(KeyCode::Home) {
            let (_, cursor) = self.active_input_data();
            *cursor = 0;
        } else if key.was_pressed(KeyCode::End) {
            let (string, cursor) = self.active_input_data();
            *cursor = string.len();
        }
    }
}
<|endoftext|>


<commit_before>//! The dump module contains code related for outputing/dumping data.
use std::fmt::Display;
use super::errors::*;

/// Enum which provides all possible output value formats supported by the dump module.
#[derive(Debug)]
pub enum OutputFormat {
    Hex,
    Decimal,
    Octal,
    Binary,
}

/// The `OutputLine` struct contains all  information needed to dump/output a single line of data.
#[derive(Debug)]
pub struct OutputLine<'a> {
    start_address: u32,
    show_address: bool,
    data: &'a [u8], // TODO NiCo: Add member for data format (output format of data)
    group_size: usize,
    columns: usize,
    show_interpretation: bool,
    output_fmt: OutputFormat,
}

impl<'a> OutputLine<'a> {
    fn new(data: &[u8]) -> OutputLine {
        OutputLine {
            start_address: 0,
            show_address: true,
            data: data,
            group_size: 1,
            columns: 8,
            show_interpretation: true,
            output_fmt: OutputFormat::Hex,
        }
    }

    pub fn format(self, fmt: OutputFormat) -> Self {
        OutputLine {
            start_address: self.start_address,
            show_address: self.show_interpretation,
            data: self.data,
            group_size: self.group_size,
            columns: self.columns,
            show_interpretation: self.show_interpretation,
            output_fmt: fmt,
        }
    }

    fn write_address(&self, f: &mut ::fmt::Formatter) -> Result<()> {
        write!(f, "{:08.X}: ", self.start_address).map_err(|e| e.into())
    }

    fn write_bytes(&self, f: &mut ::fmt::Formatter) -> Result<()> {
        let mut byte_count = 0;
        for b in self.data.iter() {
            byte_count += 1;
            let is_seperator_necessary = byte_count % self.group_size == 0;
            if is_seperator_necessary {
                self.write_formated_byte(f, b)?;
                write!(f, " ")?
            } else {
                self.write_formated_byte(f, b)?
            }
        }
        Ok(())
    }

    fn write_formated_byte(&self, f: &mut ::fmt::Formatter, byte: &u8) -> Result<()> {
        match self.output_fmt {
            OutputFormat::Hex => write!(f, "{:02.X}", byte).map_err(|e| e.into()),
            OutputFormat::Octal => write!(f, "{:02.o}", byte).map_err(|e| e.into()),
            OutputFormat::Decimal => write!(f, "{:02}", byte).map_err(|e| e.into()),
            OutputFormat::Binary => write!(f, "{:02b}", byte).map_err(|e| e.into()),
        }
    }

    fn write_interpretation(&self, f: &mut ::fmt::Formatter) -> Result<()> {
        write!(f, "   ");
        for b in self.data.iter() {
            match *b {
                character @ 20u8...126u8 => write!(f, "{}", character as char)?,
                _ => write!(f, "{}", ".")?,
            }
        }
        Ok(())
    }
}

impl<'a> ::fmt::Display for OutputLine<'a> {
    fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result {
        if self.show_address {
            self.write_address(f);
        }
        self.write_bytes(f);
        if self.show_interpretation {
            self.write_interpretation(f);
        }
        Ok(())
    }
}

mod test {
    use super::*;
    use std::fmt::Write;

    #[test]
    fn outputline_can_be_constructed() {
        let data = [1, 2, 3];
        let output_line = OutputLine::new(&data);
        assert!(true);
    }

    #[test]
    fn default_output_format_for_a_single_line() {
        let data = [1, 2, 3, 4, 5, 6, 7, 8];
        let expected_output = "00000000: 01 02 03 04 05 06 07 08    ........";
        let output_line = OutputLine::new(&data);
        let mut buffer = String::new();
        let result = write!(&mut buffer, "{}", output_line);
        assert_eq!(Ok(()), result);
        assert_eq!(expected_output, buffer);
    }

    #[test]
    fn octal_output_format_on_a_single_line() {
        let data = [8, 9, 10, 11, 12, 13, 14, 15];
        let expected_output = "00000000: 10 11 12 13 14 15 16 17    ........";
        let output_line = OutputLine::new(&data).format(OutputFormat::Octal);
        let mut buffer = String::new();
        let result = write!(&mut buffer, "{}", output_line);
        assert_eq!(Ok(()), result);
        assert_eq!(expected_output, buffer);
    }

    #[test]
    fn binary_output_format_on_a_single_line() {
        let data = [65, 66, 67, 68, 126, 124, 60, 46];
        let expected_output = "00000000: 1000001 1000010 1000011 1000100 1111110 1111100 111100 101110    ABCD~|<.";
        let output_line = OutputLine::new(&data).format(OutputFormat::Binary);
        let mut buffer = String::new();
        let result = write!(&mut buffer, "{}", output_line);
        assert_eq!(Ok(()), result);
        assert_eq!(expected_output, buffer);
    }

    #[test]
    fn interpretation_for_default_settings() {
        let data = [65, 66, 67, 68, 126, 124, 60, 46];
        let expected_output = "00000000: 41 42 43 44 7E 7C 3C 2E    ABCD~|<.";
        let output_line = OutputLine::new(&data);
        let mut buffer = String::new();
        let result = write!(&mut buffer, "{}", output_line);
        assert_eq!(Ok(()), result);
        assert_eq!(expected_output, buffer);
    }
}
<commit_msg>Add output settings<commit_after>//! The dump module contains code related for outputing/dumping data.
use std::fmt::Display;
use super::errors::*;

/// Enum which provides all possible output value formats supported by the dump module.
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum OutputFormat {
    Hex,
    Decimal,
    Octal,
    Binary,
}

pub struct OutputSettings {
    start_address: u32,
    show_address: bool,
    group_size: usize,
    columns: usize,
    show_interpretation: bool,
    output_fmt: OutputFormat,
}

impl OutputSettings {
    fn new() -> OutputSettings {
        OutputSettings {
            start_address: 0,
            show_address: true,
            group_size: 1,
            columns: 8,
            show_interpretation: true,
            output_fmt: OutputFormat::Hex,
        }
    }

    pub fn start_address(mut self, address: u32) -> Self {
        self.start_address = address;
        self
    }

    pub fn show_address(mut self, show: bool) -> Self {
        self.show_address = show;
        self
    }

    pub fn group_size(mut self, size: usize) -> Self {
        self.group_size = size;
        self
    }

    pub fn columns(mut self, columns: usize) -> Self {
        self.columns = columns;
        self
    }

    pub fn show_interpretation(mut self, show: bool) -> Self {
        self.show_interpretation = show;
        self
    }

    pub fn format(mut self, fmt: OutputFormat) -> Self {
        self.output_fmt = fmt;
        self
    }
}

/// The `OutputLine` struct contains all  information needed to dump/output a single line of data.
#[derive(Debug)]
pub struct OutputLine<'a> {
    start_address: u32,
    show_address: bool,
    data: &'a [u8], // TODO NiCo: Add member for data format (output format of data)
    group_size: usize,
    columns: usize,
    show_interpretation: bool,
    output_fmt: OutputFormat,
}

impl<'a> OutputLine<'a> {
    fn new(data: &[u8]) -> OutputLine {
        OutputLine {
            start_address: 0,
            show_address: true,
            data: data,
            group_size: 1,
            columns: 8,
            show_interpretation: true,
            output_fmt: OutputFormat::Hex,
        }
    }

    pub fn format(self, fmt: OutputFormat) -> Self {
        OutputLine {
            start_address: self.start_address,
            show_address: self.show_interpretation,
            data: self.data,
            group_size: self.group_size,
            columns: self.columns,
            show_interpretation: self.show_interpretation,
            output_fmt: fmt,
        }
    }

    fn write_address(&self, f: &mut ::fmt::Formatter) -> Result<()> {
        write!(f, "{:08.X}: ", self.start_address).map_err(|e| e.into())
    }

    fn write_bytes(&self, f: &mut ::fmt::Formatter) -> Result<()> {
        let mut byte_count = 0;
        for b in self.data.iter() {
            byte_count += 1;
            let is_seperator_necessary = byte_count % self.group_size == 0;
            if is_seperator_necessary {
                self.write_formated_byte(f, b)?;
                write!(f, " ")?
            } else {
                self.write_formated_byte(f, b)?
            }
        }
        Ok(())
    }

    fn write_formated_byte(&self, f: &mut ::fmt::Formatter, byte: &u8) -> Result<()> {
        match self.output_fmt {
            OutputFormat::Hex => write!(f, "{:02.X}", byte).map_err(|e| e.into()),
            OutputFormat::Octal => write!(f, "{:02.o}", byte).map_err(|e| e.into()),
            OutputFormat::Decimal => write!(f, "{:02}", byte).map_err(|e| e.into()),
            OutputFormat::Binary => write!(f, "{:02b}", byte).map_err(|e| e.into()),
        }
    }

    fn write_interpretation(&self, f: &mut ::fmt::Formatter) -> Result<()> {
        write!(f, "   ");
        for b in self.data.iter() {
            match *b {
                character @ 20u8...126u8 => write!(f, "{}", character as char)?,
                _ => write!(f, "{}", ".")?,
            }
        }
        Ok(())
    }
}

impl<'a> ::fmt::Display for OutputLine<'a> {
    fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result {
        if self.show_address {
            self.write_address(f);
        }
        self.write_bytes(f);
        if self.show_interpretation {
            self.write_interpretation(f);
        }
        Ok(())
    }
}

mod test {
    use super::*;
    use std::fmt::Write;

    #[test]
    fn output_settings_can_be_constructed() {
        let output_settings = OutputSettings::new();
        assert!(true);
    }

    #[test]
    fn output_settings_builder() {
        let format = OutputFormat::Binary;
        let start_address = 0xFF00AABB;
        let group_size = 2;
        let show_address = false;
        let show_interpretation = false;

        let mut output_settings = OutputSettings::new()
            .format(format)
            .start_address(start_address)
            .group_size(group_size)
            .show_address(show_address)
            .show_interpretation(show_interpretation);

        assert_eq!(output_settings.output_fmt, format);
        assert_eq!(output_settings.start_address, start_address);
        assert_eq!(output_settings.group_size, group_size);
        assert_eq!(output_settings.show_address, show_address);
        assert_eq!(output_settings.show_interpretation, show_interpretation);
    }

    #[test]
    fn output_settings_start_address() {}

    #[test]
    fn outputline_can_be_constructed() {
        let data = [1, 2, 3];
        let output_line = OutputLine::new(&data);
        assert!(true);
    }

    #[test]
    fn default_output_format_for_a_single_line() {
        let data = [1, 2, 3, 4, 5, 6, 7, 8];
        let expected_output = "00000000: 01 02 03 04 05 06 07 08    ........";
        let output_line = OutputLine::new(&data);
        let mut buffer = String::new();
        let result = write!(&mut buffer, "{}", output_line);
        assert_eq!(Ok(()), result);
        assert_eq!(expected_output, buffer);
    }

    #[test]
    fn octal_output_format_on_a_single_line() {
        let data = [8, 9, 10, 11, 12, 13, 14, 15];
        let expected_output = "00000000: 10 11 12 13 14 15 16 17    ........";
        let output_line = OutputLine::new(&data).format(OutputFormat::Octal);
        let mut buffer = String::new();
        let result = write!(&mut buffer, "{}", output_line);
        assert_eq!(Ok(()), result);
        assert_eq!(expected_output, buffer);
    }

    #[test]
    fn binary_output_format_on_a_single_line() {
        let data = [65, 66, 67, 68, 126, 124, 60, 46];
        let expected_output = "00000000: 1000001 1000010 1000011 1000100 1111110 1111100 111100 101110    ABCD~|<.";
        let output_line = OutputLine::new(&data).format(OutputFormat::Binary);
        let mut buffer = String::new();
        let result = write!(&mut buffer, "{}", output_line);
        assert_eq!(Ok(()), result);
        assert_eq!(expected_output, buffer);
    }

    #[test]
    fn interpretation_for_default_settings() {
        let data = [65, 66, 67, 68, 126, 124, 60, 46];
        let expected_output = "00000000: 41 42 43 44 7E 7C 3C 2E    ABCD~|<.";
        let output_line = OutputLine::new(&data);
        let mut buffer = String::new();
        let result = write!(&mut buffer, "{}", output_line);
        assert_eq!(Ok(()), result);
        assert_eq!(expected_output, buffer);
    }
}
<|endoftext|>


<commit_before><commit_msg>CpuBufferPool deprecations and minor doc<commit_after><|endoftext|>


<commit_before>//! SDK Configuration
//!
//! Configuration represents the global tracing configuration, overrides
//! can be set for the default OpenTelemetry limits and Sampler.
use crate::trace::{span_limit::SpanLimits, Sampler, ShouldSample};
use opentelemetry_api::trace::IdGenerator;
use std::env;
use std::str::FromStr;
use std::sync::Arc;

/// Default trace configuration
pub fn config() -> Config {
    Config::default()
}

/// Tracer configuration
#[derive(Debug)]
pub struct Config {
    /// The sampler that the sdk should use
    pub sampler: Box<dyn ShouldSample>,
    /// The id generator that the sdk should use
    pub id_generator: Box<dyn IdGenerator>,
    /// span limits
    pub span_limits: SpanLimits,
    /// Contains attributes representing an entity that produces telemetry.
    pub resource: Option<Arc<crate::Resource>>,
}

impl Config {
    /// Specify the sampler to be used.
    pub fn with_sampler<T: crate::trace::ShouldSample + 'static>(mut self, sampler: T) -> Self {
        self.sampler = Box::new(sampler);
        self
    }

    /// Specify the id generator to be used.
    pub fn with_id_generator<T: IdGenerator + 'static>(mut self, id_generator: T) -> Self {
        self.id_generator = Box::new(id_generator);
        self
    }

    /// Specify the number of events to be recorded per span.
    pub fn with_max_events_per_span(mut self, max_events: u32) -> Self {
        self.span_limits.max_events_per_span = max_events;
        self
    }

    /// Specify the number of attributes to be recorded per span.
    pub fn with_max_attributes_per_span(mut self, max_attributes: u32) -> Self {
        self.span_limits.max_attributes_per_span = max_attributes;
        self
    }

    /// Specify the number of events to be recorded per span.
    pub fn with_max_links_per_span(mut self, max_links: u32) -> Self {
        self.span_limits.max_links_per_span = max_links;
        self
    }

    /// Specify the number of attributes one event can have.
    pub fn with_max_attributes_per_event(mut self, max_attributes: u32) -> Self {
        self.span_limits.max_attributes_per_event = max_attributes;
        self
    }

    /// Specify the number of attributes one link can have.
    pub fn with_max_attributes_per_link(mut self, max_attributes: u32) -> Self {
        self.span_limits.max_attributes_per_link = max_attributes;
        self
    }

    /// Specify all limit via the span_limits
    pub fn with_span_limits(mut self, span_limits: SpanLimits) -> Self {
        self.span_limits = span_limits;
        self
    }

    /// Specify the attributes representing the entity that produces telemetry
    pub fn with_resource(mut self, resource: crate::Resource) -> Self {
        self.resource = Some(Arc::new(resource));
        self
    }

    /// Use empty resource instead of default resource in this config.
    ///
    /// Usually if no resource is provided, SDK will assign a default resource
    /// to the `TracerProvider`, which could impact the performance. Performance
    /// sensitive application can use function to disable such behavior and assign
    /// no resource to `TracerProvider`.
    pub fn with_no_resource(self) -> Self {
        self.with_resource(crate::Resource::empty())
    }
}

impl Default for Config {
    /// Create default global sdk configuration.
    fn default() -> Self {
        let mut config = Config {
            sampler: Box::new(Sampler::ParentBased(Box::new(Sampler::AlwaysOn))),
            id_generator: Box::new(crate::trace::IdGenerator::default()),
            span_limits: SpanLimits::default(),
            resource: None,
        };

        if let Some(max_attributes_per_span) = env::var("OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT")
            .ok()
            .and_then(|count_limit| u32::from_str(&count_limit).ok())
        {
            config.span_limits.max_attributes_per_span = max_attributes_per_span;
        }

        if let Some(max_events_per_span) = env::var("OTEL_SPAN_EVENT_COUNT_LIMIT")
            .ok()
            .and_then(|max_events| u32::from_str(&max_events).ok())
        {
            config.span_limits.max_events_per_span = max_events_per_span;
        }

        if let Some(max_links_per_span) = env::var("OTEL_SPAN_LINK_COUNT_LIMIT")
            .ok()
            .and_then(|max_links| u32::from_str(&max_links).ok())
        {
            config.span_limits.max_links_per_span = max_links_per_span;
        }

        config
    }
}
<commit_msg>Pull sampling probability from env var `OTEL_TRACES_SAMPLER_ARG` in the default sdk config (#737)<commit_after>//! SDK Configuration
//!
//! Configuration represents the global tracing configuration, overrides
//! can be set for the default OpenTelemetry limits and Sampler.
use crate::trace::{span_limit::SpanLimits, Sampler, ShouldSample};
use opentelemetry_api::global::{handle_error, Error};
use opentelemetry_api::trace::IdGenerator;
use std::env;
use std::str::FromStr;
use std::sync::Arc;

/// Default trace configuration
pub fn config() -> Config {
    Config::default()
}

/// Tracer configuration
#[derive(Debug)]
pub struct Config {
    /// The sampler that the sdk should use
    pub sampler: Box<dyn ShouldSample>,
    /// The id generator that the sdk should use
    pub id_generator: Box<dyn IdGenerator>,
    /// span limits
    pub span_limits: SpanLimits,
    /// Contains attributes representing an entity that produces telemetry.
    pub resource: Option<Arc<crate::Resource>>,
}

impl Config {
    /// Specify the sampler to be used.
    pub fn with_sampler<T: crate::trace::ShouldSample + 'static>(mut self, sampler: T) -> Self {
        self.sampler = Box::new(sampler);
        self
    }

    /// Specify the id generator to be used.
    pub fn with_id_generator<T: IdGenerator + 'static>(mut self, id_generator: T) -> Self {
        self.id_generator = Box::new(id_generator);
        self
    }

    /// Specify the number of events to be recorded per span.
    pub fn with_max_events_per_span(mut self, max_events: u32) -> Self {
        self.span_limits.max_events_per_span = max_events;
        self
    }

    /// Specify the number of attributes to be recorded per span.
    pub fn with_max_attributes_per_span(mut self, max_attributes: u32) -> Self {
        self.span_limits.max_attributes_per_span = max_attributes;
        self
    }

    /// Specify the number of events to be recorded per span.
    pub fn with_max_links_per_span(mut self, max_links: u32) -> Self {
        self.span_limits.max_links_per_span = max_links;
        self
    }

    /// Specify the number of attributes one event can have.
    pub fn with_max_attributes_per_event(mut self, max_attributes: u32) -> Self {
        self.span_limits.max_attributes_per_event = max_attributes;
        self
    }

    /// Specify the number of attributes one link can have.
    pub fn with_max_attributes_per_link(mut self, max_attributes: u32) -> Self {
        self.span_limits.max_attributes_per_link = max_attributes;
        self
    }

    /// Specify all limit via the span_limits
    pub fn with_span_limits(mut self, span_limits: SpanLimits) -> Self {
        self.span_limits = span_limits;
        self
    }

    /// Specify the attributes representing the entity that produces telemetry
    pub fn with_resource(mut self, resource: crate::Resource) -> Self {
        self.resource = Some(Arc::new(resource));
        self
    }

    /// Use empty resource instead of default resource in this config.
    ///
    /// Usually if no resource is provided, SDK will assign a default resource
    /// to the `TracerProvider`, which could impact the performance. Performance
    /// sensitive application can use function to disable such behavior and assign
    /// no resource to `TracerProvider`.
    pub fn with_no_resource(self) -> Self {
        self.with_resource(crate::Resource::empty())
    }
}

impl Default for Config {
    /// Create default global sdk configuration.
    fn default() -> Self {
        let mut config = Config {
            sampler: Box::new(Sampler::ParentBased(Box::new(Sampler::AlwaysOn))),
            id_generator: Box::new(crate::trace::IdGenerator::default()),
            span_limits: SpanLimits::default(),
            resource: None,
        };

        if let Some(max_attributes_per_span) = env::var("OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT")
            .ok()
            .and_then(|count_limit| u32::from_str(&count_limit).ok())
        {
            config.span_limits.max_attributes_per_span = max_attributes_per_span;
        }

        if let Some(max_events_per_span) = env::var("OTEL_SPAN_EVENT_COUNT_LIMIT")
            .ok()
            .and_then(|max_events| u32::from_str(&max_events).ok())
        {
            config.span_limits.max_events_per_span = max_events_per_span;
        }

        if let Some(max_links_per_span) = env::var("OTEL_SPAN_LINK_COUNT_LIMIT")
            .ok()
            .and_then(|max_links| u32::from_str(&max_links).ok())
        {
            config.span_limits.max_links_per_span = max_links_per_span;
        }

        let sampler_arg = env::var("OTEL_TRACES_SAMPLER_ARG").ok();
        if let Ok(sampler) = env::var("OTEL_TRACES_SAMPLER") {
            config.sampler = match sampler.as_str() {
                "always_on" => Box::new(Sampler::AlwaysOn),
                "always_off" => Box::new(Sampler::AlwaysOff),
                "traceidratio" => {
                    let ratio = sampler_arg.and_then(|r| r.parse::<f64>().ok());
                    if let Some(r) = ratio {
                        Box::new(Sampler::TraceIdRatioBased(r))
                    } else {
                        handle_error(
                            Error::Other(String::from(
                                "Missing or invalid OTEL_TRACES_SAMPLER_ARG value. Falling back to default: 1.0"))
                        );
                        Box::new(Sampler::TraceIdRatioBased(1.0))
                    }
                }
                "parentbased_always_on" => {
                    Box::new(Sampler::ParentBased(Box::new(Sampler::AlwaysOn)))
                }
                "parentbased_always_off" => {
                    Box::new(Sampler::ParentBased(Box::new(Sampler::AlwaysOff)))
                }
                "parentbased_traceidratio" => {
                    let ratio = sampler_arg.and_then(|r| r.parse::<f64>().ok());
                    if let Some(r) = ratio {
                        Box::new(Sampler::ParentBased(Box::new(Sampler::TraceIdRatioBased(
                            r,
                        ))))
                    } else {
                        handle_error(
                            Error::Other(String::from(
                            "Missing or invalid OTEL_TRACES_SAMPLER_ARG value. Falling back to default: 1.0"
                        )));
                        Box::new(Sampler::ParentBased(Box::new(Sampler::TraceIdRatioBased(
                            1.0,
                        ))))
                    }
                }
                "parentbased_jaeger_remote" => {
                    handle_error(
                        Error::Other(String::from(
                        "Unimplemented parentbased_jaeger_remote sampler. Falling back to default: parentbased_always_on"
                    )));
                    Box::new(Sampler::ParentBased(Box::new(Sampler::AlwaysOn)))
                }
                "jaeger_remote" => {
                    handle_error(
                        Error::Other(String::from("Unimplemented jaeger_remote sampler. Falling back to default: parentbased_always_on")));
                    Box::new(Sampler::ParentBased(Box::new(Sampler::AlwaysOn)))
                }
                "xray" => {
                    handle_error(
                        Error::Other(String::from("Unimplemented xray sampler. Falling back to default: parentbased_always_on")));
                    Box::new(Sampler::ParentBased(Box::new(Sampler::AlwaysOn)))
                }
                s => {
                    handle_error(
                        Error::Other(format!("Unrecognised OTEL_TRACES_SAMPLER value: {}. Falling back to default: parentbased_always_on",
                        s
                    )));
                    Box::new(Sampler::ParentBased(Box::new(Sampler::AlwaysOn)))
                }
            }
        }

        config
    }
}
<|endoftext|>