0

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

Mark
  • 143,421
  • 24
  • 428
  • 436
Oaty
  • 151
  • 1
  • 15

3 Answers3

3

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"]

  }
}

transform to snake case demo


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}"
},

snake case snippet demo

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"
}

snake case demo with macro

Mark
  • 143,421
  • 24
  • 428
  • 436
1

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

Amour Spirit
  • 125
  • 7
  • 3
    It is worth noting that VS Code supports Transform to Snake Case (shit+ctl+p) Snake Case. See: [VS Code tips — Convert to Snake Case](https://www.youtube.com/watch?v=owexcF4a8qg) on Youtube. – Amour Spirit Nov 23 '21 at 19:10
  • 2
    Thanks Amour Spirit! The TL;DR is: `ctrl + p` type `>` search for `Transform` and select `>Transform to snake case` – Michael Jun 16 '22 at 09:05
  • This version is for `PascalCase`. `getSomethingElse` is transformed to `getsometing_else` not `get_something_else` (( – nezort11 Sep 06 '22 at 13:15
0

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.

  1. ([A-Z][a-z]+$) group captures trailing Else and transforms into else (replaces with ${1:/downcase}).

  2. ((^|[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

nezort11
  • 326
  • 1
  • 4
  • 11