Skip to content

Commit 674d779

Browse files
committed
support search even no file opens
1 parent c8579f1 commit 674d779

6 files changed

Lines changed: 68 additions & 21 deletions

File tree

asm_egui/src/file_tab.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ fn file_title(
5454
}
5555
} else if response.raw.clicked() {
5656
*selected_tab_index = Some(index);
57-
top.file_path = Some(title_cloned.to_string());
57+
top.file_path = title_cloned.to_string();
5858
}
5959
}
6060

asm_egui/src/file_tree.rs

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,33 @@
11
use crate::app::EguiApp;
22
use egui::text::LayoutJob;
33
use egui::{ScrollArea, TextStyle};
4+
use java_asm::StrRef;
45
use java_asm_server::ui::{AppContainer, FileEntry, FileInfo, OpenFileMessage, RawDirInfo, UIMessage};
56

67
pub fn render_dir(ui: &mut egui::Ui, app: &mut EguiApp) {
78
let server_app = &app.ui_app;
89
let mut left = server_app.left().lock();
9-
let entries = &mut left.root_node.visible_items();
10+
let offset_key = left.offset_key.clone();
11+
let hint_key = left.hint_key.clone();
12+
left.offset_key = None; // set to none to avoid ui can't scrolling.
13+
let file_tree = &mut left.root_node.visible_items(offset_key);
14+
let required_file_index = file_tree.required_file_index;
15+
let entries = &mut file_tree.entries;
1016
let server = app.server.lock();
1117
if server.is_none() { return; }
1218
let row_height = ui.spacing().interact_size.y;
13-
let scroll_area = ScrollArea::vertical().auto_shrink(false);
14-
// scroll_area.vertical_scroll_offset();
19+
let mut scroll_area = ScrollArea::vertical().auto_shrink(false);
20+
21+
if required_file_index > 0 {
22+
// scroll to the required file
23+
let required_file_index = required_file_index as f32;
24+
let row_height_with_spacing = row_height + ui.spacing().item_spacing.y;
25+
let scroll_offset = row_height_with_spacing * required_file_index;
26+
let window_rect = ui.input(|i: &egui::InputState| i.screen_rect());
27+
let window_height: f32 = window_rect.max[1] - window_rect.min[1];
28+
scroll_area = scroll_area.vertical_scroll_offset(scroll_offset - window_height * 0.2);
29+
}
30+
1531
scroll_area.show_rows(ui, row_height, entries.len(), |ui, range| {
1632
for i in range {
1733
let entry = &mut entries[i];
@@ -20,21 +36,27 @@ pub fn render_dir(ui: &mut egui::Ui, app: &mut EguiApp) {
2036
render_dir_raw(ui, raw_dir, server_app);
2137
}
2238
FileEntry::File(file_info) => {
23-
render_file(ui, file_info, server_app);
39+
render_file(ui, file_info, server_app, &hint_key);
2440
}
2541
}
2642
}
2743
});
2844
}
2945

3046
fn render_file(
31-
ui: &mut egui::Ui, file_info: &mut FileInfo, app: &AppContainer,
47+
ui: &mut egui::Ui, file_info: &mut FileInfo, app: &AppContainer, hint: &Option<StrRef>,
3248
) {
3349
let FileInfo { title, file_key, level } = file_info;
3450
ui.horizontal(|ui| {
3551
ui.add_space((*level as f32) * 12.0);
3652
let layout_job = layout_string(ui, title.to_string());
37-
let label = ui.selectable_label(false, layout_job);
53+
let checked: bool;
54+
if let Some(hint) = hint {
55+
checked = hint == file_key;
56+
} else {
57+
checked = false;
58+
}
59+
let label = ui.selectable_label(checked, layout_job);
3860
if label.clicked() {
3961
let message = UIMessage::OpenFile(
4062
OpenFileMessage {
@@ -66,7 +88,8 @@ fn render_dir_raw(
6688
if new_opened {
6789
*opened = true;
6890
} else {
69-
// closed, close all child dir
91+
// need to close all child dir
92+
// so we passed a message to server
7093
app_container.send_message(UIMessage::CloseDir(dir_info.dir_key.clone()))
7194
}
7295
}

asm_egui/src/top_bar.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,9 @@ impl EguiApp {
4040

4141
fn file_path_input(&mut self, ui: &mut Ui) {
4242
let mut locked_top = self.ui_app.top().lock();
43-
let Some(file_path) = &mut locked_top.file_path else { return; };
43+
let mut file_path = &mut locked_top.file_path;
4444

45-
let edit_path_ui = Self::file_path_input_area(ui, file_path);
45+
let edit_path_ui = Self::file_path_input_area(ui, &mut file_path);
4646

4747
let popup_id = Id::new("file_path_popup");
4848
if edit_path_ui.gained_focus() {
@@ -80,6 +80,7 @@ impl EguiApp {
8080
let target_width_for_content = max_width - last_time_remaining;
8181

8282
let edit_path_ui = TextEdit::singleline(file_path)
83+
.hint_text("Enter class name to search...")
8384
.desired_width(target_width_for_content).show(ui).response;
8485

8586
let remaining_width = ui.min_rect().width() - target_width_for_content;

asm_server/src/impls/server.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,10 @@ use crate::impls::apk_load::read_apk;
22
use crate::server::OpenFileError;
33
use crate::ui::{AppContainer, DirInfo, Left};
44
use crate::{AccessorEnum, AccessorMut, AsmServer, ServerMut};
5-
use java_asm::StrRef;
65
use log::info;
6+
use rfd::MessageDialogResult::No;
77
use std::io::{Read, Seek};
88
use std::ops::DerefMut;
9-
use std::sync::Arc;
109
use std::time::Instant;
1110
use tokio::runtime::Runtime;
1211
use tokio::sync::mpsc;
@@ -89,6 +88,6 @@ impl AsmServer {
8988
let start = Instant::now();
9089
let dir_info = DirInfo::from_classes(&classes);
9190
info!("resolve dir info cost: {:?}", start.elapsed());
92-
app.set_left(Left { root_node: dir_info });
91+
app.set_left(Left { root_node: dir_info, offset_key: None, hint_key: None });
9392
}
9493
}

asm_server/src/server.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ impl AsmServer {
9090
let accessor_locked = self.accessor.lock();
9191
let Some(accessor) = accessor_locked.deref() else { return; };
9292
let mut left = render_target.left().lock();
93+
left.offset_key = Some(file_key.into());
94+
left.hint_key = Some(file_key.into());
9395
let mut content = render_target.content().lock();
9496
let mut top = render_target.top().lock();
9597
self.switch_or_open_lock_free(file_key, accessor, &mut left, &mut content, &mut top);
@@ -145,7 +147,7 @@ impl AsmServer {
145147
content.opened_tabs.push(current_tab);
146148
content.selected = Some(current);
147149

148-
top.file_path = Some(file_key.to_string());
150+
top.file_path = file_key.to_string();
149151
}
150152

151153
// switch left side file tree to correct place.
@@ -166,7 +168,7 @@ impl AsmServer {
166168
}
167169

168170
pub fn search(&self, top: &mut Top) {
169-
let Some(query) = &top.file_path else { return; };
171+
let query = &top.file_path;
170172
let query: StrRef = query.as_str().into();
171173
let mut fuzzy_locked = self.get_or_create_fuzzy(query.clone()).lock();
172174
let Some(fuzzy) = fuzzy_locked.deref_mut() else { return; };

asm_server/src/ui/mod.rs

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -73,13 +73,15 @@ impl AppContainer {
7373
#[derive(Default, Clone, Debug)]
7474
pub struct Top {
7575
pub loading_state: LoadingState,
76-
pub file_path: Option<String>,
76+
pub file_path: String,
7777
pub search_result: SearchResult,
7878
}
7979

8080
#[derive(Default, Clone, Debug)]
8181
pub struct Left {
8282
pub root_node: DirInfo,
83+
pub offset_key: Option<StrRef>,
84+
pub hint_key: Option<StrRef>,
8385
}
8486

8587
#[derive(Clone, Debug)]
@@ -116,14 +118,24 @@ pub struct DirInfo {
116118
pub files: FileMap,
117119
}
118120

119-
fn visible_items<'a, 'b>(dir_info: &'b mut DirInfo, container: &'a mut Vec<FileEntry<'b>>) {
121+
fn visible_items<'a, 'b>(
122+
// input
123+
dir_info: &'b mut DirInfo, offset_key: &Option<StrRef>,
124+
// output
125+
container: &'a mut Vec<FileEntry<'b>>, offset: &mut usize,
126+
) {
120127
let opened = dir_info.raw.opened;
121128
container.push(Dir(&mut dir_info.raw));
122129
if !opened { return; }
123130
for (_, dir) in dir_info.dirs.iter_mut() {
124-
visible_items(dir, container);
131+
visible_items(dir, offset_key, container, offset);
125132
}
126133
for (_, file) in dir_info.files.iter_mut() {
134+
if let Some(file_key) = offset_key {
135+
if *file_key == file.file_key {
136+
*offset = container.len();
137+
}
138+
}
127139
container.push(File(file));
128140
}
129141
}
@@ -174,10 +186,14 @@ impl DirInfo {
174186
}
175187
}
176188

177-
pub fn visible_items(&mut self) -> Vec<FileEntry> {
189+
pub fn visible_items(&'_ mut self, offset_key: Option<StrRef>) -> FileTreeBuildResult<'_> {
178190
let mut container = Vec::new();
179-
visible_items(self, &mut container);
180-
container
191+
let mut index_of_offset = 0usize;
192+
visible_items(self, &offset_key, &mut container, &mut index_of_offset);
193+
FileTreeBuildResult {
194+
entries: container,
195+
required_file_index: index_of_offset,
196+
}
181197
}
182198

183199
fn entry_parts(path: &str) -> Peekable<Enumerate<Split<char>>> {
@@ -208,6 +224,12 @@ impl DirInfo {
208224
}
209225
}
210226

227+
pub struct FileTreeBuildResult<'a> {
228+
pub entries: Vec<FileEntry<'a>>,
229+
// the index of required file which used for initial scrolling offset.
230+
pub required_file_index: usize,
231+
}
232+
211233
#[derive(Clone, Debug, Default)]
212234
pub struct Content {
213235
// the index of the selected tab in opened_tabs.

0 commit comments

Comments
 (0)