<commit_before>use std::sync::atomic::{self, AtomicPtr};
use std::cell::Cell;

static GARBAGE: Stack<Box<Drop>> = Stack::new();
static ACTIVE_SNAPSHOTS: Stack<RawSnapshot> = Stack::new();
static STATE: State = State::new();
static TICKS_BEFORE_GC: u16 = 2000;

thread_local!(static CLOCK: Cell<u16> = Cell::new(0));
thread_local!(static ACTIVE_READERS: Cell<usize> = Cell::new(0));

pub fn gc() {
    if ACTIVE_SNAPSHOTS.get() != 0 {
        return;
    }

    // Start the garbage collection.
    if !STATE.start_gc() {
        // Another thread is garbage collecting, so we short-circuit.
        return;
    }

    // Initially, every garbage is marked unused.
    let mut unused = GARBAGE.collect();

    // Traverse the active snapshots and update the reference counts.
    ACTIVE_SNAPSHOTS.take_each(|reader| {
        if reader.active.load() {
            // The reader is not released yet, and is thus considered active.

            // Remove the reader from the unused set and insert it back into the log (if it
            // exists in the unused set), as the garbage is active.
            unused.remove(reader.ptr).map(|x| GARBAGE.insert(x));
            // Put the reader back in the structure.
            ACTIVE_SNAPSHOTS.insert(reader);
        } else {
            // The reader was released. Destroy it.
            reader.destroy();
        }
    });

    // End the garbage collection cycle.
    STATE.end_gc();
}

pub fn tick() {
    let clock = CLOCK.get();
    if clock == TICKS_BEFORE_GC {
        CLOCK.set(0);
        gc();
    } else {
        CLOCK.set(clock + 1);
    }
}

pub fn read<T, F>(f: F) -> T
where F: Fn(Reader) -> T {
    let mut active = ACTIVE_READERS.get();
    ACTIVE_READERS.set(active + 1);
    if active == 0 {
        STATE.start_read();
    }

    let reader = Reader;
    let ret = f(&reader);

    active = ACTIVE_READERS.get();
    if active == 1 {
        STATE.end_read();
    }
    ACTIVE_READERS.set(active - 1);

    ret
}

pub struct Reader;

impl Reader {
    pub fn load<T>(&self, a: &Atomic<T>) -> Snapshot<T> {
        // Construct the raw reader.
        let reader = RawSnapshot {
            // Load a snapshot of the pointer.
            ptr: self.inner.load(atomic::Ordering::Relaxed),
            // We allocate the atomic boolean on the heap as it is shared between the returned RAII
            // guard and the reader stack.
            released: Box::into_raw(Box::new(AtomicBool::new(false))),
        };

        // Register the reader through the reader stack, ensuring that it is not freed before the
        // RAII guard drops (`reader.release` is set to `true`).
        ACTIVE_SNAPSHOTS.push(reader);

        Snapshot {
            raw: reader,
            _marker: PhantomData,
        }
    }
}

pub struct Stack<T> {
    head: AtomicPtr<Node<T>>,
}

struct Node<T> {
    data: T,
    next: *mut Node<T>,
}

impl<T> Stack<T> {
    const fn new() -> Stack<T> {
        Stack {
            head: AtomicPtr::new(0 as *const T),
        }
    }

    fn push(&self, t: T) {
        // Allocate the node, and immediately turn it into a `*mut` pointer.
        let n = Box::into_raw(Box::new(Node {
            data: t,
            next: null_mut(),
        }));

        loop {
            // Snapshot current head.
            let head = self.head.load(atomic::Ordering::Relaxed);

            // Update `next` pointer with snapshot.
            unsafe { (*n).next = head; }

            // If snapshot is still good, link in new node.
            if self.head.compare_and_swap(head, n, atomic::Ordering::Release) == head {
                break
            }
        }
    }

    fn take_each(&self, f: F)
    where F: Fn(T) {
        // Replace the old head with a null pointer.
        let mut node = self.head.swap(AtomicPtr::default(), atomic::Ordering::Acquire);

        // We traverse every node until the pointer is null.
        while !node.is_null() {
            // Read the node into an owned box.
            let bx = unsafe { Box::from_raw(head) };
            // Apply the provided closure.
            f(bx.data);
            // Go to the next link.
            node = bx.next;
        }
    }

    fn collect(&self) -> HashSet<T> {
        let mut hs = HashSet::new();
        self.take_each(|x| hs.insert(x));

        hs
    }
}

struct RawSnapshot<T> {
    active: *const AtomicBool,
    ptr: *const T,
}

impl RawSnapshot {
    unsafe fn destroy(self) {
        // Drop the atomic boolean stored on the heap.
        mem::drop_in_place(self.active);
    }
}

struct Snapshot<'a, T> {
    raw: RawSnapshot,
    _marker: PhantomData<'a>,
}

impl<'a, T> Snapshot<'a, T> {
    fn drop(&mut self) {
        self.raw.active.store(true);
    }
}

#[derive(Default)]
struct State {
    flags: AtomicUsize,
}

impl State {
    fn start_gc(&self) -> bool {
        // Mark that a garbage collection is pending.
        if self.flags.fetch_or(1, atomic::Ordering::Relaxed) & 1 != 0 {
            // Another thread is pending to or currently garbage collecting, so we won't do the
            // same.
            return false;
        }

        // Spin until no thread is currently modifying the stacks. This prevents premature frees in
        // the thread which is currently pushing to the active snapshots.
        loop {
            // Read the flags, and if no active snapshots or garbage collectors, activate garbage
            // collection.
            let flags = self.flags.compare_and_swap(1, 0b11, atomic::Ordering::Relaxed);
            if flags == 1 {
                // Currently, no one accesses the active snapshot stack and the CAS above means
                // that the lowest bitflag have been set, indicating that a garbage collection is
                // now active.
                return true;
            }
        }
    }

    fn end_gc(&self) {
        self.flags.fetch_sub(1, atomic::Ordering::Relaxed);
    }

    fn start_read(&self) {
        // Increment the number of threads currently pushing to the active snapshot stack. We add
        // two to account for the LSB being a separate bitflag.
        self.flags.fetch_add(2, atomic::Ordering::Relaxed);
    }

    fn end_read(&self) {
        self.flags.fetch_sub(2, atomic::Ordering::Relaxed);
    }
}

pub struct Atomic<T> {
    inner: AtomicPtr<T>,
}

impl<T> Atomic<T> {
    pub fn new(inner: T) -> Atomic<T> {
        Atomic {
            inner: AtomicPtr::new(Box::into_raw(Box::new(inner))),
        }
    }

    pub fn load(&self) -> Snapshot<T> {
        read(|r| r.load(self))
    }

    pub fn store(&self, new: Box<T>) {
        // Replace the inner by the new value.
        let old = self.inner.swap(Box::into_raw(new), atomic::Ordering::Relaxed);
        // Push the old pointer to the garbage stack.
        GARBAGE.push(Box::from_raw(old));

        tick();
    }
}
<commit_msg>Don't reset the memory reclamation clock if the thread has an active reader.<commit_after>use std::sync::atomic::{self, AtomicPtr};
use std::cell::Cell;

static GARBAGE: Stack<Box<Drop>> = Stack::new();
static ACTIVE_SNAPSHOTS: Stack<RawSnapshot> = Stack::new();
static STATE: State = State::new();
static TICKS_BEFORE_GC: u16 = 2000;

thread_local!(static CLOCK: Cell<u16> = Cell::new(0));
thread_local!(static ACTIVE_READERS: Cell<usize> = Cell::new(0));

pub fn gc() {
    // Check if there are any active readers.
    if ACTIVE_READERS.get() != 0 {
        // There are. We cannot garbage collect with active readers, hence we must skip it.
        return;
    }

    // TODO: Set this to !0 to avoid a gc from happening in a destructor.
    // Set the clock back to zero to delay the next garbage collection.
    CLOCK.set(0);

    // Start the garbage collection.
    if !STATE.start_gc() {
        // Another thread is garbage collecting, so we short-circuit. We won't set back the clock,
        // as the other thread will have collected the garbage.
        return;
    }

    // Initially, every garbage is marked unused.
    let mut unused = GARBAGE.collect();

    // Traverse the active snapshots and update the reference counts.
    ACTIVE_SNAPSHOTS.take_each(|reader| {
        if reader.active.load() {
            // The reader is not released yet, and is thus considered active.

            // Remove the reader from the unused set and insert it back into the log (if it
            // exists in the unused set), as the garbage is active.
            unused.remove(reader.ptr).map(|x| GARBAGE.insert(x));
            // Put the reader back in the structure.
            ACTIVE_SNAPSHOTS.insert(reader);
        } else {
            // The reader was released. Destroy it.
            reader.destroy();
        }
    });

    // End the garbage collection cycle.
    STATE.end_gc();
}

pub fn tick() {
    let clock = CLOCK.get();
    if clock == TICKS_BEFORE_GC {
        gc();
    } else {
        CLOCK.set(clock + 1);
    }
}

pub fn read<T, F>(f: F) -> T
where F: Fn(Reader) -> T {
    let mut active = ACTIVE_READERS.get();
    ACTIVE_READERS.set(active + 1);
    if active == 0 {
        STATE.start_read();
    }

    let reader = Reader;
    let ret = f(&reader);

    active = ACTIVE_READERS.get();
    if active == 1 {
        STATE.end_read();
    }
    ACTIVE_READERS.set(active - 1);

    ret
}

pub struct Reader;

impl Reader {
    pub fn load<T>(&self, a: &Atomic<T>) -> Snapshot<T> {
        // Construct the raw reader.
        let reader = RawSnapshot {
            // Load a snapshot of the pointer.
            ptr: self.inner.load(atomic::Ordering::Relaxed),
            // We allocate the atomic boolean on the heap as it is shared between the returned RAII
            // guard and the reader stack.
            released: Box::into_raw(Box::new(AtomicBool::new(false))),
        };

        // Register the reader through the reader stack, ensuring that it is not freed before the
        // RAII guard drops (`reader.release` is set to `true`).
        ACTIVE_SNAPSHOTS.push(reader);

        Snapshot {
            raw: reader,
            _marker: PhantomData,
        }
    }
}

pub struct Stack<T> {
    head: AtomicPtr<Node<T>>,
}

struct Node<T> {
    data: T,
    next: *mut Node<T>,
}

impl<T> Stack<T> {
    const fn new() -> Stack<T> {
        Stack {
            head: AtomicPtr::new(0 as *const T),
        }
    }

    fn push(&self, t: T) {
        // Allocate the node, and immediately turn it into a `*mut` pointer.
        let n = Box::into_raw(Box::new(Node {
            data: t,
            next: null_mut(),
        }));

        loop {
            // Snapshot current head.
            let head = self.head.load(atomic::Ordering::Relaxed);

            // Update `next` pointer with snapshot.
            unsafe { (*n).next = head; }

            // If snapshot is still good, link in new node.
            if self.head.compare_and_swap(head, n, atomic::Ordering::Release) == head {
                break
            }
        }
    }

    fn take_each(&self, f: F)
    where F: Fn(T) {
        // Replace the old head with a null pointer.
        let mut node = self.head.swap(AtomicPtr::default(), atomic::Ordering::Acquire);

        // We traverse every node until the pointer is null.
        while !node.is_null() {
            // Read the node into an owned box.
            let bx = unsafe { Box::from_raw(head) };
            // Apply the provided closure.
            f(bx.data);
            // Go to the next link.
            node = bx.next;
        }
    }

    fn collect(&self) -> HashSet<T> {
        let mut hs = HashSet::new();
        self.take_each(|x| hs.insert(x));

        hs
    }
}

struct RawSnapshot<T> {
    active: *const AtomicBool,
    ptr: *const T,
}

impl RawSnapshot {
    unsafe fn destroy(self) {
        // Drop the atomic boolean stored on the heap.
        mem::drop_in_place(self.active);
    }
}

struct Snapshot<'a, T> {
    raw: RawSnapshot,
    _marker: PhantomData<'a>,
}

impl<'a, T> Snapshot<'a, T> {
    fn drop(&mut self) {
        self.raw.active.store(true);
    }
}

#[derive(Default)]
struct State {
    flags: AtomicUsize,
}

impl State {
    fn start_gc(&self) -> bool {
        // Mark that a garbage collection is pending.
        if self.flags.fetch_or(1, atomic::Ordering::Relaxed) & 1 != 0 {
            // Another thread is pending to or currently garbage collecting, so we won't do the
            // same.
            return false;
        }

        // Spin until no thread is currently modifying the stacks. This prevents premature frees in
        // the thread which is currently pushing to the active snapshots.
        loop {
            // Read the flags, and if no active snapshots or garbage collectors, activate garbage
            // collection.
            let flags = self.flags.compare_and_swap(1, 0b11, atomic::Ordering::Relaxed);
            if flags == 1 {
                // Currently, no one accesses the active snapshot stack and the CAS above means
                // that the lowest bitflag have been set, indicating that a garbage collection is
                // now active.
                return true;
            }
        }
    }

    fn end_gc(&self) {
        self.flags.fetch_sub(1, atomic::Ordering::Relaxed);
    }

    fn start_read(&self) {
        // Increment the number of threads currently pushing to the active snapshot stack. We add
        // two to account for the LSB being a separate bitflag.
        self.flags.fetch_add(2, atomic::Ordering::Relaxed);
    }

    fn end_read(&self) {
        self.flags.fetch_sub(2, atomic::Ordering::Relaxed);
    }
}

pub struct Atomic<T> {
    inner: AtomicPtr<T>,
}

impl<T> Atomic<T> {
    pub fn new(inner: T) -> Atomic<T> {
        Atomic {
            inner: AtomicPtr::new(Box::into_raw(Box::new(inner))),
        }
    }

    pub fn load(&self) -> Snapshot<T> {
        read(|r| r.load(self))
    }

    pub fn store(&self, new: Box<T>) {
        // Replace the inner by the new value.
        let old = self.inner.swap(Box::into_raw(new), atomic::Ordering::Relaxed);
        // Push the old pointer to the garbage stack.
        GARBAGE.push(Box::from_raw(old));

        tick();
    }
}
<|endoftext|>


<commit_before>//
// gash.rs
//
// Starting code for PS2
// Running on Rust 0.9
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu, David Evans
// Version 0.4
//
#[feature(globs)];
extern mod extra;

use std::{io, run, os};
use std::io::buffered::BufferedReader;

use std::io::stdin;

use extra::getopts;
use std::path::*;
use std::libc;

struct Shell {
    pipeflag: bool,
    ioflag: bool,
    flag: bool,
    history: ~[~str],
    cmd_prompt: ~str,

}

impl Shell {
    fn new(prompt_str: &str, zerohis: &[~str]) -> Shell {
        Shell {
            pipeflag: false,
            ioflag: false,
            flag: false,
            history: zerohis.to_owned(),
            cmd_prompt: prompt_str.to_owned(),

        }
    }

    fn run(&mut self) {

        let mut stdin = BufferedReader::new(stdin());

        let mut in_chan = libc::STDIN_FILENO;
        let mut out_chan = libc::STDOUT_FILENO;

       loop {
            self.pipeflag = false;
            self.flag = false;
            self.ioflag = false;
            print(self.cmd_prompt);
            io::stdio::flush();

            let line = stdin.read_line().unwrap();
            let cmd_line = line.trim().to_owned();

            //println!("{:s}", cmd_line)   command_line is owned and trimmed of leading/lagging white space
            //println!("{:s}", line)        line is the arguement passed in as is
            let program = cmd_line.splitn(' ', 1).nth(0).expect("no program");

            //println!("{:s}", program)     program is just the command without arguements
            if cmd_line.ends_with("&")
            {
                self.flag = true;

            }

            let cmd_line1 = cmd_line.clone();

            let cmd_line2 = cmd_line1.to_owned();

            let cmd_line3 = cmd_line2.slice_to(cmd_line2.len()-2);
            let mut argvAnd: ~[~str] =
            cmd_line3.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();
            argvAnd.remove(0);

            let mut argvPipe: ~[&str];

            let mut cmd_array: ~[&str];

            if self.flag == true
            {
                cmd_array = cmd_line3.split_str(" ").collect();
                argvPipe = cmd_line3.split_str_iter('|').filter_map(|x| if x != "" {Some(x.to_owned())}else{None}).to_owned_vec();
            }
            else
            {
                cmd_array = cmd_line1.split_str(" ").collect();
                argvPipe = cmd_line1.split_str_iter('|').filter_map(|x| if x != "" {Some(x.to_owned())}else{None}).to_owned_vec();
            }

            let mut cmd_ac: ~[&str] = cmd_array.clone().to_owned();

            for i in range(0, cmd_ac.len()-1)
            {
                if cmd_ac[i] == ">"
                {
                    self.ioflag  = true;
                    //print(cmd_ac[i+1]);
                    out_chan = self.get_fd(cmd_ac.remove(i+1), "w");
                }
                if cmd_ac[i] == "<"
                {
                    self.ioflag = true;
                    //print(cmd_ac[i+1]);
                    in_chan = self.get_fd(cmd_ac.remove(i+1), "r");
                }

            }

            for i in range(0, cmd_ac.len()-1)
            {
                if cmd_ac[i] == ">"
                {
                    self.ioflag  = true;
                    cmd_ac.remove(i);
                }
                if cmd_ac[i] == "<"
                {
                    self.ioflag = true;
                    cmd_ac.remove(i);
                }

            }

            /*for i in range(0, cmd_ac.len()-1)
            {
                println(format!(" print if you are working: {:s}", cmd_ac[i]));
            }*/

            //println(format!("{:s}", program));

            //println("{:s}",cmd_line3);

            match program {
                ""      =>  { continue; },
                "exit"  =>  { return; },
                _       =>  {
                            if self.cmd_exists(program)
                            {
                            if self.flag == true
                            {
                                self.flag = false;

                                if self.ioflag == true
                                {
                                    self.ioflag = false;

                                    let myproc = run::Process::new(program, argvAnd, run::ProcessOptions
                                    {
                                            env: None,
                                            dir: None,
                                            in_fd: Some(in_chan),
                                            out_fd: Some(out_chan),
                                            err_fd: Some(libc::STDERR_FILENO)

                                    });

                            //let i = myproc.clone().unwrap().get_id();
                            //println(format!("{}", i));
                                self.run();
                                myproc.unwrap().finish();
                                }

                                else
                                {
                                    let myproc = run::Process::new(program, argvAnd, run::ProcessOptions
                                    {
                                            env: None,
                                            dir: None,
                                            in_fd: None,
                                            out_fd: None,
                                            err_fd: None

                                    });
                                    self.run();
                                    myproc.unwrap().finish();
                                }

                            }

                            else
                            {
                            self.run_cmdline(cmd_line2);

                            }

                            }

                            else
                            {
                                println!("{:s}: command not found", program);
                            }

                                //self.run_cmdline(port.recv());
                                //self.run_cmdline(port1.recv());
                            }

                        };

        }

    }

    fn get_fd(&mut self, filepth: &str, mode: &str)-> libc::c_int
    {
        unsafe
        {
            let filename = filepth.to_c_str().unwrap();
            let filemode = mode.to_c_str().unwrap();
            return libc::fileno(libc::fopen(filename, filemode));
        }
    }

    fn cd(&mut self, new_path:&Path) // the change directory method
    {

        if new_path.exists() && new_path.is_dir()
        {
            os::change_dir(new_path);

        }
        else if !new_path.is_dir()
        {
            println(format!("cd: {}: is not a Directory", new_path.display()));

        }
        else
        {
            println(format!("cd: {}: is not a File", new_path.display()));
        }

    }

    fn run_cmdline(&mut self, cmd_line: &str) {

        let mut argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();
            //argv is owned pointer to a vector of owned strings - each word gets its own place in the vector
        if argv.len() > 0 {
            self.history.push(cmd_line.to_owned());
            let program: ~str = argv.remove(0); //removes and returns the elements, shift vector left
            self.run_cmd(program, argv);
        }
    }

    fn run_cmd(&mut self, program: &str, argv: &[~str]) {

        let mut args: ~[~str] = argv.to_owned();
        match program
        {
            "cd"        =>  {
                                if !argv.is_empty()
                                {
                                    let mut my_str: ~str;
                                    my_str = args.remove(0);
                                    let file = Path::new(my_str);
                                    self.cd(&file);
                                }
                                else
                                {
                                    self.cd(&os::getcwd());
                                }
                            },

           "history"   =>  {
                                println("History:");
                                let mut i = 1;
                                for x in self.history.rev_iter()
                                {
                                    println(format!("{:d}:  {:s}", i, x.to_owned()));
                                    i = i + 1;

                                }
                           },

            _           =>

                           {
                                if self.cmd_exists(program)
                                {

                                    run::process_status(program, argv); //spawns new process, waits for completion - must take vector string args for program

                                }
                                else
                                {
                                    println!("{:s}: command not found", program);
                                }
                            }
        }
        let cwd = os::getcwd();
        print(format!("{}: ", cwd.display()));

    }

    fn cmd_exists(&mut self, cmd_path: &str) -> bool {
        let ret = run::process_output("which", [cmd_path.to_owned()]); //
        //print(ret);
        return ret.expect("exit code error.").status.success();
    }
}

fn get_cmdline_from_args() -> Option<~str> {
    /* Begin processing program arguments and initiate the parameters. */
    let args = os::args();

    let opts = ~[
        getopts::optopt("c")
    ];

    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => { m }
        Err(f) => { fail!(f.to_err_msg()) }
    };

    if matches.opt_present("c") {
        let cmd_str = match matches.opt_str("c") {
                                                Some(cmd_str) => {cmd_str.to_owned()},
                                                None => {~""}
                                              };
        return Some(cmd_str);
    } else {
        return None;
    }
}

fn main() {

    let opt_cmd_line = get_cmdline_from_args();
    let newhis = ~[];
    match opt_cmd_line {
        Some(cmd_line) => Shell::new("", newhis).run_cmdline(cmd_line),
        None           => Shell::new("gash > ", newhis).run()
    }
}
<commit_msg>Submission number 2<commit_after>//
// gash.rs
//
// Starting code for PS2
// Running on Rust 0.9
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu, David Evans
// Version 0.4
//
#[feature(globs)];
extern mod extra;

use std::{io, run, os};
use std::io::buffered::BufferedReader;

use std::io::stdin;

use extra::getopts;
use std::path::*;
use std::libc;

struct Shell {
    pipeflag: bool,
    ioflag: bool,
    flag: bool,
    history: ~[~str],
    cmd_prompt: ~str,

}

impl Shell {
    fn new(prompt_str: &str, zerohis: &[~str]) -> Shell {
        Shell {
            pipeflag: false,
            ioflag: false,
            flag: false,
            history: zerohis.to_owned(),
            cmd_prompt: prompt_str.to_owned(),

        }
    }

    fn run(&mut self) {

        let mut stdin = BufferedReader::new(stdin());

        let mut in_chan = libc::STDIN_FILENO;
        let mut out_chan = libc::STDOUT_FILENO;

       loop {
            self.pipeflag = false;
            self.flag = false;
            self.ioflag = false;
            print(self.cmd_prompt);
            io::stdio::flush();

            let line = stdin.read_line().unwrap();
            let cmd_line = line.trim().to_owned();

            //println!("{:s}", cmd_line)   command_line is owned and trimmed of leading/lagging white space
            //println!("{:s}", line)        line is the arguement passed in as is
            let program = cmd_line.splitn(' ', 1).nth(0).expect("no program");

            //println!("{:s}", program)     program is just the command without arguements
            if cmd_line.ends_with("&")
            {
                self.flag = true;

            }

            let cmd_line1 = cmd_line.clone();

            let cmd_line2 = cmd_line1.to_owned();

            let cmd_line3 = cmd_line2.slice_to(cmd_line2.len()-2);
            let mut argvAnd: ~[~str] =
            cmd_line3.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();
            argvAnd.remove(0);

            //let mut argvPipe: ~[&str];

            let mut cmd_array: ~[&str];

            if self.flag == true
            {
                cmd_array = cmd_line3.split_str(" ").collect();
                //argvPipe = cmd_line3.split_str_iter('|').filter_map(|x| if x != "" {Some(x.to_owned())}else{None}).to_owned_vec();
            }
            else
            {
                cmd_array = cmd_line1.split_str(" ").collect();
                //argvPipe = cmd_line1.split_str_iter('|').filter_map(|x| if x != "" {Some(x.to_owned())}else{None}).to_owned_vec();
            }

            let mut cmd_ac: ~[&str] = cmd_array.clone().to_owned();

            for i in range(0, cmd_ac.len()-1)
            {
                if cmd_ac[i] == ">"
                {
                    self.ioflag  = true;
                    //print(cmd_ac[i+1]);
                    out_chan = self.get_fd(cmd_ac.remove(i+1), "w");
                }
                if cmd_ac[i] == "<"
                {
                    self.ioflag = true;
                    //print(cmd_ac[i+1]);
                    in_chan = self.get_fd(cmd_ac.remove(i+1), "r");
                }

            }

            for i in range(0, cmd_ac.len()-1)
            {
                if cmd_ac[i] == ">"
                {
                    self.ioflag  = true;
                    cmd_ac.remove(i);
                }
                if cmd_ac[i] == "<"
                {
                    self.ioflag = true;
                    cmd_ac.remove(i);
                }

            }

            /*for i in range(0, cmd_ac.len()-1)
            {
                println(format!(" print if you are working: {:s}", cmd_ac[i]));
            }*/

            //println(format!("{:s}", program));

            //println("{:s}",cmd_line3);

            match program {
                ""      =>  { continue; },
                "exit"  =>  { return; },
                _       =>  {
                            if self.cmd_exists(program)
                            {
                            if self.flag == true
                            {
                                self.flag = false;

                                if self.ioflag == true
                                {
                                    self.ioflag = false;

                                    let myproc = run::Process::new(program, argvAnd, run::ProcessOptions
                                    {
                                            env: None,
                                            dir: None,
                                            in_fd: Some(in_chan),
                                            out_fd: Some(out_chan),
                                            err_fd: Some(libc::STDERR_FILENO)

                                    });

                            //let i = myproc.clone().unwrap().get_id();
                            //println(format!("{}", i));
                                self.run();
                                myproc.unwrap().finish();
                                }

                                else
                                {
                                    let myproc = run::Process::new(program, argvAnd, run::ProcessOptions
                                    {
                                            env: None,
                                            dir: None,
                                            in_fd: None,
                                            out_fd: None,
                                            err_fd: None

                                    });
                                    self.run();
                                    myproc.unwrap().finish();
                                }

                            }

                            else
                            {
                            self.run_cmdline(cmd_line2);

                            }

                            }

                            else
                            {
                                println!("{:s}: command not found", program);
                            }

                                //self.run_cmdline(port.recv());
                                //self.run_cmdline(port1.recv());
                            }

                        };

        }

    }

    fn get_fd(&mut self, filepth: &str, mode: &str)-> libc::c_int
    {
        unsafe
        {
            let filename = filepth.to_c_str().unwrap();
            let filemode = mode.to_c_str().unwrap();
            return libc::fileno(libc::fopen(filename, filemode));
        }
    }

    fn cd(&mut self, new_path:&Path) // the change directory method
    {

        if new_path.exists() && new_path.is_dir()
        {
            os::change_dir(new_path);

        }
        else if !new_path.is_dir()
        {
            println(format!("cd: {}: is not a Directory", new_path.display()));

        }
        else
        {
            println(format!("cd: {}: is not a File", new_path.display()));
        }

    }

    fn run_cmdline(&mut self, cmd_line: &str) {

        let mut argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();
            //argv is owned pointer to a vector of owned strings - each word gets its own place in the vector
        if argv.len() > 0 {
            self.history.push(cmd_line.to_owned());
            let program: ~str = argv.remove(0); //removes and returns the elements, shift vector left
            self.run_cmd(program, argv);
        }
    }

    fn run_cmd(&mut self, program: &str, argv: &[~str]) {

        let mut args: ~[~str] = argv.to_owned();
        match program
        {
            "cd"        =>  {
                                if !argv.is_empty()
                                {
                                    let mut my_str: ~str;
                                    my_str = args.remove(0);
                                    let file = Path::new(my_str);
                                    self.cd(&file);
                                }
                                else
                                {
                                    self.cd(&os::getcwd());
                                }
                            },

           "history"   =>  {
                                println("History:");
                                let mut i = 1;
                                for x in self.history.rev_iter()
                                {
                                    println(format!("{:d}:  {:s}", i, x.to_owned()));
                                    i = i + 1;

                                }
                           },

            _           =>

                           {
                                if self.cmd_exists(program)
                                {

                                    run::process_status(program, argv); //spawns new process, waits for completion - must take vector string args for program

                                }
                                else
                                {
                                    println!("{:s}: command not found", program);
                                }
                            }
        }
        let cwd = os::getcwd();
        print(format!("{}: ", cwd.display()));

    }

    fn cmd_exists(&mut self, cmd_path: &str) -> bool {
        let ret = run::process_output("which", [cmd_path.to_owned()]); //
        //print(ret);
        return ret.expect("exit code error.").status.success();
    }
}

fn get_cmdline_from_args() -> Option<~str> {
    /* Begin processing program arguments and initiate the parameters. */
    let args = os::args();

    let opts = ~[
        getopts::optopt("c")
    ];

    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => { m }
        Err(f) => { fail!(f.to_err_msg()) }
    };

    if matches.opt_present("c") {
        let cmd_str = match matches.opt_str("c") {
                                                Some(cmd_str) => {cmd_str.to_owned()},
                                                None => {~""}
                                              };
        return Some(cmd_str);
    } else {
        return None;
    }
}

fn main() {

    let opt_cmd_line = get_cmdline_from_args();
    let newhis = ~[];
    match opt_cmd_line {
        Some(cmd_line) => Shell::new("", newhis).run_cmdline(cmd_line),
        None           => Shell::new("gash > ", newhis).run()
    }
}
<|endoftext|>


<commit_before>use hir::{source_binder, Either, ModuleSource};
use ra_db::SourceDatabase;
use ra_syntax::{algo::find_node_at_offset, ast, AstNode, SourceFile, SyntaxNode};
use relative_path::{RelativePath, RelativePathBuf};

use crate::{
    db::RootDatabase, FileId, FilePosition, FileRange, FileSystemEdit, NavigationTarget,
    SourceChange, SourceFileEdit, TextRange,
};

#[derive(Debug, Clone)]
pub struct ReferenceSearchResult {
    declaration: NavigationTarget,
    references: Vec<FileRange>,
}

impl ReferenceSearchResult {
    pub fn declaration(&self) -> &NavigationTarget {
        &self.declaration
    }

    pub fn references(&self) -> &[FileRange] {
        &self.references
    }

    /// Total number of references
    /// At least 1 since all valid references should
    /// Have a declaration
    pub fn len(&self) -> usize {
        self.references.len() + 1
    }
}

// allow turning ReferenceSearchResult into an iterator
// over FileRanges
impl IntoIterator for ReferenceSearchResult {
    type Item = FileRange;
    type IntoIter = std::vec::IntoIter<FileRange>;

    fn into_iter(mut self) -> Self::IntoIter {
        let mut v = Vec::with_capacity(self.len());
        v.push(FileRange { file_id: self.declaration.file_id(), range: self.declaration.range() });
        v.append(&mut self.references);
        v.into_iter()
    }
}

pub(crate) fn find_all_refs(
    db: &RootDatabase,
    position: FilePosition,
) -> Option<ReferenceSearchResult> {
    let parse = db.parse(position.file_id);
    let (binding, analyzer) = find_binding(db, &parse.tree(), position)?;
    let declaration = NavigationTarget::from_bind_pat(position.file_id, &binding);

    let references = analyzer
        .find_all_refs(&binding)
        .into_iter()
        .map(move |ref_desc| FileRange { file_id: position.file_id, range: ref_desc.range })
        .collect::<Vec<_>>();

    return Some(ReferenceSearchResult { declaration, references });

    fn find_binding<'a>(
        db: &RootDatabase,
        source_file: &SourceFile,
        position: FilePosition,
    ) -> Option<(ast::BindPat, hir::SourceAnalyzer)> {
        let syntax = source_file.syntax();
        if let Some(binding) = find_node_at_offset::<ast::BindPat>(syntax, position.offset) {
            let analyzer = hir::SourceAnalyzer::new(db, position.file_id, binding.syntax(), None);
            return Some((binding, analyzer));
        };
        let name_ref = find_node_at_offset::<ast::NameRef>(syntax, position.offset)?;
        let analyzer = hir::SourceAnalyzer::new(db, position.file_id, name_ref.syntax(), None);
        let resolved = analyzer.resolve_local_name(&name_ref)?;
        if let Either::A(ptr) = resolved.ptr() {
            if let ast::PatKind::BindPat(binding) = ptr.to_node(source_file.syntax()).kind() {
                return Some((binding, analyzer));
            }
        }
        None
    }
}

pub(crate) fn rename(
    db: &RootDatabase,
    position: FilePosition,
    new_name: &str,
) -> Option<SourceChange> {
    let parse = db.parse(position.file_id);
    if let Some((ast_name, ast_module)) =
        find_name_and_module_at_offset(parse.tree().syntax(), position)
    {
        rename_mod(db, &ast_name, &ast_module, position, new_name)
    } else {
        rename_reference(db, position, new_name)
    }
}

fn find_name_and_module_at_offset(
    syntax: &SyntaxNode,
    position: FilePosition,
) -> Option<(ast::Name, ast::Module)> {
    let ast_name = find_node_at_offset::<ast::Name>(syntax, position.offset)?;
    let ast_module = ast::Module::cast(ast_name.syntax().parent()?)?;
    Some((ast_name, ast_module))
}

fn source_edit_from_fileid_range(
    file_id: FileId,
    range: TextRange,
    new_name: &str,
) -> SourceFileEdit {
    SourceFileEdit {
        file_id,
        edit: {
            let mut builder = ra_text_edit::TextEditBuilder::default();
            builder.replace(range, new_name.into());
            builder.finish()
        },
    }
}

fn rename_mod(
    db: &RootDatabase,
    ast_name: &ast::Name,
    ast_module: &ast::Module,
    position: FilePosition,
    new_name: &str,
) -> Option<SourceChange> {
    let mut source_file_edits = Vec::new();
    let mut file_system_edits = Vec::new();
    if let Some(module) =
        source_binder::module_from_declaration(db, position.file_id, ast_module.clone())
    {
        let src = module.definition_source(db);
        let file_id = src.file_id.as_original_file();
        match src.ast {
            ModuleSource::SourceFile(..) => {
                let mod_path: RelativePathBuf = db.file_relative_path(file_id);
                // mod is defined in path/to/dir/mod.rs
                let dst_path = if mod_path.file_stem() == Some("mod") {
                    mod_path
                        .parent()
                        .and_then(|p| p.parent())
                        .or_else(|| Some(RelativePath::new("")))
                        .map(|p| p.join(new_name).join("mod.rs"))
                } else {
                    Some(mod_path.with_file_name(new_name).with_extension("rs"))
                };
                if let Some(path) = dst_path {
                    let move_file = FileSystemEdit::MoveFile {
                        src: file_id,
                        dst_source_root: db.file_source_root(position.file_id),
                        dst_path: path,
                    };
                    file_system_edits.push(move_file);
                }
            }
            ModuleSource::Module(..) => {}
        }
    }

    let edit = SourceFileEdit {
        file_id: position.file_id,
        edit: {
            let mut builder = ra_text_edit::TextEditBuilder::default();
            builder.replace(ast_name.syntax().text_range(), new_name.into());
            builder.finish()
        },
    };
    source_file_edits.push(edit);

    Some(SourceChange::from_edits("rename", source_file_edits, file_system_edits))
}

fn rename_reference(
    db: &RootDatabase,
    position: FilePosition,
    new_name: &str,
) -> Option<SourceChange> {
    let refs = find_all_refs(db, position)?;

    let edit = refs
        .into_iter()
        .map(|range| source_edit_from_fileid_range(range.file_id, range.range, new_name))
        .collect::<Vec<_>>();

    if edit.is_empty() {
        return None;
    }

    Some(SourceChange::source_file_edits("rename", edit))
}

#[cfg(test)]
mod tests {
    use crate::{
        mock_analysis::analysis_and_position, mock_analysis::single_file_with_position, FileId,
        ReferenceSearchResult,
    };
    use insta::assert_debug_snapshot_matches;
    use test_utils::assert_eq_text;

    #[test]
    fn test_find_all_refs_for_local() {
        let code = r#"
    fn main() {
        let mut i = 1;
        let j = 1;
        i = i<|> + j;

        {
            i = 0;
        }

        i = 5;
    }"#;

        let refs = get_all_refs(code);
        assert_eq!(refs.len(), 5);
    }

    #[test]
    fn test_find_all_refs_for_param_inside() {
        let code = r#"
    fn foo(i : u32) -> u32 {
        i<|>
    }"#;

        let refs = get_all_refs(code);
        assert_eq!(refs.len(), 2);
    }

    #[test]
    fn test_find_all_refs_for_fn_param() {
        let code = r#"
    fn foo(i<|> : u32) -> u32 {
        i
    }"#;

        let refs = get_all_refs(code);
        assert_eq!(refs.len(), 2);
    }

    fn get_all_refs(text: &str) -> ReferenceSearchResult {
        let (analysis, position) = single_file_with_position(text);
        analysis.find_all_refs(position).unwrap().unwrap()
    }

    #[test]
    fn test_rename_for_local() {
        test_rename(
            r#"
    fn main() {
        let mut i = 1;
        let j = 1;
        i = i<|> + j;

        {
            i = 0;
        }

        i = 5;
    }"#,
            "k",
            r#"
    fn main() {
        let mut k = 1;
        let j = 1;
        k = k + j;

        {
            k = 0;
        }

        k = 5;
    }"#,
        );
    }

    #[test]
    fn test_rename_for_param_inside() {
        test_rename(
            r#"
    fn foo(i : u32) -> u32 {
        i<|>
    }"#,
            "j",
            r#"
    fn foo(j : u32) -> u32 {
        j
    }"#,
        );
    }

    #[test]
    fn test_rename_refs_for_fn_param() {
        test_rename(
            r#"
    fn foo(i<|> : u32) -> u32 {
        i
    }"#,
            "new_name",
            r#"
    fn foo(new_name : u32) -> u32 {
        new_name
    }"#,
        );
    }

    #[test]
    fn test_rename_for_mut_param() {
        test_rename(
            r#"
    fn foo(mut i<|> : u32) -> u32 {
        i
    }"#,
            "new_name",
            r#"
    fn foo(mut new_name : u32) -> u32 {
        new_name
    }"#,
        );
    }

    #[test]
    fn test_rename_mod() {
        let (analysis, position) = analysis_and_position(
            "
            //- /lib.rs
            mod bar;

            //- /bar.rs
            mod foo<|>;

            //- /bar/foo.rs
            // emtpy
            ",
        );
        let new_name = "foo2";
        let source_change = analysis.rename(position, new_name).unwrap();
        assert_debug_snapshot_matches!(&source_change,
@r#"Some(
    SourceChange {
        label: "rename",
        source_file_edits: [
            SourceFileEdit {
                file_id: FileId(
                    2,
                ),
                edit: TextEdit {
                    atoms: [
                        AtomTextEdit {
                            delete: [4; 7),
                            insert: "foo2",
                        },
                    ],
                },
            },
        ],
        file_system_edits: [
            MoveFile {
                src: FileId(
                    3,
                ),
                dst_source_root: SourceRootId(
                    0,
                ),
                dst_path: "bar/foo2.rs",
            },
        ],
        cursor_position: None,
    },
)"#);
    }

    #[test]
    fn test_rename_mod_in_dir() {
        let (analysis, position) = analysis_and_position(
            "
            //- /lib.rs
            mod fo<|>o;
            //- /foo/mod.rs
            // emtpy
            ",
        );
        let new_name = "foo2";
        let source_change = analysis.rename(position, new_name).unwrap();
        assert_debug_snapshot_matches!(&source_change,
@r###"
       ⋮Some(
       ⋮    SourceChange {
       ⋮        label: "rename",
       ⋮        source_file_edits: [
       ⋮            SourceFileEdit {
       ⋮                file_id: FileId(
       ⋮                    1,
       ⋮                ),
       ⋮                edit: TextEdit {
       ⋮                    atoms: [
       ⋮                        AtomTextEdit {
       ⋮                            delete: [4; 7),
       ⋮                            insert: "foo2",
       ⋮                        },
       ⋮                    ],
       ⋮                },
       ⋮            },
       ⋮        ],
       ⋮        file_system_edits: [
       ⋮            MoveFile {
       ⋮                src: FileId(
       ⋮                    2,
       ⋮                ),
       ⋮                dst_source_root: SourceRootId(
       ⋮                    0,
       ⋮                ),
       ⋮                dst_path: "foo2/mod.rs",
       ⋮            },
       ⋮        ],
       ⋮        cursor_position: None,
       ⋮    },
       ⋮)
        "###);
    }

    fn test_rename(text: &str, new_name: &str, expected: &str) {
        let (analysis, position) = single_file_with_position(text);
        let source_change = analysis.rename(position, new_name).unwrap();
        let mut text_edit_builder = ra_text_edit::TextEditBuilder::default();
        let mut file_id: Option<FileId> = None;
        if let Some(change) = source_change {
            for edit in change.source_file_edits {
                file_id = Some(edit.file_id);
                for atom in edit.edit.as_atoms() {
                    text_edit_builder.replace(atom.delete, atom.insert.clone());
                }
            }
        }
        let result = text_edit_builder.finish().apply(&*analysis.file_text(file_id.unwrap()));
        assert_eq_text!(expected, &*result);
    }
}
<commit_msg>Remove vertical ellipses in references.cs<commit_after>use hir::{source_binder, Either, ModuleSource};
use ra_db::SourceDatabase;
use ra_syntax::{algo::find_node_at_offset, ast, AstNode, SourceFile, SyntaxNode};
use relative_path::{RelativePath, RelativePathBuf};

use crate::{
    db::RootDatabase, FileId, FilePosition, FileRange, FileSystemEdit, NavigationTarget,
    SourceChange, SourceFileEdit, TextRange,
};

#[derive(Debug, Clone)]
pub struct ReferenceSearchResult {
    declaration: NavigationTarget,
    references: Vec<FileRange>,
}

impl ReferenceSearchResult {
    pub fn declaration(&self) -> &NavigationTarget {
        &self.declaration
    }

    pub fn references(&self) -> &[FileRange] {
        &self.references
    }

    /// Total number of references
    /// At least 1 since all valid references should
    /// Have a declaration
    pub fn len(&self) -> usize {
        self.references.len() + 1
    }
}

// allow turning ReferenceSearchResult into an iterator
// over FileRanges
impl IntoIterator for ReferenceSearchResult {
    type Item = FileRange;
    type IntoIter = std::vec::IntoIter<FileRange>;

    fn into_iter(mut self) -> Self::IntoIter {
        let mut v = Vec::with_capacity(self.len());
        v.push(FileRange { file_id: self.declaration.file_id(), range: self.declaration.range() });
        v.append(&mut self.references);
        v.into_iter()
    }
}

pub(crate) fn find_all_refs(
    db: &RootDatabase,
    position: FilePosition,
) -> Option<ReferenceSearchResult> {
    let parse = db.parse(position.file_id);
    let (binding, analyzer) = find_binding(db, &parse.tree(), position)?;
    let declaration = NavigationTarget::from_bind_pat(position.file_id, &binding);

    let references = analyzer
        .find_all_refs(&binding)
        .into_iter()
        .map(move |ref_desc| FileRange { file_id: position.file_id, range: ref_desc.range })
        .collect::<Vec<_>>();

    return Some(ReferenceSearchResult { declaration, references });

    fn find_binding<'a>(
        db: &RootDatabase,
        source_file: &SourceFile,
        position: FilePosition,
    ) -> Option<(ast::BindPat, hir::SourceAnalyzer)> {
        let syntax = source_file.syntax();
        if let Some(binding) = find_node_at_offset::<ast::BindPat>(syntax, position.offset) {
            let analyzer = hir::SourceAnalyzer::new(db, position.file_id, binding.syntax(), None);
            return Some((binding, analyzer));
        };
        let name_ref = find_node_at_offset::<ast::NameRef>(syntax, position.offset)?;
        let analyzer = hir::SourceAnalyzer::new(db, position.file_id, name_ref.syntax(), None);
        let resolved = analyzer.resolve_local_name(&name_ref)?;
        if let Either::A(ptr) = resolved.ptr() {
            if let ast::PatKind::BindPat(binding) = ptr.to_node(source_file.syntax()).kind() {
                return Some((binding, analyzer));
            }
        }
        None
    }
}

pub(crate) fn rename(
    db: &RootDatabase,
    position: FilePosition,
    new_name: &str,
) -> Option<SourceChange> {
    let parse = db.parse(position.file_id);
    if let Some((ast_name, ast_module)) =
        find_name_and_module_at_offset(parse.tree().syntax(), position)
    {
        rename_mod(db, &ast_name, &ast_module, position, new_name)
    } else {
        rename_reference(db, position, new_name)
    }
}

fn find_name_and_module_at_offset(
    syntax: &SyntaxNode,
    position: FilePosition,
) -> Option<(ast::Name, ast::Module)> {
    let ast_name = find_node_at_offset::<ast::Name>(syntax, position.offset)?;
    let ast_module = ast::Module::cast(ast_name.syntax().parent()?)?;
    Some((ast_name, ast_module))
}

fn source_edit_from_fileid_range(
    file_id: FileId,
    range: TextRange,
    new_name: &str,
) -> SourceFileEdit {
    SourceFileEdit {
        file_id,
        edit: {
            let mut builder = ra_text_edit::TextEditBuilder::default();
            builder.replace(range, new_name.into());
            builder.finish()
        },
    }
}

fn rename_mod(
    db: &RootDatabase,
    ast_name: &ast::Name,
    ast_module: &ast::Module,
    position: FilePosition,
    new_name: &str,
) -> Option<SourceChange> {
    let mut source_file_edits = Vec::new();
    let mut file_system_edits = Vec::new();
    if let Some(module) =
        source_binder::module_from_declaration(db, position.file_id, ast_module.clone())
    {
        let src = module.definition_source(db);
        let file_id = src.file_id.as_original_file();
        match src.ast {
            ModuleSource::SourceFile(..) => {
                let mod_path: RelativePathBuf = db.file_relative_path(file_id);
                // mod is defined in path/to/dir/mod.rs
                let dst_path = if mod_path.file_stem() == Some("mod") {
                    mod_path
                        .parent()
                        .and_then(|p| p.parent())
                        .or_else(|| Some(RelativePath::new("")))
                        .map(|p| p.join(new_name).join("mod.rs"))
                } else {
                    Some(mod_path.with_file_name(new_name).with_extension("rs"))
                };
                if let Some(path) = dst_path {
                    let move_file = FileSystemEdit::MoveFile {
                        src: file_id,
                        dst_source_root: db.file_source_root(position.file_id),
                        dst_path: path,
                    };
                    file_system_edits.push(move_file);
                }
            }
            ModuleSource::Module(..) => {}
        }
    }

    let edit = SourceFileEdit {
        file_id: position.file_id,
        edit: {
            let mut builder = ra_text_edit::TextEditBuilder::default();
            builder.replace(ast_name.syntax().text_range(), new_name.into());
            builder.finish()
        },
    };
    source_file_edits.push(edit);

    Some(SourceChange::from_edits("rename", source_file_edits, file_system_edits))
}

fn rename_reference(
    db: &RootDatabase,
    position: FilePosition,
    new_name: &str,
) -> Option<SourceChange> {
    let refs = find_all_refs(db, position)?;

    let edit = refs
        .into_iter()
        .map(|range| source_edit_from_fileid_range(range.file_id, range.range, new_name))
        .collect::<Vec<_>>();

    if edit.is_empty() {
        return None;
    }

    Some(SourceChange::source_file_edits("rename", edit))
}

#[cfg(test)]
mod tests {
    use crate::{
        mock_analysis::analysis_and_position, mock_analysis::single_file_with_position, FileId,
        ReferenceSearchResult,
    };
    use insta::assert_debug_snapshot_matches;
    use test_utils::assert_eq_text;

    #[test]
    fn test_find_all_refs_for_local() {
        let code = r#"
    fn main() {
        let mut i = 1;
        let j = 1;
        i = i<|> + j;

        {
            i = 0;
        }

        i = 5;
    }"#;

        let refs = get_all_refs(code);
        assert_eq!(refs.len(), 5);
    }

    #[test]
    fn test_find_all_refs_for_param_inside() {
        let code = r#"
    fn foo(i : u32) -> u32 {
        i<|>
    }"#;

        let refs = get_all_refs(code);
        assert_eq!(refs.len(), 2);
    }

    #[test]
    fn test_find_all_refs_for_fn_param() {
        let code = r#"
    fn foo(i<|> : u32) -> u32 {
        i
    }"#;

        let refs = get_all_refs(code);
        assert_eq!(refs.len(), 2);
    }

    fn get_all_refs(text: &str) -> ReferenceSearchResult {
        let (analysis, position) = single_file_with_position(text);
        analysis.find_all_refs(position).unwrap().unwrap()
    }

    #[test]
    fn test_rename_for_local() {
        test_rename(
            r#"
    fn main() {
        let mut i = 1;
        let j = 1;
        i = i<|> + j;

        {
            i = 0;
        }

        i = 5;
    }"#,
            "k",
            r#"
    fn main() {
        let mut k = 1;
        let j = 1;
        k = k + j;

        {
            k = 0;
        }

        k = 5;
    }"#,
        );
    }

    #[test]
    fn test_rename_for_param_inside() {
        test_rename(
            r#"
    fn foo(i : u32) -> u32 {
        i<|>
    }"#,
            "j",
            r#"
    fn foo(j : u32) -> u32 {
        j
    }"#,
        );
    }

    #[test]
    fn test_rename_refs_for_fn_param() {
        test_rename(
            r#"
    fn foo(i<|> : u32) -> u32 {
        i
    }"#,
            "new_name",
            r#"
    fn foo(new_name : u32) -> u32 {
        new_name
    }"#,
        );
    }

    #[test]
    fn test_rename_for_mut_param() {
        test_rename(
            r#"
    fn foo(mut i<|> : u32) -> u32 {
        i
    }"#,
            "new_name",
            r#"
    fn foo(mut new_name : u32) -> u32 {
        new_name
    }"#,
        );
    }

    #[test]
    fn test_rename_mod() {
        let (analysis, position) = analysis_and_position(
            "
            //- /lib.rs
            mod bar;

            //- /bar.rs
            mod foo<|>;

            //- /bar/foo.rs
            // emtpy
            ",
        );
        let new_name = "foo2";
        let source_change = analysis.rename(position, new_name).unwrap();
        assert_debug_snapshot_matches!(&source_change,
@r#"Some(
    SourceChange {
        label: "rename",
        source_file_edits: [
            SourceFileEdit {
                file_id: FileId(
                    2,
                ),
                edit: TextEdit {
                    atoms: [
                        AtomTextEdit {
                            delete: [4; 7),
                            insert: "foo2",
                        },
                    ],
                },
            },
        ],
        file_system_edits: [
            MoveFile {
                src: FileId(
                    3,
                ),
                dst_source_root: SourceRootId(
                    0,
                ),
                dst_path: "bar/foo2.rs",
            },
        ],
        cursor_position: None,
    },
)"#);
    }

    #[test]
    fn test_rename_mod_in_dir() {
        let (analysis, position) = analysis_and_position(
            "
            //- /lib.rs
            mod fo<|>o;
            //- /foo/mod.rs
            // emtpy
            ",
        );
        let new_name = "foo2";
        let source_change = analysis.rename(position, new_name).unwrap();
        assert_debug_snapshot_matches!(&source_change,
@r###"Some(
    SourceChange {
        label: "rename",
        source_file_edits: [
            SourceFileEdit {
                file_id: FileId(
                    1,
                ),
                edit: TextEdit {
                    atoms: [
                        AtomTextEdit {
                            delete: [4; 7),
                            insert: "foo2",
                        },
                    ],
                },
            },
        ],
        file_system_edits: [
            MoveFile {
                src: FileId(
                    2,
                ),
                dst_source_root: SourceRootId(
                    0,
                ),
                dst_path: "foo2/mod.rs",
            },
        ],
        cursor_position: None,
    },
)"###
       );
    }

    fn test_rename(text: &str, new_name: &str, expected: &str) {
        let (analysis, position) = single_file_with_position(text);
        let source_change = analysis.rename(position, new_name).unwrap();
        let mut text_edit_builder = ra_text_edit::TextEditBuilder::default();
        let mut file_id: Option<FileId> = None;
        if let Some(change) = source_change {
            for edit in change.source_file_edits {
                file_id = Some(edit.file_id);
                for atom in edit.edit.as_atoms() {
                    text_edit_builder.replace(atom.delete, atom.insert.clone());
                }
            }
        }
        let result = text_edit_builder.finish().apply(&*analysis.file_text(file_id.unwrap()));
        assert_eq_text!(expected, &*result);
    }
}
<|endoftext|>


<commit_before>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library 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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

extern crate clap;
#[macro_use] extern crate log;
extern crate toml;
extern crate toml_query;
#[macro_use] extern crate is_match;
#[macro_use] extern crate version;

extern crate libimagrt;
extern crate libimagerror;
extern crate libimagtodo;

use std::process::{Command, Stdio};
use std::io::stdin;

use toml::Value;

use libimagrt::runtime::Runtime;
use libimagrt::setup::generate_runtime_setup;
use libimagtodo::taskstore::TaskStore;
use libimagerror::trace::{MapErrTrace, trace_error, trace_error_exit};

mod ui;

use ui::build_ui;
fn main() {
    let rt = generate_runtime_setup("imag-todo",
                                    &version!()[..],
                                    "Interface with taskwarrior",
                                    build_ui);

    match rt.cli().subcommand_name() {
        Some("tw-hook") => tw_hook(&rt),
        Some("list") => list(&rt),
        None => {
            warn!("No command");
        },
        _ => unreachable!(),
    } // end match scmd
} // end main

fn tw_hook(rt: &Runtime) {
    let subcmd = rt.cli().subcommand_matches("tw-hook").unwrap();
    if subcmd.is_present("add") {
        let stdin = stdin();
        let stdin = stdin.lock(); // implements BufRead which is required for `FileLockEntry::import_task_from_reader()`

        match rt.store().import_task_from_reader(stdin) {
            Ok((_, line, uuid)) => println!("{}\nTask {} stored in imag", line, uuid),
            Err(e) => trace_error_exit(&e, 1),
        }
    } else if subcmd.is_present("delete") {
        // The used hook is "on-modify". This hook gives two json-objects
        // per usage und wants one (the second one) back.
        let stdin         = stdin();
        rt.store().delete_tasks_by_imports(stdin.lock()).map_err_trace().ok();
    } else {
        // Should not be possible, as one argument is required via
        // ArgGroup
        unreachable!();
    }
}

fn list(rt: &Runtime) {
    use toml_query::read::TomlValueReadExt;

    let subcmd  = rt.cli().subcommand_matches("list").unwrap();
    let verbose = subcmd.is_present("verbose");

    // Helper for toml_query::read::TomlValueReadExt::read() return value, which does only
    // return Result<T> instead of Result<Option<T>>, which is a real inconvenience.
    //
    let no_identifier = |e: &::toml_query::error::Error| -> bool {
        is_match!(e.kind(), &::toml_query::error::ErrorKind::IdentifierNotFoundInDocument(_))
    };

    let res = rt.store().all_tasks() // get all tasks
        .map(|iter| { // and if this succeeded
            // filter out the ones were we can read the uuid
            let uuids : Vec<_> = iter.filter_map(|storeid| {
                match rt.store().retrieve(storeid) {
                    Ok(fle) => {
                        match fle.get_header().read(&String::from("todo.uuid")) {
                            Ok(Some(&Value::String(ref u))) => Some(u.clone()),
                            Ok(Some(_)) => {
                                warn!("Header type error");
                                None
                            },
                            Ok(None) => {
                                warn!("Header missing field");
                                None
                            },
                            Err(e) => {
                                if !no_identifier(&e) {
                                    trace_error(&e);
                                }
                                None
                            }
                        }
                    },
                    Err(e) => {
                        trace_error(&e);
                        None
                    },
                }
            })
            .collect();

            // compose a `task` call with them, ...
            let outstring = if verbose { // ... if verbose
                let output = Command::new("task")
                    .stdin(Stdio::null())
                    .args(&uuids)
                    .spawn()
                    .unwrap_or_else(|e| {
                        trace_error(&e);
                        panic!("Failed to execute `task` on the commandline. I'm dying now.");
                    })
                    .wait_with_output()
                    .unwrap_or_else(|e| panic!("failed to unwrap output: {}", e));

                String::from_utf8(output.stdout)
                    .unwrap_or_else(|e| panic!("failed to execute: {}", e))
            } else { // ... else just join them
                uuids.join("\n")
            };

            // and then print that
            println!("{}", outstring);
        });

    res.map_err_trace().ok();
}

<commit_msg>Small embellishments<commit_after>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library 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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

extern crate clap;
#[macro_use] extern crate log;
extern crate toml;
extern crate toml_query;
#[macro_use] extern crate is_match;
#[macro_use] extern crate version;

extern crate libimagrt;
extern crate libimagerror;
extern crate libimagtodo;

use std::process::{Command, Stdio};
use std::io::stdin;

use toml::Value;

use libimagrt::runtime::Runtime;
use libimagrt::setup::generate_runtime_setup;
use libimagtodo::taskstore::TaskStore;
use libimagerror::trace::{MapErrTrace, trace_error, trace_error_exit};

mod ui;

use ui::build_ui;
fn main() {
    let rt = generate_runtime_setup("imag-todo",
                                    &version!()[..],
                                    "Interface with taskwarrior",
                                    build_ui);

    match rt.cli().subcommand_name() {
        Some("tw-hook") => tw_hook(&rt),
        Some("list") => list(&rt),
        None => {
            warn!("No command");
        },
        _ => unreachable!(),
    } // end match scmd
} // end main

fn tw_hook(rt: &Runtime) {
    let subcmd = rt.cli().subcommand_matches("tw-hook").unwrap();
    if subcmd.is_present("add") {
        let stdin = stdin();

        // implements BufRead which is required for `Store::import_task_from_reader()`
        let stdin = stdin.lock();

        match rt.store().import_task_from_reader(stdin) {
            Ok((_, line, uuid)) => println!("{}\nTask {} stored in imag", line, uuid),
            Err(e) => trace_error_exit(&e, 1),
        }
    } else if subcmd.is_present("delete") {
        // The used hook is "on-modify". This hook gives two json-objects
        // per usage und wants one (the second one) back.
        let stdin         = stdin();
        rt.store().delete_tasks_by_imports(stdin.lock()).map_err_trace().ok();
    } else {
        // Should not be possible, as one argument is required via
        // ArgGroup
        unreachable!();
    }
}

fn list(rt: &Runtime) {
    use toml_query::read::TomlValueReadExt;

    let subcmd  = rt.cli().subcommand_matches("list").unwrap();
    let verbose = subcmd.is_present("verbose");

    // Helper for toml_query::read::TomlValueReadExt::read() return value, which does only
    // return Result<T> instead of Result<Option<T>>, which is a real inconvenience.
    //
    let no_identifier = |e: &::toml_query::error::Error| -> bool {
        is_match!(e.kind(), &::toml_query::error::ErrorKind::IdentifierNotFoundInDocument(_))
    };

    let res = rt.store().all_tasks() // get all tasks
        .map(|iter| { // and if this succeeded
            // filter out the ones were we can read the uuid
            let uuids : Vec<_> = iter.filter_map(|storeid| {
                match rt.store().retrieve(storeid) {
                    Ok(fle) => {
                        match fle.get_header().read(&String::from("todo.uuid")) {
                            Ok(Some(&Value::String(ref u))) => Some(u.clone()),
                            Ok(Some(_)) => {
                                error!("Header type error, expected String at 'todo.uuid' in {}",
                                       fle.get_location());
                                None
                            },
                            Ok(None) => {
                                error!("Header missing field in {}", fle.get_location());
                                None
                            },
                            Err(e) => {
                                if !no_identifier(&e) {
                                    trace_error(&e);
                                }
                                None
                            }
                        }
                    },
                    Err(e) => {
                        trace_error(&e);
                        None
                    },
                }
            })
            .collect();

            // compose a `task` call with them, ...
            let outstring = if verbose { // ... if verbose
                let output = Command::new("task")
                    .stdin(Stdio::null())
                    .args(&uuids)
                    .spawn()
                    .unwrap_or_else(|e| {
                        trace_error(&e);
                        panic!("Failed to execute `task` on the commandline. I'm dying now.");
                    })
                    .wait_with_output()
                    .unwrap_or_else(|e| panic!("failed to unwrap output: {}", e));

                String::from_utf8(output.stdout)
                    .unwrap_or_else(|e| panic!("failed to execute: {}", e))
            } else { // ... else just join them
                uuids.join("\n")
            };

            // and then print that
            println!("{}", outstring);
        });

    res.map_err_trace().ok();
}

<|endoftext|>


<commit_before><commit_msg>Seperate the addressing from messages in network simulator.<commit_after><|endoftext|>