-
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
Tab complete paths for fs
functions in repl
#17790
Conversation
Fixes nodejs#17764
65f3d29
to
dc1c091
Compare
].join('|'); | ||
|
||
const fsRE = new RegExp( | ||
`fs\\.(?:${fsTabbableMethods})\\(["'](([\\w@./-]+\\/)?(?:[\\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.
Does it need the fs.
restriction?
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.
@Fishrock123 the restriction is not needed, but its there to avoid unexpected collisions for functions with similar names.
function readFile(fileName) {
}
readFile('...<Tab>' // this will work and might be unexpected for users
this is my opinion, what do you think?
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.
Do you think people are really likely to in the repl during an existing line-statement when they don't want autocomplete?
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 personally agree with @Fishrock123 and think it is better to keep this open. A false positive does not hurt here out of my perspective.
Also, going to echo ben's comment from the issue:
The fact that it is on tab should avoid any unexpected behavior though, I think? How does this perform on, say, the |
} else if (match = (line.match(requireRE) || line.match(fsRE))) { | ||
// require('...<Tab>') and fs.<method>('...<Tab>') | ||
|
||
const isFS = line.match(fsRE); |
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 RegExp
looks pretty intensive to me, we should not be running it twice. The if
statement could be refactored to be (matchRequire = line.match(requireRE)) || (matchFs = line.match(fsRE))
. Then we can assign match
within the body.
(Of course, the var
declaration will be needed for both.)
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.
definitely.
'unlink', | ||
'unlinkSync', | ||
'utimes', | ||
'utimesSync', |
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 will become a huge pain to maintain over time, especially since the test also duplicates it.
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.
@apapirovski thanks for the review! i thought of exporting it in the repl
to reduce this maintenance cost, but i was unsure about it. Do you have any other suggestions?
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.
@apapirovski @benjamingr An alternative implementation of regex matching is to have a Symbol
for tabCompletion
in node. Then each module would add their own implementation of the tab completion on the method level (also allowing non-core modules to enjoy this feature as well).
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.
That would actually be awesome and a nice idea.
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.
Would checking the exports for functions be enough? The regex then already specifies it must be within a string...
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 mean I sort of like the idea of a custom tabCompletion
symbol for repl
but I don't like the idea of shipping that code to everyone that doesn't even use the repl
(it's always there on the prototype, for no reason).
Maybe the answer would be to have some sort of a definitions file that repl
includes that enhances any supported modules. Like internals/repl/definitions/*.js
(stream, fs, etc.) or something. Just musing out loud...
Although I guess it depends on how the tab completion works, per method, or per module... Anyway, move along, nothing to see here... just rambling. 😆
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.
Would it be possible to create the list dynamically? e.g.
Object.keys(fs).filter(name => typeof fs[name] === 'function' && !name.startsWith('_'))
That would enable a few methods that aren't currently in this PR (e.g. writeFileSync
), although it might cause a false positive if there are any methods on fs
that don't accept a filepath as their first argument.
Personally, I think we could be liberal about enabling tab-completion, and just apply it to all fs
methods. (By comparison, Bash always tab-completes arguments that look like filepaths, even though it doesn't know the semantics of the command being used.)
looking at this behavior in a more general context, if i see |
if/once scandir lands a more general "if in string and thing typed looks like a path" feature could be implemented |
@Fishrock123 I have read that comment, but it is the same for the |
I do not see this feature possible with the current regex architecture of the repl. for example what would a tab completion for a
Then we should add code for the repl to support these functions as well. The code could be easily refactored to be extendable by other modules. |
like the author of the imgur module adds regex for their module and the author of the asar module adds regex for their module? I don't understand how any way of locking this feature to specific methods or whatever else creates a positive experience for someone using the repl. imo this is better suited to not be a feature at all if it can't be more generally applied. tab completion for |
That's the lightest of benchmarks, test/parallel has < 2,000 files in it. I regularly work inside directories that have > 200,000 files in them. That said, it probably won't be too bad in the common case. 250k files on a SSD take about 1-3 seconds to (The cold case on spinning platters probably won't do so well, though.) |
].join('|'); | ||
|
||
const fsRE = new RegExp( | ||
`fs\\.(?:${fsTabbableMethods})\\(["'](([\\w@./-]+\\/)?(?:[\\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.
It's better to add a \b
at the beginning of the RegExp, otherwise it will match something like xxxxfs.readFile("
].join('|'); | ||
|
||
const fsRE = new RegExp( | ||
`fs\\.(?:${fsTabbableMethods})\\(["'](([\\w@./-]+\\/)?(?:[\\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 personally agree with @Fishrock123 and think it is better to keep this open. A false positive does not hurt here out of my perspective.
// Test tab complete for fs module | ||
putIn.run(['.clear']); | ||
|
||
// does not auto complete empty paths |
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.
Please always use a capital letter as first character in a comment and punctuate them.
'unlinkSync', | ||
'utimes', | ||
'utimesSync', | ||
]; |
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 the same applies here as above: using a dynamical filtered list is probably better than a static one.
@Bamieh do you still work on this? |
Adds autocomplete in
repl
forfs
methods that lookup file paths. Closes #17764fs
module must be explicitly accessed byfs
.I was afraid to refactor the
require('...<Tab>')
completion into a separate function and call it in both therequire
andfs.<method>
, this would tidy up the code a little. I am willing to refactor it if I get a green light.I have the methods
readlink
andreadlinkSync
in the supported tab complete methods. I am not sure if these make sense to be added, or need a special lookup for only symlinks.P.S.
Implementing a feature to track all the variables defined for tab completion would benefit the repl tab completion in two folds:
const
andlet
) will be supported in the tab completion.Checklist
make -j4 test
(UNIX), orvcbuild test
(Windows) passesAffected core subsystem(s)
repl