vscode-postfix-ts icon indicating copy to clipboard operation
vscode-postfix-ts copied to clipboard

[proposal] Add `{{exprLast}}` template placeholder

Open zardoy opened this issue 2 years ago • 6 comments

Template Examples

{
  "name": "destruct",
  "body": "const { {{exprLast}}$1 } = {{exprRest}}",
  "when": [
    "expression",
  ]
},
{
  "name": "log2",
  "body": "console.log('{{exprLast}}', {{expr}})",
  "when": [
    "identifier",
    "expression",
    "function-call"
  ]
},

Usage Examples

defaultSettings.getGeneralSettings().clipboardLinkDetection.destruct
// => destruct
const { clipboardLinkDetection } = defaultSettings.getGeneralSettings()

(await fetchData()).customField.destruct
// => destruct
const { customField } = (await fetchData())

defaultSettings.general.clipboardLinkDetection.log2
// => log2
console.log('clipboardLinkDetection', defaultSettings.general.clipboardLinkDetection)

// update to include even more ideas

checkInterval.clear /* -> */ clearInterval(checkInterval)
closeTimeout.clear /* -> */ clearTimeout(closeTimeout) 

While {{exprLast}} can be useful in some scenarios like logging or usage for some custom function that accepts label as first argument. Another example would be usage with test() & capitalize filter.

However, for now I can imagine only one case, where {{exprRest}} can be useful (destruct example above).

zardoy avatar Sep 29 '22 13:09 zardoy

If you want, I can add this kind of hovers & completions image

zardoy avatar Sep 29 '22 13:09 zardoy

Most sublime approach i’ve ever seen

sa2urami avatar Oct 05 '22 13:10 sa2urami

!!!

sa2urami avatar Oct 05 '22 13:10 sa2urami

I like the idea, especially the destructuring example. However I have mixed feelings when it comes to naming those new segments with exprLast and exprRest. It's kind of hardcoded to solve those two specific problems you have had but this is not too flexible. This time you need last segment and the rest segment but other time you might need first segment and rest (but then rest will be everything from second to last).

I came up with another idea which is just a small extension to what you have already done. Just instead of exprLast and the others why not make this flexible by design? Since this basically only makes sense for custom templates it should probably be always driven by configuration regex per template so for instance the examples above could look like this:

{
  "name": "destruct",
  "body": "const { {{expr:$last}}$1 } = {{expr:$rest}}",
  "groupsRegex": "(?<rest>.*)\\.(?<last>.*)(?:\\(\\))?",
  // alternatively:
  "groups": {
    "last": "\\.([^().]+)(?=$|\\(\\)$)",
    "rest": ".*(?=\\.)"
  },
  "when": [
    "expression",
  ]
},
{
  "name": "log2",
  "body": "console.log('{{expr:$last}}', {{expr}})",
  "groupsRegex": "\\.(?<last>[^().]*)(?:\\(\\))?$",
  "when": [
    "identifier",
    "expression",
    "function-call"
  ]
},

It matches pretty well: image

There is one flaw in that though. It might require quite advanced reg exps to be able to handle it and won't be as reliable as getting the last part from AST. Those were relatively easy examples but I can imagine it gets harder with more complex expressions. However we could mix those two solutions so for instance there could be few predefined segments, for instance $last could be handled by AST and maybe few others as well but the rest we can leave to regular expressions. What do you think?

ipatalas avatar Oct 28 '22 16:10 ipatalas

Wow, I actually have a lot of snippets (not postfixes) that use some kind of "groupsRegex", so I like the idea. on the other hand with these predefined placeholders we can not only avoid user of thinking how to handle complex expression but also reuse our code.

Also tbh I can't imagine for now other use cases, where other placeholders would be useful, but again I like this level of flexibility.

However, @ipatalas what do you think of merging this feature with exprRegex and exprLastRegex? (#92) It seems so logical to me (as I can imagine a lot of cases when I want to match only function name for example in function-call's). Or you can add some other property which regex will be matched before function args. Example:

cache[user.getId()].matchAgainstMe(…).postfix

Maybe we can add some kind of general property into snippets e.g.

{
"name":…,
"body":…,
"locations":…,
"regex":{
"expr":…
}
}

zardoy avatar Oct 28 '22 19:10 zardoy

Wow, I actually have a lot of snippets (not postfixes) that use some kind of "groupsRegex", so I like the idea. on the other hand with these predefined placeholders we can not only avoid user of thinking how to handle complex expression but also reuse our code.

Also tbh I can't imagine for now other use cases, where other placeholders would be useful, but again I like this level of flexibility.

Yeah, I can't imagine anything now so for now we can stay with this hardcoded ones and then when more ideas come into place we can extend that to be more flexible.

However, @ipatalas what do you think of merging this feature with exprRegex and exprLastRegex? (#92) It seems so logical to me (as I can imagine a lot of cases when I want to match only function name for example in function-call's).

Absolutely, it makes sense. It will allow more tailored postfixes which can be only valid for very specific use cases.

ipatalas avatar Oct 28 '22 19:10 ipatalas