Consider:
x <- list(`a b` = 1)
x$a<tab>
(i.e., press the 'tab' key after typing 'x$a')
The auto-complete mechanism will fill the buffer like so:
x$a b
This is not particularly helpful because this is now a syntax error.
It seems to me there's a simple fix -- in
utils:::specialCompletions(), we can wrap the result of
utils:::specialOpCompletionsHelper() with backticks for non-syntactic
names ([1]):
comps <- specialOpCompletionsHelper(op, suffix, prefix)
if (length(comps) == 0L) comps <- ""
+non_syntactic <- make.names(comps) != comps
+comps[non_syntactic] <- paste0("`", comps[non_syntactic], "`")
sprintf("%s%s%s", prefix, op, comps)
I'm somewhat surprised this hasn't come up before (I searched for
'completeToken', 'specialCompletions', and
'specialOpCompletionsHelper' here and on Bugzilla), so I'm checking
with the list first if I'm missing anything before filing a patch.
Mike C
[1] https://github.com/r-devel/r-svn/blob/4657f65a377cb5ef318c6548bc264e3b0f9517a0/src/library/utils/R/completion.R#L536-L538
tab-complete for non-syntactic names could attempt backtick-wrapping
7 messages · Ivan Krylov, Michael Chirico, Deepayan Sarkar +1 more
? Wed, 1 Mar 2023 01:36:02 -0800 Michael Chirico via R-devel <r-devel at r-project.org> ?????:
+comps[non_syntactic] <- paste0("`", comps[non_syntactic], "`")
There are a few more corner cases. For example, comps could contain backticks (which should be escaped with backslashes) and backslashes (which should also be escaped). Thankfully, \uXXXX-style Unicode escape sequences are not currently supported inside backticks, and "escape the backslash" rule already takes care of them. The deparse() function already knows these rules: name <- 'hello world ` \\uFF' cat(deparse1(as.name(name), backtick=TRUE), '\n') # `hello world \` \\uFF` `hello world \` \\uFF` <- 'hello' `hello world \` \\uFF` # [1] "hello"
Best regards, Ivan
Great suggestion! I've started a patch: https://bugs.r-project.org/show_bug.cgi?id=18479
On Wed, Mar 1, 2023 at 1:56 AM Ivan Krylov <krylov.r00t at gmail.com> wrote:
? Wed, 1 Mar 2023 01:36:02 -0800 Michael Chirico via R-devel <r-devel at r-project.org> ?????:
+comps[non_syntactic] <- paste0("`", comps[non_syntactic], "`")
There are a few more corner cases. For example, comps could contain backticks (which should be escaped with backslashes) and backslashes (which should also be escaped). Thankfully, \uXXXX-style Unicode escape sequences are not currently supported inside backticks, and "escape the backslash" rule already takes care of them. The deparse() function already knows these rules: name <- 'hello world ` \\uFF' cat(deparse1(as.name(name), backtick=TRUE), '\n') # `hello world \` \\uFF` `hello world \` \\uFF` <- 'hello' `hello world \` \\uFF` # [1] "hello" -- Best regards, Ivan
There turn out to be a few more things to fix. One problem is easy to solve: vapply() needs a third argument specifying the type of the return value. (Can we have unit tests for tab completion?) The other problem is harder: `comps` defaults to an empty string, and you can't have a symbol consisting of an empty string, because this value is internally reserved for missing function arguments. I think you can return(paste0(prefix, op)) if length(comps) == 0L, but this is still somewhat worrying. R tries to prevent empty names, so I wouldn't expect specialOpCompletionsHelper() to return an empty string, but I can't prove it right now. On the other hand, x$'a string' is the same as x$`a string`. Could we just drop as.name() and keep the return value being a string literal? I'm not sure about this, either.
Best regards, Ivan
On Thu, Mar 2, 2023 at 2:09?PM Ivan Krylov <krylov.r00t at gmail.com> wrote:
There turn out to be a few more things to fix. One problem is easy to solve: vapply() needs a third argument specifying the type of the return value. (Can we have unit tests for tab completion?)
There are tests in src/library/utils/tests/completion.R which should get run by make check-devel (which runs R CMD check on all base packages).
The other problem is harder: `comps` defaults to an empty string, and you can't have a symbol consisting of an empty string, because this value is internally reserved for missing function arguments. I think you can return(paste0(prefix, op)) if length(comps) == 0L, but this is still somewhat worrying. R tries to prevent empty names, so I wouldn't expect specialOpCompletionsHelper() to return an empty string, but I can't prove it right now. On the other hand, x$'a string' is the same as x$`a string`. Could we just drop as.name() and keep the return value being a string literal? I'm not sure about this, either.
See my just-posted response on bugzilla for other issues to look out for. Best, -Deepayan
-- Best regards, Ivan
______________________________________________ R-devel at r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-devel
I personally wouldn't like using a string, and this comment makes me think it's against the r-core preference as well: https://bugs.r-project.org/show_bug.cgi?id=18429#c1 Thanks both for catching the sloppy mistake in vapply() :) Let's continue discussion on the bug/PR.
On Thu, Mar 2, 2023 at 12:39 AM Ivan Krylov <krylov.r00t at gmail.com> wrote:
There turn out to be a few more things to fix. One problem is easy to solve: vapply() needs a third argument specifying the type of the return value. (Can we have unit tests for tab completion?) The other problem is harder: `comps` defaults to an empty string, and you can't have a symbol consisting of an empty string, because this value is internally reserved for missing function arguments. I think you can return(paste0(prefix, op)) if length(comps) == 0L, but this is still somewhat worrying. R tries to prevent empty names, so I wouldn't expect specialOpCompletionsHelper() to return an empty string, but I can't prove it right now. On the other hand, x$'a string' is the same as x$`a string`. Could we just drop as.name() and keep the return value being a string literal? I'm not sure about this, either. -- Best regards, Ivan
x$`string` is not the same as x$'string'. They may act similarly now, but they do not parse the same.
vapply(as.list(quote(list$`component`)), typeof, "")
[1] "symbol" "symbol" "symbol"
vapply(as.list(quote(list$"component")), typeof, "")
[1] "symbol" "symbol" "character"
vapply(as.list(quote(list$'component')), typeof, "")
[1] "symbol" "symbol" "character" Single and double quoted character sequences do parse to the same thing (character) but backquoted ones parse to symbols (aka names). -Bill
On Thu, Mar 2, 2023 at 12:39?AM Ivan Krylov <krylov.r00t at gmail.com> wrote:
There turn out to be a few more things to fix. One problem is easy to solve: vapply() needs a third argument specifying the type of the return value. (Can we have unit tests for tab completion?) The other problem is harder: `comps` defaults to an empty string, and you can't have a symbol consisting of an empty string, because this value is internally reserved for missing function arguments. I think you can return(paste0(prefix, op)) if length(comps) == 0L, but this is still somewhat worrying. R tries to prevent empty names, so I wouldn't expect specialOpCompletionsHelper() to return an empty string, but I can't prove it right now. On the other hand, x$'a string' is the same as x$`a string`. Could we just drop as.name() and keep the return value being a string literal? I'm not sure about this, either. -- Best regards, Ivan
______________________________________________ R-devel at r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-devel