~/bend-docscommunity

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)