dts-lsp 0.1.7

Language Server for Device Tree Source files
use crate::file_depot::FileDepot;
use crate::utils::Symbol;
use std::collections::HashMap;
use std::collections::HashSet;
use std::sync::{Arc, Mutex};
use tower_lsp::lsp_types::{Range, Url};

#[cfg(test)]
use crate::{info, log_message};
#[cfg(test)]
use tower_lsp::lsp_types::MessageType;

#[derive(Eq, Hash, PartialEq, Clone)]
struct Define {
    uri: Url,
    name: String,
}

struct Data {
    define_to_symbol: HashMap<Define, (Range, String)>,
    fd: FileDepot,
}

impl Data {
    fn new(fd: &FileDepot) -> Data {
        Data {
            define_to_symbol: HashMap::new(),
            fd: fd.clone(),
        }
    }

    fn add_define(&mut self, name: &str, uri: &Url, range: Range, value: &str) {
        self.define_to_symbol.insert(
            Define {
                uri: uri.clone(),
                name: name.to_string(),
            },
            (range, value.to_string()),
        );
    }

    fn find_define(&self, uri: &Url, name: &str) -> Option<Symbol> {
        let mut visited = HashSet::new();
        let mut to_visit = vec![uri.clone()];

        let v = self.fd.get_component(uri);
        for f in &v {
            if !visited.contains(f) {
                to_visit.push(f.clone());
            }
        }

        while let Some(uri) = to_visit.pop() {
            if let Some(x) = self.define_to_symbol.get(&Define {
                name: name.to_string(),
                uri: uri.clone(),
            }) {
                return Some(Symbol::new(uri.clone(), x.0));
            }
            visited.insert(uri);
        }

        None
    }

    fn invalidate(&mut self, uri: &Url) {
        let mut v = Vec::new();

        for k in self.define_to_symbol.keys() {
            if k.uri == *uri {
                v.push(k.clone());
            }
        }

        for key in v {
            self.define_to_symbol.remove(&key);
        }
    }

    #[cfg(test)]
    fn dump(&self) {
        info!("====== (defines) ======");
        for (k, v) in &self.define_to_symbol {
            info!("url: {}: {}", k.uri, v.1);
        }
        info!("======================");
    }
}

#[derive(Clone)]
pub struct IncludesDepot {
    data: Arc<Mutex<Data>>,
}

impl IncludesDepot {
    pub fn new(fd: &FileDepot) -> IncludesDepot {
        IncludesDepot {
            data: Arc::new(Mutex::new(Data::new(fd))),
        }
    }

    pub fn add_define(&self, name: &str, uri: &Url, range: Range, value: &str) {
        self.data
            .lock()
            .unwrap()
            .add_define(name, uri, range, value);
    }

    pub fn find_define(&self, uri: &Url, name: &str) -> Option<Symbol> {
        self.data.lock().unwrap().find_define(uri, name)
    }

    #[cfg(test)]
    pub fn dump(&self) {
        self.data.lock().unwrap().dump();
    }

    pub fn invalidate(&self, uri: &Url) {
        self.data.lock().unwrap().invalidate(uri);
    }
}