-
Notifications
You must be signed in to change notification settings - Fork 30.7k
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
RFC: Revamp the REPL Tab completion feature #17826
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice work so far, I like it! 👍
Do you have a specific list of functions inside Node core where this could be added?
Also, can you add documentation for repl.replComplete
?
lib/repl.js
Outdated
@@ -964,6 +964,9 @@ function complete(line, callback) { | |||
// REPL commands (e.g. ".break"). | |||
var filter; | |||
var match = null; | |||
|
|||
var functionCallRE = /\b(\w+)\([^)]*$/; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think there can be arbitrary whitespace before the opening (
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. I will add test cases and go through the code again to make sure its production ready. meanwhile i just wanted to submit the PR to get feedback for the general direction of the feature rather than the code details.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does (\w+)
catch all valid function names?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Misses $
, but otherwise seems OK. %
may also be needed for natives support.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: this can be const
lib/repl.js
Outdated
// console.log("::a, b = 0, /*c,*/ d::", annotate("a, b = 0, /*c,*/ d")) | ||
// console.log("::a, \"bamieh, ahm\", \"incom::", annotate("a, \"bamieh, ahm\", \"incom")) | ||
|
||
exports.replComplete = Symbol('REPL Complete'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i feel like this name is a bit unclear, maybe tabComplete
and REPL Tab Complete
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks for the review! As i said the code still needs some work, but i wanted to put it out ASAP to get feedback in order to know if i should put in more time into this feature
@addaleax Awesome, I wanted to make sure that the feature is aligned with node. I will add test cases, update the docs, rename things and rewrite some parts to make sure its production ready |
lib/repl.js
Outdated
let started = false; | ||
return params.split(',').reduce((acc, cur, i, array) => { | ||
if(/'|"|`|\/\*|\*\//.test(cur)) { | ||
if(started === true) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here can be simplified to if(started) { ... }
lib/repl.js
Outdated
try { | ||
var args = parseInputParameteres(paramsPassed); | ||
console.log('paramsPassed::', paramsPassed) | ||
console.log('args::', args) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we remove these two console.log
? 😉
lib/repl.js
Outdated
} else if (line.match(functionCallRE)) { | ||
const fnParenthesesIndex = line.lastIndexOf('('); | ||
const fullMethod = line.slice(0, fnParenthesesIndex); | ||
const paramsPassed = line.slice(fnParenthesesIndex+1) || ''; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
eslint:
line.slice(fnParenthesesIndex+1)
-> line.slice(fnParenthesesIndex + 1)
lib/repl.js
Outdated
|
||
this.eval(evalExpr, this.context, 'repl', (e, completer) => { | ||
var completionGroup = []; | ||
if(typeof completer === 'function') { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: be sure to run make lint
... there needs to be a space between the if
and the (
here :-)
@Jansell sorry i have been a little busy, but this PR is undergoing major rework. again i submitted the PR to request comments on the concept not the actual code. Hopefully I will submit my final iteration later on tomorrow. |
@Bamieh it seems like there are some linting issues and a test it constantly failing:
Would you be so kind and have a look? :-) |
const walk = require('internal/deps/acorn/dist/walk'); | ||
|
||
function parseFunctionArgs(input, r) { | ||
if(input === '') return ['']; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Please add a empty space after the if
in all cases (so also below).
const trimmedStr = input.trim(); | ||
const lastArgIndex = input.lastIndexOf(','); | ||
const lastArg = input.substr(lastArgIndex + 1).trim(); | ||
return parseFunctionArgs(input.substring(0, lastArgIndex), lastArg); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The indentation looks wrong here. Does the linter pass here?
} | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Non blocking nit: please only use a single new line.
|
||
inputs.forEach(input => { | ||
const results = parseFunctionArgs(input.args); | ||
assert.strictEqual(results.length, input.expectedResult.length); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a obsolete check because the next line will verify that the input and result is identical.
// tab completion Symbol | ||
{ | ||
assert.strictEqual(typeof repl.tabComplete, 'symbol'); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test does not need a own scope as it does not interfere with anything else.
@@ -203,6 +203,86 @@ testMe.complete('toSt', common.mustCall(function(error, data) { | |||
assert.deepStrictEqual(data, [['toString'], 'toSt']); | |||
})); | |||
|
|||
// tab completion Symbol |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Please always use a capital letter as first character of a comment and punctuate them.
Ping @Bamieh |
@BridgeAR please keep the PR opened, I have it scheduled on friday to finish it. |
Closing due to long inactivity. @Bamieh please feel free to open a new PR or to leave a comment so this PR can be reopened in case you would like to continue working on this. |
This feature reworks the
tab complete
feature in the repl module.Rather than using regular expressions to guess the completion options, the tab completion will call a method on the function through a
Symbol
attached on these methods, which returns an array of possible completion options.Notes
repl.replComplete
Symbol attached on them.Benefits
Context
Recently i submitted a PR to implement tab completion for the fs module, and i was faced with many design issues mainly because of how impractical the regexp approach is for expanding the tab completion feature.
@starkwang @apapirovski @benjamingr can you provide feedback on this please, since you are in context with this issue already. Thanks!
Semver: Major or Minor
I believe this does not introduce any breaking changes so it could be introduced as a minor semver.
RFC
I am requesting comments and feedback on the approach and some general guidance. This PR is far from complete but it contains the initial direction of implementation. Also I have an already opened PR for the fs path autocomplete, if this PR receives positive feedback i will refactor the other one to use this feature.
Final notes
Finally, I will leave you with this piece of wisdom my brain crafted while implementing the feature 😄
Cheers!