Sublime Text binding: insert semicolon at eol and come back - macros

I'm new to Sublime Text key bindings. Is there a way, when the caret isn't at the end of the line, to insert a semicolon at the end? In macro I guess it'd be: go to eol -> insert ; -> come back. But I'm not sure how to do the come back part.
Thanks.

You would have to use a plugin I think since you want to restore the previous position, though I could be wrong. This is an ST3 version.
import sublime
import sublime_plugin
class SemicolonInsertCommand(sublime_plugin.TextCommand):
def run(self, edit):
region_name = "original_cursors"
view = self.view
view.add_regions(region_name, view.sel())
view.run_command("move_to", {"extend": False, "to": "eol"})
view.run_command("insert", {"characters": ";"})
view.sel().clear()
cursors = view.get_regions(region_name)
for cursor in cursors:
view.sel().add(sublime.Region(cursor.b, cursor.b))
view.erase_regions(region_name)
Create a key binding with the command semicolon_insert. I assumed your macro definition was supposed to be eol not eof.
Edit:
ST2 compatible version
import sublime
import sublime_plugin
class SemicolonInsertCommand(sublime_plugin.TextCommand):
def run(self, edit):
region_name = "original_cursors"
view = self.view
view.add_regions(region_name, list(view.sel()), "")
view.run_command("move_to", {"extend": False, "to": "eol"})
view.run_command("insert", {"characters": ";"})
view.sel().clear()
cursors = view.get_regions(region_name)
for cursor in cursors:
view.sel().add(sublime.Region(cursor.b, cursor.b))
view.erase_regions(region_name)

Record a macro, save it, and configure a shortcut for it.
Create the Macro
In vintage Mode
Start recording macro q followed by MACRO_ID ( LETTER [a-z] )
Create a bookmark Ctrl+F2
Move to end of line and into insert mode Shift+A
Add the semi-colon ; and put back in command mode Esc
Go to bookmark Shift+F2
Remove bookmark Ctrl+Shift+F2
Stop recording macro q
You can replay your macro: # followed by YOUR_MACRO_ID
Save the macro
Go to: Tools > Save Macro...
Name it and save it e.g. Packages/User/Macros/complete-semi-colon.sublime-macro
Create a shortcut for the macro
Open your Key Bindings config file: Preferences > Key Bindings - User
Create a shortcut for your new macro e.g. Ctrl+; e.g.
{
"keys": ["ctrl+;"],
"command": "run_macro_file",
"args": {
"file": "Packages/User/Macros/complete-semi-colon.sublime-macro"
}
}
You can do something similar without vintage mode. The important parts are the bookmark, and the macro shortcut configuration.
Enjoy.

Slight modification to code above. Add toggle behavior. So when you again invoke key combination semicolon will be removed. This is Sublime Text 3 version.
class SemicolonInsertCommand(sublime_plugin.TextCommand):
def run(self, edit):
region_name = "original_cursors"
view = self.view
view.add_regions(region_name, view.sel())
view.run_command("move_to", {"extend": False, "to": "eol"})
pos = view.sel()[0].begin()
last_chr = view.substr(pos-1)
if last_chr != ';':
view.run_command("insert", {"characters": ";"})
else:
view.run_command("left_delete")
view.sel().clear()
cursors = view.get_regions(region_name)
for cursor in cursors:
view.sel().add(sublime.Region(cursor.b, cursor.b))
view.erase_regions(region_name)
To add keyboard shortcut insert next line to "Preferences > Key Bindings - User":
{ "keys": ["ctrl+alt+enter"], "command": "semicolon_insert" }

Related

vs code snippet: how to use variable transforms twice in a row

See the following snippet:
"srcPath":{
"prefix": "getSrcPath",
"body": [
"$TM_FILEPATH",
"${1:${TM_FILEPATH/(.*)src.(.*)/${2}/i}}",
"${TM_FILEPATH/[\\\\]/./g}"
]
},
The output of lines 1-3 is :
D:\root\src\view\test.lua
view\test.lua
D:.root.src.view.test.lua
How can I get output like 'view/test.lua'?
Try this snippet:
"srcPath":{
"prefix": "getSrcPath",
"body": [
"$TM_FILEPATH",
"${TM_FILEPATH/.*src.|(\\\\)/${1:+/}/g}",
"${TM_FILEPATH/[\\\\]/\\//g}"
]
}
.*src.|(\\\\) will match everything up to and including the ...src\ path information. We don't save it in a capture group because we aren't using it in the replacement part of the transform.
The (\\\\) matches any \ in the rest of the path - need the g flag to get them all.
Replace: ${1:+/} which means if there is a capture group 1 in .*src.|(\\\\) then replace it with a /. Note we don't match the rest of the path after src\ only the \'s that might follow it. So, not matching those other path parts just allows them to remain in the result.
You were close on this one:
"${TM_FILEPATH/[\\\\]/\\//g}" just replace any \\\\ with \\/.
With the extension File Templates you can insert a "snippet" that contains a variable and multiple find-replace operations.
With a key binding:
{
"key": "ctrl+alt+f", // or any other combo
"command": "templates.pasteTemplate",
"args": {
"text": [
"${relativeFile#find=.*?src/(.*)#replace=$1#find=[\\\\/]#flags=g#replace=.#}"
]
}
}
At the moment only possible with a key binding or via multi command (or similar). Will add an issue to also make it possible by prefix.
Also some of the standard variables are missing.

unnamed/slim snippets in vscode

I'm using vscode to edit latex (with the latex workshop plugin), and
I recently started creating my own snippets and really like the feature. However, I find the syntax a bit heavy for creating "small" snippets that just abbreviate frequent sequences of words. In particular, I find it cumbersome to have to give a 'name' to each snippet.
Is there a mechanism for "slim" snippets/aliases, that would e.g. take as input a file where each snippet is one line -- the first word being the abbreviation and the rest what is abbreviated?
You have a couple of options. One is to write an extension that could do this - I'll show code that works like an extension that'll work - it looks complicated but use is pretty simple.
Second, you can come close using the Hyper Snips extension where your snippet file (say latex.hsnips) could like like this:
snippet dategreeting "Gives you the current date!"
Hello from your hsnip on ``rv = new Date().toDateString()``!
endsnippet
snippet // "Fraction simple" A
\frac{$1}{$2}$0
endsnippet
snippet stte A
some text to expand
endsnippet
The descriptions in "" are not necessary and I eliminated it in the last snippet. The A flag will immediately insert your replacement text, without it you would Tab to insert the replacement text. As the examples here show you can use javascript within a snippet if you want.
The gif doesn't show it well bit here is a demo of auto-expansion with Hyper Snips:
Alternatively, download the extension macro-commander. It allows you to use vscode extension commands in a macro within your settings. This macro would go into your settings.json file:
"macros": {
"slimSnippetsInsertion" : [
{
"javascript": [
"const editor = vscode.window.activeTextEditor;",
"const document = editor.document;",
"const we = new vscode.WorkspaceEdit();",
"const cursorPosition = editor.selection.active;", // use whether an actual selection or not, returns a Position
"let keyWordRange = document.getWordRangeAtPosition(cursorPosition);", // returns a Range of start/end Positions or undefined
"if (keyWordRange === undefined) {",
"await window.showInformationMessage(`cursor must be in or immediately after word to be replaced`);",
"return;",
"}",
"let wordAtCursor = document.getText(keyWordRange);", // this is the key word to find in slimSnippets.txt
"const thisWorkspace = vscode.workspace.workspaceFolders[0].uri.toString();",
// file:///c:/Users/Mark/OneDrive/Test Bed
"const snippetFileContent = await vscode.workspace.fs.readFile(vscode.Uri.parse(`${thisWorkspace}/.vscode/slimSnippets.txt`));",
"const snippets = snippetFileContent.toString();",
// ignore leading spaces/tabs before keys
// using a named capturing group for the replacement text
"const regex = new RegExp(`\\r?(?<=\\n|^)[\\t ]*(?<key>${wordAtCursor})[\\t ]+?(?<replacementText>.*?)(?=\\r?\\n|$)`);",
"let found = snippets.match(regex);", // returns null if no matches
// matched a key but only spaces as replacement text, so do nothing and exit
"if (found && found.groups.replacementText.trimStart().length === 0) {",
"await window.showInformationMessage(`replacement text is only spaces, not replacing`);",
"return;",
"}",
"if (found) {", // found at least a matching key
"if (found.groups.replacementText) {", // found non-space replacement text
// replace `\n` and `\t` with unicode values for newline and tab
"let replace = found.groups.replacementText.replace(/\\\\n/g, '\\u000A').replace(/\\\\t/g, '\\u0009');",
"let snippet = new vscode.SnippetString(replace)",
"if (editor.selections.length === 1) editor.insertSnippet(snippet, keyWordRange);", // if zero or one selection"
// if multiple selections, uses first key and replacement text"
"else editor.insertSnippet(snippet);",
"}",
"else await window.showInformationMessage(`matching key found but with no replacement text in slimSnippets.txt`);",
"}",
"else await window.showInformationMessage(`no matching key found in slimSnippets.txt`);",
]
}
You can see where I made it to read a simpleSnippets.txt file located in the .vscode folder in the workspace - but you can change the location as long as you alter the path info in the command: vscode.workspace.fs.readFile above.
The slimSnippets.txt file is just a simple text file where the first word in each line is the key and the rest of the line is the replacement.
howdy1 $1 first $2 sentence with tabstops
howdy1 this won't be used, duplicate key above
howdy2 second sentence with variable $TM_FILENAME
key3 videos 111111 // one space necessary between key and replacement text
// it will be removed, others retained
key1 222222
stte some text to expand
mt2e more text to expand
[replacement text can have placeholders, tabstops and choices just like regular snippets]
[join multiple-lines snippets into one string with newlines as below]
[some text\nsome more text] [\t can be used for tabs]
key5 line 1\n\tline 2\n\t\tline 3
Keys are single words and if there is no replacement text (or there are only spaces in the file after a key) nothing will happen - the key will not be replaced.
The text actually inserted can be plain text or use vscode's snippet format - see the sample text file above.
The cursor must be immediately after the word or in the word and the word can be selected or not. It must be a word in the regex sense - not continuous text adjoining the word before or after it - just a standalone word, it can be anywhere on the line.
If you have duplicate keys, the first will be used. There can be empty line spaces between key/replacement lines or not.
You will not get intellisense for the keys. I may work on that.
Finally, you will need a keybinding to trigger this macro (in keybindings.json):
{
"key": "ctrl+;", // whatever keybinding you wish
"command": "macros.slimSnippetsInsertion"
},

Sublime Text: Create a folder with multiple children files with one command

Is it possible to create a command that would create a folder and multiple children files with the same name and different extensions?
For example I would open the command and type in a name of "desktop-header"
the result would be the following being created
desktop-header (folder)
desktop-header.js
desktop-header.php
_desktop-header.sass
I've been following BEM and end up needing to create all the blocks manually.
I'm not even sure what to search to see if there is an answer to this.
thanks!
Yes, you can write arbitrary python code in the a command. Just select Tools > Developer > New Plugin... and paste the following code. This will create a folder, which contains the 3 files, relatively to the current view.
import os
import sublime
import sublime_plugin
class CreateBemFilesCommand(sublime_plugin.WindowCommand):
def run(self):
window = self.window
view_path = window.active_view().file_name()
if not view_path:
sublime.error_message("Save your file first.")
return
base_folder_path, _ = os.path.split(view_path)
def on_done(name):
folder_path = os.path.join(base_folder_path, name)
# add your file names
file_names = [
name + ".js",
name + ".php",
"_" + name + ".sass"
]
file_paths = [
os.path.join(folder_path, file_name)
for file_name in file_names
]
# create the folder
os.makedirs(folder_path, exist_ok=True)
# create the files
for file_path in file_paths:
with open(file_path, "a"):
pass
# open the files in Sublime Text
window.open_file(file_path)
window.show_input_panel(
"Input the folder name", "", on_done, None, None)
afterwards create a keybinding like this:
{
"keys": ["alt+shift+b"],
"command": "create_bem_files",
},

What's The Best Way To Write Multi-Line Code Snippets In VS-Code?

In Sublime Text, multi-line code snippets can be defined with white-spaces in a snippet file.
But as far as I know, VS-Code needs a JSON entry. These require either:
Hard-breaks into a list of double-quoted strings, or
Soft-break a long string using line-breaks \n
This is inconvenient compared to the WYSIWYG approaches other IDEs provide out of the box.
Are there better ways for defining long-blocks of code?
You can define the body of your snippet as an array of strings, each beginning on a new line.
Like this:
"Create for loop":{
"prefix": "mkfor",
"body":[
"for(int i = 0; i < 3; i++)",
"{",
" //code goes here",
"}"
],
"description": "Creates a for loop"
}
or if you install Easy Snippet Maker extension, you can create your snippets by highlighting texts.
You can check out this video for a quick short tutorial
https://youtu.be/g1ouTcFxQSU
Go to File --> Preferences --> User Snippets. Select your preferred language.
Now type the following code to make a for loop snippet:
"Create for loop":{
"prefix": "for",
"body":[
"for(int i = 0; i < 10; i++)",
"{",
" //code goes here",
"}"
],
"description": "Creates a for loop"
}
You are done.
Type "for" in the editor and use the first prediction.
SHORTCUT--
install Snippet-creator extension.
Highlight the code that you need to make snippet.
press ctrl+shift+P and type "Create snippet" on the command palette and
press ENTER.
select language for which you want to create snippet(eg:-CPP), then type
snippet name, type snippet shortcut and then type snippet description.
You are now good to go.
Type the snippet shortcut in the editor that you entered in step 4, and select the prediction (if no prediction comes press ctrl+space) that comes first.
Hope this helps :)
Note: goto File->Preferences->User Snippets. Then select the language in which youcreated the snippet. You will find the snippet there.
I cannot find a good way to create multi-line snippets either. It's probably one of the features I'd like to see improved the most. As another answer suggested, there are a couple extensions out there to help with Snippet creation (like this and this). However, they don't escape literal dollar signs and indentation isn't great.
When browsing for answers to this, I stumbled across a Pen by Denis Malinochkin (linked from this issue). However, it also did not escape dollar signs properly, so I forked it and added this line to handle literal dollar signs. Here it is: https://codepen.io/cbejensen/pen/WXLxaE
Hope that helps!
P.S. - This is the line I added:
line = line.replace(new RegExp(/\$/, 'g'), '\\$');
I've created an extension to store snippets in a markdown file:
https://marketplace.visualstudio.com/items?itemName=usernamehw.snippets-in-markdown
Hit cmd+shift+p on mac machine, and search for "Configure User Snippets" then create a file and paste below json code.
provide prefix, Body, and description.
Reference: https://code.visualstudio.com/docs/editor/userdefinedsnippets
{
"forLoop": {
"prefix": "forLoop",
"body": [
"for (const ${2:element} of ${1:array}) {",
"\t$0",
"}"
],
"description": "For Loop"
},
"reactClass": {
"prefix": "reactClass",
"body": [
"import React from 'react';",
"class ${1:ComponentName} extends React.Component {",
"\t$0constructor(props) {",
"\t$0\t$0super(props)",
"",
"render() {",
"return (<div> ${2:Component} </div>)",
"}",
"export default ${3:ComponentName}"
],
"description": "For React Component class"
},
"function": {
"scope": "javascript,typescript",
"prefix": "function",
"body": [
"import React from 'react';",
"import withStyles from '#material-ui/core/styles/withStyles';",
"import { makeStyles } from '#material-ui/core/styles';",
"",
"import Styles from './style.js';",
"",
"const useStyles = makeStyles(Styles);",
"",
"function $1(props){",
"const classes = useStyles();",
"\treturn (",
"\t\t<React.Fragment>",
"\t\t\t<div className={classes.root}>",
"\t\t\t\t$1",
"\t\t\t</div>",
"\t\t</React.Fragment>",
"\t)",
"}",
"export default withStyles(useStyles)($1);"
],
"description": "react class"
}
}
I use this JSON Escape formatter(?) to process a large amount of HTML into a snippet:
https://www.freeformatter.com/json-escape.html
(The result of this process should be added in quotes "..." into the "body" part of the JSON object.
I've written a script which you can create your own complex snippets. just using the file you'd like. so you dont' need to write the source code in a string or string array.
https://github.com/banxi1988/vscode-snippets-ext-template

Inserting cursor in middle of Komodo Edit macro

I have set up a macro for Smarty in Komodo Edit which adds a {$|#dumpr} when I press my specified key binding (which, for info is Ctrl+Alt+P).
What I would like is the cursor to be automatically inserted between the $ and the | so I can type my variable name without having to manually navigate my way in there.
Any help?
Many thanks.
Use the currentPos and gotoPos methods:
komodo.assertMacroVersion(2);
if (komodo.view && komodo.view.scintilla) { komodo.view.scintilla.focus(); } // bug 67103
var currentPos = komodo.editor.currentPos;
komodo.editor.insertText(currentPos, '{$|#dumpr}');
komodo.editor.gotoPos(currentPos+2);