dts-lsp 0.1.2

Language Server for Device Tree Source files
use crate::utils::convert_range;
use crate::utils::Symbol;
use crate::FileDepot;
use std::collections::HashMap;
use std::collections::HashSet;
use tokio::sync::Mutex;
use tower_lsp::lsp_types::Range;
use tower_lsp::lsp_types::*;
use tower_lsp::Client;

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

struct Data {
    label_to_symbol: HashMap<Label, Range>,
    fd: FileDepot,
    client: Client,
}

impl Data {
    fn new(client: &Client, fd: &FileDepot) -> Data {
        Data {
            label_to_symbol: HashMap::new(),
            client: client.clone(),
            fd: fd.clone(),
        }
    }
    async fn add_label(&mut self, label: &str, uri: &Url, range: tree_sitter::Range) {
        self.label_to_symbol.insert(
            Label {
                uri: uri.clone(),
                name: label.to_string(),
            },
            convert_range(&range),
        );
    }

    async fn find_label(&self, uri: &Url, label: &str) -> Option<Symbol> {
        let mut visited = HashSet::new();
        let mut to_visit = Vec::new();

        to_visit.push(uri.clone());

        while let Some(uri) = to_visit.pop() {
            self.client
                .log_message(MessageType::INFO, &format!("processing {}", uri))
                .await;

            if let Some(range) = self.label_to_symbol.get(&Label {
                name: label.to_string(),
                uri: uri.clone(),
            }) {
                let s = Symbol::new(uri, *range);
                return Some(s);
            }

            if let Some(x) = self.fd.get_neighbours(&uri).await {
                for f in x.lock().await.iter() {
                    if !visited.contains(f) {
                        to_visit.push(f.clone())
                    }
                }
            }

            visited.insert(uri);
        }

        None
    }
}

pub struct LabelsDepot {
    data: Mutex<Data>,
    client: Client,
}

impl LabelsDepot {
    pub fn new(client: Client, fd: FileDepot) -> LabelsDepot {
        LabelsDepot {
            data: Mutex::new(Data::new(&client, &fd)),
            client,
        }
    }

    pub async fn add_label(&self, label: &str, uri: &Url, range: tree_sitter::Range) {
        let mut data = self.data.lock().await;
        data.add_label(label, uri, range).await;
    }

    pub async fn find_label(&self, uri: &Url, label: &str) -> Option<Symbol> {
        let data = self.data.lock().await;
        data.find_label(uri, label).await
    }

    pub async fn dump(&self) {
        let data = self.data.lock().await;
        self.client
            .log_message(MessageType::INFO, "====== (labels) ======")
            .await;
        for k in data.label_to_symbol.keys() {
            self.client
                .log_message(MessageType::INFO, &format!("url: {}: {}", k.uri, k.name))
                .await;
        }
        self.client
            .log_message(MessageType::INFO, "======================")
            .await;
    }
}