Skip to content

Commit 1fdf05e

Browse files
Merge pull request #16 from NuschtOS/index-meta
2 parents 96fac7a + 6f066dd commit 1fdf05e

File tree

6 files changed

+150
-69
lines changed

6 files changed

+150
-69
lines changed

fixx/src/lib.rs

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::string::FromUtf8Error;
2+
13
use wasm_bindgen::prelude::*;
24

35
#[wasm_bindgen]
@@ -17,8 +19,28 @@ impl Index {
1719
.map_err(|err| format!("{:?}", err))
1820
}
1921

20-
pub fn search(&self, query: String, max_results: usize) -> Result<Vec<SearchedOption>, String> {
21-
match self.0.search(&query, max_results) {
22+
pub fn chunk_size(&self) -> u32 {
23+
self.0.meta().chunk_size
24+
}
25+
26+
pub fn scopes(&self) -> Result<Vec<String>, String> {
27+
self
28+
.0
29+
.meta()
30+
.scopes
31+
.iter()
32+
.map(|scope| String::try_from(scope.clone()))
33+
.collect::<Result<Vec<String>, FromUtf8Error>>()
34+
.map_err(|err| format!("{:?}", err))
35+
}
36+
37+
pub fn search(
38+
&self,
39+
scope_id: Option<u8>,
40+
query: String,
41+
max_results: usize,
42+
) -> Result<Vec<SearchedOption>, String> {
43+
match self.0.search(scope_id, &query, max_results) {
2244
Ok(options) => Ok(
2345
options
2446
.into_iter()
@@ -29,10 +51,6 @@ impl Index {
2951
}
3052
}
3153

32-
pub fn all(&self, max: usize) -> Result<Vec<String>, String> {
33-
self.0.all(max).map_err(|err| format!("{:?}", err))
34-
}
35-
3654
pub fn get_idx_by_name(&self, name: String) -> Result<Option<usize>, String> {
3755
self
3856
.0

ixx/src/action/index.rs

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,22 +23,32 @@ pub(crate) struct Config {
2323
#[derive(Deserialize)]
2424
#[serde(rename_all = "camelCase")]
2525
pub(crate) struct Scope {
26+
name: Option<String>,
2627
options_json: PathBuf,
2728
url_prefix: Url,
2829
options_prefix: Option<String>,
2930
}
3031

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

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

38+
let mut index = Index::new(module.chunk_size);
39+
3740
for scope in config.scopes {
3841
println!("Parsing {}", scope.options_json.to_string_lossy());
3942
let file = File::open(scope.options_json)?;
4043
let options: HashMap<String, option::Option> = serde_json::from_reader(file)?;
4144

45+
let scope_idx = index.push_scope(
46+
scope
47+
.name
48+
.map(|x| x.to_string())
49+
.unwrap_or_else(|| scope.url_prefix.to_string()),
50+
);
51+
4252
for (name, option) in options {
4353
// internal options which cannot be hidden when importing existing options.json
4454
if name == "_module.args" {
@@ -50,14 +60,15 @@ pub(crate) fn index(module: IndexModule) -> anyhow::Result<()> {
5060
None => name,
5161
};
5262
let option = into_option(&scope.url_prefix, &name, option)?;
53-
raw_options.insert(name, option);
63+
raw_options.insert(name.clone(), (scope_idx, option));
5464
}
5565
}
5666

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

59-
let mut index = Index::default();
60-
raw_options.keys().for_each(|name| index.push(name));
69+
for (name, (scope_idx, _)) in &raw_options {
70+
index.push(*scope_idx, name);
71+
}
6172

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

@@ -70,8 +81,12 @@ pub(crate) fn index(module: IndexModule) -> anyhow::Result<()> {
7081
std::fs::create_dir(&module.meta_output)?;
7182
}
7283

73-
let options: Vec<libixx::Option> = raw_options.into_values().collect();
74-
for (idx, chunk) in options.chunks(module.chunk_size).enumerate() {
84+
let options = raw_options
85+
.into_values()
86+
.map(|(_, options)| options)
87+
.collect::<Vec<_>>();
88+
89+
for (idx, chunk) in options.chunks(module.chunk_size as usize).enumerate() {
7590
let mut file = File::create(module.meta_output.join(format!("{}.json", idx)))?;
7691
serde_json::to_writer(&mut file, &chunk)?;
7792
}
@@ -91,7 +106,7 @@ fn into_option(
91106
.map(|declaration| update_declaration(url_prefix, declaration))
92107
.collect::<anyhow::Result<_>>()?,
93108
default: option.default.map(|option| option.render()),
94-
description: option.description,
109+
description: markdown::to_html(&option.description),
95110
example: option.example.map(|example| example.render()),
96111
read_only: option.read_only,
97112
r#type: option.r#type,

ixx/src/action/search.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ pub(crate) fn search(module: SearchModule) -> anyhow::Result<()> {
88
let mut file = File::open(module.index)?;
99
let index = Index::read_from(&mut file)?;
1010

11-
let result = index.search(&module.query, module.max_results as usize)?;
11+
let result = index.search(module.scope_id, &module.query, module.max_results as usize)?;
1212
for (idx, name) in result {
1313
println!("idx: {}, name: {}", idx, name);
1414
}

ixx/src/args.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ pub(super) struct IndexModule {
2424
pub(crate) meta_output: PathBuf,
2525

2626
#[clap(short, long, default_value = "100")]
27-
pub(super) chunk_size: usize,
27+
pub(super) chunk_size: u32,
2828
}
2929

3030
#[derive(Parser)]
@@ -34,6 +34,9 @@ pub(super) struct SearchModule {
3434
#[clap(short, long, default_value = "index.ixx")]
3535
pub(super) index: PathBuf,
3636

37+
#[clap(short, long)]
38+
pub(super) scope_id: Option<u8>,
39+
3740
#[clap(short, long, default_value = "10")]
3841
pub(super) max_results: u32,
3942
}

libixx/src/index.rs

Lines changed: 68 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,32 @@ use binrw::{binrw, BinRead, BinWrite, Endian, NullString};
44

55
use crate::IxxError;
66

7-
#[binrw(magic = b"ixx01", little)]
8-
#[derive(Default, Debug, Clone, PartialEq)]
7+
#[binrw]
8+
#[brw(magic = b"ixx01")]
9+
#[derive(Debug, Clone, PartialEq)]
910
pub struct Index {
10-
#[bw(calc = entries.len() as u32)]
11+
meta: Meta,
12+
#[bw(calc = options.len() as u32)]
1113
count: u32,
1214
#[br(count = count)]
13-
entries: Vec<Entry>,
15+
options: Vec<OptionEntry>,
16+
}
17+
18+
#[binrw]
19+
#[derive(Debug, Clone, PartialEq)]
20+
pub struct Meta {
21+
pub chunk_size: u32,
22+
#[bw(calc = scopes.len() as u8)]
23+
scope_count: u8,
24+
#[br(count = scope_count)]
25+
pub scopes: Vec<NullString>,
1426
}
1527

1628
#[binrw]
1729
#[derive(Default, Debug, Clone, PartialEq)]
18-
pub struct Entry {
30+
pub struct OptionEntry {
31+
/// index in the scopes Vec
32+
scope_id: u8,
1933
#[bw(calc = labels.len() as u16)]
2034
count: u16,
2135
#[br(count = count)]
@@ -32,11 +46,23 @@ struct Reference {
3246
#[binrw]
3347
#[derive(Debug, Clone, PartialEq)]
3448
enum Label {
49+
#[brw(magic = b"0")]
3550
InPlace(NullString),
51+
#[brw(magic = b"1")]
3652
Reference(Reference),
3753
}
3854

3955
impl Index {
56+
pub fn new(chunk_size: u32) -> Self {
57+
Self {
58+
meta: Meta {
59+
chunk_size,
60+
scopes: vec![],
61+
},
62+
options: vec![],
63+
}
64+
}
65+
4066
pub fn read(buf: &[u8]) -> Result<Self, IxxError> {
4167
Self::read_from(&mut Cursor::new(buf))
4268
}
@@ -49,13 +75,13 @@ impl Index {
4975
Ok(BinWrite::write_options(self, write, Endian::Little, ())?)
5076
}
5177

52-
pub fn push(&mut self, option: &str) {
78+
pub fn push(&mut self, scope_id: u8, option: &str) {
5379
let labels = option
5480
.split('.')
5581
.map(|segment| {
5682
let segment = segment.into();
5783

58-
for (option_idx, Entry { labels: option }) in self.entries.iter().enumerate() {
84+
for (option_idx, OptionEntry { labels: option, .. }) in self.options.iter().enumerate() {
5985
for (label_idx, label) in option.iter().enumerate() {
6086
if let Label::InPlace(inplace) = label {
6187
if inplace != &segment {
@@ -74,17 +100,17 @@ impl Index {
74100
})
75101
.collect();
76102

77-
self.entries.push(Entry { labels });
103+
self.options.push(OptionEntry { scope_id, labels });
78104
}
79105

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

83-
if self.entries.len() <= option_idx {
109+
if self.options.len() <= option_idx {
84110
return Err(IxxError::ReferenceOutOfBounds);
85111
}
86112

87-
let entry = &self.entries[option_idx].labels;
113+
let entry = &self.options[option_idx].labels;
88114

89115
let label_idx = reference.label_idx as usize;
90116

@@ -106,7 +132,7 @@ impl Index {
106132
let segment = segment.into();
107133

108134
'outer: {
109-
for (option_idx, Entry { labels: option }) in self.entries.iter().enumerate() {
135+
for (option_idx, OptionEntry { labels: option, .. }) in self.options.iter().enumerate() {
110136
for (label_idx, label) in option.iter().enumerate() {
111137
if let Label::InPlace(inplace) = label {
112138
if inplace != &segment {
@@ -128,27 +154,41 @@ impl Index {
128154

129155
Ok(
130156
self
131-
.entries
157+
.options
132158
.iter()
133159
.enumerate()
134-
.find(|(idx, Entry { labels: option })| do_labels_match(*idx, option, &labels))
160+
.find(|(idx, OptionEntry { labels: option, .. })| do_labels_match(*idx, option, &labels))
135161
.map(|(idx, _)| idx),
136162
)
137163
}
138164

139-
pub fn search(&self, query: &str, max_results: usize) -> Result<Vec<(usize, String)>, IxxError> {
165+
pub fn search(
166+
&self,
167+
scope_id: Option<u8>,
168+
query: &str,
169+
max_results: usize,
170+
) -> Result<Vec<(usize, String)>, IxxError> {
140171
let search = query
141172
.split('*')
142173
.map(|segment| segment.to_lowercase())
143174
.collect::<Vec<_>>();
144175

145-
if search.is_empty() {
146-
return Ok(vec![]);
147-
}
148-
149176
let mut results = Vec::new();
150177

151-
for (idx, Entry { labels: option }) in self.entries.iter().enumerate() {
178+
for (
179+
idx,
180+
OptionEntry {
181+
scope_id: option_scope_id,
182+
labels: option,
183+
},
184+
) in self.options.iter().enumerate()
185+
{
186+
if let Some(scope_id) = scope_id {
187+
if *option_scope_id != scope_id {
188+
continue;
189+
}
190+
}
191+
152192
let mut option_name = String::new();
153193
for label in option {
154194
option_name.push_str(&String::try_from(
@@ -185,28 +225,18 @@ impl Index {
185225
Ok(results)
186226
}
187227

188-
pub fn all(&self, max: usize) -> Result<Vec<String>, IxxError> {
189-
let mut options = Vec::new();
190-
191-
for Entry { labels: option } in &self.entries[..max] {
192-
let mut option_name = String::new();
193-
for label in option {
194-
option_name.push_str(&String::try_from(
195-
match label {
196-
Label::InPlace(data) => data,
197-
Label::Reference(reference) => self.resolve_reference(reference)?,
198-
}
199-
.clone(),
200-
)?);
201-
option_name.push('.')
202-
}
203-
// remove last dot...
204-
option_name.pop();
228+
pub fn meta(&self) -> &Meta {
229+
&self.meta
230+
}
205231

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

209-
Ok(options)
237+
let idx = self.meta.scopes.len();
238+
self.meta.scopes.push(scope.into());
239+
idx as u8
210240
}
211241
}
212242

0 commit comments

Comments
 (0)