c4spar / deno-cliffy

Command line framework for deno 🦕 Including Commandline-Interfaces, Prompts, CLI-Table, Arguments Parser and more...

Home Page:https://cliffy.io

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Suggestion: Erase the prompt before validating

RuiNtD opened this issue · comments

commented

Prompts should be erased (in the console) before running the validate function, in case something logs to console while validating.

Not sure if it's a good idea to erase the prompt by default. If the validation takes some time, the prompt dissapears for a while.

I could provide a function to clear the prompt manuelly or an option to clear it automatically.

But this is theoretically already possible by checking the permission state and using cliffy's tty module (you don't need to clear the prompt, it's enough to move the cursor up. the prompt module will then automatically clear everything after and below the cursor):

await Input.prompt({
  message: "Select a file",
  validate: async (path) => {
    const { state } = await Deno.permissions.query({
      name: "read",
      path,
    });

    state === "prompt" && console.log();
    const { isFile } = await Deno.stat(path);
    state === "prompt" && tty.cursorUp(2);

    return isFile;
  },
});
 ? Select a file › deno.jsonc
⚠️ ┌ Deno requests read access to "deno.jsonc".
   ├ Requested by `Deno.stat()` API
   ├ Run again with --allow-read to bypass this prompt.
   └ Allow? [y/n] (y = yes, allow; n = no, deny) > y

But i also noticed the same issue happens if an error accours during validation.

 ? Select a file › deno.jsoncerror: Uncaught (in promise) Error: some error
    throw new Error("some error");

i think atleast it would be a good idea to move the cursor to the next line before validating. So it looks like this:

 ? Select a file › sdgsdfsdf
error: Uncaught (in promise) Error: some error
    throw new Error("some error");

With this change, the workaround could look like this:

await Input.prompt({
  message: "Select a file",
  validate: async (path) => {
    const { state } = await Deno.permissions.query({
      name: "read",
      path,
    });

    const { isFile } = await Deno.stat(path);
    state === "prompt" && tty.cursorUp(1);

    return isFile;
  },
});
commented

Tried logging an empty line and moving the cursor up. Didn't clear the prompt, unfortunately.

(Screenshot is taken during the await delay(1000))

This might work for you as a workaround. But since you have activated the hint, you need to move the cursor down 2 lines.

await Input.prompt({
  message: "Where is your legacy instance?",
  default: Deno.args[0],
  hint: "This should be a .minecraft folder containing Wynntils for 1.12.2",
  validate: async (legacyPath) => {
    legacyPath = join(legacyPath, "wynntils", "configs");

    const { state } = await Deno.permissions.query({
      name: "read",
      path: legacyPath,
    });

    if (state === "prompt") {
      console.log();
      console.log();
    }

    try {
      const uuids = [...Deno.readDirSync(legacyPath)]
        .filter((v) => v.isDirectory)
        .map((v) => v.name);
      if (uuids.length === 0) {
        return "Failed to find any legacy Wynntils configs in this folder.";
      }
      state === "prompt" && tty.cursorUp(3);
      return true;
    } catch (e) {
      state === "prompt" && tty.cursorUp(3);
      return e.message;
    }
  },
});

I will think about a solution how we can improve this.

Or if you want to clear the prompt completely than you can just call tty.cursorLeft.eraseDown();:

await Input.prompt({
  message: "Where is your legacy instance?",
  default: Deno.args[0],
  hint: "This should be a .minecraft folder containing Wynntils for 1.12.2",
  validate: async (legacyPath) => {
    legacyPath = join(legacyPath, "wynntils", "configs");

    tty.cursorLeft.eraseDown();

    try {
      const uuids = [...Deno.readDirSync(legacyPath)]
        .filter((v) => v.isDirectory)
        .map((v) => v.name);
      if (uuids.length === 0) {
        return "Failed to find any legacy Wynntils configs in this folder.";
      }
      return true;
    } catch (e) {
      return e.message;
    }
  },
});