mirror of
https://github.com/openai/codex.git
synced 2026-04-28 18:32:04 +03:00
4.3 KiB
4.3 KiB
DOs
- Check Simple Conditions Before Locking: Gate on cheap checks like
query.is_empty()or identical queries without taking the mutex.
// Good: no lock held for trivial early-exit
if query.is_empty() {
let max_total = MAX_FILE_SEARCH_RESULTS.get();
let matches = collect_top_level_suggestions(&self.search_dir, max_total);
self.app_tx.send(AppEvent::FileSearchResult {
query: String::new(),
matches,
});
return;
}
// Only now take the lock
let mut st = self.state.lock().unwrap();
if query == st.latest_query {
return;
}
- Model State Explicitly (avoid overloading): Prefer clear flags or enums over
Option<String>when representing “never shown” vs “empty string”.
// Prefer explicit fields
struct SearchState {
latest_query: String,
has_shown_popup: bool, // instead of latest_query: Option<String>
}
- Keep Code Paths Symmetric: Make empty and non-empty query flows update/search state consistently to preserve invariants.
fn handle_query(&self, query: String) {
if query.is_empty() {
self.finish_empty_query(&query); // updates scheduling state as needed
} else {
self.start_non_empty_search(query); // sets active_search + cancellation_token
}
}
fn finish_empty_query(&self, query: &str) {
// Clear any scheduled search consistently
let mut st = self.state.lock().unwrap();
st.is_search_scheduled = false;
st.active_search = None;
drop(st);
let max_total = MAX_FILE_SEARCH_RESULTS.get();
let matches = collect_top_level_suggestions(&self.search_dir, max_total);
self.app_tx.send(AppEvent::FileSearchResult {
query: query.to_string(),
matches,
});
}
- Short-Circuit Unchanged Inputs: Avoid re-scheduling when the query did not change; combine with the empty check if appropriate.
let unchanged = {
let st = self.state.lock().unwrap();
query == st.latest_query
};
if unchanged {
return;
}
- Put Imports At The Top: Keep
usestatements at module scope; use descriptive types.
use std::collections::HashSet;
use std::fs;
- Use Descriptive Names: Prefer self-explanatory identifiers over two-letter names in filesystem loops.
let mut seen: HashSet<String> = HashSet::new();
if let Ok(dir_iter) = fs::read_dir(cwd) {
for dir_entry in dir_iter.flatten() {
let entry_path = dir_entry.path();
let Some(name) = entry_path.strip_prefix(cwd).ok().and_then(|p| p.to_str()) else { continue };
// ...
}
}
DON’Ts
- Don’t Hold Locks During I/O or Heavy Work: Copy out what you need, drop the lock, then perform filesystem or compute operations.
// Anti-pattern: lock held across I/O
let mut st = self.state.lock().unwrap();
for entry in std::fs::read_dir(&self.search_dir).unwrap() { /* ... */ }
// Better:
let search_dir = self.search_dir.clone();
drop(st);
for entry in std::fs::read_dir(search_dir).unwrap() { /* ... */ }
- Don’t Introduce APIs Without Clear Need: Avoid adding methods like
reset()unless they’re necessary, consistently used, and tested.
// Instead of adding a broad reset(), cancel the active search via existing state.
let mut st = self.state.lock().unwrap();
if let Some(active) = st.active_search.take() {
active.cancellation_token.store(true, std::sync::atomic::Ordering::Relaxed);
}
st.is_search_scheduled = false;
- Don’t Overload
Option<String>For Multiple States:NonevsSome("")is ambiguous; model intent explicitly.
// Avoid:
latest_query: Option<String>
// Prefer:
latest_query: String,
has_shown_popup: bool,
- Don’t Put
useInside Functions For Common Types: Keep module imports centralized; localuseobscures dependencies.
// Avoid inside fn:
fn collect_top_level_suggestions(...) {
use std::collections::HashSet; // <-- move to top
}
- Don’t Diverge State Between Code Paths: Ensure the “empty query” fast path doesn’t skip essential bookkeeping done by the normal path.
// Avoid: empty path bypasses state updates
if query.is_empty() {
// send results and return; state not updated
return;
}
// Prefer: both paths maintain scheduler/active_search invariants
handle_query(query);