tabby/
lib.rs

1use anyhow::Result;
2use miniserde::{json, Deserialize, Serialize};
3use std::{
4    fmt::{self, Display},
5    path::{Path, PathBuf},
6};
7
8pub mod setup;
9
10pub struct Completions {
11    pub completions: Vec<String>,
12}
13
14impl Display for Completions {
15    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> fmt::Result {
16        let last = self.completions.len() - 1;
17
18        for (index, completion) in self.completions.iter().enumerate() {
19            if index == last {
20                write!(f, "{}", completion)?;
21            } else {
22                writeln!(f, "{}", completion)?;
23            }
24        }
25
26        Ok(())
27    }
28}
29
30#[derive(Serialize, Deserialize, Debug, Clone)]
31pub struct CompletionData {
32    #[serde(rename = "cli-name")]
33    /// Name used to invoke the CLI.
34    pub cli_name: String,
35    /// Completion items used for generating tab completions.
36    pub commands: Option<Vec<CompletionItem>>,
37}
38
39#[derive(Serialize, Deserialize, Debug, Clone)]
40pub struct CompletionItem {
41    /// Name of the command.
42    pub name: String,
43    /// List of flags supported by the command.
44    pub flags: Vec<String>,
45}
46
47pub struct Completer {
48    /// Data tabby uses to generate tab completions.
49    pub completion_data: CompletionData,
50    /// Path to `tabby.config.json`.
51    pub config_path: PathBuf,
52}
53
54impl Completer {
55    pub fn new<P: AsRef<Path>>(config_path: P) -> Result<Completer> {
56        let text = std::fs::read_to_string(&config_path).unwrap();
57        let completion_data = json::from_str::<CompletionData>(&text)?;
58
59        let completer = Completer {
60            config_path: config_path.as_ref().to_owned(),
61            completion_data,
62        };
63
64        Ok(completer)
65    }
66
67    pub fn from<P: AsRef<Path>>(p: P) -> Result<Completer> {
68        Self::new(p.as_ref().to_owned())
69    }
70
71    pub fn get_completions(&self) -> Completions {
72        let args = std::env::args().collect::<Vec<String>>();
73        let mut completions = vec![];
74
75        if args.len() > 2 {
76            let current_word = args[2].replace("--word=", "");
77
78            let mut line = args[4].to_string();
79
80            let position = args[6].parse::<u64>().unwrap();
81
82            if position > line.len() as u64 {
83                line.push_str(" ");
84            }
85
86            let split = line.split(" ").collect::<Vec<&str>>();
87
88            match split.len() {
89                2 => {
90                    // volt.exe
91                    if current_word == "" {
92                        for command in self.completion_data.commands.as_ref().unwrap().iter() {
93                            completions.push(command.name.to_string());
94                        }
95                    } else {
96                        for command in self.completion_data.commands.as_ref().unwrap().iter() {
97                            if command.name.starts_with(&current_word) {
98                                completions.push(command.name.to_string());
99                            }
100                        }
101                    }
102                }
103                _ => {
104                    // volt.exe --verbose or volt.exe install
105
106                    if current_word.starts_with("--") || current_word == "" {
107                        for command in self.completion_data.commands.as_ref().unwrap().iter() {
108                            if command.name == split[1] {
109                                for flag in command.flags.iter() {
110                                    if flag.starts_with(&current_word) {
111                                        completions.push(flag.to_string());
112                                    }
113                                }
114                            }
115                        }
116                    }
117                }
118            }
119        }
120
121        Completions { completions }
122    }
123
124    pub fn install(&self) -> Result<()> {
125        setup::install(&self)?;
126        Ok(())
127    }
128
129    pub fn display_completions(completions: &Vec<String>) {
130        for completion in completions.iter() {
131            println!("{}", completion);
132        }
133    }
134}