Open gentunian opened 6 years ago
It would be possible with a custom prompt - but that's not a feature of the input prompt right now.
Maybe a solution is to have an extra property, like suffix
append that after the cursor. I don't think there's a way this could work with the transformer function.
Hey @SBoudrias :)
I was reading your code and trying to hack it. I was only reading the parts of interests and this hack seems to work only for suffixes because prompt is based on length:
--- a/lib/prompts/input.js
+++ b/lib/prompts/input.js
@@ -55,7 +55,7 @@ class InputPrompt extends Base {
bottomContent = chalk.red('>> ') + error;
}
- this.screen.render(message, bottomContent);
+ this.screen.render(message, bottomContent, this.getQuestion() + this.rl.line);
}
--- a/lib/utils/screen-manager.js
+++ b/lib/utils/screen-manager.js
@@ -22,7 +22,7 @@ class ScreenManager {
this.rl = rl;
}
- render(content, bottomContent) {
+ render(content, bottomContent, changedPrompt) {
this.rl.output.unmute();
this.clean(this.extraLinesUnderPrompt);
@@ -30,7 +30,7 @@ class ScreenManager {
* Write message to screen and setPrompt to control backspace
*/
- var promptLine = lastLine(content);
+ var promptLine = changedPrompt? changedPrompt: lastLine(content);
var rawPromptLine = stripAnsi(promptLine);
I will give it another review for working in most cases.
Sample test:
var inquirer = require('inquirer');
inquirer.prompt([{
name: 'suffix',
type: 'input',
message: 'suffix:',
transformer: function (a, b) {
return `${a}.suffix`
}
}, {
name: 'middle',
type: 'input',
message: 'middle:',
transformer: function (a, b) {
return `test==>${a}<==my-input`
}
}, {
name: 'prefix',
type: 'input',
message: 'prefix:',
transformer: function (a, b) {
return `prefix==>${a}`
}
}]);
After giving this a little thought and understanding of the code, this seems unlikely to be implemented.
My impressions are that this feature should be implemented on the transformation as it's the only point where the user takes control of the readline
output buffer. The transformation function basically sticks in the middle so it seems there's no way to know where the user is typing just because the user can transform the output as the way he/she may like.
From the above, it follows that the transformation (if exists) should inform where the user want the cursor to be positioned. This is possible to do, but not elegant, this is my example:
For achieving that behaviour, the transform
function should provide the prompt information. As I said, not elegant at all:
var inquirer = require('inquirer');
inquirer.prompt([{
name: 'suffix',
type: 'input',
message: 'suffix:',
transformer: function (a, b) {
return `${a}.mydomain.com`
}
}, {
name: 'middle',
type: 'input',
message: 'middle:',
transformer: function (a, b) {
return {
text: `test==>${a}<==my-input`,
caret: `test==>`
}
}
}, {
name: 'prefix',
type: 'input',
message: 'prefix:',
transformer: function (a, b) {
return {
text: `test==>${a}`,
caret: `test==>`
}
}
}, {
name: 'complex',
type: 'input',
message: 'complex:',
transformer: function (a, b) {
return {
text: `${a} <--> ${a}`,
caret: `${a} <--> `
}
}
}]);
For this to work, the inquirer.js library needs this patch:
diff --git a/lib/prompts/input.js b/lib/prompts/input.js
index 4fd765e..da77b38 100644
--- a/lib/prompts/input.js
+++ b/lib/prompts/input.js
@@ -42,11 +42,20 @@ class InputPrompt extends Base {
var bottomContent = '';
var message = this.getQuestion();
var transformer = this.opt.transformer;
+ var caretOffset = '';
if (this.status === 'answered') {
message += chalk.cyan(this.answer);
} else if (transformer) {
- message += transformer(this.rl.line, this.answers);
+ var transform = transformer(this.rl.line, this.answers);
+ if (typeof transform === 'string') {
+ message += transform;
+ } else if (transform.caret && transform.text) {
+ message += transform.text;
+ caretOffset = transform.caret;
+ } else {
+
+ }
} else {
message += this.rl.line;
}
@@ -55,7 +64,7 @@ class InputPrompt extends Base {
bottomContent = chalk.red('>> ') + error;
}
- this.screen.render(message, bottomContent);
+ this.screen.render(message, bottomContent, this.getQuestion() + caretOffset);
}
/**
diff --git a/lib/utils/screen-manager.js b/lib/utils/screen-manager.js
index f19126e..d33257a 100644
--- a/lib/utils/screen-manager.js
+++ b/lib/utils/screen-manager.js
@@ -22,7 +22,7 @@ class ScreenManager {
this.rl = rl;
}
- render(content, bottomContent) {
+ render(content, bottomContent, changedPrompt) {
this.rl.output.unmute();
this.clean(this.extraLinesUnderPrompt);
@@ -30,17 +30,13 @@ class ScreenManager {
* Write message to screen and setPrompt to control backspace
*/
- var promptLine = lastLine(content);
+ var promptLine = changedPrompt? changedPrompt: lastLine(content);
var rawPromptLine = stripAnsi(promptLine);
// Remove the rl.line from our prompt. We can't rely on the content of
// rl.line (mainly because of the password prompt), so just rely on it's
// length.
- var prompt = rawPromptLine;
- if (this.rl.line.length) {
- prompt = prompt.slice(0, -this.rl.line.length);
- }
- this.rl.setPrompt(prompt);
+ this.rl.setPrompt(rawPromptLine);
// SetPrompt will change cursor position, now we can get correct value
var cursorPos = this.rl._getCursorPos();
lib/prompts/input.js
was quickly and dirty modified to test the functionality and show the idea. Those if statements are a bad idea.
Hum, I wonder if we could provide the caret in a way like this:
inquirer.prompt([{
name: 'suffix',
type: 'input',
message: 'suffix:',
transformer: function (a, b) {
return `${a}${inquirer.CARET}.mydomain.com`
}
}]);
inquirer.CARET
could be a Symbol or a unique enough string we'd search for and when found use to position the caret maybe?
Nice tip. I found a solution for that :)
I've chosen a custom string for specifying the caret. Not sure how could I reach the inquirer namespace inside input.js
without including inquirer.js
.
It could be placed in a custom file just like constants.js
or something like that. So client code will use inquirer.CARET
and library code will use internally that file.
@SBoudrias this is the commit, can you take a look? :)
EDIT: I'm testing this thing out, but the main idea is not so bad.
Here are the results:
I've detected only one minor issue when not specifying the cursor position. The cursor will be 1 character to the left than where it should be.
Sample code:
var inquirer = require('inquirer');
inquirer.prompt([{
name: 'suffix',
type: 'input',
message: 'suffix transform:',
transformer: function (a, b) {
return `${a}${inquirer.CARET}.mydomain.com`
}
}, {
name: 'middle',
type: 'input',
message: 'in the middle CARET:',
transformer: function (a, b) {
return `optional---> ${a}${inquirer.CARET} <---optional`;
}
}, {
name: 'prefix',
type: 'input',
message: 'prefix transform:',
transformer: function (a, b) {
return `append-me: ${a}${inquirer.CARET}`;
}
}, {
name: 'complex',
type: 'input',
message: 'complex and mixed:',
transformer: function (a, b) {
return `${a} <--> ${a}${inquirer.CARET}`;
}
}, {
name: 'nocaret',
type: 'input',
message: 'transformer without CARET:',
transformer: function (a, b) {
return `${a} ----NO CARET ----`;
}
}, {
name: 'normal',
type: 'input',
message: 'this is normal:'
}]);
Seems good, wanna send a PR?
Why not optionally allow a tuple return instead? You can place the cursor position at the end of the string if the transformer returns a simple string; otherwise, place the cursor after the first element in the tuple and render the rest of the tuple after the cursor.
@twang-rs Sounds good but you will need to refactor more code if you plan to apply this logic into screen.render
. I think the solution should maintain the current interface and methods.
That is, in order to maintain the interfaces you should process this tuple before calling screen.render
.
Hi there :)
I'm using the
transformer
function to visually append hinted data such as:works as expected, but how could I play with the caret cursor so it's positioned where the user is typing:
Full example:
Is it possible?