I am using latex on Sublime text 3; I would like to put $ sign in a wrap way around the highlighted text. For example, I have a character say
X_{d}
I would like it to do a keyboard shortcut that prints a $ sign before it and after it. How may I do so when I press on alt-shift-w I get
<p>X_{d}</p>
Is there a way to get $?
like $X_{d}$ rather than <p>
You can achieve this by adding the following to your User keybindings:
{ "keys": ["alt+shift+w"], "command": "insert_snippet", "args": { "contents": "\\$${1:$SELECTION}\\$" },
"context": [
{ "key": "selector", "operator": "equal", "operand": "text.tex" },
]
},
To make it reversible, you'll need to write a Python plugin, as the functionality isn't built in to ST:
Tools menu -> Developer -> New Plugin...
Select all and replace with the following
import sublime
import sublime_plugin
import re
class TextAroundSelectionEventListener(sublime_plugin.EventListener):
def on_query_context(self, view, key, operator, operand, match_all):
if key not in ('text_preceding_selection', 'text_following_selection'):
return None
match = False
for sel in view.sel():
line = view.line(sel)
before_sel = sublime.Region(line.begin(), sel.begin())
after_sel = sublime.Region(sel.end(), line.end())
check_region = before_sel if key == 'text_preceding_selection' else after_sel
if operator in (sublime.OP_EQUAL, sublime.OP_NOT_EQUAL):
match = view.substr(check_region) == operand
if operator == sublime.OP_NOT_EQUAL:
match = not match
else:
if operator in (sublime.OP_REGEX_MATCH, sublime.OP_NOT_REGEX_MATCH):
operand += r'$'
method = re.match if operator in (sublime.OP_REGEX_MATCH, sublime.OP_NOT_REGEX_MATCH) else re.search
try:
match = bool(method(operand, view.substr(check_region)))
except re.error as e:
print('error in keybinding context operand "' + str(operand) + '" for key "' + key + '":', e)
return None
if operator in (sublime.OP_NOT_REGEX_MATCH, sublime.OP_NOT_REGEX_CONTAINS):
match = not match
if match != match_all:
return match
return match
class TrimCharsAroundSelection(sublime_plugin.TextCommand):
def run(self, edit, **kwargs):
chars_to_trim = kwargs.get('chars_to_trim', 1)
for sel in reversed(self.view.sel()):
self.view.replace(edit, sublime.Region(sel.end(), sel.end() + chars_to_trim), '')
self.view.replace(edit, sublime.Region(sel.begin() - chars_to_trim, sel.begin()), '')
Save in the folder ST suggests (Packages/User/) as text_around_sel.py
Then, use the following keybindings:
{ "keys": ["alt+shift+w"], "command": "insert_snippet", "args": { "contents": "\\$${1:$SELECTION}\\$" },
"context": [
{ "key": "selector", "operator": "equal", "operand": "text.tex" },
{ "key": "text_preceding_selection", "operator": "not_regex_contains", "operand": "\\$$" },
{ "key": "text_following_selection", "operator": "not_regex_contains", "operand": "^\\$" },
]
},
{ "keys": ["alt+shift+w"], "command": "trim_chars_around_selection", "args": { "chars_to_trim": 1 },
"context": [
{ "key": "selector", "operator": "equal", "operand": "text.tex" },
{ "key": "text_preceding_selection", "operator": "regex_contains", "operand": "\\$$" },
{ "key": "text_following_selection", "operator": "regex_contains", "operand": "^\\$" },
]
},
Explanation and reasoning:
The preceding_text and following_text contexts that are built in to ST always include the selected text, no matter where the text selection caret is, making it no use for detecting text around/outside the selection.
(If the selection included the dollars at either end, it would be possible without creating any new context listeners, by using the text key, and ^ and $ anchors.)
Therefore, we need to write our own contexts that will correctly ignore the selection. Unfortunately, limitations in Sublime's (Find) API mean that we have to use Python's re module to do this, which is a much less powerful regex engine - though for the purposes of this question, it doesn't matter. (Probably there is a "hacky" way round it if needed, by copying the relevant contents of the line into a temporary hidden view (i.e. output panel) and using Sublime's find API on that to ensure the anchors work as expected etc., but that is out of scope for this task.)
The trim_chars_around_selection command then goes through all selections in reverse order (so the selection offsets from the beginning of the document don't change while the document is being modified by the plugin) and removes the specified number of characters from either end of the selection.
The code given by #Keith Hall could be further generalize to cut any and add any value. I will point this out here.
Suppose you want to wrap a latex file with a certain R and T that is by pressing on a combination of characters the selected string say Tamer would be RTamerT and when press on the key bindings once again it becomes Tamer.
{ "keys": ["alt+shift+q"], "command": "insert_snippet", "args": { "contents": "R${1:$SELECTION}T", "scope": "text.tex.latex"},
"context": [
{ "key": "selector", "operator": "equal", "operand": "text.tex" },
{ "key": "text_preceding_selection", "operator": "not_regex_contains", "operand": "R" },
{ "key": "text_following_selection", "operator": "not_regex_contains", "operand": "^T" },
]
},
{ "keys": ["alt+shift+q"], "command": "trim_chars_around_selection", "args": { "chars_to_trim": 1, "scope": "text.tex.latex" },
"context": [
{ "key": "selector", "operator": "equal", "operand": "text.tex" },
{ "key": "text_preceding_selection", "operator": "regex_contains", "operand": "R" },
{ "key": "text_following_selection", "operator": "regex_contains", "operand": "^T" },
]
},
I thought of sharing as I wanted to find a new kind of wrap that generalizes the code of Keith but do not know how to do the coding in sublime text. Trial and error have help me to find my way and thought of sharing it with you
I created a custom map using Inkscape as described on the HighMaps docs pages at: http://www.highcharts.com/docs/maps/custom-maps
Everything up to step 16 seems to go smoothly.
Step 16 says that the only remaining thing to do is to add data or use the MapData option and this is where I am struggling.
How does one link the custom shapes in the map to data points? Using the shape name in a JoinBy?
http://jsfiddle.net/GeertClaes/aWJ2D/
$(function () {
// Initiate the chart
$('#container').highcharts('Map', {
title:{text:''},
subTitle:{text:''},
credits:{enabled:false},
legend:{enabled: false},
series:
[
{
"type": "map",
"data": [
{
"name": "Status1-CurrentPeriod",
"path": "M0,-695,0,-682C1,-682,2,-683,3,-683,15,-683,25,-672,25,-658,25,-645,15,-634,3,-634,2,-634,1,-634,1,-634L1,-622,108,-622,107,-694,0,-695z"
},
{
"name": "Status1-Period-1",
"path": "M0,-684,1,-633C15,-635,26,-646,26,-658,26,-672,14,-682,0,-684z"
},
{
"name": "Status2-CurrentPeriod",
"path": "M178,-695,178,-682C179,-682,180,-683,181,-683,193,-683,203,-672,203,-658,203,-645,193,-634,181,-634,180,-634,180,-634,179,-634L179,-622,286,-622,285,-694,178,-695z"
},
{
"name": "Status2-Period-1",
"path": "M178,-684,179,-633C193,-635,204,-646,204,-658,204,-672,193,-682,178,-684z"
},
{
"name": "Status3-CurrentPeriod",
"path": "M357,-695,357,-682C358,-682,359,-683,360,-683,372,-683,382,-672,382,-658,382,-645,372,-634,360,-634,359,-634,359,-634,358,-634L358,-622,465,-622,464,-694,357,-695z"
},
{
"name": "Status3-Period-1",
"path": "M357,-684,358,-633C372,-635,383,-646,383,-658,383,-672,372,-682,357,-684z"
},
{
"name": "Status4-CurrentPeriod",
"path": "M535,-695,535,-682C536,-682,537,-683,538,-683,550,-683,560,-672,560,-658,560,-645,550,-634,538,-634,537,-634,536,-634,536,-634L536,-622,643,-622,642,-694,535,-695z"
},
{
"name": "Status4-Period-1",
"path": "M535,-684,536,-633C550,-635,561,-646,561,-658,561,-672,549,-682,535,-684z"
},
{
"name": "Status5-CurrentPeriod",
"path": "M713,-695,713,-682C714,-682,715,-683,716,-683,728,-683,738,-672,738,-658,738,-645,728,-634,716,-634,715,-634,715,-634,714,-634L714,-622,821,-622,820,-694,713,-695z"
},
{
"name": "Status5-Period-1",
"path": "M713,-684,714,-633C728,-635,739,-646,739,-658,739,-672,728,-682,713,-684z"
},
{
"name": "Status6-CurrentPeriod",
"path": "M892,-695,892,-682C893,-682,894,-683,895,-683,907,-683,917,-672,917,-658,917,-645,907,-634,895,-634,894,-634,893,-634,893,-634L893,-622,1000,-622,999,-694,892,-695z"
},
{
"name": "Status6-Period-1",
"path": "M892,-684,893,-633C907,-635,918,-646,918,-658,918,-672,907,-682,892,-684z"
}
]
}
]
});
});
There's a couple of ways:
1.) The easiest is to add it into your data using the value property. This is discouraged because it hardcodes the value for the map paths:
"data": [
{
"name": "Status1-CurrentPeriod",
"path": "M0,-695,0,-682C1,-682,2,-683,3,-683,15,-683,25,-672,25,-658,25,-645,15,-634,3,-634,2,-634,1,-634,1,-634L1,-622,108,-622,107,-694,0,-695z",
"value": 6 // <-- here's a numerical value for this path
}
2.) Seperate your mapData from your data. Map the values in mapData to the values in data with a joinBy. This makes your map paths reusable:
series: [{
"type": "map",
"joinBy": ['name', 'name'], // <- mapping 'name' in data to 'name' in mapData
"data": [
{
"name": "Status1-CurrentPeriod",
"value": 6
}
],
"mapData": [
{
"name": "Status1-CurrentPeriod",
"path": "M0,-695,0,-682C1,-682,2,-683,3,-683,15,-683,25,-672,25,-658,25,-645,15,-634,3,-634,2,-634,1,-634,1,-634L1,-622,108,-622,107,-694,0,-695z"
}
...
}]
Update fiddle here.