complete.bend source
complete.bend on the hub · documented module
# Autocomplete passage suggestions (book / chapter / verse prefixes)import Baseimport ./books.bend as Booksimport ./books_data.bend as Ddef char1(+c: Char) -> String: String.from_list(c <> Nil{})def starts_with_ci(+s: String, +p: String) -> Bool: String.starts_with(String.to_lower(s), String.to_lower(p))def rev_str(xs: List<&2, String>, acc: List<&2, String>) -> List<&2, String>: match xs: case Nil{}: acc case h <> t: rev_str(t, h <> acc)type AcPh is Data: AcScan{} AcTest{name: String, code: String, hit: Bool} AcHit{name: String, code: String, done: Bool}def suggest_books_go( fuel: Nat, ph: AcPh, xs: List<D.BookName>, +prefix: String, +limit: Nat, acc: List<&2, String>) -> List<&2, String>: match fuel: case 0n: acc case 1n+p: match ph: case AcScan{}: match xs: case Nil{}: acc case D.BookName{+c, +name} <> t: suggest_books_go( p, AcTest{name, c, starts_with_ci(name, prefix)}, t, prefix, limit, acc ) case AcTest{+name, +code, hit}: match hit: case True{}: suggest_books_go(p, AcHit{name, code, Nat.is_eq(limit, 0n)}, xs, prefix, limit, acc) case False{}: suggest_books_go(p, AcScan{}, xs, prefix, limit, acc) case AcHit{+name, +code, done}: match done: case True{}: acc case False{}: suggest_books_go( p, AcScan{}, xs, prefix, Nat.sub(limit, 1n), String.append(name, String.append(" -> ", code)) <> acc )def suggest_books(+prefix: String, +limit: Nat) -> List<&2, String>: rev_str(suggest_books_go(200n, AcScan{}, D.book_names(), prefix, limit, Nil{}), Nil{})type TtSt is Data: TtCheck{} TtDecide{stop: Bool} TtTake{}def is_tok_stop(+c: Char) -> Bool: Bool.or(Char.is_space(c), Bool.or(Char.is_eq(c, ':'), Char.is_eq(c, '.')))def take_tok_go(fuel: Nat, st: TtSt, rest: String, acc: String) -> String & String: match fuel: case 0n: (acc, rest) case 1n+p: match st: case TtCheck{}: match rest: case SNil{}: (acc, "") case SCon{+h, +t}: take_tok_go(p, TtDecide{is_tok_stop(h)}, rest, acc) case TtDecide{stop}: match stop: case True{}: (acc, rest) case False{}: take_tok_go(p, TtTake{}, rest, acc) case TtTake{}: match rest: case SNil{}: (acc, "") case SCon{+h, +t}: take_tok_go(p, TtCheck{}, t, String.append(acc, char1(h)))def take_token(+s: String) -> String & String: take_tok_go(Nat.add(Nat.mul(3n, String.length(s)), 3n), TtCheck{}, String.trim(s), "")def drop_sep_h(+h: Char, t: String, drop: Bool) -> String: match drop: case True{}: String.trim(t) case False{}: String.trim(SCon{h, t})def drop_sep_go(s: String) -> String: match s: case SNil{}: "" case SCon{+h, +t}: drop_sep_h(h, t, Bool.or(Char.is_eq(h, ':'), Char.is_eq(h, '.')))def drop_sep(+s: String) -> String: drop_sep_go(String.trim(s))def fst_str(pair: String & String) -> String: match pair: case (a, b): adef snd_str(pair: String & String) -> String: match pair: case (a, b): bdef suggest_verses_line(+code: String, +name: String, +ch: U32, max_m: Maybe<&2, U32>) -> List<&2, String>: match max_m: case None{}: Nil{} case Some{+mx}: String.append( String.append(String.append(name, " "), U32.show(ch)), String.append(":(1-", String.append(U32.show(mx), ")")) ) <> Nil{}def autocomplete_vs_m( +code: String, +name: String, +ch: U32, +rest: String, +limit: Nat, vs_m: Maybe<&2, U32>) -> List<&2, String>: match vs_m: case None{}: suggest_verses_line(code, name, ch, Books.verse_count(code, ch)) case Some{+v}: String.append( String.append( String.append(String.append(String.append(name, " "), U32.show(ch)), ":"), U32.show(v) ), String.append( " -> ", String.append( String.append(String.append(String.append(code, "."), U32.show(ch)), "."), U32.show(v) ) ) ) <> Nil{}def autocomplete_vs(+code: String, +name: String, +ch: U32, +rest: String, +limit: Nat) -> List<&2, String>: autocomplete_vs_m(code, name, ch, rest, limit, U32.read(fst_str(take_token(rest))))def autocomplete_cv_rest(+code: String, +name: String, +ch: U32, +rest: String, +limit: Nat, empty: Bool) -> List<&2, String>: match empty: case True{}: String.append( String.append(String.append(name, " "), U32.show(ch)), String.append(" -> ", String.append(String.append(code, "."), U32.show(ch))) ) <> Nil{} case False{}: autocomplete_vs(code, name, ch, rest, limit)def autocomplete_cv_num( +code: String, +name: String, +ch_s: String, +rest: String, +limit: Nat, ch_m: Maybe<&2, U32>) -> List<&2, String>: match ch_m: case None{}: String.append(name, " <chapter>") <> Nil{} case Some{+ch}: autocomplete_cv_rest(code, name, ch, rest, limit, String.is_empty(rest))def autocomplete_cv_pair(+code: String, +name: String, pair: String & String, +limit: Nat) -> List<&2, String>: match pair: case (+ch_s, rest2): autocomplete_cv_num(code, name, ch_s, String.trim(drop_sep(rest2)), limit, U32.read(ch_s))def autocomplete_cv(+code: String, +name: String, +rest: String, +limit: Nat) -> List<&2, String>: autocomplete_cv_pair(code, name, take_token(drop_sep(rest)), limit)def autocomplete_with_book_go(+book_raw: String, +rest: String, +limit: Nat, m: Maybe<&2, String>) -> List<&2, String>: match m: case None{}: suggest_books(book_raw, limit) case Some{+code}: autocomplete_cv(code, Books.display_name(code), rest, limit)def autocomplete_with_book(+book_raw: String, +rest: String, +limit: Nat) -> List<&2, String>: autocomplete_with_book_go(book_raw, rest, limit, Books.resolve_alias(book_raw))def autocomplete_book_go(+book_raw: String, +rest: String, +limit: Nat, empty: Bool) -> List<&2, String>: match empty: case True{}: suggest_books(book_raw, limit) case False{}: autocomplete_with_book(book_raw, rest, limit)def autocomplete_book(+book_raw: String, +rest: String, +limit: Nat) -> List<&2, String>: autocomplete_book_go(book_raw, rest, limit, String.is_empty(rest))def autocomplete_pair(pair: String & String, +limit: Nat) -> List<&2, String>: match pair: case (book_raw, rest0): autocomplete_book(book_raw, String.trim(rest0), limit)def autocomplete(+input: String, +limit: Nat) -> List<&2, String>: autocomplete_pair(take_token(String.trim(input)), limit)def show_suggestions_rest(xs: List<&2, String>) -> IO(Unit): match xs: case Nil{}: IO.print("") case h <> t: do IO<Unit>: IO.print(h) IO.print("\n") show_suggestions_rest(t)def show_suggestions(xs: List<&2, String>) -> IO(Unit): match xs: case Nil{}: IO.print("(no suggestions)\n") case h <> t: do IO<Unit>: IO.print(h) IO.print("\n") show_suggestions_rest(t)