Skip to content

R: approach snippets in a more conventional VS Code way #7234

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
jennybc opened this issue Apr 11, 2025 · 8 comments
Closed

R: approach snippets in a more conventional VS Code way #7234

jennybc opened this issue Apr 11, 2025 · 8 comments
Labels
area: completions Issues related to Completions lang: r

Comments

@jennybc
Copy link
Member

jennybc commented Apr 11, 2025

Currently ark provides, unconditionally, a fixed set of R snippets:

https://github.com/posit-dev/ark/blob/main/crates/ark/resources/snippets/r.code-snippets

Thoughts about how to improve this area:

  • The existing snippets were ported from RStudio and, to some of us, contain a rather peculiar set of snippets. It feels like we might be on autopilot, maintaining something created a long time ago, without re-examining and curating it? I don't think these would be the top snippets we'd create if we were starting from scratch. Also the completion landscape has changed dramatically since these snippets were created, now that we've got a true LSP and also given code completion from LLMs.
  • There's no way to turn the built-in ark snippets off. So there's no recourse if you find them to be a net negative to your completion life. And they do tend to show up near the top of the list, conceivably squatting on the coveted top spot.
  • In RStudio, you either get the default snippets or your custom snippets. There is no combining of them. If you want custom snippets AND you like some of the default snippets, you copy those defaults into your custom snippets. We should at least consider this design for Positron as well. What I mostly mean is: maybe we should get out of the snippet business entirely, but we help people to develop their own custom snippets. For example, by providing some great example content when the user first start their own snippet file.
    • Personally, I never use any of the snippets that ark is currently providing and anecdotally this is also true for various colleagues I consulted. Instead, those of us who use snippets use custom ones we've created for ourselves.
  • Currently, it is possible to augment the built-in snippets by using a VS Code mechanism. The entry point is Snippets: Configure Snippets in the command palette. That allows snippet customization at the user or workspace level, via a dedicated .code-snippets file (more below). These snippets appear to be combined with the snippet completions coming from the LSP. I can confirm that if you use "r" as the scope, these snippets are thrown into the mix along with those coming from ark.

Here is the initial content of a snippet file initiated with VS Code / Positron:

{
	// Place your r_testing workspace snippets here. Each snippet is defined under a snippet name and has a scope, prefix, body and 
	// description. Add comma separated ids of the languages where the snippet is applicable in the scope field. If scope 
	// is left empty or omitted, the snippet gets applied to all languages. The prefix is what is 
	// used to trigger the snippet and the body will be expanded and inserted. Possible variables are: 
	// $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders. 
	// Placeholders with the same ids are connected.
	// Example:
	// "Print to console": {
	// 	"scope": "javascript,typescript",
	// 	"prefix": "log",
	// 	"body": [
	// 		"console.log('$1');",
	// 		"$2"
	// 	],
	// 	"description": "Log output to console"
	// }
}

Issue inspired by #7101 and general work on R completions.

@jennybc jennybc added lang: r area: completions Issues related to Completions labels Apr 11, 2025
@jennybc
Copy link
Member Author

jennybc commented Apr 14, 2025

The official docs for snippets clarify the r.json file mentioned in #7101, vis-à-vis a .code-snippets file: https://code.visualstudio.com/docs/editing/userdefinedsnippets#_language-snippet-scope

Single-language user-defined snippets are defined in a specific language's snippet file (for example javascript.json), which you can access by language identifier through Snippets: Configure Snippets. A snippet is only accessible when editing the language for which it is defined.

Multi-language and global user-defined snippets are all defined in "global" snippet files (JSON with the file suffix .code-snippets), which is also accessible through Snippets: Configure Snippets. In a global snippets file, a snippet definition may have an additional scope property that takes one or more language identifiers, which makes the snippet available only for those specified languages. If no scope property is given, then the global snippet is available in all languages.

Most user-defined snippets are scoped to a single language, and so are defined in a language-specific snippet file.

@jennybc
Copy link
Member Author

jennybc commented Apr 14, 2025

The Python extension contributes only 2 snippets, which is consistent with my hunch that perhaps positron-r / ark should provide no snippets (or almost none?):

{
"import <module>": {
"prefix": "im",
"body": "import ${1:module}$0",
"description": "Import a package or module"
},
"from <module> import <names>": {
"prefix": "from",
"body": "from ${1:module} import ${2:names}$0",
"description": "Import names from a package or module"
}
}

@dkaschek
Copy link

It would be great to see support for snippets with executable R code similar to RStudio. As an example, snippets in RStudio allow expressions like `r date()` to insert the current date into the output from the snippet. There are many more cases where R code in snippets helps creating more dynamic snippets.

@jennybc
Copy link
Member Author

jennybc commented Apr 21, 2025

Since I'm advocating for the removal of built-in R snippets, that doesn't bode well for a feature request for even more capable R snippets.

I just want to note that VS Code and, therefore, Positron offer another snippet-y way of doing things like "insert the current date", e.g.:

https://mattferderer.com/create-a-snippet-or-shortcut-in-vs-code-to-insert-the-current-date-time

I think this is a great example of the benefits of building on VS Code: we get a lot of features "for free" and this could be one of them.

@jennybc
Copy link
Member Author

jennybc commented Apr 21, 2025

If we remove built-in snippets from ark, we could still shape the user's experience of configuring R snippets by providing some examples. Here's where the content of a bare language-specific snippet file lives:

async function createLanguageSnippetFile(pick: ISnippetPick, fileService: IFileService, textFileService: ITextFileService) {
if (await fileService.exists(pick.filepath)) {
return;
}
const contents = [
'{',
'\t// Place your snippets for ' + pick.label + ' here. Each snippet is defined under a snippet name and has a prefix, body and ',
'\t// description. The prefix is what is used to trigger the snippet and the body will be expanded and inserted. Possible variables are:',
'\t// $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders. Placeholders with the ',
'\t// same ids are connected.',
'\t// Example:',
'\t// "Print to console": {',
'\t// \t"prefix": "log",',
'\t// \t"body": [',
'\t// \t\t"console.log(\'$1\');",',
'\t// \t\t"$2"',
'\t// \t],',
'\t// \t"description": "Log output to console"',
'\t// }',
'}'
].join('\n');
await textFileService.write(pick.filepath, contents);
}

Currently, the selected language just gets inserted for the pick.label placeholder, but you could imagine going beyond that. This initial content is not truly a configuration point, but Positron could feature 1 R and 1 Python example, instead of a javascript example.

@jennybc
Copy link
Member Author

jennybc commented Apr 25, 2025

This appears to be the landscape for user-defined snippet files:

  • A language-specific snippet file that is user-level. The language is conveyed by the file name via a language identifier.
    • Example path: ~/Library/Application Support/Positron/User/snippets/r.json
  • A global snippet file, where "global" means "not scoped to a specific language", at the user-level. Language scope(s) can be optionally specified in the snippets themselves.
    • Example path: ~/Library/Application Support/Positron/User/snippets/jenny.code-snippets
  • A global snippet file for a workspace.
    • Example path: PATH/TO/THE/WORKSPACE/ROOT/.vscode/SOMETHING.code-snippets

@jennybc jennybc changed the title R: better snippets and/or better control over snippets R: approach snippets in a more conventional VS Code way Apr 25, 2025
jennybc added a commit that referenced this issue Apr 28, 2025
Part of #7234 

In posit-dev/ark#782, I remove the so-called
snippet source of completions in ark.

Previously, the completions coming from the snippet source were a mix of
snippets related to R reserved words (such as `if`, `while`, or `for`)
and a collection of other snippets relating to various functions in base
R (such as `matrix()` or `lapply()`). This was an eclectic mix of
snippets inherited from RStudio.

After [#782](posit-dev/ark#782), completion
handling for reserved words lives with ark's keyword source. The usual
snippets still appear (or do not), in the same contexts, just via a
different internal mechanism. Functions like `matrix()` or `lapply()`,
however, no longer have special handling and receive the same completion
treatment as any other function on the search path.

If users want such snippets, we're going to follow the existing VS Code
vibe, which is to recommend that the user configure custom snippets, via
the command palette and *Snippets: Configure Snippets*:

<img width="218" alt="Screenshot 2025-04-25 at 3 34 23 PM"
src="https://github.com/user-attachments/assets/0b167aec-5ae8-4798-843f-4691027842fb"
/>

A newly created snippet file using this interface is pre-populated with
a big comment that explains what sort of content to place in the file.
Snippet files comes in 2 main flavors:

* "global": contains snippets that are not limited to one language.
Individual snippets in such a global file can have a `scope` which
specifies one or more languages. Created via `createSnippetFile()`.

<img width="607" alt="Screenshot 2025-04-25 at 3 38 00 PM"
src="https://github.com/user-attachments/assets/b2c039a3-65dc-451a-9b3a-fd162d08e537"
/>

* language-specific: contains snippets for one specific language.
Created via `createLanguageSnippetFile()`.

<img width="301" alt="Screenshot 2025-04-25 at 3 45 05 PM"
src="https://github.com/user-attachments/assets/facb30ca-4e20-4c84-8741-68fe30e235f7"
/>

This PR modifies the placeholder content for both functions. The main
idea is to give examples for R and Python, instead of
javascript/typescript. This PR is similar in spirit to other changes
we've made to make default or example content more data science / R /
Python oriented.

The mechanics are pretty bone-headed, but that is motivated by our
overlay strategy and making things as easy as possible for upstream
merges.

*I plan to complement this PR with a companion PR to the website aimed
at helping snippet users coming from RStudio.*
jennybc added a commit that referenced this issue Apr 29, 2025
For posit-dev/ark#782
Addresses #7234
Addresses #3108

### Release Notes

#### New Features

- R snippets are now handled in the conventional way for VS Code, i.e.
via optional `.code-snippets` files at the user or workspace level or an
R-specific `r.json` file. Newly configured snippet files contain
examples for R and Python. The only R snippets that remain built-in are
those relating to reserved words (#7234).

#### Bug Fixes

- It is now possible to get completions via `?` for functions, e.g., in
the `apply()` family or for `switch()` (#3108).

### QA Notes

<!--
  Add additional information for QA on how to validate the change,
  paying special attention to the level of risk, adjacent areas that
  could be affected by the change, and any important contextual
  information not present in the linked issues.
-->
@jennybc
Copy link
Member Author

jennybc commented Apr 29, 2025

QA Notes:

Relevant instructions have been newly added to the docs: https://positron.posit.co/r-snippets.html

Ideas for verification:

  • Before creating any snippet files, observe that there are no snippets for lapply() or switch() or the other not-a-reserved-word snippets targetted for deletion in Eliminate built-in snippets ark#780. The completion behaviour for these is now the usual completion for a function.
  • From the command palette do Snippets: Configure Snippets and experiment with:
    • a global snippet file at the user and/or workspace level
    • an R-specific snippet file
    • a Python-specific snippet file
      Confirm you get example content specific to R and/or Python. And that, once uncommented, this leads to functioning snippets in R and Python.

@testlabauto
Copy link
Contributor

Verified Fixed

Positron Version(s) : 2025.06.0-14
OS Version          : OSX

Test scenario(s)

Tried all types of snippets and everything looks good.

Link(s) to TestRail test cases run or created:

@github-actions github-actions bot locked as resolved and limited conversation to collaborators May 17, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area: completions Issues related to Completions lang: r
Projects
None yet
Development

No branches or pull requests

4 participants