Yep, I'm aware this is current functionality. I'm asking for a friend (Azure Data Studio).
I need a user snippet that will convert either Camel Case or Pascal Case (highlighted) strings to lower Snake Case. I adapted this answer here which gets me close but it can't handle a sequence of Upper Case letters e.g. HTML.
"snake":{
"prefix": "snake",
"body": "${TM_SELECTED_TEXT/(^[A-Z][a-z]*|[a-z])([A-Z])?/${1:/downcase}${2:+_}${2:/downcase}/g}"
}
Ideally I could get results like
Converts a string to snake case.
Use String.prototype.match() to break the string into words using an
appropriate regexp.
Use Array.prototype.map(),
Array.prototype.slice(), Array.prototype.join() and
String.prototype.toLowerCase() to combine them, adding _ as a
separator.
const toSnakeCase = str =>
str &&
str
.match(/[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|\b)|[A-Z]?[a-z]+[0-9]*|[A-Z]|[0-9]+/g)
.map(x => x.toLowerCase())
.join('_');
toSnakeCase('camelCase'); // 'camel_case'
toSnakeCase('some text'); // 'some_text'
toSnakeCase('some-mixed_string With spaces_underscores-and-hyphens'); // 'some_mixed_string_with_spaces_underscores_and_hyphens'
toSnakeCase('AllThe-small Things'); // 'all_the_small_things'
toKebabCase('IAmEditingSomeXMLAndHTML');
from 30 seconds of code: convert to snake_case
Here is a simplification - although you will need to use some macro extension to run multiple commands. On the other hand, just like my previous answer, it does handle ALL of your test cases and is much simpler as it incorporates the newer built-in command Transform to Snake Case.
However, that built-in snake case transform command only works for camelCase => snake_case. It cannot handle spaces or hyphens and so fails on most of your test cases but it does handle sequences like XMLAndHTML well.
The following keybinding (in your keybindings.json) does handle all your test cases by first replacing the spaces and hyphens with underscores. Then it runs the editor.action.transformToSnakecase command on the result.
Using my extension Find and Transform create this keybinding:
{
"key": "alt+u", // whatever keybinding you like
"command": "findInCurrentFile",
"args": {
"replace": [
"$${",
"return `${selectedText}`.replace(/[-\\s]/g, '_');",
"}$$"
],
"restrictFind": "selections", // only work on selections
"postCommands": "editor.action.transformToSnakecase"
// for SCREAMING_SNAKE_CASE use the below
// "postCommands": ["editor.action.transformToSnakecase", "editor.action.transformToUppercase"]
}
}
Previous answer
Try this (I converted the regex from your second link):
"snake": {
"prefix": "snake",
"body": "${TM_SELECTED_TEXT/([A-Z]{2,})(?=[A-Z][a-z]+[0-9]*|$)|([A-Z]?[a-z]+[0-9]*|[A-Z]|[0-9]+)([- _])?/${1:/downcase}${2:/downcase}${2:+_}/gm}"
},
Right now it adds an extra _ at the end which you could just backspace over or put it into a macro that does that for you. Here using multi-command:
{
"key": "alt+enter", whatever keybinding you want
"command": "extension.multiCommand.execute",
"args": {
"sequence": [
{
"command": "editor.action.insertSnippet",
"args": {
"snippet": "${TM_SELECTED_TEXT/([A-Z]{2,})(?=[A-Z][a-z]+[0-9]*|$)|([A-Z]?[a-z]+[0-9]*|[A-Z]|[0-9]+)([- _])?/${1:/downcase}${2:/downcase}_/gm}"
},
},
"deleteLeft"
]
},
"when": "editorTextFocus && editorHasSelection"
}
This version does not include a trailing _
Thank you for pointing me in the correct direction on this.
"snake": {
"prefix": "snake",
"body": "${TM_SELECTED_TEXT/([A-Z][a-z]+$)|([A-Z][a-z]+)/${1:/downcase}${2:/downcase}${2:+_}/g}"
}
Sample VS Code Snippet
"pyp": {
"prefix": "Generate full Property",
"body": [
"#property",
"def ${1:name}(self) -> ${2:str}:",
" \"\"\"Specifies ${1:name}",
"",
" :getter: Gets ${1:name} value.",
" :setter: Sets ${1:name} value.",
" \"\"\"",
" return self._${1/([A-Z][a-z]+$)|([A-Z][a-z]+)/${1:/downcase}${2:/downcase}${2:+_}/g}",
"",
"#${1:name}.setter",
"def ${1:name}(self, value: ${2:str}):",
" self._${1/([A-Z][a-z]+$)|([A-Z][a-z]+)/${1:/downcase}${2:/downcase}${2:+_}/g} = value${0}"
],
"description": "pyp"
}
Sample on snippet-generator.app
This solution works for camelCase to snake_case transformation (without _)
${TM_SELECTED_TEXT/([A-Z][a-z]+$)|((^|[A-Z])[a-z]+)/${1:/downcase}${2:/downcase}${2:+_}/gm}
Example
Transform getSomethingMoreElse into get_something_more_else:
([A-Z][a-z]+$)|((^|[A-Z])[a-z]+) is a regex.
([A-Z][a-z]+$) group captures trailing Else and transforms into else (replaces with ${1:/downcase}).
((^|[A-Z])[a-z]+) (word is at start or starts from capital letter) group captures get, Something, More and casts into lowercase + _ (replaces with ${2:/downcase}${2:+_}).
My comment on Amour Spirit answer:
This version is for PascalCase. getSomethingElse is transformed to getsometing_else not get_something_else
Related
See the following snippet:
"srcPath":{
"prefix": "getSrcPath",
"body": [
"$TM_FILEPATH",
"${1:${TM_FILEPATH/(.*)src.(.*)/${2}/i}}",
"${TM_FILEPATH/[\\\\]/./g}"
]
},
The output of lines 1-3 is :
D:\root\src\view\test.lua
view\test.lua
D:.root.src.view.test.lua
How can I get output like 'view/test.lua'?
Try this snippet:
"srcPath":{
"prefix": "getSrcPath",
"body": [
"$TM_FILEPATH",
"${TM_FILEPATH/.*src.|(\\\\)/${1:+/}/g}",
"${TM_FILEPATH/[\\\\]/\\//g}"
]
}
.*src.|(\\\\) will match everything up to and including the ...src\ path information. We don't save it in a capture group because we aren't using it in the replacement part of the transform.
The (\\\\) matches any \ in the rest of the path - need the g flag to get them all.
Replace: ${1:+/} which means if there is a capture group 1 in .*src.|(\\\\) then replace it with a /. Note we don't match the rest of the path after src\ only the \'s that might follow it. So, not matching those other path parts just allows them to remain in the result.
You were close on this one:
"${TM_FILEPATH/[\\\\]/\\//g}" just replace any \\\\ with \\/.
With the extension File Templates you can insert a "snippet" that contains a variable and multiple find-replace operations.
With a key binding:
{
"key": "ctrl+alt+f", // or any other combo
"command": "templates.pasteTemplate",
"args": {
"text": [
"${relativeFile#find=.*?src/(.*)#replace=$1#find=[\\\\/]#flags=g#replace=.#}"
]
}
}
At the moment only possible with a key binding or via multi command (or similar). Will add an issue to also make it possible by prefix.
Also some of the standard variables are missing.
The extension adds support for Renpy language, a language very similar to Python. In this language, it's possible to embed Python code in different ways.
Single line statement:
define e = Character("Eileen", who_color="#c8ffc8")
default sidebar = False
$ sampleFunction("Eileen", 1.0)
To embed python inside single-line statements, I use the following TextMate Grammar pattern:
{
"comment": "Match begin and end of python one line statements",
"name": "meta.embedded.python.line",
"begin": "(?<=(\\$|define|default)\\s)",
"end": "\\R$",
"patterns": [{ "include": "source.python" }]
}
In this case, I can know when a statement ends.
Python block:
python:
def foo():
return "bar"
These blocks can be nested within other language blocks, for example:
init:
image movie = Movie()
python:
povname = ""
pov = DynamicCharacter("povname", color=(255, 0, 0, 255))
$ ectc = Character('Eileen', color=(200, 255, 200, 255))
In the case of the block, since it's delimited by indentation, I can't determine where it ends. If these blocks couldn't be nested, I could capture the end with a regular expression, e.g. ^(?=\S), since it can be nested I can't detect when it ends.
I tried to add the TextMate scope source.python via the SemanticTokenProvider, but it seems that it's not possible to add a textmate scope using the SemanticTokensBuilder. Also tried with TextMate patterns but have not succeeded.
I would like to find a way to make the contents of Python blocks have the source.python TextMate scope, regardless of whether it's nested or not.
If there is always a line after the block that has the same indent as the word python: you could try
{
"begin": "^(\\s*)(python:)",
"end": "^\\1(?=\S)",
"beginCaptures": { "2": { "name": "keyword.other" } },
"patterns": [{ "include": "source.python" }]
}
I'm in a file called event-list.tsx, and I'm trying to create a snippet that writes the following code:
const EventList: FC = () => {
return <div>
</div>;
};
export default EventList;
Thus far, in typescriptreact.json I've written the following snippet setting, which results in awkward-looking code (it puts out const event-list rather than const EventList
"react arrow func component": {
"prefix": "rafce",
"body": [
"const ${TM_FILENAME_BASE}: FC = () => {",
" return <div>",
" ",
" </div>;",
"};",
"",
"export default ${TM_FILENAME_BASE};",
""
]
},
I know how to remove the hyphen from the snippet:
${TM_FILENAME_BASE/-//}
I also figured out how to capitalize the first character:
${TM_FILENAME_BASE/(^.)/${1:/upcase}/}
But I can't figure out how to apply all three of the changes I want. I know the regular expression needed to capitalize every character that comes after a hyphen (a positive lookbehind), but I don't know how to apply it here. There is nothing in the documentation chapter implying the possibility to chain multiple transforms onto each other.
Try the following global regex
${TM_FILENAME_BASE/(.)([^-]*)-?/${1:/upcase}${2}/g}
Find a part before a - and Upcase the first letter, repeat for the whole string
"${TM_FILENAME_BASE/(\\w+)-?/${1:/capitalize}/g}",
(\\w+)-? : You only need one capture group if you use /capitalize.
The hyphens are removed by virtue of matching them (-?) but not including them in the output.
The g flag is necessary to keep matching every (\\w+)-? instance and perform a transform for each.
And since you are reusing an earlier transform you can simplify the whole thing like this:
"react arrow func component": {
"prefix": "rafce",
"body": [
"const ${1:${TM_FILENAME_BASE/(\\w*)-?/${1:/capitalize}/g}}: FC = () => {",
" return <div>",
" ",
" </div>;",
"};",
"",
"export default $1;",
""
]
},
Note that
${1:${TM_FILENAME_BASE/(\\w*)-?/${1:/capitalize}/g}}
stores the result of that transform in variable $1 - which can simply be used later (or earlier) by itself to output the same result!
I'm in the process of setting up a file for personal snippets in VSCode for LaTeX.
Is there a way to combine placeholders (Syntax: ${1:foo}) and normal curly braces?
In my example I want my code to output:
\fcolorbox {frame}{background}{text}
where every variable is a placeholder. My generated snippet code (.json) looks as follows:
"Colorbox fcolorbox": {
"prefix": "colbox",
"body": [
"\\fcolorbox ${{1:frame}}${{2:background}}${{3:text}}"
],
"description": "Colorbox fcolorbox"
}
but doesn't work since it outputs and interprets the $ and {} as LaTeX symbols.
Is there a way to fix this and make the placeholders work?
This produces the requested result: \fcolorbox {frame}{background}{text}
"Colorbox fcolorbox": {
"prefix": "colbox",
"body": [
"\\fcolorbox {${1:frame}}{${2:background}}{${3:text}}"
],
"description": "Colorbox fcolorbox"
}
In Sublime Text, multi-line code snippets can be defined with white-spaces in a snippet file.
But as far as I know, VS-Code needs a JSON entry. These require either:
Hard-breaks into a list of double-quoted strings, or
Soft-break a long string using line-breaks \n
This is inconvenient compared to the WYSIWYG approaches other IDEs provide out of the box.
Are there better ways for defining long-blocks of code?
You can define the body of your snippet as an array of strings, each beginning on a new line.
Like this:
"Create for loop":{
"prefix": "mkfor",
"body":[
"for(int i = 0; i < 3; i++)",
"{",
" //code goes here",
"}"
],
"description": "Creates a for loop"
}
or if you install Easy Snippet Maker extension, you can create your snippets by highlighting texts.
You can check out this video for a quick short tutorial
https://youtu.be/g1ouTcFxQSU
Go to File --> Preferences --> User Snippets. Select your preferred language.
Now type the following code to make a for loop snippet:
"Create for loop":{
"prefix": "for",
"body":[
"for(int i = 0; i < 10; i++)",
"{",
" //code goes here",
"}"
],
"description": "Creates a for loop"
}
You are done.
Type "for" in the editor and use the first prediction.
SHORTCUT--
install Snippet-creator extension.
Highlight the code that you need to make snippet.
press ctrl+shift+P and type "Create snippet" on the command palette and
press ENTER.
select language for which you want to create snippet(eg:-CPP), then type
snippet name, type snippet shortcut and then type snippet description.
You are now good to go.
Type the snippet shortcut in the editor that you entered in step 4, and select the prediction (if no prediction comes press ctrl+space) that comes first.
Hope this helps :)
Note: goto File->Preferences->User Snippets. Then select the language in which youcreated the snippet. You will find the snippet there.
I cannot find a good way to create multi-line snippets either. It's probably one of the features I'd like to see improved the most. As another answer suggested, there are a couple extensions out there to help with Snippet creation (like this and this). However, they don't escape literal dollar signs and indentation isn't great.
When browsing for answers to this, I stumbled across a Pen by Denis Malinochkin (linked from this issue). However, it also did not escape dollar signs properly, so I forked it and added this line to handle literal dollar signs. Here it is: https://codepen.io/cbejensen/pen/WXLxaE
Hope that helps!
P.S. - This is the line I added:
line = line.replace(new RegExp(/\$/, 'g'), '\\$');
I've created an extension to store snippets in a markdown file:
https://marketplace.visualstudio.com/items?itemName=usernamehw.snippets-in-markdown
Hit cmd+shift+p on mac machine, and search for "Configure User Snippets" then create a file and paste below json code.
provide prefix, Body, and description.
Reference: https://code.visualstudio.com/docs/editor/userdefinedsnippets
{
"forLoop": {
"prefix": "forLoop",
"body": [
"for (const ${2:element} of ${1:array}) {",
"\t$0",
"}"
],
"description": "For Loop"
},
"reactClass": {
"prefix": "reactClass",
"body": [
"import React from 'react';",
"class ${1:ComponentName} extends React.Component {",
"\t$0constructor(props) {",
"\t$0\t$0super(props)",
"",
"render() {",
"return (<div> ${2:Component} </div>)",
"}",
"export default ${3:ComponentName}"
],
"description": "For React Component class"
},
"function": {
"scope": "javascript,typescript",
"prefix": "function",
"body": [
"import React from 'react';",
"import withStyles from '#material-ui/core/styles/withStyles';",
"import { makeStyles } from '#material-ui/core/styles';",
"",
"import Styles from './style.js';",
"",
"const useStyles = makeStyles(Styles);",
"",
"function $1(props){",
"const classes = useStyles();",
"\treturn (",
"\t\t<React.Fragment>",
"\t\t\t<div className={classes.root}>",
"\t\t\t\t$1",
"\t\t\t</div>",
"\t\t</React.Fragment>",
"\t)",
"}",
"export default withStyles(useStyles)($1);"
],
"description": "react class"
}
}
I use this JSON Escape formatter(?) to process a large amount of HTML into a snippet:
https://www.freeformatter.com/json-escape.html
(The result of this process should be added in quotes "..." into the "body" part of the JSON object.
I've written a script which you can create your own complex snippets. just using the file you'd like. so you dont' need to write the source code in a string or string array.
https://github.com/banxi1988/vscode-snippets-ext-template