diff --git a/Cargo.toml b/Cargo.toml index 2c76282..5375c76 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -74,5 +74,4 @@ native-dialog = "0.7.0" [target.'cfg(target_arch = "wasm32")'.dependencies] wasm-bindgen = "0.2.91" wasm-bindgen-futures = "0.4.41" -console_error_panic_hook = "0.1.7" web-sys = { version = "=0.3.67", features = ["console", "Document", "Window", "Element", "Clipboard", "DateTimeValue", "HtmlElement", "HtmlDocument", "HtmlTextAreaElement", "Blob", "HtmlAreaElement", "Url"] } diff --git a/src/bookmark.rs b/src/bookmark.rs index 75a0893..e0e71e7 100644 --- a/src/bookmark.rs +++ b/src/bookmark.rs @@ -122,7 +122,7 @@ impl Bookmarks { } /// # Safety - /// `inner` must be sorted least to greatest, i.e. it is up to the caller to assure `inner.is_sorted()` + /// `inner` must be sorted least to greatest, i.e.; it is up to the caller to assure `inner.is_sorted()` #[inline] pub unsafe fn from_raw(inner: Vec) -> Self { Self { diff --git a/src/cli.rs b/src/cli.rs index 1c5e494..21db250 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -99,7 +99,7 @@ fn get_predicate(args: &mut Vec) -> SearchPredicate { } fn file_size(path: impl AsRef) -> Option { - File::open(path).ok().and_then(|file| file.metadata().ok()).map(|metadata| metadata.len() as u64) + File::open(path).ok().and_then(|file| file.metadata().ok()).map(|metadata| metadata.len()) } fn increment_progress_bar(completed: &AtomicU64, size: u64, total: u64, action: &str) { diff --git a/src/color.rs b/src/color.rs index c690ec1..0f726b7 100644 --- a/src/color.rs +++ b/src/color.rs @@ -19,6 +19,7 @@ pub enum TextColor { TreeString, TreeKey, TreePrimitive, + Custom(u32), } impl TextColor { @@ -43,6 +44,7 @@ impl TextColor { Self::TreeString => 0x7FE9AC, Self::TreeKey => 0x6EADE2, Self::TreePrimitive => 0xD19A66, + Self::Custom(value) => value & 0xFFFFFF, } } } diff --git a/src/element_action.rs b/src/element_action.rs index 72f7462..825894e 100644 --- a/src/element_action.rs +++ b/src/element_action.rs @@ -209,7 +209,7 @@ impl ElementAction { if !open_file(&path.display().to_string()) { break 'm; } *_subscription = Some(FileUpdateSubscription { subscription_type, - indices, + indices: indices.clone(), rx, watcher, tab_uuid: _tab_uuid, @@ -248,7 +248,7 @@ impl ElementAction { break 'm; }; if let Ok(mut file) = OpenOptions::new().write(true).create(true).open(&path) { - if let Some(key) = key + if let Some(key) = key.as_deref() && element.id() != NbtChunk::ID { if write!(&mut file, "{key}: ").is_err() { break 'm; } @@ -259,7 +259,7 @@ impl ElementAction { if !open_file(&path.display().to_string()) { break 'm; } *_subscription = Some(FileUpdateSubscription { subscription_type: FileUpdateSubscriptionType::Snbt, - indices, + indices: indices.clone(), rx, watcher, tab_uuid: _tab_uuid, diff --git a/src/elements/chunk.rs b/src/elements/chunk.rs index 19a5945..4346dd2 100644 --- a/src/elements/chunk.rs +++ b/src/elements/chunk.rs @@ -41,20 +41,20 @@ impl Clone for NbtRegion { fn clone(&self) -> Self { unsafe { let (map, chunks) = &*self.chunks; - let boxx = alloc(Layout::new::<(Vec, [NbtElement; 32 * 32])>()).cast::<(Vec, [NbtElement; 32 * 32])>(); - let mapp = alloc(Layout::array::(map.len()).unwrap_unchecked()).cast::(); - let chunkss = alloc(Layout::array::(32 * 32).unwrap_unchecked()).cast::(); - map.as_ptr().copy_to_nonoverlapping(mapp, map.len()); + let box_ptr = alloc(Layout::new::<(Vec, [NbtElement; 32 * 32])>()).cast::<(Vec, [NbtElement; 32 * 32])>(); + let map_ptr = alloc(Layout::array::(map.len()).unwrap_unchecked()).cast::(); + let chunks_ptr = alloc(Layout::array::(32 * 32).unwrap_unchecked()).cast::(); + map.as_ptr().copy_to_nonoverlapping(map_ptr, map.len()); for n in 0..1024 { - chunkss.add(n).write(chunks.get_unchecked(n).clone()); + chunks_ptr.add(n).write(chunks.get_unchecked(n).clone()); } - boxx.write(( - Vec::from_raw_parts(mapp, map.len(), map.len()), - chunkss.cast::<[NbtElement; 32 * 32]>().read(), + box_ptr.write(( + Vec::from_raw_parts(map_ptr, map.len(), map.len()), + chunks_ptr.cast::<[NbtElement; 32 * 32]>().read(), )); Self { - chunks: Box::from_raw(boxx), + chunks: Box::from_raw(box_ptr), height: self.height, true_height: self.true_height, max_depth: self.max_depth, @@ -337,7 +337,7 @@ impl NbtRegion { /// /// * `value` must be variant `NbtElement::Chunk` /// - /// * `self.map` must not contain a chunk in this `pos` already + /// * `self.map` must not contain a chunk in this `pos` yet /// /// * `pos` is between 0..=1023 #[inline] @@ -450,7 +450,6 @@ impl NbtRegion { |key, value| key.parse::().ok() == x.parse::().ok() && value.is_some_and(|value| value.parse::().ok() == z.parse::().ok()), true, ); - // first check required so this don't render when it's the only selected let y2 = y.saturating_sub(remaining_scroll * 16); if y2 != ctx.selected_y && y2 >= HEADER_SIZE && ctx.key_duplicate_error { ctx.red_line_numbers[1] = y2; @@ -745,10 +744,10 @@ impl Clone for NbtChunk { #[inline] fn clone(&self) -> Self { unsafe { - let boxx = alloc(Layout::new::()).cast::(); - boxx.write(self.inner.deref().clone()); + let box_ptr = alloc(Layout::new::()).cast::(); + box_ptr.write(self.inner.deref().clone()); Self { - inner: Box::from_raw(boxx), + inner: Box::from_raw(box_ptr), last_modified: self.last_modified, compression: self.compression, x: self.x, @@ -859,7 +858,6 @@ impl NbtChunk { let mut y = ctx.y_offset; for (name, value) in self.children() { ctx.check_for_key_duplicate(|text, _| text == name, false); - // first check required so this don't render when it's the only selected if y.saturating_sub(*remaining_scroll * 16) != ctx.selected_y && y.saturating_sub(*remaining_scroll * 16) >= HEADER_SIZE && ctx.key_duplicate_error { ctx.red_line_numbers[1] = y.saturating_sub(*remaining_scroll * 16); ctx.draw_error_underline( diff --git a/src/elements/compound.rs b/src/elements/compound.rs index 70a5026..47e794f 100644 --- a/src/elements/compound.rs +++ b/src/elements/compound.rs @@ -41,10 +41,10 @@ impl Clone for NbtCompound { #[allow(clippy::cast_ptr_alignment)] fn clone(&self) -> Self { unsafe { - let boxx = alloc(Layout::new::()).cast::(); - boxx.write(self.entries.deref().clone()); + let box_ptr = alloc(Layout::new::()).cast::(); + box_ptr.write(self.entries.deref().clone()); Self { - entries: Box::from_raw(boxx), + entries: Box::from_raw(box_ptr), height: self.height, true_height: self.true_height, max_depth: self.max_depth, @@ -285,7 +285,6 @@ impl NbtCompound { let mut y = ctx.y_offset; for (name, value) in self.children() { ctx.check_for_key_duplicate(|text, _| text == name, false); - // first check required so this don't render when it's the only selected if y.saturating_sub(remaining_scroll * 16) != ctx.selected_y && y.saturating_sub(remaining_scroll * 16) >= HEADER_SIZE && ctx.key_duplicate_error { ctx.red_line_numbers[1] = y.saturating_sub(remaining_scroll * 16); ctx.draw_error_underline( @@ -487,7 +486,6 @@ impl NbtCompound { let mut y = ctx.y_offset; for (name, value) in self.children() { ctx.check_for_key_duplicate(|text, _| text == name, false); - // first check required so this don't render when it's the only selected if y.saturating_sub(*remaining_scroll * 16) != ctx.selected_y && y.saturating_sub(*remaining_scroll * 16) >= HEADER_SIZE && ctx.key_duplicate_error { ctx.red_line_numbers[1] = y.saturating_sub(*remaining_scroll * 16); ctx.draw_error_underline( @@ -1012,7 +1010,7 @@ impl CompoundMap { }; let mut new_bookmarks = Box::<[Bookmark]>::new_uninit_slice(bookmarks[true_line_number..true_line_number + true_height].len()); let mut new_bookmarks_len = 0; - // yeah, it's hacky but there's not much else I *can* do. plus: it works extremely well. + // yeah, it's hacky... but there's not much else I *can* do. plus: it works extremely well. for (idx, entry) in self.entries.iter_mut().enumerate() { entry.hash = idx as u64; } diff --git a/src/elements/element.rs b/src/elements/element.rs index c396950..ac40541 100644 --- a/src/elements/element.rs +++ b/src/elements/element.rs @@ -131,63 +131,68 @@ impl Clone for NbtElement { #[allow(non_snake_case)] impl NbtElement { + #[inline] + pub fn set_id(&mut self, id: u8) { + unsafe { core::ptr::write(core::ptr::addr_of_mut!(self.id.id), id); } + } + #[must_use] #[inline] - pub const fn Byte(this: NbtByte) -> Self { + pub fn Byte(this: NbtByte) -> Self { let mut this = Self { byte: ManuallyDrop::new(this), }; - this.id.id = NbtByte::ID; + this.set_id(NbtByte::ID); this } #[must_use] #[inline] - pub const fn Short(this: NbtShort) -> Self { + pub fn Short(this: NbtShort) -> Self { let mut this = Self { short: ManuallyDrop::new(this), }; - this.id.id = NbtShort::ID; + this.set_id(NbtShort::ID); this } #[must_use] #[inline] - pub const fn Int(this: NbtInt) -> Self { + pub fn Int(this: NbtInt) -> Self { let mut this = Self { int: ManuallyDrop::new(this), }; - this.id.id = NbtInt::ID; + this.set_id(NbtInt::ID); this } #[must_use] #[inline] - pub const fn Long(this: NbtLong) -> Self { + pub fn Long(this: NbtLong) -> Self { let mut this = Self { long: ManuallyDrop::new(this), }; - this.id.id = NbtLong::ID; + this.set_id(NbtLong::ID); this } #[must_use] #[inline] - pub const fn Float(this: NbtFloat) -> Self { + pub fn Float(this: NbtFloat) -> Self { let mut this = Self { float: ManuallyDrop::new(this), }; - this.id.id = NbtFloat::ID; + this.set_id(NbtFloat::ID); this } #[must_use] #[inline] - pub const fn Double(this: NbtDouble) -> Self { + pub fn Double(this: NbtDouble) -> Self { let mut this = Self { double: ManuallyDrop::new(this), }; - this.id.id = NbtDouble::ID; + this.set_id(NbtDouble::ID); this } @@ -197,7 +202,7 @@ impl NbtElement { let mut this = Self { byte_array: ManuallyDrop::new(this), }; - this.id.id = NbtByteArray::ID; + this.set_id(NbtByteArray::ID); this } @@ -207,7 +212,7 @@ impl NbtElement { let mut this = Self { string: ManuallyDrop::new(this), }; - this.id.id = NbtString::ID; + this.set_id(NbtString::ID); this } @@ -217,7 +222,7 @@ impl NbtElement { let mut this = Self { list: ManuallyDrop::new(this), }; - this.id.id = NbtList::ID; + this.set_id(NbtList::ID); this } @@ -227,16 +232,17 @@ impl NbtElement { let mut this = Self { compound: ManuallyDrop::new(this), }; - this.id.id = NbtCompound::ID; + this.set_id(NbtCompound::ID); this } #[must_use] + #[inline] pub fn IntArray(this: NbtIntArray) -> Self { let mut this = Self { int_array: ManuallyDrop::new(this), }; - this.id.id = NbtIntArray::ID; + this.set_id(NbtIntArray::ID); this } @@ -246,7 +252,7 @@ impl NbtElement { let mut this = Self { long_array: ManuallyDrop::new(this), }; - this.id.id = NbtLongArray::ID; + this.set_id(NbtLongArray::ID); this } @@ -256,7 +262,7 @@ impl NbtElement { let mut this = Self { chunk: ManuallyDrop::new(this), }; - this.id.id = NbtChunk::ID; + this.set_id(NbtChunk::ID); this } @@ -266,7 +272,7 @@ impl NbtElement { let mut this = Self { region: ManuallyDrop::new(this), }; - this.id.id = NbtRegion::ID; + this.set_id(NbtRegion::ID); this } } @@ -305,10 +311,8 @@ impl NbtElement { s = s2.trim_start(); return if let Some(s2) = s.strip_prefix('f') { Some((s2.trim_start(), Self::Float(NbtFloat { value: f32::NAN }))) - } else if let Some(s2) = s.strip_prefix('d') { - Some((s2.trim_start(), Self::Double(NbtDouble { value: f64::NAN }))) } else { - Some((s2.trim_start(), Self::Double(NbtDouble { value: f64::NAN }))) + Some((s2.strip_prefix('d').unwrap_or(s2).trim_start(), Self::Double(NbtDouble { value: f64::NAN }))) }; } @@ -321,16 +325,9 @@ impl NbtElement { value: f32::INFINITY, }), )) - } else if let Some(s2) = s.strip_prefix('d') { - Some(( - s2.trim_start(), - Self::Double(NbtDouble { - value: f64::INFINITY, - }), - )) } else { Some(( - s2.trim_start(), + s2.strip_prefix('d').unwrap_or(s2).trim_start(), Self::Double(NbtDouble { value: f64::INFINITY, }), @@ -392,7 +389,7 @@ impl NbtElement { digit_end_idx }; if digit_end_idx > 0 { - let suffix = (s[digit_end_idx..]) + let suffix = s[digit_end_idx..] .trim_start() .as_bytes() .first() @@ -401,36 +398,36 @@ impl NbtElement { Some(b'b') => Some(( &s[(digit_end_idx + 1)..], Self::Byte(NbtByte { - value: (s[..digit_end_idx]).parse().ok()?, + value: s[..digit_end_idx].parse().ok()?, }), )), Some(b's') => Some(( &s[(digit_end_idx + 1)..], Self::Short(NbtShort { - value: (s[..digit_end_idx]).parse().ok()?, + value: s[..digit_end_idx].parse().ok()?, }), )), Some(b'l') => Some(( &s[(digit_end_idx + 1)..], Self::Long(NbtLong { - value: (s[..digit_end_idx]).parse().ok()?, + value: s[..digit_end_idx].parse().ok()?, }), )), Some(b'f') => Some(( &s[(digit_end_idx + 1)..], Self::Float(NbtFloat { - value: (s[..digit_end_idx]).parse().ok()?, + value: s[..digit_end_idx].parse().ok()?, }), )), Some(b'd') => Some(( &s[(digit_end_idx + 1)..], Self::Double(NbtDouble { - value: (s[..digit_end_idx]).parse().ok()?, + value: s[..digit_end_idx].parse().ok()?, }), )), Some(b'|') => Some({ let mut s = s; - let Ok(x @ 0..=31) = (s[..digit_end_idx]).parse::() else { + let Ok(x @ 0..=31) = s[..digit_end_idx].parse::() else { return None; }; s = s[digit_end_idx..].trim_start().split_at(1).1.trim_start(); @@ -942,7 +939,7 @@ impl NbtElement { /// /// * `self` cannot contain that specific variant of `Self`, i.e. `Self::NbtByte` in an `Self::NbtIntArray` /// - /// If any changes are made to this error list then duplicate may have to be updated as it relies on this never occurring + /// If any changes are made to this error list, then the duplicate may have to be updated as it relies on this never occurring #[inline] pub fn insert(&mut self, idx: usize, value: Self) -> Result<(), Self> { unsafe { diff --git a/src/elements/list.rs b/src/elements/list.rs index 9cbeb2c..53bc7a6 100644 --- a/src/elements/list.rs +++ b/src/elements/list.rs @@ -43,13 +43,13 @@ impl Clone for NbtList { unsafe { let len = self.elements.len(); let ptr = alloc(Layout::array::(len).unwrap_unchecked()).cast::(); - let boxx = alloc(Layout::new::>()).cast::>(); + let box_ptr = alloc(Layout::new::>()).cast::>(); for n in 0..len { ptr.add(n).write(self.elements.get_unchecked(n).clone()); } - boxx.write(Vec::from_raw_parts(ptr.cast::(), len, len)); + box_ptr.write(Vec::from_raw_parts(ptr.cast::(), len, len)); Self { - elements: Box::from_raw(boxx), + elements: Box::from_raw(box_ptr), height: self.height, true_height: self.true_height, max_depth: self.max_depth, @@ -93,10 +93,10 @@ impl NbtList { true_height += element.true_height() as u32; ptr.add(n).write(element); } - let boxx = alloc(Layout::new::>()).cast::>(); - boxx.write(Vec::from_raw_parts(ptr, len, len)); + let box_ptr = alloc(Layout::new::>()).cast::>(); + box_ptr.write(Vec::from_raw_parts(ptr, len, len)); Some(Self { - elements: Box::from_raw(boxx), + elements: Box::from_raw(box_ptr), height: 1 + len as u32, true_height, max_depth: 0, @@ -544,7 +544,11 @@ impl<'a> Iterator for ValueMutIterator<'a> { fn next(&mut self) -> Option { match self { Self::Generic(iter) => iter.next(), - // SAFETY: the only problem here is aliasing, which is assumed to not occur due to `map` indices not being identical, if they are identical it's UB, so all we need is to check if we have two pointers to the same data, which doesn't occur in mutation + // SAFETY: the only problem here is aliasing, + // which is assumed to not occur due to `map` indices not being identical + // (if they are identical it's UB). + // so all we need is to check if we have two pointers to the same data, + // which doesn't occur in mutation Self::Region(array, iter) => unsafe { let chunk = iter.next().map(|&x| { array @@ -571,7 +575,11 @@ impl<'a> DoubleEndedIterator for ValueMutIterator<'a> { fn next_back(&mut self) -> Option { match self { Self::Generic(iter) => iter.next_back(), - // SAFETY: the only problem here is aliasing, which is assumed to not occur due to `map` indices not being identical, if they are identical it's UB, so all we need is to check if we have two pointers to the same data, which doesn't occur in mutation + // SAFETY: the only problem here is aliasing, + // which is assumed to not occur due to `map` indices not being identical + // (if they are identical it's UB). + // so all we need is to check if we have two pointers to the same data, + // which doesn't occur in mutation Self::Region(array, iter) => unsafe { let chunk = iter.next_back().map(|&x| { array diff --git a/src/main.rs b/src/main.rs index 979edab..81f7d18 100644 --- a/src/main.rs +++ b/src/main.rs @@ -22,6 +22,7 @@ stmt_expr_attributes, unchecked_math )] +#![feature(panic_update_hook)] #![cfg_attr(all(windows, not(debug_assertions)), windows_subsystem = "windows")] use std::cell::UnsafeCell; @@ -158,14 +159,6 @@ macro_rules! log { }; } -#[macro_export] -macro_rules! debg { - () => { - #[cfg(debug_assertions)] - $crate::log!("[{}:{}:{}]", file!(), line!(), column!()) - }; -} - #[wasm_bindgen(module = "/web/script.js")] #[cfg(target_arch = "wasm32")] extern "C" { @@ -180,6 +173,9 @@ extern "C" { #[wasm_bindgen(js_name = "save")] fn save(name: &str, bytes: Vec); + + #[wasm_bindgen(js_name = "onPanic")] + fn on_panic(msg: String); } pub static mut WORKBENCH: UnsafeCell = UnsafeCell::new(unsafe { Workbench::uninit() }); @@ -200,7 +196,9 @@ pub fn open_file(name: String, bytes: Vec) { #[cfg_attr(target_arch = "wasm32", wasm_bindgen(start))] #[cfg(target_arch = "wasm32")] pub fn wasm_main() { - ::console_error_panic_hook::set_once(); + std::panic::set_hook(Box::new(|info| { + on_panic(info.to_string()); + })); wasm_bindgen_futures::spawn_local(async move { window::run().await; }); @@ -229,7 +227,7 @@ pub fn main() -> ! { --version, -v Displays the version of nbtworkbench you're running. -?, -h, --help, /? Displays this dialog. --mode, -m Changes the `find` mode to take the field as either, a containing substring, a regex (match whole), or snbt. [default: normal] - --search, -s Searches for results matching the in either, the key, the value, or both (note that substrings and regex saerch the same pattern in both key and value, while the regex uses it's key field to match equal strings). [default: all] + --search, -s Searches for results matching the in either, the key, the value, or both (note that substrings and regex search the same pattern in both key and value, while the regex uses it's key field to match equal strings). [default: all] --format, -f Specifies the format to be reformatted to; either `nbt`, `snbt`, `dat/dat_old/gzip` or `zlib`. --out-dir, -d Specifies the output directory. [default: ./] --out-ext, -e Specifies the output file extension (if not specified, it will infer from --format)"# @@ -251,7 +249,7 @@ pub fn main() -> ! { /// * gear icon to swap toolbar with settings panel /// * __ctrl + h__, open a playground `nbt` file to help with user interaction (bonus points if I have some way to tell if you haven't used this editor before) /// * [`last_modified`](NbtChunk) field actually gets some impl -/// * autosave +/// * auto save /// * blur behind tooltip /// # Major Features /// * macros @@ -578,7 +576,7 @@ impl SortAlgorithm { pub fn sort(self, map: &mut CompoundMap) { if let Self::None = self { return; } let hashes = map.entries.iter().map(|entry| entry.hash).collect::>(); - // yeah, it's hacky but there's not much else I *can* do. plus: it works extremely well. + // yeah, it's hacky... but there's not much else I *can* do. plus: it works extremely well. for (idx, entry) in map.entries.iter_mut().enumerate() { entry.hash = idx as u64; } @@ -925,8 +923,9 @@ pub struct LinkedQueue { // perf enhancement impl Drop for LinkedQueue { fn drop(&mut self) { - while let Some(box SinglyLinkedNode { value: _, prev }) = self.tail.take() { - self.tail = prev; + while let Some(box SinglyLinkedNode { value: _, mut prev }) = self.tail.take() { + // take is not required, but then intellij gets upset. + self.tail = prev.take(); } } } @@ -974,8 +973,9 @@ impl LinkedQueue { pub const fn is_empty(&self) -> bool { self.len == 0 } pub fn clear(&mut self) { - while let Some(box SinglyLinkedNode { value: _, prev }) = self.tail.take() { - self.tail = prev; + while let Some(box SinglyLinkedNode { value: _, mut prev }) = self.tail.take() { + // take is not required, but then intellij gets upset. + self.tail = prev.take(); } self.len = 0; } @@ -1305,7 +1305,7 @@ impl OptionExt for Option { /// /// # Panics /// -/// * When `debug_assertions` is true, it panics with the respective `msg` +/// * When `debug_assertions` are true, it panics with the respective `msg` #[allow(unused_variables)] // intellij being freaky pub unsafe fn panic_unchecked(msg: &str) -> ! { #[cfg(debug_assertions)] diff --git a/src/selected_text.rs b/src/selected_text.rs index a2bddcc..7d55c8a 100644 --- a/src/selected_text.rs +++ b/src/selected_text.rs @@ -11,7 +11,7 @@ use crate::text::{Cachelike, SelectedTextKeyResult, Text}; use crate::vertex_buffer_builder::VertexBufferBuilder; #[derive(Clone, Debug)] -#[allow(clippy::module_name_repetitions)] // yeah no it's better like this +#[allow(clippy::module_name_repetitions)] // yeah no, it's better like this pub struct SelectedTextCache { keyfix: Option<(Box, TextColor)>, value: Box, @@ -269,7 +269,7 @@ impl SelectedText { pub fn width(&self) -> usize { self.prefix.0.width() + self.keyfix.as_ref().map(|x| x.0.width()).unwrap_or(0) + self.value.width() + self.valuefix.as_ref().map(|x| x.0.width()).unwrap_or(0) + self.suffix.0.width() } #[cfg_attr(not(debug_assertions), inline)] - #[allow(clippy::cognitive_complexity, clippy::too_many_lines)] // i handled this fn well + #[allow(clippy::cognitive_complexity, clippy::too_many_lines)] // I handled this fn well #[must_use] pub fn on_key_press(&mut self, key: KeyCode, char: Option, flags: u8) -> SelectedTextKeyResult { if key == KeyCode::ArrowUp { diff --git a/src/tab.rs b/src/tab.rs index 44a816f..bfb3506 100644 --- a/src/tab.rs +++ b/src/tab.rs @@ -44,7 +44,6 @@ pub struct Tab { } impl Tab { - #[must_use] pub fn new(nbt: NbtElement, path: &Path, compression: FileFormat, window_height: usize, window_width: usize) -> Result { if !(nbt.id() == NbtCompound::ID || nbt.id() == NbtRegion::ID) { return Err(anyhow!("Parsed NBT was not a Compound or Region")) } @@ -295,7 +294,7 @@ impl Tab { { let uv = if mx == Some(208) && !skip_tooltips { - builder.draw_tooltip(&["Clipboard (C)"], (mouse_x, mouse_y), false); + builder.draw_tooltip(&["Clipboard (V)"], (mouse_x, mouse_y), false); UNKNOWN_NBT_UV } else { UNKNOWN_NBT_GHOST_UV @@ -356,6 +355,7 @@ impl Tab { #[must_use] pub fn left_margin(&self, held: Option<&NbtElement>) -> usize { ((self.value.true_height() + held.map_or(0, NbtElement::true_height)).ilog10() as usize + 1) * 8 + 4 + 8 } + #[inline] pub fn set_scroll(&mut self, scroll: f32) { #[cfg(target_os = "macos")] const SCROLL_MULTIPLIER: f32 = 4.0; @@ -372,6 +372,7 @@ impl Tab { self.scroll = self.scroll(); } + #[inline] pub fn set_horizontal_scroll(&mut self, scroll: f32, held: Option<&NbtElement>) { #[cfg(target_os = "macos")] const SCROLL_MULTIPLIER: f32 = 4.0; diff --git a/src/window.rs b/src/window.rs index 803436d..da4195b 100644 --- a/src/window.rs +++ b/src/window.rs @@ -129,7 +129,7 @@ pub struct State<'window> { } impl<'window> State<'window> { - #[allow(clippy::too_many_lines)] // yeah, but.... what am I supposed to do? + #[allow(clippy::too_many_lines)] // yeah, but... what am I supposed to do? async fn new(window: &'window Window, size: PhysicalSize) -> State<'window> { let instance = Instance::new(InstanceDescriptor { backends: Backends::all(), diff --git a/src/workbench.rs b/src/workbench.rs index 309b5f1..e2e872d 100644 --- a/src/workbench.rs +++ b/src/workbench.rs @@ -1,5 +1,4 @@ use std::fmt::Write; -use std::fs::read; use std::path::{Path, PathBuf}; use std::str::FromStr; use std::sync::mpsc::TryRecvError; @@ -127,7 +126,7 @@ impl Workbench { .nth(1) .and_then(|x| PathBuf::from_str(&x).ok()) { - if let Err(e) = workbench.on_open_file(path, read(path).unwrap_or(vec![]), window_properties) { + if let Err(e) = workbench.on_open_file(path, std::fs::read(path).unwrap_or(vec![]), window_properties) { workbench.alert(Alert::new("Error!", TextColor::Red, e.to_string())) } else { break 'create_tab; @@ -437,8 +436,6 @@ impl Workbench { return true; } } - } else { - // features, idk } } true @@ -729,7 +726,7 @@ impl Workbench { value.1.shut(); let _ = tab.bookmarks.remove(line_number..line_number + true_height); tab.bookmarks[line_number..].decrement(height, true_height); - // no need for encompass_or_equal since that's handled by `drop` + // no need for encompass_or_equal since `drop` handles that self.held_entry = HeldEntry::FromKnown(value, indices.into_boxed_slice()); true } else { @@ -1370,7 +1367,7 @@ impl Workbench { pub fn shift_selected_text_up(&mut self) { let tab = tab_mut!(self); if let Some(SelectedText(Text { additional: SelectedTextAdditional { y, indices, .. }, .. })) = &mut tab.selected_text { - if indices.is_empty() { return } // well it could be empty + if indices.is_empty() { return } // well, it could be empty let child_idx = unsafe { indices .last() @@ -1427,7 +1424,7 @@ impl Workbench { pub fn shift_selected_text_down(&mut self) { let tab = tab_mut!(self); if let Some(SelectedText(Text { additional: SelectedTextAdditional { y, indices, .. }, .. })) = &mut tab.selected_text { - // well it could be empty + // well, it could be empty if indices.is_empty() { return } let child_idx = unsafe { indices @@ -1553,7 +1550,7 @@ impl Workbench { } else { let total = sum_indices(indices.iter().copied(), &tab.value) - 1; let mut indices = vec![]; - // SAFETY: total is -1'd meaning that it's original range of 1..=root.height() is now ..root.height(), which is in range + // SAFETY: total is -1'd means that it's original range of 1..=root.height() is now ..root.height(), which is in range let (k, v) = 'w: { let mut iter = TraverseParents::new(total, &mut tab.value); while let Some((position, idx, key, value, _)) = iter.next() { @@ -1608,7 +1605,7 @@ impl Workbench { let total = if let Some(SelectedText(Text { additional: SelectedTextAdditional { indices, .. }, .. })) = tab.selected_text.as_ref() { let mut total = sum_indices(indices.iter().copied(), &tab.value); total += 1; // move down - // down needs a check that it doesn't surpass the end + // needs a check that it doesn't surpass the end if total >= tab.value.height() { return } total } else { @@ -2144,7 +2141,7 @@ impl Workbench { (None, NbtElement::from_id(NbtCompound::ID)) } else if key == KeyCode::Backquote && tab.value.id() == NbtRegion::ID { (None, NbtElement::from_id(NbtChunk::ID)) - } else if key == KeyCode::KeyC { + } else if key == KeyCode::KeyV { let Some(clipboard) = get_clipboard() else { self.alert(Alert::new("Error!", TextColor::Red, "Failed to get clipboard")); return true; @@ -2325,7 +2322,7 @@ impl Workbench { let mut ctx = RenderContext::new(selected_y, selected_key, selected_value, selecting_key, ghost, left_margin, (self.mouse_x, self.mouse_y), tab.freehand_mode); if self.mouse_y >= HEADER_SIZE && self.action_wheel.is_none() { builder.draw_texture_region_z( - (0, (self.mouse_y & !15)), + (0, self.mouse_y & !15), BASE_Z, HOVERED_STRIPE_UV, (builder.window_width(), 16), @@ -2554,8 +2551,6 @@ impl Workbench { hovered, ); } - } else { - // features, idk } } diff --git a/web/index.html b/web/index.html index 9f341d3..f79a1e5 100644 --- a/web/index.html +++ b/web/index.html @@ -32,20 +32,53 @@ overflow: hidden; background-color: #0F0F0F; } + + #panic { + width: 100%; + height: 100%; + position: absolute; + top: 0; + left: 0; + display: grid; + opacity: 0; + transition: opacity 0.5s ease-in-out; + -moz-transition: opacity 0.5s ease-in-out; + -o-transition: opacity 0.5s ease-in-out; + -webkit-transition: opacity 0.5s ease-in-out; + z-index: -1; + } + + #panic_background { + background-color: #FF7F7F; + } + + #panic_text { + position: absolute; + left: 50%; + top: 45%; + transform: translate(-50%, -55%); + color: white; + text-align: center; + font-size: 30px; + font-family: Calibri, sans-serif + } - +
+ + + + +
+
+
+
+

NBT Workbench has crashed!

+

If you'd like to help out and report this problem, please:

+ +
+
+
\ No newline at end of file diff --git a/web/script.js b/web/script.js index cfaae57..23c4824 100644 --- a/web/script.js +++ b/web/script.js @@ -1,14 +1,14 @@ export function tryOpenDialog() { - shouldOpenDialog = true; + document.getElementById("shouldOpenDialog").innerText = "true"; } export function getClipboard() { - return clipboard; + return document.getElementById("clipboard").innerText; } export function onInput() { if (!navigator.userAgent.toLowerCase().includes("firefox") && !navigator.userAgent.toLowerCase().includes("safari")) { - window.navigator.clipboard.readText().then((str) => clipboard = str).catch(x => x) + window.navigator.clipboard.readText().then((str) => document.getElementById("clipboard").innerText = str).catch(x => x) } } @@ -18,3 +18,12 @@ export function save(name, bytes) { download.download = name; download.click(); } + +export function onPanic(error) { + let stack = new Error().stack; + document.getElementById("crashReportRaw").innerText = error + "\n\nStack:\n\n" + stack + "\n"; + let panic = document.getElementById("panic"); + panic.style.opacity = "0.8"; + panic.style.display = "grid"; + panic.style.zIndex = "1"; +}