Skip to content

Commit 385f1a8

Browse files
dragonfly1033andybalaam
authored andcommitted
feat(multiverse): Add search feature to multiverse
1 parent dfc0ef8 commit 385f1a8

File tree

9 files changed

+122
-10
lines changed

9 files changed

+122
-10
lines changed

crates/matrix-sdk-search/src/index.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ impl RoomIndex {
7878
pub fn new(path: &Path, room_id: &RoomId) -> Result<RoomIndex, IndexError> {
7979
let path = path.join(room_id.as_str());
8080
let schema = RoomMessageSchema::new();
81-
fs::create_dir(path.clone())?;
81+
fs::create_dir_all(path.clone())?;
8282
let index = Index::create_in_dir(path, schema.as_tantivy_schema())?;
8383
RoomIndex::new_with(index, schema, room_id)
8484
}
@@ -99,9 +99,11 @@ impl RoomIndex {
9999
Ok(dir) => Ok(dir),
100100
Err(err) => match err {
101101
OpenDirectoryError::DoesNotExist(path) => {
102-
fs::create_dir(path.clone()).map_err(|err| OpenDirectoryError::IoError {
103-
io_error: Arc::new(err),
104-
directory_path: path.to_path_buf(),
102+
fs::create_dir_all(path.clone()).map_err(|err| {
103+
OpenDirectoryError::IoError {
104+
io_error: Arc::new(err),
105+
directory_path: path.to_path_buf(),
106+
}
105107
})?;
106108
MmapDirectory::open(path)
107109
}

crates/matrix-sdk/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ pub mod widget;
6767

6868
pub use account::Account;
6969
pub use authentication::{AuthApi, AuthSession, SessionTokens};
70+
#[cfg(feature = "experimental-search")]
71+
pub use client::search::SearchIndexStoreKind;
7072
pub use client::{
7173
sanitize_server_name, Client, ClientBuildError, ClientBuilder, LoopCtrl, ServerVendorInfo,
7274
SessionChange,

labs/multiverse/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ futures-util.workspace = true
2020
imbl.workspace = true
2121
indexmap.workspace = true
2222
itertools.workspace = true
23-
matrix-sdk = { path = "../../crates/matrix-sdk", features = ["sso-login"] }
23+
matrix-sdk = { path = "../../crates/matrix-sdk", features = ["sso-login", "experimental-search"] }
2424
matrix-sdk-base = { path = "../../crates/matrix-sdk-base" }
2525
matrix-sdk-common = { path = "../../crates/matrix-sdk-common" }
2626
matrix-sdk-ui = { path = "../../crates/matrix-sdk-ui" }

labs/multiverse/src/main.rs

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ use futures_util::{StreamExt as _, pin_mut};
2020
use imbl::Vector;
2121
use layout::Flex;
2222
use matrix_sdk::{
23-
AuthSession, Client, SqliteCryptoStore, SqliteEventCacheStore, SqliteStateStore,
24-
ThreadingSupport,
23+
AuthSession, Client, SearchIndexStoreKind, SqliteCryptoStore, SqliteEventCacheStore,
24+
SqliteStateStore, ThreadingSupport,
2525
authentication::matrix::MatrixSession,
2626
config::StoreConfig,
2727
encryption::{BackupDownloadStrategy, EncryptionSettings},
@@ -38,7 +38,7 @@ use matrix_sdk_ui::{
3838
use ratatui::{prelude::*, style::palette::tailwind, widgets::*};
3939
use throbber_widgets_tui::{Throbber, ThrobberState};
4040
use tokio::{spawn, task::JoinHandle};
41-
use tracing::{error, warn};
41+
use tracing::{debug, error, warn};
4242
use tracing_subscriber::EnvFilter;
4343
use widgets::{
4444
recovery::create_centered_throbber_area, room_view::RoomView, settings::SettingsView,
@@ -48,6 +48,7 @@ use crate::widgets::{
4848
create_room::CreateRoomView,
4949
help::HelpView,
5050
room_list::{ExtraRoomInfo, RoomInfos, RoomList, Rooms},
51+
search::SearchingView,
5152
status::Status,
5253
};
5354

@@ -88,6 +89,8 @@ pub enum GlobalMode {
8889
Exiting { shutdown_task: JoinHandle<()> },
8990
/// Mode where we have opened create room screen
9091
CreateRoom { view: CreateRoomView },
92+
/// Mode where we have opened create room screen
93+
Searching { view: SearchingView },
9194
}
9295

9396
/// Helper function to create a centered rect using up certain percentage of the
@@ -358,6 +361,10 @@ impl App {
358361
self.set_global_mode(GlobalMode::CreateRoom { view: CreateRoomView::new() })
359362
}
360363

364+
Event::Key(KeyEvent { modifiers: KeyModifiers::CONTROL, code: Char('s'), .. }) => {
365+
self.set_global_mode(GlobalMode::Searching { view: SearchingView::new() })
366+
}
367+
361368
_ => self.room_view.handle_event(event).await,
362369
}
363370

@@ -371,6 +378,7 @@ impl App {
371378
GlobalMode::Help
372379
| GlobalMode::Default
373380
| GlobalMode::CreateRoom { .. }
381+
| GlobalMode::Searching { .. }
374382
| GlobalMode::Exiting { .. } => {}
375383
GlobalMode::Settings { view } => {
376384
view.on_tick();
@@ -448,6 +456,29 @@ impl App {
448456
}
449457
}
450458
}
459+
GlobalMode::Searching { view } => {
460+
if let Event::Key(key) = event
461+
&& let KeyModifiers::NONE = key.modifiers
462+
{
463+
match key.code {
464+
Enter => {
465+
if let Some(query) = view.get_text() {
466+
if let Some(room) = self.room_view.room() {
467+
if let Some(results) = room.search(&query, 100).await {
468+
view.results(results);
469+
} else {
470+
debug!("No results found in search.")
471+
}
472+
} else {
473+
warn!("No room in view.")
474+
}
475+
}
476+
}
477+
Esc => self.set_global_mode(GlobalMode::Default),
478+
_ => view.handle_key_press(key),
479+
}
480+
}
481+
}
451482
GlobalMode::Exiting { .. } => {}
452483
}
453484
}
@@ -456,6 +487,7 @@ impl App {
456487
GlobalMode::Default
457488
| GlobalMode::Help
458489
| GlobalMode::CreateRoom { .. }
490+
| GlobalMode::Searching { .. }
459491
| GlobalMode::Settings { .. } => {}
460492
GlobalMode::Exiting { shutdown_task } => {
461493
if shutdown_task.is_finished() {
@@ -523,6 +555,9 @@ impl Widget for &mut App {
523555
GlobalMode::CreateRoom { view } => {
524556
view.render(area, buf);
525557
}
558+
GlobalMode::Searching { view } => {
559+
view.render(area, buf);
560+
}
526561
}
527562
}
528563
}
@@ -556,7 +591,8 @@ async fn configure_client(cli: Cli) -> Result<Client> {
556591
auto_enable_backups: true,
557592
})
558593
.with_enable_share_history_on_invite(true)
559-
.with_threading_support(ThreadingSupport::Enabled { with_subscriptions: true });
594+
.with_threading_support(ThreadingSupport::Enabled { with_subscriptions: true })
595+
.search_index_store(SearchIndexStoreKind::Directory(session_path.join("indexData")));
560596

561597
if let Some(proxy_url) = proxy {
562598
client_builder = client_builder.proxy(proxy_url).disable_ssl_verification();

labs/multiverse/src/widgets/help.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ impl Widget for &mut HelpView {
6565
Cell::from("Open a thread on the focused timeline item"),
6666
]),
6767
Row::new(vec![Cell::from("Ctrl-r"), Cell::from("Create a new room")]),
68+
Row::new(vec![Cell::from("Ctrl-s"), Cell::from("Search")]),
6869
];
6970
let widths = [Constraint::Length(5), Constraint::Length(5)];
7071

labs/multiverse/src/widgets/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ pub mod popup_input;
77
pub mod recovery;
88
pub mod room_list;
99
pub mod room_view;
10+
pub mod search;
1011
pub mod settings;
1112
pub mod status;
1213

labs/multiverse/src/widgets/room_view/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,8 @@ impl RoomView {
189189
}
190190
}
191191

192-
fn room(&self) -> Option<Room> {
192+
/// Get currently focused [`Room`]
193+
pub fn room(&self) -> Option<Room> {
193194
self.room_id().and_then(|room_id| self.client.get_room(room_id))
194195
}
195196

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
use crossterm::event::KeyEvent;
2+
use matrix_sdk::ruma::OwnedEventId;
3+
use ratatui::{
4+
layout::Flex,
5+
prelude::*,
6+
widgets::{Block, Borders, Cell, Clear, Padding, Row, Table, TableState},
7+
};
8+
9+
use crate::widgets::popup_input::PopupInput;
10+
11+
#[derive(Default)]
12+
pub struct SearchingView {
13+
input: PopupInput,
14+
results: Option<Vec<OwnedEventId>>,
15+
}
16+
17+
impl SearchingView {
18+
pub fn new() -> Self {
19+
Self {
20+
input: PopupInput::new("Search", "(Enter search query)")
21+
.height_constraint(Constraint::Percentage(100))
22+
.width_constraint(Constraint::Percentage(100)),
23+
results: None,
24+
}
25+
}
26+
27+
pub fn results(&mut self, values: Vec<OwnedEventId>) {
28+
self.results = Some(values);
29+
}
30+
31+
pub fn get_text(&self) -> Option<String> {
32+
let name = self.input.get_input();
33+
if !name.is_empty() { Some(name) } else { None }
34+
}
35+
36+
pub fn handle_key_press(&mut self, key: KeyEvent) {
37+
self.input.handle_key_press(key);
38+
}
39+
}
40+
41+
impl Widget for &mut SearchingView {
42+
fn render(self, area: Rect, buf: &mut Buffer) {
43+
let vertical = Layout::vertical([Constraint::Length(3), Constraint::Percentage(80)])
44+
.flex(Flex::Center);
45+
let horizontal = Layout::horizontal([Constraint::Percentage(50)]).flex(Flex::Center);
46+
let [area] = horizontal.areas(area);
47+
let [search_area, results_area] = vertical.areas(area);
48+
49+
let rows = if let Some(results) = &self.results {
50+
results
51+
.iter()
52+
.map(|ev_id| Row::new([Cell::new(ev_id.to_string())]))
53+
.collect::<Vec<Row<'_>>>()
54+
} else {
55+
vec![Row::new([Cell::new("No results found!")])]
56+
};
57+
58+
let block =
59+
Block::bordered().title(" Search ").borders(Borders::ALL).padding(Padding::left(2));
60+
61+
let results_table = Table::new(rows, [Constraint::Percentage(100)]).block(block);
62+
63+
Clear.render(results_area, buf);
64+
StatefulWidget::render(results_table, results_area, buf, &mut TableState::default());
65+
66+
self.input.render(search_area, buf);
67+
}
68+
}

labs/multiverse/src/widgets/status.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ impl StatefulWidget for &mut Status {
130130
GlobalMode::Help => "Press q to exit the help screen",
131131
GlobalMode::Settings { .. } => "Press ESC to exit the settings screen",
132132
GlobalMode::CreateRoom { .. } => "Press ESC to exit the create room screen",
133+
GlobalMode::Searching { .. } => "Press ESC to exit the search screen",
133134
GlobalMode::Default => "Press F1 to show the help screen",
134135
GlobalMode::Exiting { .. } => "",
135136
}

0 commit comments

Comments
 (0)