@@ -1459,6 +1459,7 @@ fn split_selection_on_newline(cx: &mut Context) {
14591459 doc.set_selection(view.id, selection);
14601460}
14611461
1462+#[allow(clippy::too_many_arguments)]
14621463fn search_impl(
14631464 doc: &mut Document,
14641465 view: &mut View,
@@ -1467,6 +1468,7 @@ fn search_impl(
14671468 movement: Movement,
14681469 direction: Direction,
14691470 scrolloff: usize,
1471+ wrap_around: bool,
14701472) {
14711473 let text = doc.text().slice(..);
14721474 let selection = doc.selection(view.id);
@@ -1492,16 +1494,22 @@ fn search_impl(
14921494
14931495 // use find_at to find the next match after the cursor, loop around the end
14941496 // Careful, `Regex` uses `bytes` as offsets, not character indices!
1495− let mat = match direction {
1496− Direction::Forward => regex
1497− .find_at(contents, start)
1498− .or_else(|| regex.find(contents)),
1499− Direction::Backward => regex.find_iter(&contents[..start]).last().or_else(|| {
1500− offset = start;
1501− regex.find_iter(&contents[start..]).last()
1502− }),
1497+ let mut mat = match direction {
1498+ Direction::Forward => regex.find_at(contents, start),
1499+ Direction::Backward => regex.find_iter(&contents[..start]).last(),
15031500 };
1504− // TODO: message on wraparound
1501+
1502+ if wrap_around && mat.is_none() {
1503+ mat = match direction {
1504+ Direction::Forward => regex.find(contents),
1505+ Direction::Backward => {
1506+ offset = start;
1507+ regex.find_iter(&contents[start..]).last()
1508+ }
1509+ }
1510+ // TODO: message on wraparound
1511+ }
1512+
15051513 if let Some(mat) = mat {
15061514 let start = text.byte_to_char(mat.start() + offset);
15071515 let end = text.byte_to_char(mat.end() + offset);
@@ -1554,6 +1562,7 @@ fn rsearch(cx: &mut Context) {
15541562fn searcher(cx: &mut Context, direction: Direction) {
15551563 let reg = cx.register.unwrap_or('/');
15561564 let scrolloff = cx.editor.config.scrolloff;
1565+ let wrap_around = cx.editor.config.search.wrap_around;
15571566
15581567 let doc = doc!(cx.editor);
15591568
@@ -1587,6 +1596,7 @@ fn searcher(cx: &mut Context, direction: Direction) {
15871596 Movement::Move,
15881597 direction,
15891598 scrolloff,
1599+ wrap_around,
15901600 );
15911601 },
15921602 );
@@ -1601,16 +1611,27 @@ fn search_next_or_prev_impl(cx: &mut Context, movement: Movement, direction: Dir
16011611 if let Some(query) = registers.read('/') {
16021612 let query = query.last().unwrap();
16031613 let contents = doc.text().slice(..).to_string();
1604− let case_insensitive = if cx.editor.config.smart_case {
1614+ let search_config = &cx.editor.config.search;
1615+ let case_insensitive = if search_config.smart_case {
16051616 !query.chars().any(char::is_uppercase)
16061617 } else {
16071618 false
16081619 };
1620+ let wrap_around = search_config.wrap_around;
16091621 if let Ok(regex) = RegexBuilder::new(query)
16101622 .case_insensitive(case_insensitive)
16111623 .build()
16121624 {
1613− search_impl(doc, view, &contents, ®ex, movement, direction, scrolloff);
1625+ search_impl(
1626+ doc,
1627+ view,
1628+ &contents,
1629+ ®ex,
1630+ movement,
1631+ direction,
1632+ scrolloff,
1633+ wrap_around,
1634+ );
16141635 } else {
16151636 // get around warning `mutable_borrow_reservation_conflict`
16161637 // which will be a hard error in the future
@@ -1649,7 +1670,7 @@ fn search_selection(cx: &mut Context) {
16491670fn global_search(cx: &mut Context) {
16501671 let (all_matches_sx, all_matches_rx) =
16511672 tokio::sync::mpsc::unbounded_channel::<(usize, PathBuf)>();
1652− let smart_case = cx.editor.config.smart_case;
1673+ let smart_case = cx.editor.config.search.smart_case;
16531674 let file_picker_config = cx.editor.config.file_picker.clone();
16541675
16551676 let completions = search_completions(cx, None);
@@ -2707,12 +2728,13 @@ pub mod cmd {
27072728 "mouse" => runtime_config.mouse = arg.parse()?,
27082729 "line-number" => runtime_config.line_number = arg.parse()?,
27092730 "middle-click_paste" => runtime_config.middle_click_paste = arg.parse()?,
2710− "smart-case" => runtime_config.smart_case = arg.parse()?,
27112731 "auto-pairs" => runtime_config.auto_pairs = arg.parse()?,
27122732 "auto-completion" => runtime_config.auto_completion = arg.parse()?,
27132733 "completion-trigger-len" => runtime_config.completion_trigger_len = arg.parse()?,
27142734 "auto-info" => runtime_config.auto_info = arg.parse()?,
27152735 "true-color" => runtime_config.true_color = arg.parse()?,
2736+ "search.smart-case" => runtime_config.search.smart_case = arg.parse()?,
2737+ "search.wrap-around" => runtime_config.search.wrap_around = arg.parse()?,
27162738 _ => anyhow::bail!("Unknown key `{}`.", args[0]),
27172739 }
27182740