简体   繁体   中英

Is there a way to select code between certain characters

TL DR

Is there some extension, or other functionality, to select code above and below the cursor that is surrounded by some characters, eg %% or % ===== or anything else?

Why

I am coding Matlab in VSCode, since the builtin Matlab editor lacks a lot of useful functionalities. However, One thing that I miss is the ability to run 'sections':

%% section 1
x = 0:0.01:pi;
y = sin(y);
plot(x,y);

%% section 2
x = 0:0.01:pi;
y = cos(y);
plot(x,y);

%% section 3
x = 0:0.01:pi;
y = tan(y);
plot(x,y);

A section can be run using Ctrl + Enter . Since I use Matlab on Windows, there is no support for running the Matlab interpreter from the terminal/cmd.

So I created some AutoHotKey scripts that will copy selected code, open the Matlab window, paste it, and run. This works fine, however, when I want to run a very large section, this means that I have to select this manually, and press my defined shortcut to call the AutoHotkey script. Hence above question.

So say I have the cursor at some line in section 2 , how can I select only the code in this section (including or excluding section 'headers', these are comments so does not matter).

I have made an extension Select By that allows the selection based on regular expressions relative to the cursor position. You can specify different expressions for forward and backward search and if you want to include the searched text in the selection.

You can set up to 5 regex searches.

The extension defines 5 commands that can be used in keyboard shortcuts

This can (of course) be done by writing a custom extension.

Since this seems like useful functionality in general and an interesting exercise, I've added the required capability to my personal vscode-smcpeak extension.

To use it:

  1. Install vscode-smcpeak . This has to be installed manually for now. At time of writing, 0.0.7 is latest.
  2. Install macros by ctf0 . This one can be installed from within VSCode. Restart VSCode after installing it. (See below regarding the choice of "macros" extension.)
  3. Add to your settings.json (File → Preferences → Settings, then click the "Open Settings (JSON)" icon in the upper right):
    // Custom macros for ctf0.macros extension
    "macros.list": {
        // https://stackoverflow.com/questions/57749780/is-there-a-way-to-select-code-between-certain-characters
        "selectPercentRegion": [
            {
                "command": "smcpeak.goToLineMatching",
                "args": {
                    "regex": "^%%",
                    "moveUp": true,
                    "select": false,
                    "allowZeroMove": true
                }
            },
            {
                "command": "smcpeak.goToLineMatching",
                "args": {
                    "regex": "^%%",
                    "moveUp": false,
                    "select": true,
                    "allowZeroMove": false
                }
            },
            "smcpeak.revealCurrentSelection"
        ]
    },
  1. Add to keybindings.json (File → Preferences → Keyboard Shortcuts, then click the "Open Keyboard Shortcuts (JSON)" icon in the upper right):
    {
        "key": "ctrl+alt+m",   // or whatever
        "command": "macros.selectPercentRegion"
    },

(Note: VSCode will always complain that macros.selectPercentRegion is not a valid command. That's a limitation of the "macros" extension.)

Then, with the cursor within a region delimited by the specified regexes, press the keybinding to activate the macro:

宏调用之前和之后的屏幕截图

Why use two extensions?

The accepted answer , by rioV8 uses a single extension to answer the OP's question. This looks like a good solution to me, and is simpler to use than mine, so I approve of that being the accepted answer.

However, there is an advantage to my approach: it allows the behavior to be modified in settings.json . For example, the OP asked in a follow-up question about having the command additionally copy the text to the clipboard after selecting. Using the macro-based solution, this is an easy modification to settings.json ; simply add:

            "editor.action.clipboardCopyAction"

to the end of the selectPercentRegion macro. (That is the command normally bound to Ctrl+C.)

Thus, while my suggestion has more moving parts, I personally prefer this approach.

Which macros extension to use?

As Mark noted in a comment, the most popular macros extension, geddski.macros , is unmaintained. It furthermore has a rather serious bug in that the commands are not properly sequenced, leading to race conditions. (I actually saw this once during my testing.)

There are two forks of geddski.macros on the marketplace , l7ssha.macrosRe and ctf0.macros . l7ssha.macrosRe only adds the "delay" ability , which is an awkward way to resolve the race conditions. ctf0.macros, on the other hand, fully fixes the race condition (via a complete rewrite ).

Therefore, I recommend ctf0.macros , and in fact have edited my answer to use it rather than the original geddski.macros extension.

However, be aware:

  • ctf0.macros uses macros.list rather than macros in settings.json
  • ctf0.macros requires a restart of VSCode after installation to activate

How it works

The additions are in vscode-smcpeak commit 6d5f5d4689 .

My extension registers a new command, smcpeak.goToLineMatching , that searches up or down for a line containing a regex. The logic is very simple, just a loop and regex test.

It also registers smcpeak.revealCurrentSelection , needed because otherwise the selected text might be offscreen and nothing scrolls to it by default.

The macro selectPercentRegion uses goToLineMatching to look upwards for one regex, setting the anchor (selection start) there, then uses it again to look down for another regex (although they are the same here), extending the selection to that point. Then it scrolls to ensure the selection is visible.

It should be straightforward to transplant this code to your own extension if you don't want the rest of the stuff that mine provides. (But mine does not bind any keys, so there should be no downside to having the extra stuff.)

Here is another way to do this, with an extension I wrote Find and Transform .

Make this keybinding in your keybindings.json (or it could be a setting too):

{
  "key": "alt+m",                   // whatever keybinding you want
  "command": "findInCurrentFile",
  "args": {
    "find": "^(%%[\\s\\S]+?)(?=^$)|(^%%[\\s\\S]+)",
    "run": [
      "$${",
        "const sections = vscode.window.activeTextEditor.selections;",
        "await vscode.commands.executeCommand('cursorUndo');",
        
        "const mySection = sections.find(section => section.contains(vscode.window.activeTextEditor.selection));",
        "if (mySection) {",
          "vscode.window.activeTextEditor.selections = [mySection];"
        "}",
        
      "}$$",
    ],

    "isRegex": true,
    "postCommands": "editor.action.clipboardCopyAction"
  }
}

The find regex finds and selects all %%.... sections. But since you only want the section where your cursor started, some code is run to restore that original cursor and then find that section that contains the one current cursor. Then that section is selected. And in the postCommand that selection is saved to the clipboard.

That is using javascript and the vscode extension api within a keybinding or setting.

选择光标周围的文本

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM