///|
/// 描述一次同步补全发生时的行缓冲区和当前词。
pub(all) struct CompletionContext {
  /// 光标之前的完整文本。
  before_cursor : String
  /// 光标之后的完整文本。
  after_cursor : String
  /// 光标前最大的连续非空白后缀。
  current_word : String
} derive(@debug.Debug)

///|
/// 保存一个 `LineEditor` 的共享 completer 注册状态。
priv struct CompletionState {
  mut completer : ((CompletionContext) -> Array[String])?
}

///|
fn CompletionState::new() -> CompletionState {
  { completer: None }
}

///|
fn CompletionState::get(
  self : CompletionState,
) -> ((CompletionContext) -> Array[String])? {
  self.completer
}

///|
/// 注册或替换当前 editor 的同步 completer。
///
/// completer 在用户按 Tab 时同步执行。参数中的三个字符串均由 MoonBit 独立持有;返回
/// 的每个字符串表示对 `current_word` 的完整替换。空字符串会被忽略,重复候选保留第一
/// 项;空数组表示没有候选。单候选直接替换,多候选先扩展最长公共前缀,再次按 Tab 时
/// 按返回顺序列出候选。库不会用非前缀的公共部分缩短当前输入。
///
/// **Parameters:**
///
/// - `completer`:不抛异常的同步 callback;库不会按当前词筛选返回值或追加空格。
///
/// **Errors:**
///
/// 当前进程正在读取,或者从 completion callback 中重入时抛出 `Busy`。
///
/// **Lifecycle:**
///
/// `LineEditor` 的所有别名共享同一个 completer。callback 只由 MoonBit 状态持有;读取
/// 开始时取得的快照会强持有到本次 `read_line()` 结束。
///
/// **Thread safety:**
///
/// 此方法不提供跨线程同步;活跃读取期间不会等待,而是抛出 `Busy`。
pub fn LineEditor::set_completer(
  self : LineEditor,
  completer : (CompletionContext) -> Array[String],
) -> Unit raise ReadlineError {
  self.ensure_usable()
  guard self.owner.can_update_completion() else { raise Busy }
  self.completion.completer = Some(completer)
}

///|
/// 清除当前 editor 注册的同步 completer。
///
/// 清除后,后续 Tab 不再调用先前的 callback。已经开始的读取不会在运行中切换
/// completer。
///
/// **Errors:**
///
/// 当前进程正在读取,或者从 completion callback 中重入时抛出 `Busy`。
///
/// **Lifecycle:**
///
/// `LineEditor` 的所有别名共享清除结果;不需要单独释放 callback 注册。
pub fn LineEditor::clear_completer(
  self : LineEditor,
) -> Unit raise ReadlineError {
  self.ensure_usable()
  guard self.owner.can_update_completion() else { raise Busy }
  self.completion.completer = None
}