1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
|
use bufio;
use common::{location};
use errors;
use fmt;
use io;
use strconv;
def REMEMBER_SKIP = -2;
// Prompts the user to choose between several options.
export fn choose(
ctx: *context,
rule: *rule,
loc: location,
choices: (str, *editgroup)...
) (*editgroup | void | errors::cancelled) = {
if (ctx.engine.yes) {
return choices[0].1;
};
if (rule.remember >= 0) {
return choices[rule.remember].1;
};
if (rule.remember == REMEMBER_SKIP) {
return;
};
show_rule(ctx, rule);
let ctxlines = 3;
let ectx = edit_getcontext(ctx, loc, ctxlines);
defer edit_context_finish(&ectx);
edit_context_show(ctx, &ectx);
const scan = bufio::newscanner(ctx.engine.tty);
defer bufio::finish(&scan);
for (true) {
fmt::fprintln(ctx.engine.tty, "\nSuggested solutions:")!;
let num = 1;
for (let choice .. choices) {
fmt::fprintfln(ctx.engine.tty, "{}: {}", num, choice.0)!;
num += 1;
};
fmt::fprint(ctx.engine.tty,
"Enter choice, or [s]kip, [S]kip always, [p]review all, [q]uit, or [?] (1): ")!;
const choice = match (bufio::scan_line(&scan)!) {
case let line: str =>
yield line;
case io::EOF =>
fmt::fatal("Aborted");
};
switch (choice) {
case "?" =>
choose_show_help(ctx);
case "+" =>
ctxlines += 2;
edit_context_finish(&ectx);
ectx = edit_getcontext(ctx, loc, ctxlines);
edit_context_show(ctx, &ectx);
fmt::fprintln(ctx.engine.tty)!;
case "q" =>
fmt::errorln("Warning! Edits to some files may have already been written.")!;
return errors::cancelled;
case "p" =>
preview_choices(ctx, choices...);
case "s" =>
return;
case "S" =>
rule.remember = REMEMBER_SKIP;
return;
case =>
if (choice == "") {
choice = "1";
};
const ch = match (strconv::stou(choice)) {
case let u: uint =>
yield u - 1;
case => continue;
};
if (ch >= len(choices)) {
continue;
};
const (explanation, choice) = choices[ch];
if (approve(ctx, explanation, rule, choice, ch, &scan)) {
return choice;
};
};
};
};
fn choose_show_help(ctx: *context) void = {
fmt::fprint(ctx.engine.tty, `Enter a number: choose this item
[p]: preview suggested edits
[+]: add more lines of context
[q]: quit, without saving changes to the current file
[?]: show this help
`)!;
};
fn preview_choices(
ctx: *context,
choices: (str, *editgroup)...
) void = {
for (let choice .. choices) {
fmt::fprintfln(ctx.engine.tty,
"\n{}{}?{}", C_BOLD, choice.0, C_RESET)!;
const doc = document_clone(ctx);
defer document_destroy(&doc);
for (let edit &.. choice.1.edits) {
apply(&doc, edit);
};
diff(&doc, ctx.engine.tty, 3)!;
};
};
fn approve(
ctx: *context,
explanation: str,
rule: *rule,
edit: *editgroup,
idx: uint,
scan: *bufio::scanner,
) bool = {
show_context(ctx, edit, explanation, 3);
for (true) {
fmt::fprint(ctx.engine.tty, " [y]es, [Y]es (always), [n]o (y): ")!;
const choice = match (bufio::scan_line(scan)!) {
case let line: str =>
yield line;
case io::EOF =>
fmt::fatal("Aborted");
};
switch (choice) {
case "", "y" =>
return true;
case "Y" =>
rule.remember = idx: int;
return true;
case "n" =>
return false;
case => void;
};
};
};
|