Skip to content

Commit decf248

Browse files
committed
Optimize search and git change updates
1 parent 6cd689d commit decf248

15 files changed

Lines changed: 694 additions & 224 deletions

File tree

anycode-backend/Cargo.toml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ version = "0.0.18"
44
edition = "2024"
55

66
[profile.release]
7-
opt-level = 3
8-
strip = true
9-
lto = true
10-
codegen-units = 1
11-
panic = 'abort'
7+
# opt-level = 3
8+
# strip = true
9+
# lto = true
10+
# codegen-units = 1
11+
# panic = 'abort'
1212

1313
[dependencies]
1414
openssl = { version = "0.10", features = ["vendored"] }

anycode-backend/src/app_state.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use crate::code::Code;
44
use crate::config::Config;
55
use crate::git::GitManager;
66
use crate::lsp::LspManager;
7+
use crate::search::FileSearchResult;
78
use crate::terminal::Terminal;
89
use anyhow::{Result, anyhow};
910
use lsp_types::PublishDiagnosticsParams;
@@ -31,6 +32,7 @@ pub struct SocketData {
3132
pub opened_dirs: HashSet<String>,
3233
pub search_cancel: Option<CancellationToken>,
3334
pub search_pattern: Option<String>,
35+
pub search_last_file_result: Option<FileSearchResult>,
3436
}
3537

3638
#[derive(Clone)]

anycode-backend/src/git.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1406,6 +1406,10 @@ impl GitManager {
14061406
}
14071407
};
14081408

1409+
if !has_staged_changes && !is_conflicted && added == 0 && removed == 0 {
1410+
return Ok(None);
1411+
}
1412+
14091413
Ok(Some(GitFileStatus {
14101414
path: abs_path.to_string_lossy().to_string(),
14111415
status: file_status,

anycode-backend/src/handlers/search_handler.rs

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,22 @@ use serde::{Deserialize, Serialize};
44
use serde_json::{self, json};
55
use socketioxide::extract::{Data, SocketRef, State};
66
use tokio::sync::mpsc;
7+
use tokio::time::{self, Duration, MissedTickBehavior};
78
use tokio_util::sync::CancellationToken;
89
use tracing::info;
910

11+
const SEARCH_RESULT_BATCH_INTERVAL: Duration = Duration::from_millis(200);
12+
1013
#[derive(Debug, Serialize, Deserialize, Clone)]
1114
pub struct SearchRequest {
1215
pub pattern: String,
1316
}
1417

18+
#[derive(Debug, Serialize)]
19+
struct SearchResultsBatch {
20+
results: Vec<FileSearchResult>,
21+
}
22+
1523
pub async fn handle_search(
1624
socket: SocketRef,
1725
Data(search_request): Data<SearchRequest>,
@@ -37,6 +45,7 @@ pub async fn handle_search(
3745
// Save the cancel in the socket data
3846
data.search_cancel = Some(cancel.clone());
3947
data.search_pattern = Some(search_request.pattern.clone());
48+
data.search_last_file_result = None;
4049

4150
// Prepare search, get the current directory and create channel to collect results
4251
let current_dir = std::env::current_dir().unwrap();
@@ -63,10 +72,35 @@ pub async fn handle_search(
6372
// Collect results and send them to the socket
6473
tokio::spawn(async move {
6574
let mut matches = 0;
75+
let mut batch = Vec::new();
76+
let mut batch_interval = time::interval(SEARCH_RESULT_BATCH_INTERVAL);
77+
batch_interval.set_missed_tick_behavior(MissedTickBehavior::Skip);
78+
batch_interval.tick().await;
79+
6680
// In cancel case, the loop will be ended automatically
67-
while let Some(file_result) = result_rx.recv().await {
68-
let _ = socket.emit("search:result", &file_result);
69-
matches += file_result.matches.len();
81+
loop {
82+
tokio::select! {
83+
maybe_file_result = result_rx.recv() => {
84+
match maybe_file_result {
85+
Some(file_result) => {
86+
matches += file_result.matches.len();
87+
batch.push(file_result);
88+
}
89+
None => break,
90+
}
91+
}
92+
_ = batch_interval.tick() => {
93+
if !batch.is_empty() {
94+
let results = std::mem::take(&mut batch);
95+
let _ = socket.emit("search:results", &SearchResultsBatch { results });
96+
}
97+
}
98+
}
99+
}
100+
101+
if !batch.is_empty() {
102+
let results = std::mem::take(&mut batch);
103+
let _ = socket.emit("search:results", &SearchResultsBatch { results });
70104
}
71105

72106
let _ = socket.emit(
@@ -95,5 +129,6 @@ pub async fn handle_search_cancel(socket: SocketRef, state: State<AppState>) {
95129
// Clear the cancel token
96130
data.search_cancel = None;
97131
data.search_pattern = None;
132+
data.search_last_file_result = None;
98133
}
99134
}

anycode-backend/src/handlers/watch_handler.rs

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,11 @@ async fn handle_search_update(
268268
if pattern.trim().is_empty() {
269269
return None;
270270
}
271-
Some((sid.clone(), pattern.clone()))
271+
Some((
272+
sid.clone(),
273+
pattern.clone(),
274+
data.search_last_file_result.clone(),
275+
))
272276
})
273277
.collect::<Vec<_>>()
274278
};
@@ -277,10 +281,23 @@ async fn handle_search_update(
277281
return;
278282
}
279283

280-
for (_, pattern) in searches {
284+
for (sid, pattern, last_file_result) in searches {
281285
let cancel = CancellationToken::new();
282286
if let Some(file_result) = search_file_result(path, &pattern, cancel).await {
283-
let _ = socket.emit("search:result", &file_result).await;
287+
if last_file_result.as_ref() == Some(&file_result) {
288+
continue;
289+
}
290+
291+
{
292+
let mut sockets_data = socket2data.lock().await;
293+
if let Some(data) = sockets_data.get_mut(&sid) {
294+
data.search_last_file_result = Some(file_result.clone());
295+
}
296+
}
297+
298+
let _ = socket
299+
.emit("search:results", &json!({ "results": [file_result] }))
300+
.await;
284301
}
285302
}
286303
}

anycode-backend/src/search.rs

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ pub fn multiline_search(content: &str, pattern: &str) -> Vec<SearchResult> {
121121
results
122122
}
123123

124-
#[derive(Debug, Serialize, Deserialize, Clone)]
124+
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
125125
pub struct SearchResult {
126126
pub line: usize,
127127
pub column: usize,
@@ -189,7 +189,7 @@ pub async fn file_search(
189189
Ok(results)
190190
}
191191

192-
#[derive(Debug, Serialize, Deserialize, Clone)]
192+
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
193193
pub struct FileSearchResult {
194194
pub file_path: String,
195195
pub display_path: String,
@@ -236,17 +236,7 @@ pub async fn global_search(
236236
cancel: CancellationToken,
237237
result_tx: mpsc::Sender<FileSearchResult>,
238238
) -> Result<()> {
239-
let mut files = collect_files_recursively(dir_path)?;
240-
241-
// Sort files by depth
242-
files.sort_by(|a, b| {
243-
let depth_a = a.components().count();
244-
let depth_b = b.components().count();
245-
match depth_a.cmp(&depth_b) {
246-
std::cmp::Ordering::Equal => a.cmp(b),
247-
other => other,
248-
}
249-
});
239+
let files = collect_files_recursively(dir_path)?;
250240

251241
let semaphore = Arc::new(Semaphore::new(8));
252242
let mut handles = Vec::new();

anycode-base/src/editor.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1064,7 +1064,7 @@ export class AnycodeEditor {
10641064
return;
10651065
}
10661066

1067-
if (event.metaKey && event.key === "f" || this.search.isFocused()) {
1067+
if ((event.metaKey && !event.shiftKey && event.key.toLowerCase() === "f") || this.search.isFocused()) {
10681068
event.preventDefault();
10691069
this.handleSearchKey(event);
10701070
return;
@@ -1466,7 +1466,7 @@ export class AnycodeEditor {
14661466
const { key, altKey, ctrlKey, metaKey, shiftKey } = event;
14671467
let isSearch = false;
14681468

1469-
if (metaKey && key.toLowerCase() == 'f') {
1469+
if (metaKey && !shiftKey && key.toLowerCase() == 'f') {
14701470
this.renderer.removeAllHighlights(this.search);
14711471

14721472
this.search.setActive(true);
@@ -1521,7 +1521,7 @@ export class AnycodeEditor {
15211521
const patternLines = pattern.split(/\r?\n/);
15221522
const isMultiline = patternLines.length > 1;
15231523

1524-
if (event.metaKey && event.key === 'f') {
1524+
if (event.metaKey && !event.shiftKey && event.key.toLowerCase() === 'f') {
15251525
event.preventDefault();
15261526
event.stopPropagation();
15271527
// ignore search

anycode/App.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ const App: React.FC = () => {
6666
['git:update', editors.handleGitUpdate],
6767
['acp:message', agents.handleAcpMessage],
6868
['acp:history', agents.handleAcpHistory],
69-
['search:result', search.handleSearchResult],
69+
['search:results', search.handleSearchResults],
7070
['search:end', search.handleSearchEnd],
7171
] as const;
7272

@@ -85,7 +85,7 @@ const App: React.FC = () => {
8585
git.handleGitStatusUpdate,
8686
agents.handleAcpMessage,
8787
agents.handleAcpHistory,
88-
search.handleSearchResult,
88+
search.handleSearchResults,
8989
search.handleSearchEnd,
9090
]);
9191

@@ -228,7 +228,7 @@ const App: React.FC = () => {
228228
return;
229229
}
230230

231-
if (e.metaKey && e.key === 'f') {
231+
if (e.metaKey && !e.shiftKey && e.key.toLowerCase() === 'f') {
232232
e.preventDefault();
233233
}
234234

0 commit comments

Comments
 (0)