manix/
nixpkgs_tree_docsource.rs1use crate::{
2 contains_insensitive_ascii, starts_with_insensitive_ascii, Cache, DocEntry, DocSource, Errors,
3 Lowercase,
4};
5use serde::{Deserialize, Serialize};
6use std::{collections::HashMap, process::Command};
7
8#[derive(Debug, Serialize, Deserialize)]
9pub struct NixpkgsTreeDatabase {
10 keys: Vec<String>,
11}
12
13impl NixpkgsTreeDatabase {
14 pub fn new() -> Self {
15 Self { keys: Vec::new() }
16 }
17}
18
19#[derive(Serialize, Deserialize)]
20struct Keys(HashMap<String, Keys>);
21
22impl Into<Vec<String>> for Keys {
23 fn into(self) -> Vec<String> {
24 let mut res = Vec::<String>::new();
25 for (mut name, keys) in self.0 {
26 res.push(name.clone());
27 name.push('.');
28 for key in Into::<Vec<String>>::into(keys) {
29 let mut name = name.clone();
30 name.push_str(&key);
31 res.push(name);
32 }
33 }
34 res
35 }
36}
37
38impl DocSource for NixpkgsTreeDatabase {
39 fn all_keys(&self) -> Vec<&str> {
40 self.keys.iter().map(|k| k.as_str()).collect()
41 }
42 fn search(&self, query: &Lowercase) -> Vec<DocEntry> {
43 self.keys
44 .iter()
45 .filter(|k| starts_with_insensitive_ascii(k.as_bytes(), query))
46 .map(|k| DocEntry::NixpkgsTreeDoc(k.clone()))
47 .collect()
48 }
49 fn search_liberal(&self, query: &Lowercase) -> Vec<DocEntry> {
50 self.keys
51 .iter()
52 .filter(|k| contains_insensitive_ascii(k.as_bytes(), query))
53 .map(|k| DocEntry::NixpkgsTreeDoc(k.clone()))
54 .collect()
55 }
56 fn update(&mut self) -> Result<bool, Errors> {
57 let new_keys = gen_keys()?;
58 let old = std::mem::replace(&mut self.keys, new_keys);
59
60 Ok(old != self.keys)
61 }
62}
63impl Cache for NixpkgsTreeDatabase {}
64
65fn gen_keys() -> Result<Vec<String>, Errors> {
66 const CODE: &str = r#"
67let
68 pkgs = import <nixpkgs> { };
69 f = with builtins; v: (mapAttrs
70 (name: value:
71 if (tryEval value).success
72 && ! (tryEval (pkgs.lib.isDerivation value)).value
73 && isAttrs value
74 then mapAttrs (_: _: {}) value
75 else {}
76 )
77 v
78 );
79in
80(f (pkgs // { pkgs = {}; lib = {}; })) // { lib = f pkgs.lib; }
81 "#;
82
83 let command = Command::new("nix-instantiate")
84 .arg("--json")
85 .arg("--strict")
86 .arg("--eval")
87 .arg("-E")
88 .arg(CODE)
89 .output()?;
90
91 let keys = serde_json::from_slice::<Keys>(&command.stdout)?;
92
93 Ok(Into::<Vec<String>>::into(keys))
94}