aboutsummaryrefslogtreecommitdiff
path: root/.config/awesome/quarrel/native/src/util.rs
blob: 85a257477796fbc6f5403e70129974aac2eca6d9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
use std::{
    cell::RefCell,
    fs::File,
    fs::OpenOptions,
    io::{
        Read,
        Seek,
        Write
    },
    rc::Rc,
    str::FromStr,
};

use html_escape::decode_html_entities_to_string;
use mlua::prelude::*;
use serde::Serialize;

pub fn decode_html(_: &Lua, string: String) -> LuaResult<String> {
    let mut output = String::new();
    decode_html_entities_to_string(string, &mut output);
    Ok(output)
}

enum ReadMode {
    Line,
    Number,
    All,
}

impl FromStr for ReadMode {
    type Err = ();

    fn from_str(value: &str) -> Result<Self, Self::Err> {
        Ok(match value {
            "l" => Self::Line,
            "n" => Self::Number,
            _ => Self::All,
        })
    }
}

#[derive(Serialize)]
#[serde(untagged)]
enum StringOrNumber {
    String(String),
    Number(u64),
}

pub struct FileHandle(Rc<RefCell<File>>);

impl LuaUserData for FileHandle {
    fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
        methods.add_method("read", |lua, this: &FileHandle, mode: String| {
            let content = this.read()?;
            Ok(lua.to_value(&match ReadMode::from_str(&mode).unwrap() {
                ReadMode::Line => StringOrNumber::String(
                    content
                        .lines()
                        .next()
                        .map_or_else(String::new, |slice| slice.trim().to_owned()),
                ),
                ReadMode::Number => StringOrNumber::Number(
                    content.trim().parse::<u64>().map_err(LuaError::external)?,
                ),
                ReadMode::All => StringOrNumber::String(content),
            }))
        });
        methods.add_method("write", |_, this: &FileHandle, content: String| {
            this.write(content.as_bytes())
        });
        methods.add_method("lines", |_, this: &FileHandle, (): ()| {
            Ok(this
                .read()?
                .lines()
                .map(ToOwned::to_owned)
                .collect::<Vec<String>>())
        });
        methods.add_method("rewind", |_, this: &FileHandle, (): ()| this.rewind());
    }
}

impl FileHandle {
    pub fn new(_: &Lua, path: String) -> LuaResult<Self> {
        Ok(Self(Rc::new(RefCell::new(File::open(path)?))))
        // Ok(Self(Rc::new(RefCell::new(OpenOptions::new().write(true).read(true).open(path)?))))
    }

    fn read(&self) -> LuaResult<String> {
        let mut content = String::new();
        self.0.borrow_mut().read_to_string(&mut content)?;
        Ok(content)
    }

    fn rewind(&self) -> LuaResult<()> {
        self.0.borrow_mut().rewind().map_err(LuaError::external)
    }

    fn write(&self, buf: &[u8]) -> LuaResult<usize> {
        self.0.borrow_mut().write(buf).map_err(LuaError::external)
    }
}