use hjkl_engine::search::SearchPrompt;
use hjkl_vim_types::{Operator, RangeKind};
use super::*;
use crate::vim_state::{vim, vim_mut};
use hjkl_engine::Editor;
use hjkl_engine::buf_helpers::{buf_cursor_pos, buf_set_cursor_rc};
use hjkl_engine::tag::{is_html_filetype, scan_tag_opener};
pub fn enter_search<H: hjkl_engine::types::Host>(
ed: &mut Editor<hjkl_buffer::View, H>,
forward: bool,
) {
ed.set_search_prompt_state(Some(SearchPrompt {
text: String::new(),
cursor: 0,
forward,
operator: None,
}));
ed.set_search_history_cursor(None);
ed.set_search_pattern(None);
}
pub fn enter_search_op<H: hjkl_engine::types::Host>(
ed: &mut Editor<hjkl_buffer::View, H>,
forward: bool,
op: Operator,
count: usize,
) {
let origin = ed.cursor();
ed.set_search_prompt_state(Some(SearchPrompt {
text: String::new(),
cursor: 0,
forward,
operator: Some((op, count.max(1), origin)),
}));
ed.set_search_history_cursor(None);
ed.set_search_pattern(None);
}
pub fn apply_op_search_range<H: hjkl_engine::types::Host>(
ed: &mut Editor<hjkl_buffer::View, H>,
op: Operator,
origin: (usize, usize),
) {
let target = ed.cursor();
run_operator_over_range(ed, op, origin, target, RangeKind::Exclusive);
}
pub fn walk_change_list<H: hjkl_engine::types::Host>(
ed: &mut Editor<hjkl_buffer::View, H>,
dir: isize,
count: usize,
) {
let (list, _) = ed.change_list();
if list.is_empty() {
return;
}
let len = list.len();
let mut idx: isize = match (ed.change_list_cursor(), dir) {
(None, -1) => len as isize - 1,
(None, 1) => return, (Some(i), -1) => i as isize - 1,
(Some(i), 1) => i as isize + 1,
_ => return,
};
for _ in 1..count {
let next = idx + dir;
if next < 0 || next >= len as isize {
break;
}
idx = next;
}
if idx < 0 || idx >= len as isize {
return;
}
let idx = idx as usize;
ed.set_change_list_cursor(Some(idx));
let (row, col) = list[idx];
ed.jump_cursor(row, col);
}
pub fn sync_clipboard_register_for<H: hjkl_engine::types::Host>(
ed: &mut Editor<hjkl_buffer::View, H>,
selector: Option<char>,
) {
if !matches!(selector, Some('+') | Some('*')) {
return;
}
if let Some(text) = ed.host_mut().read_clipboard() {
let linewise = text.ends_with('\n');
ed.sync_clipboard_register(text, linewise);
}
}
pub fn insert_register_text<H: hjkl_engine::types::Host>(
ed: &mut Editor<hjkl_buffer::View, H>,
selector: char,
) {
use hjkl_buffer::Edit;
sync_clipboard_register_for(ed, Some(selector));
let text = match selector {
'/' => match &ed.last_search_pattern() {
Some(s) if !s.is_empty() => s.clone(),
_ => return,
},
'.' => match &vim(ed).last_insert_text {
Some(s) if !s.is_empty() => s.clone(),
_ => return,
},
_ => match ed.with_registers(|r| r.read(selector).cloned()) {
Some(slot) if !slot.text.is_empty() => slot.text,
_ => return,
},
};
ed.sync_buffer_content_from_textarea();
let cursor = buf_cursor_pos(ed.buffer());
ed.mutate_edit(Edit::InsertStr {
at: cursor,
text: text.clone(),
});
let mut row = cursor.row;
let mut col = cursor.col;
for ch in text.chars() {
if ch == '\n' {
row += 1;
col = 0;
} else {
col += 1;
}
}
buf_set_cursor_rc(ed.buffer_mut(), row, col);
ed.mark_content_dirty();
if let Some(ref mut session) = vim_mut(ed).insert_session {
session.row_min = session.row_min.min(row);
session.row_max = session.row_max.max(row);
}
}
pub(super) fn compute_enter_indent(settings: &hjkl_engine::Settings, prev_line: &str) -> String {
if !settings.autoindent {
return String::new();
}
let base: String = prev_line
.chars()
.take_while(|c| *c == ' ' || *c == '\t')
.collect();
if settings.smartindent {
let unit = if settings.expandtab {
if settings.softtabstop > 0 {
" ".repeat(settings.softtabstop)
} else {
" ".repeat(settings.shiftwidth)
}
} else {
"\t".to_string()
};
let last_non_ws = prev_line.chars().rev().find(|c| !c.is_whitespace());
if matches!(last_non_ws, Some('{' | '(' | '[')) {
return format!("{base}{unit}");
}
if is_html_filetype(&settings.filetype) {
let trimmed_end_len = prev_line
.trim_end_matches(|c: char| c.is_whitespace())
.len();
let trimmed = &prev_line[..trimmed_end_len];
if let Some(stripped) = trimmed.strip_suffix('>')
&& scan_tag_opener(trimmed, stripped.len()).is_some()
{
return format!("{base}{unit}");
}
}
}
base
}