dsktp 0.1.0

A utility for listing and interacting with .desktop files on unix systems
Documentation
//! Low level parser for freedesktop .desktop specification

use lazy_static::lazy_static;
use regex::Regex;

pub type AST = Vec<(String, Vec<KeyValue>)>;

pub struct KeyValue {
    pub key: String,
    pub value: String,
}

enum Token {
    Section(String),
    KeyValue(String, String),
    Ignore,
}

pub fn parse(bits: Vec<u8>) -> AST {
    let txt = String::from_utf8_lossy(&bits);
    let tokens = txt
        .split("\n")
        .map(tokenize)
        // NOTE: how to continue as iterator?
        .collect();

    parse_tokens(tokens)
}

fn tokenize(line: &str) -> Token {
    lazy_static! {
        static ref SECTION_RE: Regex = Regex::new(r"^\[(.*)\]$").unwrap();
        static ref KEY_VALUE_RE: Regex = Regex::new(r"^(\w+)=(.*)$").unwrap();
    }
    if let Some(captures) = SECTION_RE.captures(line) {
        return Token::Section(captures[1].to_string());
    }
    if let Some(captures) = KEY_VALUE_RE.captures(line) {
        return Token::KeyValue(captures[1].to_string(), captures[2].to_string());
    }

    Token::Ignore
}

fn parse_tokens(tokens: Vec<Token>) -> AST {
    let mut acc: Vec<(String, Vec<KeyValue>)> = Vec::new();
    for token in tokens {
        match token {
            Token::Ignore => {
                continue;
            }
            Token::Section(name) => {
                acc.push((name, Vec::new()));
            }
            Token::KeyValue(key, value) => {
                if let Some(inner) = acc.last_mut() {
                    let (_, ref mut key_values) = inner;
                    key_values.push(KeyValue { key, value })
                }
            }
        }
    }

    acc
}