Travis Heeter
Travis Heeter

Reputation: 14074

Sublime Key Bindings for console.log depending on the file type

I'd like to use Ctrl+Shift+C to paste a basic output syntax relevant to the type of file I'm in.

console.log('');
console.log();

for .vue, .js or .html, and

writeDump();
abort;

for .cfc (also I want this to happen on Ctrl+Shift+W).

Here's the code I have so far:

{ "keys": ["ctrl+shift+c"],
  "command": "insert_snippet",
  "args": {
    "contents": "console.log(`${1:}$SELECTION`);\nconsole.log(${1:}$SELECTION);\n${0}"
  }, "context":
  [
    { 
      "key": "selector", 
      "operator": "equal", 
      "operand": ["source.js","source.html"], 
      "match_all": true 
    }
  ]
},
{ "keys": ["ctrl+shift+c"],
  "command": "insert_snippet",
  "args": {
    "contents": "console.log(`${1:}$SELECTION`);\nconsole.log(${1:}$SELECTION);\n${0}"
  }, "context":
  [
    { 
      "key": "selector", 
      "operator": "equal", 
      "operand": "source.vue", 
      "match_all": true 
    }
  ]
},
{ "keys": ["ctrl+shift+w","ctrl+shift+c"],
  "command": "insert_snippet",
  "args": {
    "contents": "writeDump(${1:}$SELECTION\"$2);\nabort;\n${0}"
  }, "context":
  [
    { 
      "key": "selector", 
      "operator": "equal", 
      "operand": "source.cfc", 
      "match_all": true 
    }
  ]
},

However Ctrl+Shift+C always puts console.log, regardless of the file type, and Ctrl+Shift+W closes the current sublime window - meaning it's not being overwritten at all.

Upvotes: 0

Views: 127

Answers (2)

Travis Heeter
Travis Heeter

Reputation: 14074

@OdatNurd's amazing answer explained a lot of the inner-workings of key bindings, and put me on the right track, but I wanted to post my final solution without hijacking his post, and not in the comments because the code is too verbose to be readable there.

I have tested all of the functionality and this works as expected:

{ 
    "keys": ["ctrl+shift+c"],
    "command": "insert_snippet",
    "args": {
        "contents": 
        "console.log(`${1:}$SELECTION`);\nconsole.log(${1:}$SELECTION);\n${0}"
    }
},
{ 
    "keys": ["ctrl+shift+c"],
    "command": "insert_snippet",
    "args": {
        "contents": 
        "console.log(`${1:}$SELECTION`);\nconsole.log(${1:}$SELECTION);\n${0}"
    }, 
    "context": [
        { 
            "key": "selector", 
            "operator": "equal", 
            "operand": "text.html.vue",
            "match_all": true 
        }
    ]
},
{ 
    "keys": ["ctrl+shift+w"],
    "command": "insert_snippet",
    "args": {
        "contents": "writeDump(${1:}$SELECTION\"$2);\nabort;\n${0}"
    }
},
{ 
    "keys": ["ctrl+shift+c"],
    "command": "insert_snippet",
    "args": {
        "contents": "writeDump(${1:}$SELECTION\"$2);\nabort;\n${0}"
    }, 
    "context": [
        { 
            "key": "selector", 
            "operator": "equal", 
            "operand": "embedding.cfml", 
            "match_all": true 
        }
    ]
},

Working backwards, the same way Sublime reads key bindings:

Ctrl+Shift+C for ColdFusion files

  • As prescribed by @OdatNurd, I separated out the C and W bindings, with the C coming first. This will supersede any other Ctrl+Shift+C snippet, and make the writeDump appear rather than console.log, but only if the file is related to ColdFusion. Unfortunately, I'm not using CFML files so I wasn't able to figure out a way to distinguish between .cfml and .cfc. The CFML Package for Sublime does not seem to differentiate between the two - at least at the top scope level. If someone figures this out, let us know.

Ctrl+Shift+W

  • I decided to remove the context from this entry so that "close all windows" would never happen. If I make a mistake, I would rather writeDump be written - which is easily undone - than all the windows close - not so easy to undo.

Ctrl+Shift+C for Vue files

  • I kept this separate (I will address this later) and simply changed the operand to match the Scope Name (Ctrl+Alt+Shift+P), which was text.html.vue

Ctrl+Shift+C for everything else:

  • Similar to removing the context for Ctrl+Shift+W, I did that here as a catch-all for console.log. Now, Ctrl+Shift+C will paste the console.log snippet in any file that is not specifically defined in key-bindings. This is because Ctrl+Shift+C is not assigned to anything by default.

Upvotes: 0

OdatNurd
OdatNurd

Reputation: 22791

The key bindings in your question are not fully correct in that some scopes are (potentially) invalid and at least the first one has a syntax issue in it that's causing Sublime to ignore the context in it completely.

The scope for HTML files if you're using the built in syntax for HTML in Sublime is text.html and not source.html, which I've reflected in the bindings below. In addition the scopes for Vue and CFC files may also be incorrect. I don't use those languages and so I just installed the first package I found that supports syntax highlighting in those types of files, so you may be using something different than I picked.

To be sure, you can use Tools > Developer > Show Scope Name from the main menu (or press the associated key) to see the scope at the cursor in any file in a popup. Generally the first line in the popup is the one you want to use to constrain your key bindings to a particular type of file.

Additionally, in each of the (corrected) bindings below, the contents of the snippet have been adjusted slightly so that we can verify that the right thing is inserted at the right time.

Binding #1

{ "keys": ["ctrl+shift+c"],
  "command": "insert_snippet",
  "args": {
    "contents": "console.log(`${1:}$SELECTION`);\nconsole.log(${1:}$SELECTION);\n${0}"
  }, "context":
  [
    { 
      "key": "selector", 
      "operator": "equal", 
      "operand": ["source.js","source.html"], 
      "match_all": true 
    }
  ]
},

This binding is not valid because the operand in a context needs to be a string and not a list of strings. As such Sublime thinks that the context is broken and silently ignores it, which makes Ctrl+Shift+C active in every type of file, which is the behaviour you're currently seeing.

It is possible to include multiple scopes in the operand, but you do it as a single string and not as a list. An example of that is the following:

{ "keys": ["ctrl+shift+c"],
  "command": "insert_snippet",
  "args": {
    "contents": "/* js;html */ console.log(`${1:}$SELECTION`);\nconsole.log(${1:}$SELECTION);\n${0}"
  }, "context":
  [
    { 
      "key": "selector", 
      "operator": "equal", 
      "operand": "source.js, text.html", 
      "match_all": true 
    }
  ]
},

Here the operand is two scopes separated by commas, which makes the binding active as long as the scope matches either one of them. Additionally, the scope for HTML has been corrected from source.html to text.html.

Binding #2

{ "keys": ["ctrl+shift+c"],
  "command": "insert_snippet",
  "args": {
    "contents": "console.log(`${1:}$SELECTION`);\nconsole.log(${1:}$SELECTION);\n${0}"
  }, "context":
  [
    { 
      "key": "selector", 
      "operator": "equal", 
      "operand": "source.vue", 
      "match_all": true 
    }
  ]
},

This binding is technically valid, but source.vue may not be the correct scope for this, depending on what syntax definition you're using to provide syntax highlighting for Vue files.

{ "keys": ["ctrl+shift+c"],
  "command": "insert_snippet",
  "args": {
    "contents": "/* vue */ console.log(`${1:}$SELECTION`);\nconsole.log(${1:}$SELECTION);\n${0}"
  }, "context":
  [
    { 
      "key": "selector", 
      "operator": "equal", 
      "operand": "text.html.vue", 
      "match_all": true 
    }
  ]
},

For the Vue syntax highlighting package that I picked, the scope for Vue files is text.html.vue, which I've reflected here; otherwise everything about this binding is correct.

Note that the scope for HTML is text.html and the scope for Vue is text.html.vue. Following the rules of how scopes are matched, text.html.vue matches the scope text.html, which has some implications on the bindings depending on what you want to have happen (and assuming that this scope matches the package that you're using).

If you want to inject the same code in Vue as you do in HTML files, you can exclude this binding completely and the one for HTML above will match it and do what you want directly.

On the other hand, if you want to do something specific for Vue, then it's important that this binding come after the HTML binding in your key bindings file. Sublime evaluates key bindings from the bottom of the file up and uses the first one that matches. Since text.html.vue matches text.html, you need to have a specific rule for Vue files lower in the file to make sure it gets found and used first.

Binding #3

{ "keys": ["ctrl+shift+w","ctrl+shift+c"],
  "command": "insert_snippet",
  "args": {
    "contents": "writeDump(${1:}$SELECTION\"$2);\nabort;\n${0}"
  }, "context":
  [
    { 
      "key": "selector", 
      "operator": "equal", 
      "operand": "source.cfc", 
      "match_all": true 
    }
  ]
},

Again, except for the scope in this binding being potentially wrong, there's nothing wrong with this binding except that based on your description above, it may not be doing what you expect.

{ "keys": ["ctrl+shift+w","ctrl+shift+c"],
  "command": "insert_snippet",
  "args": {
    "contents": "writeDump(${1:}$SELECTION\"$2);\nabort;\n${0}"
  }, "context":
  [
    { 
      "key": "selector", 
      "operator": "equal", 
      "operand": "embedding.cfml", 
      "match_all": true 
    }
  ]
},

The scope in the CFML package I selected to test with uses embedding.cfml as the scope, which is reflected here.

Of more importance, using two keys as a list in the binding such as this turns the binding into a key chord. This means that in order to trigger this, you need to press Ctrl+Shift+W followed by Ctrl+Shift+c.

It sounds from the description in your question that you might want two distinct key bindings that both do the same thing. If that's the case then you need to duplicate the entire binding and change the key in the second one.

Upvotes: 1

Related Questions