Skip to content

Commit

Permalink
v0.8.0 forwardNextExtendSelection, closes #10
Browse files Browse the repository at this point in the history
  • Loading branch information
rioj7 committed Aug 18, 2020
1 parent a29a4fc commit 644dc3b
Show file tree
Hide file tree
Showing 3 changed files with 160 additions and 27 deletions.
82 changes: 82 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ The ranges are specified in the `settings.json` file for entry `selectby.regexes
* `backwardInclude`: should the matched **backward** search text be part of the selection (default: true)
* `forwardInclude`: should the matched **forward** search text be part of the selection (default: true)
* `forwardNextInclude`: should the matched **forwardNext** search text be part of the selection (default: true)
* `forwardNextExtendSelection`: should we extend the selection with the matched **forwardNext** search text if the begin of the selection matches the **forward** regex (default: false). See explanation.
* `copyToClipboard`: copy the selection to the clipboard (default: false)
* `showSelection`: modify the selection to include the new searched positions. Useful if `copyToClipboard` is true. (default: true)
* `debugNotify`: show a notify message of the used search properties (User and Workspace properties are merged) (default: false)
Expand Down Expand Up @@ -111,6 +112,87 @@ Define a keybinding:
}
```

## Select By with forwardNextExtendSelection

Based on idea by [johnnytemp](https://github.com/rioj7/select-by/pull/10).

If you set `forwardNextExtendSelection` to `true` the selection is extended with the next occurrence of `forwardNext` Regular Expression if the start of the selection matches the `forward` Regular Expression.

The `forwardNext` Regular Expression must match at the selection end. If there is not a match at the selection end we start a new `forward` search at the selection end, just like a normal `forward`-`forwardNext`. You can extend the `forwardNext` match to any position by prefixing the Regular Expression with `[\s\S]*?` or `.*?` (non greedy anything), depending if you want to include new lines or not.

At the moment it only works if `forwardNextInclude` is `true`.

### Example 1: Extend with the next item of a tuple

If there are no more elements in the tuple after the selection go to the next tuple.

Put this in your `settings.json` file:

```json
"selectby.regexes": {
"extendNextTupleItem": {
"forward": "\\(",
"forwardNext": "[^,)]+(\\s*,\\s*)?",
"forwardInclude": false,
"forwardNextExtendSelection" : true
}
}
```

And define a keybinding.

If it is not important that the selection starts at the first tuple item and the items are all word charcters you can use:

```json
"selectby.regexes": {
"extendNextTupleItem2": {
"forward": "(?=\\w+)",
"forwardNext": "\\w+(\\s*,\\s*)?",
"forwardNextExtendSelection" : true
}
}
```

The `forward` Regular Expression searches for a location that is followed by a tuple item. It is an empty match.

### Example 2: Extend selection always with forwardNext

If you want to extend the selection always with `forwardNext`, you can set the `forward` Regular Expression to the string `(?=[\s\S])` or `(?=.)`, depending if you want to include new lines or not.

The examples are to extend the selection with the next part of the sentence. If you have line breaks in the sentence you should use the second alternative.

```json
"selectby.regexes": {
"extendWithSentensePart": {
"forward": "(?=.)",
"forwardNext": ".*?[,.]",
"forwardNextExtendSelection" : true
}
}
```

or

```json
"selectby.regexes": {
"extendWithSentensePart": {
"forward": "(?=[\s\S])",
"forwardNext": "[\s\S]*?[,.]",
"forwardNextExtendSelection" : true
}
}
```

But this could already be done with this setting:

```json
"selectby.regexes": {
"extendWithSentensePart": {
"forward": "[\\s\\S]*?[,.]"
}
}
```

## User and Workspace settings
The Workspace/folder setting does override the global User setting. The settings are deep-merged.

Expand Down
96 changes: 71 additions & 25 deletions extension.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@ function activate(context) {
var regex;
regex = getProperty(search, "backward");
if (regex && isString(regex)) {
var incMatch = getProperty(search, "backwardInclude", true);
let incMatch = getProperty(search, "backwardInclude", true);
regex = new RegExp(regex, flags);
selectStart = 0;
regex.lastIndex = 0;
var result;
let result;
while ((result=regex.exec(docText)) != null) {
if (result.index >= offsetCursor) break;
selectStart = incMatch ? result.index : regex.lastIndex;
Expand All @@ -41,40 +41,86 @@ function activate(context) {
var selectEnd = editor.document.offsetAt(editor.selection.end);
regex = getProperty(search, "forward");
var regexForwardNext = getProperty(search, "forwardNext");
let forwardNextInclude = getProperty(search, "forwardNextInclude", true);
let forwardNextExtendSelection = getProperty(search, "forwardNextExtendSelection", false);
let searchForwardNext = (forwardResult, startForwardNext) => {
if (!(regexForwardNext && isString(regexForwardNext))) return [undefined, undefined];
let regexForwardNextModified = regexForwardNext.replace(/{{(\d+)}}/g, (match, p1) => {
let groupNr = parseInt(p1, 10);
if (groupNr >= forwardResult.length) { return ""; }
return forwardResult[groupNr];
});
let regex = new RegExp(regexForwardNextModified, flags);
regex.lastIndex = startForwardNext;
let matchStart = docText.length;
let matchEnd = docText.length;
let result;
let incMatch = forwardNextInclude;
while ((result=regex.exec(docText)) != null) {
matchStart = result.index;
matchEnd = incMatch ? regex.lastIndex : result.index;
break;
}
return [matchStart, matchEnd];
};
var startForwardNext = selectEnd;
var forwardResult = [];
let needNewForwardSearch = true;
if (regex && isString(regex)) {
var incMatch = getProperty(search, "forwardInclude", true);
let forwardInclude = getProperty(search, "forwardInclude", true);
let incMatch = forwardInclude;
if (regexForwardNext && isString(regexForwardNext)) { // we have to flip the incMatch
incMatch = !incMatch;
}
regex = new RegExp(regex, flags);
regex.lastIndex = selectEnd;
selectEnd = docText.length;
var result;
while ((result=regex.exec(docText)) != null) {
selectEnd = incMatch ? regex.lastIndex : result.index;
startForwardNext = regex.lastIndex;
forwardResult = result.slice();
break;
if (forwardNextExtendSelection) {
selectStart = offsetCursor; // ignore any backward search
let result;
if (forwardInclude) {
regex.lastIndex = selectStart; // check if forward is found at begin of selection
if ((result=regex.exec(docText)) != null) {
if (result.index === selectStart) {
needNewForwardSearch = false;
forwardResult = result.slice();
}
}
} else { // check if forward is exact before selection
let matchEnd = docText.length;
regex.lastIndex = 0;
let result;
while ((result=regex.exec(docText)) != null) {
matchEnd = regex.lastIndex;
if (matchEnd >= offsetCursor) break;
}
if (matchEnd === offsetCursor) {
needNewForwardSearch = false;
forwardResult = result.slice();
}
}
if (!needNewForwardSearch) { // test if forwardNext is at selectEnd
if (searchForwardNext(forwardResult, selectEnd)[0] !== selectEnd) {
needNewForwardSearch = true;
}
}
}
if (needNewForwardSearch) {
regex.lastIndex = selectEnd;
selectEnd = docText.length;
startForwardNext = docText.length;
let result;
while ((result=regex.exec(docText)) != null) {
selectEnd = incMatch ? regex.lastIndex : result.index;
startForwardNext = regex.lastIndex;
forwardResult = result.slice();
break;
}
}
}
if (regexForwardNext && isString(regexForwardNext)) {
selectStart = selectEnd;
var incMatch = getProperty(search, "forwardNextInclude", true);
regexForwardNext = regexForwardNext.replace(/{{(\d+)}}/g, (match, p1) => {
let groupNr = parseInt(p1, 10);
if (groupNr >= forwardResult.length) { return ""; }
return forwardResult[groupNr];
});
regex = new RegExp(regexForwardNext, flags);
regex.lastIndex = startForwardNext;
selectEnd = docText.length;
var result;
while ((result=regex.exec(docText)) != null) {
selectEnd = incMatch ? regex.lastIndex : result.index;
break;
if (needNewForwardSearch) {
selectStart = selectEnd;
}
selectEnd = searchForwardNext(forwardResult, startForwardNext)[1];
}
if (getProperty(search, "copyToClipboard", false)) {
vscode.env.clipboard.writeText(docText.substring(selectStart, selectEnd)).then((v)=>v, (v)=>null);
Expand Down
9 changes: 7 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"description": "Select text range based on certain criteria (regex,...) and move cursor by regex",
"publisher": "rioj7",
"license": "MIT",
"version": "0.7.4",
"version": "0.8.0",
"engines": {"vscode": "^1.37.0"},
"categories": ["Other"],
"keywords": ["select","text","range", "move", "cursor"],
Expand Down Expand Up @@ -90,6 +90,10 @@
"type": "boolean",
"description": "(Optional) should the matched forwardNext search text be part of the selection (default: true)"
},
"forwardNextExtendSelection": {
"type": "boolean",
"description": "(Optional) should we extend the selection with the matched forwardNext search text if the begin of the selection matches the forward regex (default: false)"
},
"copyToClipboard": {
"type": "boolean",
"description": "(Optional) copy the selection to the clipboard (default: false)"
Expand All @@ -110,7 +114,8 @@
"dependencies": {
"backwardInclude": ["backward"],
"forwardInclude": ["forward"],
"forwardNextInclude": ["forwardNext"]
"forwardNextInclude": ["forwardNext"],
"forwardNextExtendSelection": ["forwardNext"]
}
}
},
Expand Down

0 comments on commit 644dc3b

Please sign in to comment.