Skip to content

Commit

Permalink
meta: add scopes
Browse files Browse the repository at this point in the history
  • Loading branch information
MarcelCoding committed Oct 14, 2024
1 parent 384d046 commit 7c4e805
Show file tree
Hide file tree
Showing 6 changed files with 132 additions and 39 deletions.
29 changes: 25 additions & 4 deletions fixx/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::string::FromUtf8Error;

use wasm_bindgen::prelude::*;

#[wasm_bindgen]
Expand All @@ -21,8 +23,24 @@ impl Index {
self.0.meta().chunk_size
}

pub fn search(&self, query: String, max_results: usize) -> Result<Vec<SearchedOption>, String> {
match self.0.search(&query, max_results) {
pub fn scopes(&self) -> Result<Vec<String>, String> {
self
.0
.meta()
.scopes
.iter()
.map(|scope| String::try_from(scope.clone()))
.collect::<Result<Vec<String>, FromUtf8Error>>()
.map_err(|err| format!("{:?}", err))
}

pub fn search(
&self,
scope_id: Option<u8>,
query: String,
max_results: usize,
) -> Result<Vec<SearchedOption>, String> {
match self.0.search(scope_id, &query, max_results) {
Ok(options) => Ok(
options
.into_iter()
Expand All @@ -33,8 +51,11 @@ impl Index {
}
}

pub fn all(&self, max: usize) -> Result<Vec<String>, String> {
self.0.all(max).map_err(|err| format!("{:?}", err))
pub fn all(&self, scope_id: Option<u8>, max: usize) -> Result<Vec<String>, String> {
self
.0
.all(scope_id, max)
.map_err(|err| format!("{:?}", err))
}

pub fn get_idx_by_name(&self, name: String) -> Result<Option<usize>, String> {
Expand Down
21 changes: 16 additions & 5 deletions ixx/src/action/index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,22 +23,32 @@ pub(crate) struct Config {
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct Scope {
name: Option<String>,
options_json: PathBuf,
url_prefix: Url,
options_prefix: Option<String>,
}

pub(crate) fn index(module: IndexModule) -> anyhow::Result<()> {
let mut raw_options: BTreeMap<String, libixx::Option> = BTreeMap::new();
let mut raw_options: BTreeMap<String, (u8, libixx::Option)> = BTreeMap::new();

let config_file = File::open(module.config)?;
let config: Config = serde_json::from_reader(config_file)?;

let mut index = Index::default();

for scope in config.scopes {
println!("Parsing {}", scope.options_json.to_string_lossy());
let file = File::open(scope.options_json)?;
let options: HashMap<String, option::Option> = serde_json::from_reader(file)?;

let scope_idx = index.push_scope(
scope
.name
.map(|x| x.to_string())
.unwrap_or_else(|| scope.url_prefix.to_string()),
);

for (name, option) in options {
// internal options which cannot be hidden when importing existing options.json
if name == "_module.args" {
Expand All @@ -50,14 +60,15 @@ pub(crate) fn index(module: IndexModule) -> anyhow::Result<()> {
None => name,
};
let option = into_option(&scope.url_prefix, &name, option)?;
raw_options.insert(name, option);
raw_options.insert(name, (scope_idx, option));
}
}

println!("Read {} options", raw_options.len());

let mut index = Index::default();
raw_options.keys().for_each(|name| index.push(name));
for (name, (scope_idx, _)) in &raw_options {
index.push(*scope_idx, name);
}

println!("Writing index to {}", module.index_output.to_string_lossy());

Expand All @@ -70,7 +81,7 @@ pub(crate) fn index(module: IndexModule) -> anyhow::Result<()> {
std::fs::create_dir(&module.meta_output)?;
}

let options: Vec<libixx::Option> = raw_options.into_values().collect();
let options = raw_options.into_values().collect::<Vec<_>>();
for (idx, chunk) in options.chunks(module.chunk_size).enumerate() {
let mut file = File::create(module.meta_output.join(format!("{}.json", idx)))?;
serde_json::to_writer(&mut file, &chunk)?;
Expand Down
2 changes: 1 addition & 1 deletion ixx/src/action/search.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ pub(crate) fn search(module: SearchModule) -> anyhow::Result<()> {
let mut file = File::open(module.index)?;
let index = Index::read_from(&mut file)?;

let result = index.search(&module.query, module.max_results as usize)?;
let result = index.search(module.scope_id, &module.query, module.max_results as usize)?;
for (idx, name) in result {
println!("idx: {}, name: {}", idx, name);
}
Expand Down
3 changes: 3 additions & 0 deletions ixx/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ pub(super) struct SearchModule {
#[clap(short, long, default_value = "index.ixx")]
pub(super) index: PathBuf,

#[clap(short, long)]
pub(super) scope_id: Option<u8>,

#[clap(short, long, default_value = "10")]
pub(super) max_results: u32,
}
74 changes: 59 additions & 15 deletions libixx/src/index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,27 @@ use crate::IxxError;
#[derive(Default, Debug, Clone, PartialEq)]
pub struct Index {
meta: Meta,
#[bw(calc = entries.len() as u32)]
#[bw(calc = options.len() as u32)]
count: u32,
#[br(count = count)]
entries: Vec<Entry>,
options: Vec<OptionEntry>,
}

#[binrw]
#[derive(Default, Debug, Clone, PartialEq)]
pub struct Meta {
pub chunk_size: u32,
#[bw(calc = scopes.len() as u8)]
scope_count: u8,
#[br(count = scope_count)]
pub scopes: Vec<NullString>,
}

#[binrw]
#[derive(Default, Debug, Clone, PartialEq)]
pub struct Entry {
pub struct OptionEntry {
/// index in the scopes Vec
scope_id: u8,
#[bw(calc = labels.len() as u16)]
count: u16,
#[br(count = count)]
Expand Down Expand Up @@ -59,13 +65,13 @@ impl Index {
Ok(BinWrite::write_options(self, write, Endian::Little, ())?)
}

pub fn push(&mut self, option: &str) {
pub fn push(&mut self, scope_id: u8, option: &str) {
let labels = option
.split('.')
.map(|segment| {
let segment = segment.into();

for (option_idx, Entry { labels: option }) in self.entries.iter().enumerate() {
for (option_idx, OptionEntry { labels: option, .. }) in self.options.iter().enumerate() {
for (label_idx, label) in option.iter().enumerate() {
if let Label::InPlace(inplace) = label {
if inplace != &segment {
Expand All @@ -84,17 +90,17 @@ impl Index {
})
.collect();

self.entries.push(Entry { labels });
self.options.push(OptionEntry { scope_id, labels });
}

fn resolve_reference(&self, reference: &Reference) -> Result<&NullString, IxxError> {
let option_idx = reference.option_idx as usize;

if self.entries.len() <= option_idx {
if self.options.len() <= option_idx {
return Err(IxxError::ReferenceOutOfBounds);
}

let entry = &self.entries[option_idx].labels;
let entry = &self.options[option_idx].labels;

let label_idx = reference.label_idx as usize;

Expand All @@ -116,7 +122,7 @@ impl Index {
let segment = segment.into();

'outer: {
for (option_idx, Entry { labels: option }) in self.entries.iter().enumerate() {
for (option_idx, OptionEntry { labels: option, .. }) in self.options.iter().enumerate() {
for (label_idx, label) in option.iter().enumerate() {
if let Label::InPlace(inplace) = label {
if inplace != &segment {
Expand All @@ -138,15 +144,20 @@ impl Index {

Ok(
self
.entries
.options
.iter()
.enumerate()
.find(|(idx, Entry { labels: option })| do_labels_match(*idx, option, &labels))
.find(|(idx, OptionEntry { labels: option, .. })| do_labels_match(*idx, option, &labels))
.map(|(idx, _)| idx),
)
}

pub fn search(&self, query: &str, max_results: usize) -> Result<Vec<(usize, String)>, IxxError> {
pub fn search(
&self,
scope_id: Option<u8>,
query: &str,
max_results: usize,
) -> Result<Vec<(usize, String)>, IxxError> {
let search = query
.split('*')
.map(|segment| segment.to_lowercase())
Expand All @@ -158,7 +169,20 @@ impl Index {

let mut results = Vec::new();

for (idx, Entry { labels: option }) in self.entries.iter().enumerate() {
for (
idx,
OptionEntry {
scope_id: option_scope_id,
labels: option,
},
) in self.options.iter().enumerate()
{
if let Some(scope_id) = scope_id {
if *option_scope_id != scope_id {
continue;
}
}

let mut option_name = String::new();
for label in option {
option_name.push_str(&String::try_from(
Expand Down Expand Up @@ -195,10 +219,20 @@ impl Index {
Ok(results)
}

pub fn all(&self, max: usize) -> Result<Vec<String>, IxxError> {
pub fn all(&self, scope_id: Option<u8>, max: usize) -> Result<Vec<String>, IxxError> {
let mut options = Vec::new();

for Entry { labels: option } in &self.entries[..max] {
for OptionEntry {
scope_id: option_scope_id,
labels: option,
} in &self.options[..max]
{
if let Some(scope_id) = scope_id {
if *option_scope_id != scope_id {
continue;
}
}

let mut option_name = String::new();
for label in option {
option_name.push_str(&String::try_from(
Expand All @@ -222,6 +256,16 @@ impl Index {
pub fn meta(&self) -> &Meta {
&self.meta
}

pub fn push_scope(&mut self, scope: String) -> u8 {
if self.meta.scopes.len() == u8::MAX.into() {
panic!("You reached the limit of 256 scopes. Please contact the developers for further assistance.");
}

let idx = self.meta.scopes.len();
self.meta.scopes.push(scope.into());
idx as u8
}
}

fn do_labels_match(option_idx: usize, option: &[Label], search: &[Reference]) -> bool {
Expand Down
42 changes: 28 additions & 14 deletions libixx/src/test/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,18 @@ use crate::Index;
fn test() {
let mut index = Index::default();

index.push("home.enableDebugInfo");
index.push("home.enableNixpkgsReleaseCheck");
index.push("home.file.<name>.enable");
index.push("home.language.measurement");
index.push("home.pointerCursor.gtk.enable");
index.push("home.pointerCursor.x11.enable");
index.push("programs.home-manager.enable");
index.push("services.home-manager.autoUpgrade.enable");
index.push("services.home-manager.autoUpgrade.frequency");
index.push(0, "home.enableDebugInfo");
index.push(0, "home.enableNixpkgsReleaseCheck");
index.push(0, "home.file.<name>.enable");
index.push(0, "home.language.measurement");
index.push(0, "home.pointerCursor.gtk.enable");
index.push(0, "home.pointerCursor.x11.enable");
index.push(0, "programs.home-manager.enable");
index.push(0, "services.home-manager.autoUpgrade.enable");
index.push(0, "services.home-manager.autoUpgrade.frequency");

assert_eq!(
index.search("ho*auto", 10).unwrap(),
index.search(None, "ho*auto", 10).unwrap(),
vec![
(
7usize,
Expand All @@ -29,25 +29,39 @@ fn test() {
);

assert_eq!(
index.search("ho*auto*ena", 10).unwrap(),
index.search(None, "ho*auto*ena", 10).unwrap(),
vec![(
7usize,
"services.home-manager.autoUpgrade.enable".to_string()
)]
);

assert_eq!(
index.search("ho*en*Nix", 10).unwrap(),
index.search(None, "ho*en*Nix", 10).unwrap(),
vec![(1usize, "home.enableNixpkgsReleaseCheck".to_string())]
);

assert_eq!(
index.search("ho*en*Nix*Rel*Che", 10).unwrap(),
index.search(None, "ho*en*Nix*Rel*Che", 10).unwrap(),
vec![(1usize, "home.enableNixpkgsReleaseCheck".to_string())]
);

assert_eq!(
index.search("enablenixpkgsreleasecheck", 10).unwrap(),
index.search(None, "enablenixpkgsreleasecheck", 10).unwrap(),
vec![(1usize, "home.enableNixpkgsReleaseCheck".to_string())]
);

// TEST scopes
assert_eq!(
index
.search(Some(0), "enablenixpkgsreleasecheck", 10)
.unwrap(),
vec![(1usize, "home.enableNixpkgsReleaseCheck".to_string())]
);
assert_eq!(
index
.search(Some(1), "enablenixpkgsreleasecheck", 10)
.unwrap(),
vec![]
);
}

0 comments on commit 7c4e805

Please sign in to comment.