Skip to content
| Marketplace
Sign in
Visual Studio Code>Other>My Code ActionsNew to Visual Studio Code? Get it now.
My Code Actions

My Code Actions

rioj7

|
1,668 installs
| (1) | Free
Define Code Actions based on Language ID of the file
Installation
Launch VS Code Quick Open (Ctrl+P), paste the following command, and press enter.
Copied to clipboard
More Info

My Code Actions

Not every Language Server provides Code Actions to fix Warnings or Errors shown in the PROBLEMS panel and the squiggles shown in the editor text.

With this extension you can define Quick Fixes for any language.

It can also serve as an alternative to fixed text snippets. You can construct a number of include/import statements at the start of a new file for the actions that do not have a diagnostics property.

You can restrict an action if it applies to a certain Diagnostic message (problem in the PROBLEMS panel). It will then only show if you request Quick Fixes when the cursor is on a problem (squiggle) and there is a match for one of the regular expressions and the Diagnostic message.

The actions are specified in the settings.json file for entry my-code-actions.actions.

  • the key is a list of language id's for which the actions should be shown
  • the value is an object where the key is the title that is shown in the Quick Fix context menu.
    This makes it possible to define actions in the Global settings and merge them with actions specific for a workspace. (It is not working for Multi Root Workspaces yet (TODO))
  • the properties for an action are
    • diagnostics : (optional) an array of regular expressions. Only show the action when the cursor is on a problem (squiggle) and one of the regular expressions is a match for the problem diagnostic message.
      The capture groups of the matched regular expression can be used in the title and the text property.
      You can copy the diagnostic message from the PROBLEMS panel to get a starting string for the regular expression.
    • atCursor : Regular expressions to search surrounding the cursor location. Search the match that contains the cursor location. Capture groups can be used in variable {{atCursor:}}"
    • file : File path for which file to modify. If file starts with / it is relative to the workspace folder of the current file, otherwise it is relative to the current file, use / as directory separator, you can use a few variables and fields (default: current file)
    • action : a string describing the action to take: insert or replace (default: insert)
      Properties used when:
      • "action": "insert"
        • where : string describing the position of the insert (default: "start")
          Possible values:
          • start : At the start of the file
          • beforeLast : Before the last line matching the insertFind property or at the start
          • afterLast : After the last line matching the insertFind property or at the start
          • beforeFirst : Before the first line matching the insertFind property or at the start
        • insertFind : A regular expression that determines the insert location together with where property. Can contain fields.
        • text: the text to insert, can contain fields.
          You must add a \n to the text if it should be on a single line.
      • "action": "replace"
        • where : string describing the position to start the search (default: "start")
          Possible values:
          • start : At the start of the file
          • atCursor : the position where the atCursor property matches
        • replaceFind : A string or array of strings. Each a regular expression, with capture groups and fields, that is matched to the lines of the file. Each regex starts on the line where the previous regex has found a match.
        • replaceGlobal : (optional) Replace all the occurrences in the file starting at where. (default: false).
        • text: the text with group references, like $1, and fields that replaces the string matched by the last regex of replaceFind.
    • ask : an array of Input Box descriptions. Entered values can be used with the {{ask:name}} field.
      If you have multiple edits it is best to put all the needed asks in the first edit. This allows you to escape all the edits.
      An Input Box description has the following properties (each property value can use fields, even already asked names):
      • name : the name to store the entered value
      • placeHolder : (optional)
      • prompt : (optional)
      • title : (optional)
      • value : (optional)
    • edits : An array of edits that can have the following properties:
      • action : "insert" or "replace"
      • file : use a different file as specified in the action file property
      • text : if the action is "insert" and the text string is found in the file this edit is skipped.
      • where : start or beforeLast or afterLast or beforeFirst or atCursor
      • insertFind
      • replaceFind
      • replaceGlobal
      • ask
      • condFind : A string or array of strings. Each a regular expression, that is matched to the lines of the file. Each regex starts the search after the found match of the previous regex. The edit is performed when the strings are NOT found before condFindStop.
      • condFindStop : A regular expression string, that is matched to the lines of the file. The condFind stops searching when a regex has no match before condFindStop is found. Only test for condFindStop when first string of condFind is found. If not defined there is no stop condition.
      • needsContinue : Does the next edit depend on the location or the content of this edit. Do we have to run the action again to continue with the edits. Determines if a message is shown to the user. (default: conditional edit= true, other edit= undefined)
        Depending on the value:
        • undefined : (not present) go to next edit
        • true/false : then stop edits and yes/no show Continue message
        • "nextCondFail": (next edit condFind fails)
          Use the condFind of the next edit to determine if we stop the edits:
          • condFind is not found: then stop edits and show Continue message
          • condFind is found : go to next edit.

If you specify a file property and the file is not yet opened by Visual Studio Code (just a tab of the file is not enough) you get an error message asking you to open the file. You can use the "Open file" button in the message. If the file does not exists you get another error message allowing you to create the file. You must keep the file tab to be able to edit the file by the Quick Fix, otherwise you get the same error message. Apply the same Quick Fix when Visual Studio Code has read the file. You have to save the file yourself.

If the insert text is already found in the source code that particular action is not shown. That only applies if the action is in the current file and does not contains an edits property.

The other settings are:

  • my-code-actions.diagLookup : Object with arrays of lookup strings for diagnostics capture group 1 as key. The strings can be used in the {{diagLookup:n}} field.
      "my-code-actions.diagLookup": {
        "mat-expansion-panel": ["MatExpansionModule", "@angular/material/expansion"]
      }
    
  • my-code-actions.lookup : Object with strings for a normal lookup by key
    Can be used to name often used strings. To use the same regular expression in different places you can name it:
    "my-code-actions.lookup": {
      "appName": "app",
      "NgModuleStart": "@NgModule\\(\\{",
      "NgModuleEnd": "\\}\\)",
      "importsStart": "imports\\s*:\\s*\\["
    }
    
    You can define them at different levels (User/Workspace/Folder) and thus overrule named strings because VSC merges the content of a setting.

Be aware that you need to escape the \ and the " inside strings in the JSON file. But not needed for the \n character in the text property.

There are multiple methods to see the Quick Fixes:

  • use Ctrl+. in the editor
  • click on the lightbulb shown in the editor (only visible when there is a Quick Fix)
  • select a problem in the PROBLEMS panel and use any of the above methods when the problem icon changes to a lightbulb.

cursor location for atCursor

If there is no diagnostics test the start of the first selection is used. Most likely you don't have anything selected when asking for a Quick Fix so it is the current cursor location.

If there is a diagnostics test the start of the diagnostic squiggle is used. If there is a diagnostic (entry in PROBLEMS panel) you can call the Quick Fix from the PROBLEMS panel. The cursor in the editor can be anywhere in the file. To be consistent in the file location the extension uses the start of the diagnostic squiggle. If this position does not fall inside a match or is at the edge of the match for the atCursor regex you don't get an action.

File Variables

In the file property you can use the following variable:

  • ${fileBasenameNoExtension}

This variable is constructed from the current file.

Fields

In all strings, apart from diagnostics, we can use fields to make actions more generic or reduce the possible typos.

The diagnostic and atCursor fields are replaced before the text is used as a replace string using the last regex of replaceFind. So any capture group reference outside a field refers to a capture group of replaceFind.

Diagnostic Field: {{diag:text}}

Often part of the text you want inserted in the action is also mentioned in the diagnostics message. If you put this text in a capture group you can use this capture group.

The syntax:

{{diag:replace_text}}

The field is replaced with the replace_text where capture group references ($1 etc.) are taken from the diagnostics message regular expression.
An example field: {{diag:__$1__}}

For python you can describe a generic import action:

  "my-code-actions.actions": {
    "[python]": {
      "import {{diag:$1}}": {
        "diagnostics": ["\"(.*?)\" is not defined"],
        "text": "import {{diag:$1}}\n",
        "where": "afterLast",
        "insertFind": "^(import |from \\w+ import )"
      }
    }
  }

Diagnostic Lookup Field: {{diagLookup:n}}

If you need to fill in different strings based on a text in the diagnostic message, like Class name, module names you can use the Diagnostic Lookup Field. The first capture group of the diagnostic message is used as a key in the settings my-code-actions.diagLookup. The array of strings returned can be used by using the number of the index in the field.

The syntax:

{{diagLookup:n}}

n is the index in the array.

atCursor Field: {{atCursor:text}}

Often part of the text you want inserted in the action is near the cursor position. If you put this text in a capture group you can use this capture group. The range (squiggle) in the diagnostic message is often only marking a single identifier.

The syntax:

{{atCursor:replace_text}}

The field is replaced with the replace_text where capture group references ($1 etc.) are taken from the atCursor regular expression.
An example field: {{atCursor:$1}}

ask Field: {{ask:name}}

When you have 1 or more ask Input Boxes you can use the entered value with this field.

The syntax:

{{ask:name}}

Lookup Field: {{lookup:key}}

If you use the same string (regular expression) multiple times you can reduce the possibility of typos by naming this string and using a Lookup Field.

The syntax:

{{lookup:key}}

key is used in the object that is the setting my-code-actions.lookup.

An example

This example contains:

  • a few insert actions for C and C++
  • in HTML replace a class name and also in the used CSS file
  • a generic import action for Python
  • a generic import for Angular, where only the MatExpansionModule is specified, mat-expansion-panel is mentioned in the diagnostic message and captured as group 1.
  • add a method to a PHP class using {{atCursor:}} for the class name
  "my-code-actions.actions": {
    "[c,cpp]": {
      "include stdio": { "text": "#include <stdio.h>\n" },
      "include vector": { "text": "#include <vector>\n" },
      "include mylib": {
        "text": "#include \"mylib.h\"\n",
        "diagnostics": ["identifier \"[^\"]+\" is undefined"]
      }
    },
    "[html]": {
      "Rename CSS class selector": {
        "atCursor": " class=\"([^\"]+)\"",
        "edits": [
          {
            "file": "style.css",
            "action": "replace",
            "ask": [
              {
                "name": "find",
                "placeHolder": "Enter class",
                "title": "Which class to replace:",
                "value": "{{atCursor:$1}}"
              },
              {
                "name": "replace",
                "placeHolder": "Enter class",
                "title": "Rename:",
                "value": "{{ask:find}}"
              }
            ],
            "replaceFind": "\\.{{ask:find}}\\b",
            "replaceGlobal": true,
            "text": ".{{ask:replace}}"
          },
          {
            "action": "replace",
            "replaceFind": "( class=\"[^\"]*?)\\b{{ask:find}}\\b([^\"]*\")",
            "replaceGlobal": true,
            "text": "$1{{ask:replace}}$2"
          }
        ]
      }
    },
    "[python]": {
      "import {{diag:$1}}": {
        "diagnostics": ["\"(.*?)\" is not defined"],
        "text": "import {{diag:$1}}\n",
        "where": "afterLast",
        "insertFind": "^(import |from \\w+ import )"
      }
    },
    "[typescript]": {
      "Add {{diagLookup:0}} to imports": {
        "diagnostics": ["'(.*?)' is not a known element"],
        "file": "{{lookup:appName}}.module.ts",
        "edits": [
          {
            "where": "afterLast",
            "insertFind": "^import",
            "text": "import { {{diagLookup:0}} } from '{{diagLookup:1}}';\n",
            "needsContinue": "nextCondFail"
          },
          {
            "condFind": "{{lookup:NgModuleStart}}",
            "where": "afterLast",
            "insertFind": "^import",
            "text": "@NgModule({ imports: [ {{diagLookup:0}} ] });\n",
            "needsContinue": false
          },
          {
            "condFind": ["{{lookup:NgModuleStart}}", "{{lookup:importsStart}}"],
            "condFindStop": "{{lookup:NgModuleEnd}}",
            "action": "replace",
            "replaceFind": ["{{lookup:NgModuleStart}}", "({{lookup:NgModuleEnd}})"],
            "text": ", imports: [ {{diagLookup:0}} ]\n$1",
            "needsContinue": false
          },
          {
            "action": "replace",
            "replaceFind": ["{{lookup:NgModuleStart}}", "{{lookup:importsStart}}", "(\\s*\\])"],
            "text": ", {{diagLookup:0}}$1"
          }
        ]
      }
    },
    "[php]": {
      "Add method {{diag:$1}} to {{atCursor:$1}}": {
        "diagnostics": ["Undefined method '(.*?)'."],
        "atCursor": "([_a-zA-Z0-9]+)::{{diag:$1}}",
        "file": "{{atCursor:$1}}.php",
        "where": "afterLast",
        "insertFind": "class {{atCursor:$1}} {",
        "text": "public function {{diag:$1}}() { }\n"
      }
    }
  },
  "my-code-actions.diagLookup": {
    "mat-expansion-panel": ["MatExpansionModule", "@angular/material/expansion"]
  },
  "my-code-actions.lookup": {
    "appName": "app",
    "NgModuleStart": "@NgModule\\(\\{",
    "NgModuleEnd": "\\}\\)",
    "importsStart": "imports\\s*:\\s*\\["
  }

TODO

  • Support for Multi Root Workspace (read configuration for current active editor)
  • use captured groups from the diagnostics regular expression or regular expression for the selected range or problem range
  • other actions like: delete
  • Default actions defined in the extenstion for a collection of languages
    The user has to select which default actions (languages) will be loaded. Actions stored in separate JSON files in the extension
  • Contact us
  • Jobs
  • Privacy
  • Manage cookies
  • Terms of use
  • Trademarks
© 2025 Microsoft