Merge branch 'st2-updates'
@@ -3,7 +3,7 @@
|
||||
<metadata>
|
||||
<id>EthanBrown.SublimeText2.EditorPackages</id>
|
||||
<title>Sublime Text 2 - Editor Enhancing Packages</title>
|
||||
<version>0.0.5</version>
|
||||
<version>0.1.0</version>
|
||||
<authors>Various</authors>
|
||||
<owners>Ethan Brown</owners>
|
||||
<summary>A number of packages helpful for increased editor productivity.</summary>
|
||||
@@ -91,7 +91,7 @@
|
||||
-->
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<iconUrl>https://raw.github.com/Iristyle/ChocolateyPackages/master/SublimeText2.app/Sublime_Text.png</iconUrl>
|
||||
<releaseNotes></releaseNotes>
|
||||
<releaseNotes>* Use a local package cache to prevent first-time package restore / load errors</releaseNotes>
|
||||
<dependencies>
|
||||
<dependency id="PowerShell" version="3.0"/>
|
||||
<dependency id="SublimeText2.app" />
|
||||
|
1
EthanBrown.SublimeText2.EditorPackages/tools/PackageCache/Abacus/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
.DS_Store
|
@@ -0,0 +1,212 @@
|
||||
import sublime, sublime_plugin, re, sys
|
||||
from string import Template
|
||||
|
||||
class AbacusCommand(sublime_plugin.TextCommand):
|
||||
"""
|
||||
Main entry point. Find candidates for alignment,
|
||||
calculate appropriate column widths, and then
|
||||
perform a series of replacements.
|
||||
"""
|
||||
def run(self, edit):
|
||||
candidates = []
|
||||
separators = sublime.load_settings("Abacus.sublime-settings").get("com.khiltd.abacus.separators")
|
||||
indentor = Template("$indentation$left_col")
|
||||
lg_aligner = Template("$left_col$separator")
|
||||
rg_aligner = Template("$left_col$gutter$separator_padding$separator")
|
||||
|
||||
#Run through the separators accumulating alignment candidates
|
||||
#starting with the longest ones i.e. '==' before '='.
|
||||
longest_first = self.sort_separators(separators)
|
||||
|
||||
#Favor those that lean right so assignments with slice notation in them
|
||||
#get handled sanely
|
||||
for separator in [righty for righty in longest_first if righty["gravity"] == "right"]:
|
||||
self.find_candidates_for_separator(separator, candidates)
|
||||
|
||||
for separator in [lefty for lefty in longest_first if lefty["gravity"] == "left"]:
|
||||
self.find_candidates_for_separator(separator, candidates)
|
||||
|
||||
#After accumulation is done, figure out what the minimum required
|
||||
#indentation and column width is going to have to be to make every
|
||||
#candidate happy.
|
||||
max_indent, max_left_col_width = self.calc_left_col_width(candidates)
|
||||
|
||||
#Perform actual alignments based on gravitational affinity of separators
|
||||
for candidate in candidates:
|
||||
indent = 0
|
||||
if not candidate["preserve_indent"]:
|
||||
indent = max_indent
|
||||
else:
|
||||
indent = candidate["adjusted_indent"]
|
||||
|
||||
sep_width = len(candidate["separator"])
|
||||
right_col = candidate["right_col"].strip()
|
||||
left_col = indentor.substitute( indentation = " " * indent,
|
||||
left_col = candidate["left_col"] )
|
||||
#Marry the separator to the proper column
|
||||
if candidate["gravity"] == "left":
|
||||
#Separator sits flush left
|
||||
left_col = lg_aligner.substitute(left_col = left_col,
|
||||
separator = candidate["separator"] )
|
||||
elif candidate["gravity"] == "right":
|
||||
gutter_width = max_left_col_width + max_indent - len(left_col) - len(candidate["separator"])
|
||||
#Push the separator ONE separator's width over the tab boundary
|
||||
left_col = rg_aligner.substitute( left_col = left_col,
|
||||
gutter = " " * gutter_width,
|
||||
separator_padding = " " * sep_width,
|
||||
separator = candidate["separator"] )
|
||||
#Most sane people will want a space between the operator and the value.
|
||||
right_col = " %s" % right_col
|
||||
#Snap the left side together
|
||||
left_col = left_col.ljust(max_indent + max_left_col_width)
|
||||
candidate["replacement"] = "%s%s\n" % (left_col, right_col)
|
||||
|
||||
#Replace each line in its entirety
|
||||
full_line = self.region_from_line_number(candidate["line"])
|
||||
#sys.stdout.write(candidate["replacement"])
|
||||
self.view.replace(edit, full_line, candidate["replacement"])
|
||||
|
||||
#Scroll and muck with the selection
|
||||
if candidates:
|
||||
self.view.sel().clear()
|
||||
for region in [self.region_from_line_number(changed["line"]) for changed in candidates]:
|
||||
start_of_right_col = region.begin() + max_indent + max_left_col_width
|
||||
insertion_point = sublime.Region(start_of_right_col, start_of_right_col)
|
||||
self.view.sel().add(insertion_point)
|
||||
#self.view.show_at_center(insertion_point)
|
||||
else:
|
||||
sublime.status_message('Abacus - no alignment token found on selected line(s)')
|
||||
|
||||
def sort_separators(self, separators):
|
||||
return sorted(separators, key=lambda sep: -len(sep["token"]))
|
||||
|
||||
def find_candidates_for_separator(self, separator, candidates):
|
||||
"""
|
||||
Given a particular separator, loop through every
|
||||
line in the current selection looking for it and
|
||||
add unique matches to a list.
|
||||
"""
|
||||
debug = sublime.load_settings("Abacus.sublime-settings").get("com.khiltd.abacus.debug")
|
||||
token = separator["token"]
|
||||
selection = self.view.sel()
|
||||
new_candidates = []
|
||||
for region in selection:
|
||||
for line in self.view.lines(region):
|
||||
line_no = self.view.rowcol(line.begin())[0]
|
||||
|
||||
#Never match a line more than once
|
||||
if len([match for match in candidates if match["line"] == line_no]):
|
||||
continue
|
||||
|
||||
#Collapse any string literals that might
|
||||
#also contain our separator token so that
|
||||
#we can reliably find the location of the
|
||||
#real McCoy.
|
||||
line_content = self.view.substr(line)
|
||||
collapsed = line_content
|
||||
|
||||
for match in re.finditer(r"(\"[^\"]*(?<!\\)\"|'[^']*(?<!\\)'|\%(q|Q)?\{.*\})", line_content):
|
||||
quoted_string = match.group(0)
|
||||
collapsed = collapsed.replace(quoted_string, "\007" * len(quoted_string))
|
||||
|
||||
#Look for ':' but not '::', '=' but not '=>'
|
||||
#And remember that quoted strings were collapsed
|
||||
#up above!
|
||||
token_pos = None
|
||||
safe_token = re.escape(token)
|
||||
token_matcher = re.compile(r"(?<![^a-zA-Z0-9_ \007])%s(?![^a-zA-Z0-9_# \007])" % (safe_token))
|
||||
potential_matches = [m for m in token_matcher.finditer(collapsed)]
|
||||
|
||||
if debug:
|
||||
print "Pattern:"
|
||||
print token_matcher.pattern
|
||||
print "Matches:"
|
||||
print potential_matches
|
||||
|
||||
if len(potential_matches):
|
||||
#Split on the first/last occurrence of the token
|
||||
if separator["gravity"] == "right":
|
||||
token_pos = potential_matches[-1].start()
|
||||
elif separator["gravity"] == "left":
|
||||
token_pos = potential_matches[0].start()
|
||||
|
||||
#Do you see what I see?
|
||||
if debug:
|
||||
sys.stdout.write("%s\n" % line_content.encode("ascii", "ignore"))
|
||||
sys.stdout.write(" " * token_pos)
|
||||
sys.stdout.write("^\n")
|
||||
|
||||
#Now we can slice
|
||||
left_col = self.detab(line_content[:token_pos]).rstrip()
|
||||
right_col = self.detab(line_content[token_pos + len(token):])
|
||||
sep = line_content[token_pos:token_pos + len(token)]
|
||||
initial_indent = re.match("\s+", left_col) or 0
|
||||
|
||||
if initial_indent:
|
||||
initial_indent = len(initial_indent.group(0))
|
||||
#Align to tab boundary
|
||||
if initial_indent % self.tab_width >= self.tab_width / 2:
|
||||
initial_indent = self.snap_to_next_boundary(initial_indent, self.tab_width)
|
||||
else:
|
||||
initial_indent -= initial_indent % self.tab_width
|
||||
candidate = { "line": line_no,
|
||||
"original": line_content,
|
||||
"separator": sep,
|
||||
"gravity": separator["gravity"],
|
||||
"adjusted_indent": initial_indent,
|
||||
"preserve_indent": separator.get("preserve_indentation", False),
|
||||
"left_col": left_col.lstrip(),
|
||||
"right_col": right_col.rstrip() }
|
||||
new_candidates.append(candidate)
|
||||
#Poke more stuff in the accumulator
|
||||
candidates.extend(new_candidates)
|
||||
|
||||
def calc_left_col_width(self, candidates):
|
||||
"""
|
||||
Given a list of lines we've already matched against
|
||||
one or more separators, loop through them all to
|
||||
normalize their indentation and determine the minimum
|
||||
possible column width that will accomodate them all
|
||||
when aligned to a tab stop boundary.
|
||||
"""
|
||||
max_width = 0
|
||||
max_indent = 0
|
||||
max_sep_width = 0
|
||||
|
||||
for candidate in candidates:
|
||||
max_indent = max([candidate["adjusted_indent"], max_indent])
|
||||
max_sep_width = max([len(candidate["separator"]), max_sep_width])
|
||||
max_width = max([len(candidate["left_col"].rstrip()), max_width])
|
||||
|
||||
max_width += max_sep_width
|
||||
|
||||
#Bump up to the next multiple of tab_width
|
||||
max_width = self.snap_to_next_boundary(max_width, self.tab_width)
|
||||
|
||||
return max_indent, max_width
|
||||
|
||||
@property
|
||||
def tab_width(self):
|
||||
"""
|
||||
Exceptionally inefficient
|
||||
"""
|
||||
return int(self.view.settings().get('tab_size', 4))
|
||||
|
||||
def detab(self, input):
|
||||
"""
|
||||
Goodbye tabs!
|
||||
"""
|
||||
return input.expandtabs(self.tab_width)
|
||||
|
||||
def region_from_line_number(self, line_number):
|
||||
"""
|
||||
Given a zero-based line number, return a region
|
||||
encompassing it (including the newline).
|
||||
"""
|
||||
return self.view.full_line(self.view.text_point(line_number, 0))
|
||||
|
||||
def snap_to_next_boundary(self, value, interval):
|
||||
"""
|
||||
Alignment voodoo
|
||||
"""
|
||||
return value + (interval - value % interval)
|
@@ -0,0 +1,56 @@
|
||||
{
|
||||
"com.khiltd.abacus.debug": true,
|
||||
"com.khiltd.abacus.separators":
|
||||
[
|
||||
{
|
||||
"token": ":",
|
||||
"gravity": "left",
|
||||
"preserve_indentation": true
|
||||
},
|
||||
{
|
||||
"token": "=",
|
||||
"gravity": "right",
|
||||
"preserve_indentation": true
|
||||
},
|
||||
{
|
||||
"token": "+=",
|
||||
"gravity": "right",
|
||||
"preserve_indentation": true
|
||||
},
|
||||
{
|
||||
"token": "-=",
|
||||
"gravity": "right",
|
||||
"preserve_indentation": true
|
||||
},
|
||||
{
|
||||
"token": "*=",
|
||||
"gravity": "right",
|
||||
"preserve_indentation": true
|
||||
},
|
||||
{
|
||||
"token": "/=",
|
||||
"gravity": "right",
|
||||
"preserve_indentation": true
|
||||
},
|
||||
{
|
||||
"token": "?=",
|
||||
"gravity": "right",
|
||||
"preserve_indentation": true
|
||||
},
|
||||
{
|
||||
"token": "||=",
|
||||
"gravity": "right",
|
||||
"preserve_indentation": true
|
||||
},
|
||||
{
|
||||
"token": "%=",
|
||||
"gravity": "right",
|
||||
"preserve_indentation": true
|
||||
},
|
||||
{
|
||||
"token": "==",
|
||||
"gravity": "right",
|
||||
"preserve_indentation": true
|
||||
}
|
||||
]
|
||||
}
|
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"com.khiltd.abacus.separators":
|
||||
[
|
||||
{
|
||||
"token": ":",
|
||||
"gravity": "left",
|
||||
"preserve_indentation": false
|
||||
}
|
||||
]
|
||||
}
|
@@ -0,0 +1,6 @@
|
||||
[
|
||||
{
|
||||
"keys": ["ctrl+alt+]"], "command": "abacus"
|
||||
}
|
||||
]
|
||||
|
@@ -0,0 +1,6 @@
|
||||
[
|
||||
{
|
||||
"keys": ["super+ctrl+alt+]"], "command": "abacus"
|
||||
}
|
||||
]
|
||||
|
@@ -0,0 +1,6 @@
|
||||
[
|
||||
{
|
||||
"keys": ["ctrl+alt+]"], "command": "abacus"
|
||||
}
|
||||
]
|
||||
|
@@ -0,0 +1,6 @@
|
||||
[
|
||||
{
|
||||
"caption": "Abacus: align selection",
|
||||
"command": "abacus"
|
||||
}
|
||||
]
|
@@ -0,0 +1,97 @@
|
||||
[
|
||||
{
|
||||
"id": "selection",
|
||||
"children":
|
||||
[
|
||||
{ "id": "abacus" },
|
||||
{
|
||||
"command": "abacus",
|
||||
"caption": "Abacus Align"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"caption": "Preferences",
|
||||
"mnemonic": "n",
|
||||
"id": "preferences",
|
||||
"children":
|
||||
[
|
||||
{
|
||||
"caption": "Package Settings",
|
||||
"mnemonic": "P",
|
||||
"id": "package-settings",
|
||||
"children":
|
||||
[
|
||||
{
|
||||
"caption": "Abacus",
|
||||
"children":
|
||||
[
|
||||
{
|
||||
"command": "open_file",
|
||||
"args": { "file": "${packages}/Abacus/Abacus.sublime-settings" },
|
||||
"caption": "Settings - Default"
|
||||
},
|
||||
{
|
||||
"command": "open_file",
|
||||
"args": { "file": "${packages}/User/Abacus.sublime-settings" },
|
||||
"caption": "Settings - User"
|
||||
},
|
||||
{
|
||||
"command": "open_file_settings",
|
||||
"caption": "Settings - Syntax Specific - User"
|
||||
},
|
||||
{
|
||||
"command": "open_file",
|
||||
"args": {
|
||||
"file": "${packages}/Abacus/Default (Windows).sublime-keymap",
|
||||
"platform": "Windows"
|
||||
},
|
||||
"caption": "Key Bindings – Default"
|
||||
},
|
||||
{
|
||||
"command": "open_file",
|
||||
"args": {
|
||||
"file": "${packages}/Abacus/Default (OSX).sublime-keymap",
|
||||
"platform": "OSX"
|
||||
},
|
||||
"caption": "Key Bindings – Default"
|
||||
},
|
||||
{
|
||||
"command": "open_file",
|
||||
"args": {
|
||||
"file": "${packages}/Abacus/Default (Linux).sublime-keymap",
|
||||
"platform": "Linux"
|
||||
},
|
||||
"caption": "Key Bindings – Default"
|
||||
},
|
||||
{
|
||||
"command": "open_file",
|
||||
"args": {
|
||||
"file": "${packages}/User/Default (Windows).sublime-keymap",
|
||||
"platform": "Windows"
|
||||
},
|
||||
"caption": "Key Bindings – User"
|
||||
},
|
||||
{
|
||||
"command": "open_file",
|
||||
"args": {
|
||||
"file": "${packages}/User/Default (OSX).sublime-keymap",
|
||||
"platform": "OSX"
|
||||
},
|
||||
"caption": "Key Bindings – User"
|
||||
},
|
||||
{
|
||||
"command": "open_file",
|
||||
"args": {
|
||||
"file": "${packages}/User/Default (Linux).sublime-keymap",
|
||||
"platform": "Linux"
|
||||
},
|
||||
"caption": "Key Bindings – User"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
@@ -0,0 +1,59 @@
|
||||
Abacus Alignment Plugin for Sublime Text 2
|
||||
================
|
||||
|
||||

|
||||
|
||||
I'm pretty anal about aligning things in my code, but the alignment plugins I tried were more-or-less one-trick-ponies, and I didn't like any of their tricks, so I made my own.
|
||||
|
||||
My one anal pony trick involves allowing you to slide the operator like an abacus bead, toward either the left or the right hand side, by giving each possible token a `gravity` property like so:
|
||||
|
||||
``` json
|
||||
{
|
||||
"com.khiltd.abacus.separators":
|
||||
[
|
||||
{
|
||||
"token": ":",
|
||||
"gravity": "left",
|
||||
"preserve_indentation": true
|
||||
},
|
||||
{
|
||||
"token": "=",
|
||||
"gravity": "right",
|
||||
"preserve_indentation": true
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Abacus focuses on aligning assignments in as language-agnostic a manner as possible and strives to address most of the open issues in that other, more popular plugin (it won't even jack up your Backbone routes!). It is, however, an *alignment* tool and *not* a full-blown beautifier. It works best when there's one assignment per line; if you like shoving dozens of CSS or JSON declarations on a single line then you are an enemy of readability and this plugin will make every effort to hinder and harm your creature on Earth as far as it is able.
|
||||
|
||||
`preserve_indentation` is a tip that you might be working in a language where whitespace is significant, thereby suggesting that Abacus should make no effort to normalize indentation across lines. It's not foolproof, especially if you set your tab width really, really low, but it tries harder than Cory Doctorow ever has. OK, you're right... It would be impossible for anyone to try harder than that.
|
||||
|
||||
Usage
|
||||
============
|
||||
|
||||
Make a selection, then `command + option + control + ]`.
|
||||
|
||||
Think the plugin's crazy? Add the following to your config:
|
||||
|
||||
```
|
||||
"com.khiltd.abacus.debug": true
|
||||
```
|
||||
|
||||
and Abacus will dump its thoughts out to Sublime Text's console like so:
|
||||
|
||||
```
|
||||
margin:0;
|
||||
^
|
||||
padding:0;
|
||||
^
|
||||
border-style:none;
|
||||
^
|
||||
```
|
||||
|
||||
Caveats
|
||||
============
|
||||
|
||||
I've used nothing but Macs since 1984 and do absolutely **no** testing in Windows or Ububian's window manager of the minute. If something's broken in some OS I don't own, you'll need to have a suggestion as to how it can be fixed as I'm unlikely to have any idea what you're talking about.
|
||||
|
||||
I don't care if you like real tabs or Windows line endings and don't bother with handling them. Seriously, what year is this?
|
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"com.khiltd.abacus.separators":
|
||||
[
|
||||
{
|
||||
"token": "=>",
|
||||
"gravity": "right",
|
||||
"preserve_indentation": true
|
||||
}
|
||||
]
|
||||
}
|
@@ -0,0 +1 @@
|
||||
{"url": "https://github.com/khiltd/Abacus", "version": "2013.01.11.00.24.46", "description": "An Alignment Plugin for Sublime Text 2 that actually works `\u2318\u2325^ ]`"}
|
5
EthanBrown.SublimeText2.EditorPackages/tools/PackageCache/Block Cursor Everywhere/.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
*.pyc
|
||||
*.cache
|
||||
*.sublime-project
|
||||
.DS_store
|
||||
.c9revisions
|
@@ -0,0 +1,48 @@
|
||||
# BlockCursorEverywhere #
|
||||
|
||||

|
||||
|
||||
It can become very difficult to keep track of your cursor location. This is solved by having a "block" cursor, which is very easy to spot no matter where it is on screen. Unfortunately, Sublime Text 2 does not (yet) support this feature natively. This Plugin mimics this functionality by highlighting the area behind the cursor whenever it moves (similar to how you might highlight syntax errors, or color a comment).
|
||||
|
||||
## Installation ##
|
||||
|
||||
### With Package Control ###
|
||||
|
||||
If you have the [Package Control][package_control] installed, you can install BlockCursorEverywhere from inside Sublime Text itself. Open the Command Palette and select "Package Control: Install Package", then search for BlockCursorEverywhere and you’re done!
|
||||
|
||||
### Without Package Control ###
|
||||
|
||||
Go to your Sublime Text 2 Packages directory:
|
||||
|
||||
Windows: %USERPROFILE%\AppData\Roaming\Sublime Text 2\Packages\
|
||||
Mac: ~/Library/Application Support/Sublime Text 2/Packages/
|
||||
|
||||
and clone the repository there
|
||||
|
||||
git clone git://github.com/ingshtrom/BlockCursorEverywhere
|
||||
|
||||
|
||||
## Configuration ##
|
||||
|
||||
These are the settings that I prefer. You can change the style of the block cursor by adding a section to your theme file like so:
|
||||
|
||||
```xml
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Block Cursor</string>
|
||||
<key>scope</key>
|
||||
<string>block_cursor</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#000000</string>
|
||||
<key>background</key>
|
||||
<string>#FF1111</string>
|
||||
</dict>
|
||||
</dict>
|
||||
```
|
||||
|
||||
---------
|
||||
|
||||
[sublime]: http://www.sublimetext.com/2
|
||||
[package_control]: http://wbond.net/sublime_packages/package_control
|
@@ -0,0 +1,38 @@
|
||||
import sublime
|
||||
import sublime_plugin
|
||||
|
||||
|
||||
class BlockCursorEverywhere(sublime_plugin.EventListener):
|
||||
def view_is_widget(self, view):
|
||||
settings = view.settings()
|
||||
return bool(settings.get('is_widget'))
|
||||
|
||||
def show_block_cursor(self, view):
|
||||
validRegions = []
|
||||
for s in view.sel():
|
||||
if s.a != s.b:
|
||||
continue
|
||||
validRegions.append(sublime.Region(s.a, s.a + 1))
|
||||
if validRegions.__len__:
|
||||
view.add_regions('BlockCursorListener', validRegions, 'block_cursor')
|
||||
else:
|
||||
view.erase_regions('BlockCursorListener')
|
||||
|
||||
def on_selection_modified(self, view):
|
||||
if view.settings().get('is_widget') or not("Vintage" in view.settings().get('ignored_packages') or view.settings().get('command_mode')):
|
||||
view.erase_regions('BlockCursorListener')
|
||||
return
|
||||
self.show_block_cursor(view)
|
||||
|
||||
def on_deactivated(self, view):
|
||||
view.erase_regions('BlockCursorListener')
|
||||
view.settings().clear_on_change('command_mode')
|
||||
self.current_view = None
|
||||
|
||||
def on_activated(self, view):
|
||||
self.on_selection_modified(view)
|
||||
view.settings().add_on_change('command_mode', self.on_command_mode_change)
|
||||
self.current_view = view
|
||||
|
||||
def on_command_mode_change(self):
|
||||
self.on_selection_modified(self.current_view)
|
@@ -0,0 +1 @@
|
||||
{"url": "https://github.com/ingshtrom/BlockCursorEverywhere", "version": "2013.01.20.10.51.30", "description": "Sublime Text 2 plugin to mimic a block cursor in Vintage command mode."}
|
3
EthanBrown.SublimeText2.EditorPackages/tools/PackageCache/BracketHighlighter/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
*.pyc
|
||||
|
||||
.DS_Store
|
@@ -0,0 +1,68 @@
|
||||
# Version 1.9.0
|
||||
- Add experimental CFML support (defaulted off)
|
||||
- Add auto-detection of self-closing tags (defaulted on)
|
||||
|
||||
# Version 1.8.0
|
||||
- Add new commands: "Show Bracket String Escape Mode" and "Toggle Bracket String Escape Mode". Default is "regex"
|
||||
|
||||
# Version 1.7.2
|
||||
- Feed general bracket type to bracket plugins
|
||||
- Adjust bracket select plugin to better handle HTML tags
|
||||
|
||||
# Version 1.7.1
|
||||
- Reorganize some settings
|
||||
- Limit auto-highlight selections by configurable threshold setting
|
||||
|
||||
# Version 1.7.0
|
||||
- Hide parent quote highlighting when child quotes are highlighted
|
||||
- Allow the searching for brackets in non-quoted code scoped as strings (like regex)
|
||||
- Add setting "highlight_string_brackets_only" which allows never highlighting quotes but leaves internal string bracket highlighting on
|
||||
- deprecate "enable_forward_slash_regex_strings" in favor of "find_brackets_in any_strings"
|
||||
|
||||
# Version 1.6.2
|
||||
- Fix adjacent_only with multi_select
|
||||
|
||||
# Version 1.6.1
|
||||
- Suppress string highlighting when adjacent_only is set, but allow internal string brackets to still get highlighted with adjacent_only settings if match_string_brackets is true
|
||||
|
||||
# Version 1.6.0
|
||||
- Add setting to match only when cursor is between brackets
|
||||
|
||||
# Version 1.5.3
|
||||
- Allow turning off gutter icons for multi-select via settings
|
||||
- Fix multi-select detection
|
||||
- Default the internal settings if setting is not found
|
||||
|
||||
# Version 1.5.2
|
||||
- Use tiny icons when line height is less than 16
|
||||
- Use no icon if icon cannot be found
|
||||
- Optimize png icons
|
||||
|
||||
# Version 1.5.1
|
||||
- Ignore selection/edit events inside the main routine
|
||||
|
||||
# Version 1.5.0
|
||||
- More responsive highlighting (thanks tito); delay setting no longer needed
|
||||
- Organize bracket plugins
|
||||
- Included more configurable custom gutter icons
|
||||
|
||||
# Version 1.4.1
|
||||
- Make adjusment to regex modifier code to correctly count back modifiers in perl
|
||||
|
||||
# Version 1.4.0
|
||||
- Account for perl regex, substitutions, and translations surrounded by "/" for string bracket matching
|
||||
- Account for regex modifiers when matching regex surrounded by "/" in javascript and perl
|
||||
|
||||
# Version 1.3.0
|
||||
- Fixed escaped brackets in string handling. Also a bit more efficient.
|
||||
|
||||
# Version 1.2.0
|
||||
- Fix angle bracket avoidance when finding brackets inside strings, and make it cleaner
|
||||
|
||||
# Version 1.1.0
|
||||
- Add python raw string support for quote highlighting
|
||||
- Add highlighting of brackets in strings; will work in all strings, but mainly meant for regex. True by default
|
||||
- Add support for targetting regex strings like in javascript that are scoped as strings, but are not quoted, but use '/'s. True by default
|
||||
|
||||
# Version 1.0.0
|
||||
- All previous work and releases
|
@@ -0,0 +1,152 @@
|
||||
[
|
||||
// Toggle Global Enable
|
||||
{
|
||||
"caption": "BracketHighlighter: Toggle Global Enable",
|
||||
"command": "bh_toggle_enable"
|
||||
},
|
||||
// Search to end of file for bracket
|
||||
{
|
||||
"caption": "BracketHighlighter: Match Brackets (ignore threshold)",
|
||||
"command": "bh_key",
|
||||
"args": {"lines" : true}
|
||||
},
|
||||
// Remove brackets
|
||||
{
|
||||
"caption": "BracketHighlighter: Remove Brackets",
|
||||
"command": "bh_remove_brackets"
|
||||
},
|
||||
// Go to left bracket
|
||||
{
|
||||
"caption": "BracketHighlighter: Jump to Left Bracket",
|
||||
"command": "bh_key",
|
||||
"args":
|
||||
{
|
||||
"lines" : true,
|
||||
"plugin":
|
||||
{
|
||||
"type": ["__all__"],
|
||||
"command": "bh_modules.bracketselect",
|
||||
"args": {"select": "left"}
|
||||
}
|
||||
}
|
||||
},
|
||||
// Go to right bracket
|
||||
{
|
||||
"caption": "BracketHighlighter: Jump to Right Bracket",
|
||||
"command": "bh_key",
|
||||
"args":
|
||||
{
|
||||
"lines" : true,
|
||||
"plugin":
|
||||
{
|
||||
"type": ["__all__"],
|
||||
"command": "bh_modules.bracketselect",
|
||||
"args": {"select": "right"}
|
||||
}
|
||||
}
|
||||
},
|
||||
// Select text between brackets
|
||||
{
|
||||
"caption": "BracketHighlighter: Select Bracket Content",
|
||||
"command": "bh_key",
|
||||
"args":
|
||||
{
|
||||
"lines" : true,
|
||||
"plugin":
|
||||
{
|
||||
"type": ["__all__"],
|
||||
"command": "bh_modules.bracketselect"
|
||||
}
|
||||
}
|
||||
},
|
||||
// Fold contents between brackets
|
||||
{
|
||||
"caption": "BracketHighlighter: Fold Bracket Content",
|
||||
"command": "bh_key",
|
||||
"args":
|
||||
{
|
||||
"plugin": {
|
||||
"type": ["__all__"],
|
||||
"command" : "bh_modules.foldbracket"
|
||||
}
|
||||
}
|
||||
},
|
||||
{ "caption": "-" },
|
||||
// Toggle between string and regex escape mode for string brackets
|
||||
{
|
||||
"caption": "BracketHighlighter: Toggle String Bracket Escape Mode",
|
||||
"command": "bh_toggle_string_escape_mode"
|
||||
},
|
||||
// Toggle high visibility mode
|
||||
{
|
||||
"caption": "BracketHighlighter: Toggle High Visibility Mode",
|
||||
"command": "bh_toggle_high_visibility"
|
||||
},
|
||||
{ "caption": "-" },
|
||||
// Select tag name of HTML/XML tag (both opening name and closing)
|
||||
{
|
||||
"caption": "BracketHighlighter: Select Tag Name (closing and opening)",
|
||||
"command": "bh_key",
|
||||
"args":
|
||||
{
|
||||
"plugin":
|
||||
{
|
||||
"type": ["cfml", "html", "angle"],
|
||||
"command": "bh_modules.tagnameselect"
|
||||
}
|
||||
}
|
||||
},
|
||||
// Select the attribute to the right of the cursor (will wrap inside the tag)
|
||||
{
|
||||
"caption": "BracketHighlighter: Select Next Attribute (right)",
|
||||
"command": "bh_key",
|
||||
"args":
|
||||
{
|
||||
"plugin":
|
||||
{
|
||||
"type": ["cfml", "html", "angle"],
|
||||
"command": "bh_modules.tagattrselect",
|
||||
"args": {"direction": "right"}
|
||||
}
|
||||
}
|
||||
},
|
||||
// Select the attribute to the left of the cursor (will wrap inside the tag)
|
||||
{
|
||||
"caption": "BracketHighlighter: Select Next Attribute (left)",
|
||||
"command": "bh_key",
|
||||
"args":
|
||||
{
|
||||
"plugin":
|
||||
{
|
||||
"type": ["cfml", "html", "angle"],
|
||||
"command": "bh_modules.tagattrselect",
|
||||
"args": {"direction": "left"}
|
||||
}
|
||||
}
|
||||
},
|
||||
// Convert single quote string to double quoted string and vice versa
|
||||
// Will handle escaping or unescaping quotes within the string
|
||||
{
|
||||
"caption": "BracketHighlighter: Swap Quotes",
|
||||
"command": "bh_key",
|
||||
"args":
|
||||
{
|
||||
"lines" : true,
|
||||
"plugin":
|
||||
{
|
||||
"type": ["single_quote", "double_quote", "py_single_quote", "py_double_quote"],
|
||||
"command": "bh_modules.swapquotes"
|
||||
}
|
||||
}
|
||||
},
|
||||
// Swap Brackets
|
||||
{
|
||||
"caption": "BracketHighlighter: Swap Brackets",
|
||||
"command": "swap_brackets"
|
||||
},
|
||||
// Surround selection with brackets from quick panel
|
||||
{
|
||||
"caption": "BracketHighlighter: Wrap Selections with Brackets",
|
||||
"command": "wrap_brackets"
|
||||
}
|
||||
]
|
@@ -0,0 +1,16 @@
|
||||
[
|
||||
// Navigate tabstops in wrapped selection
|
||||
{
|
||||
"keys": ["tab"],
|
||||
"command": "bh_next_wrap_sel",
|
||||
"context":
|
||||
[
|
||||
{
|
||||
"operand": true,
|
||||
"operator": "equal",
|
||||
"match_all": true,
|
||||
"key": "bh_wrapping"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
@@ -0,0 +1,153 @@
|
||||
[
|
||||
// Toggle Global Enable
|
||||
{
|
||||
"keys": ["ctrl+alt+super+e"],
|
||||
"command": "bh_toggle_enable"
|
||||
},
|
||||
// Search to end of file for bracket
|
||||
{
|
||||
"keys": ["ctrl+alt+super+b"],
|
||||
"command": "bh_key",
|
||||
"args":
|
||||
{
|
||||
"lines" : true
|
||||
}
|
||||
},
|
||||
// Go to left bracket
|
||||
{
|
||||
"keys": ["ctrl+alt+super+up"],
|
||||
"command": "bh_key",
|
||||
"args":
|
||||
{
|
||||
"lines" : true,
|
||||
"plugin":
|
||||
{
|
||||
"type": ["__all__"],
|
||||
"command": "bh_modules.bracketselect",
|
||||
"args": {"select": "left"}
|
||||
}
|
||||
}
|
||||
},
|
||||
// Go to right bracket
|
||||
{
|
||||
"keys": ["ctrl+alt+super+down"],
|
||||
"command": "bh_key",
|
||||
"args":
|
||||
{
|
||||
"lines" : true,
|
||||
"plugin":
|
||||
{
|
||||
"type": ["__all__"],
|
||||
"command": "bh_modules.bracketselect",
|
||||
"args": {"select": "right"}
|
||||
}
|
||||
}
|
||||
},
|
||||
// Remove brackets
|
||||
{
|
||||
"keys": ["ctrl+alt+super+r"],
|
||||
"command": "bh_remove_brackets"
|
||||
},
|
||||
// Toggle string escape mode for sub bracket search in strings
|
||||
{
|
||||
"keys": ["ctrl+alt+super+x"],
|
||||
"command": "bh_toggle_string_escape_mode"
|
||||
},
|
||||
// Select text between brackets
|
||||
{
|
||||
"keys": ["ctrl+alt+super+s"],
|
||||
"command": "bh_key",
|
||||
"args":
|
||||
{
|
||||
"lines" : true,
|
||||
"plugin":
|
||||
{
|
||||
"type": ["__all__"],
|
||||
"command": "bh_modules.bracketselect"
|
||||
}
|
||||
}
|
||||
},
|
||||
// Select tag name of HTML/XML tag (both opening name and closing)
|
||||
{
|
||||
"keys": ["ctrl+alt+super+t"],
|
||||
"command": "bh_key",
|
||||
"args":
|
||||
{
|
||||
"plugin":
|
||||
{
|
||||
"type": ["cfml", "html", "angle"],
|
||||
"command": "bh_modules.tagnameselect"
|
||||
}
|
||||
}
|
||||
},
|
||||
// Select the attribute to the right of the cursor (will wrap inside the tag)
|
||||
{
|
||||
"keys": ["ctrl+alt+super+right"],
|
||||
"command": "bh_key",
|
||||
"args":
|
||||
{
|
||||
"plugin":
|
||||
{
|
||||
"type": ["cfml", "html", "angle"],
|
||||
"command": "bh_modules.tagattrselect",
|
||||
"args": {"direction": "right"}
|
||||
}
|
||||
}
|
||||
},
|
||||
// Select the attribute to the left of the cursor (will wrap inside the tag)
|
||||
{
|
||||
"keys": ["ctrl+alt+super+left"],
|
||||
"command": "bh_key",
|
||||
"args":
|
||||
{
|
||||
"plugin":
|
||||
{
|
||||
"type": ["cfml", "html", "angle"],
|
||||
"command": "bh_modules.tagattrselect",
|
||||
"args": {"direction": "left"}
|
||||
}
|
||||
}
|
||||
},
|
||||
// Convert single quote string to double quoted string and vice versa
|
||||
// Will handle escaping or unescaping quotes within the string
|
||||
{
|
||||
"keys": ["ctrl+alt+super+q"],
|
||||
"command": "bh_key",
|
||||
"args":
|
||||
{
|
||||
"lines" : true,
|
||||
"plugin":
|
||||
{
|
||||
"type": ["single_quote", "double_quote", "py_single_quote", "py_double_quote"],
|
||||
"command": "bh_modules.swapquotes"
|
||||
}
|
||||
}
|
||||
},
|
||||
// Fold contents between brackets
|
||||
{
|
||||
"keys": ["ctrl+alt+super+["],
|
||||
"command": "bh_key",
|
||||
"args":
|
||||
{
|
||||
"plugin": {
|
||||
"type": ["__all__"],
|
||||
"command" : "bh_modules.foldbracket"
|
||||
}
|
||||
}
|
||||
},
|
||||
// Swap brackets with another type
|
||||
{
|
||||
"keys": ["ctrl+alt+super+e"],
|
||||
"command": "swap_brackets"
|
||||
},
|
||||
// Surround selection with brackets from quick panel
|
||||
{
|
||||
"keys": ["ctrl+alt+super+w"],
|
||||
"command": "wrap_brackets"
|
||||
},
|
||||
// Toggle high visibility mode
|
||||
{
|
||||
"keys": ["ctrl+alt+super+v"],
|
||||
"command": "bh_toggle_high_visibility"
|
||||
}
|
||||
]
|
@@ -0,0 +1,260 @@
|
||||
[
|
||||
{
|
||||
"id": "tools",
|
||||
"caption": "Tools",
|
||||
"children":
|
||||
[
|
||||
{
|
||||
"id": "packages",
|
||||
"caption": "Packages",
|
||||
"children":
|
||||
[
|
||||
{
|
||||
"id": "brackethighlighter",
|
||||
"caption": "BracketHighlighter",
|
||||
"children":
|
||||
[
|
||||
// Toggle Global Enable
|
||||
{
|
||||
"caption": "BracketHighlighter: Toggle Global Enable",
|
||||
"command": "bh_toggle_enable"
|
||||
},
|
||||
{ "caption": "-" },
|
||||
// Search to end of file for bracket
|
||||
{
|
||||
"caption": "Match Brackets (ignore threshold)",
|
||||
"command": "bh_key",
|
||||
"args": {"lines" : true}
|
||||
},
|
||||
// Remove brackets
|
||||
{
|
||||
"caption": "Remove Brackets",
|
||||
"command": "bh_remove_brackets"
|
||||
},
|
||||
// Go to left bracket
|
||||
{
|
||||
"caption": "Jump to Left Bracket",
|
||||
"command": "bh_key",
|
||||
"args":
|
||||
{
|
||||
"lines" : true,
|
||||
"plugin":
|
||||
{
|
||||
"type": ["__all__"],
|
||||
"command": "bh_modules.bracketselect",
|
||||
"args": {"select": "left"}
|
||||
}
|
||||
}
|
||||
},
|
||||
// Go to right bracket
|
||||
{
|
||||
"caption": "Jump to Right Bracket",
|
||||
"command": "bh_key",
|
||||
"args":
|
||||
{
|
||||
"lines" : true,
|
||||
"plugin":
|
||||
{
|
||||
"type": ["__all__"],
|
||||
"command": "bh_modules.bracketselect",
|
||||
"args": {"select": "right"}
|
||||
}
|
||||
}
|
||||
},
|
||||
// Select text between brackets
|
||||
{
|
||||
"caption": "Select Bracket Content",
|
||||
"command": "bh_key",
|
||||
"args":
|
||||
{
|
||||
"lines" : true,
|
||||
"plugin":
|
||||
{
|
||||
"type": ["__all__"],
|
||||
"command": "bh_modules.bracketselect"
|
||||
}
|
||||
}
|
||||
},
|
||||
// Fold contents between brackets
|
||||
{
|
||||
"caption": "Fold Bracket Content",
|
||||
"command": "bh_key",
|
||||
"args":
|
||||
{
|
||||
"plugin": {
|
||||
"type": ["__all__"],
|
||||
"command" : "bh_modules.foldbracket"
|
||||
}
|
||||
}
|
||||
},
|
||||
{ "caption": "-" },
|
||||
// Toggle between string and regex escape mode for string brackets
|
||||
{
|
||||
"caption": "Toggle String Bracket Escape Mode",
|
||||
"command": "bh_toggle_string_escape_mode"
|
||||
},
|
||||
// Toggle high visibility mode
|
||||
{
|
||||
"caption": "Toggle High Visibility Mode",
|
||||
"command": "bh_toggle_high_visibility"
|
||||
},
|
||||
{ "caption": "-" },
|
||||
// Select tag name of HTML/XML tag (both opening name and closing)
|
||||
{
|
||||
"caption": "Select Tag Name (closing and opening)",
|
||||
"command": "bh_key",
|
||||
"args":
|
||||
{
|
||||
"plugin":
|
||||
{
|
||||
"type": ["cfml", "html", "angle"],
|
||||
"command": "bh_modules.tagnameselect"
|
||||
}
|
||||
}
|
||||
},
|
||||
// Select the attribute to the right of the cursor (will wrap inside the tag)
|
||||
{
|
||||
"caption": "Select Next Attribute (right)",
|
||||
"command": "bh_key",
|
||||
"args":
|
||||
{
|
||||
"plugin":
|
||||
{
|
||||
"type": ["cfml", "html", "angle"],
|
||||
"command": "bh_modules.tagattrselect",
|
||||
"args": {"direction": "right"}
|
||||
}
|
||||
}
|
||||
},
|
||||
// Select the attribute to the left of the cursor (will wrap inside the tag)
|
||||
{
|
||||
"caption": "Select Next Attribute (left)",
|
||||
"command": "bh_key",
|
||||
"args":
|
||||
{
|
||||
"plugin":
|
||||
{
|
||||
"type": ["cfml", "html", "angle"],
|
||||
"command": "bh_modules.tagattrselect",
|
||||
"args": {"direction": "left"}
|
||||
}
|
||||
}
|
||||
},
|
||||
{ "caption": "-" },
|
||||
// Convert single quote string to double quoted string and vice versa
|
||||
// Will handle escaping or unescaping quotes within the string
|
||||
{
|
||||
"caption": "Swap Quotes",
|
||||
"command": "bh_key",
|
||||
"args":
|
||||
{
|
||||
"lines" : true,
|
||||
"plugin":
|
||||
{
|
||||
"type": ["single_quote", "double_quote", "py_single_quote", "py_double_quote"],
|
||||
"command": "bh_modules.swapquotes"
|
||||
}
|
||||
}
|
||||
},
|
||||
// Swap brackets
|
||||
{
|
||||
"caption": "Swap Brackets",
|
||||
"command": "swap_brackets"
|
||||
},
|
||||
// Surround selection with brackets from quick panel
|
||||
{
|
||||
"caption": "Wrap Selections with Brackets",
|
||||
"command": "wrap_brackets"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"caption": "Preferences",
|
||||
"mnemonic": "n",
|
||||
"id": "preferences",
|
||||
"children":
|
||||
[
|
||||
{
|
||||
"caption": "Package Settings",
|
||||
"mnemonic": "P",
|
||||
"id": "package-settings",
|
||||
"children":
|
||||
[
|
||||
{
|
||||
"caption": "Bracket Highlighter",
|
||||
"children":
|
||||
[
|
||||
{
|
||||
"command": "open_file",
|
||||
"args": {"file": "${packages}/BracketHighlighter/bh_core.sublime-settings"},
|
||||
"caption": "Bracket Settings – Default"
|
||||
},
|
||||
{
|
||||
"command": "open_file",
|
||||
"args": {"file": "${packages}/User/bh_core.sublime-settings"},
|
||||
"caption": "Bracket Settings – User"
|
||||
},
|
||||
{ "caption": "-" },
|
||||
{
|
||||
"command": "open_file",
|
||||
"args": {"file": "${packages}/BracketHighlighter/bh_wrapping.sublime-settings"},
|
||||
"caption": "Wrap Settings – Default"
|
||||
},
|
||||
{
|
||||
"command": "open_file",
|
||||
"args": {"file": "${packages}/User/bh_wrapping.sublime-settings"},
|
||||
"caption": "Wrap Settings – User"
|
||||
},
|
||||
{ "caption": "-" },
|
||||
{
|
||||
"command": "open_file",
|
||||
"args": {"file": "${packages}/BracketHighlighter/bh_swapping.sublime-settings"},
|
||||
"caption": "Swap Settings – Default"
|
||||
},
|
||||
{
|
||||
"command": "open_file",
|
||||
"args": {"file": "${packages}/User/bh_swapping.sublime-settings"},
|
||||
"caption": "Swap Settings – User"
|
||||
},
|
||||
{ "caption": "-" },
|
||||
{
|
||||
"command": "open_file",
|
||||
"args": {"file": "${packages}/BracketHighlighter/Example.sublime-keymap"},
|
||||
"caption": "Example Key Bindings"
|
||||
},
|
||||
{
|
||||
"command": "open_file",
|
||||
"args": {
|
||||
"file": "${packages}/User/Default (Windows).sublime-keymap",
|
||||
"platform": "Windows"
|
||||
},
|
||||
"caption": "Key Bindings – User"
|
||||
},
|
||||
{
|
||||
"command": "open_file",
|
||||
"args": {
|
||||
"file": "${packages}/User/Default (OSX).sublime-keymap",
|
||||
"platform": "OSX"
|
||||
},
|
||||
"caption": "Key Bindings – User"
|
||||
},
|
||||
{
|
||||
"command": "open_file",
|
||||
"args": {
|
||||
"file": "${packages}/User/Default (Linux).sublime-keymap",
|
||||
"platform": "Linux"
|
||||
},
|
||||
"caption": "Key Bindings – User"
|
||||
},
|
||||
{ "caption": "-" }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
@@ -0,0 +1,372 @@
|
||||
{
|
||||
//Debug logging
|
||||
"debug_enable": false,
|
||||
|
||||
// Path to find icons at
|
||||
"icon_path": "BracketHighlighter/icons",
|
||||
|
||||
// When only either the left or right bracket can be found
|
||||
// this defines if the unmatched bracket should be shown.
|
||||
"show_unmatched" : true,
|
||||
|
||||
// High visibilty style and color for high visibility mode
|
||||
// (solid|outline|underline)
|
||||
"high_visibility_style": "outline",
|
||||
// (scope|__default__|__bracket__)
|
||||
"high_visibility_color": "__bracket__",
|
||||
|
||||
// Match brackets only when the cursor is touching the inside of the bracket
|
||||
"match_only_adjacent": false,
|
||||
|
||||
// Character threshold to search
|
||||
"search_threshold": 5000,
|
||||
|
||||
// Set mode for string escapes to ignore (regex|string)
|
||||
"bracket_string_escape_mode": "string",
|
||||
|
||||
// Set max number of multi-select brackets that will be searched automatically
|
||||
"auto_selection_threshold" : 10,
|
||||
|
||||
// Disable gutter icons when doing multi-select
|
||||
"no_multi_select_icons": false,
|
||||
|
||||
// Rules that define the finding and matching of brackets
|
||||
// that are contained in a common scope.
|
||||
// Useful for bracket pairs that are the same but
|
||||
// share a common scope. Brackets are found by
|
||||
// Finding the extent of the scope and using regex
|
||||
// to look at the beginning and end to identify bracket.
|
||||
// Use only if they cannot be targeted with traditional bracket
|
||||
// rules.
|
||||
"scope_brackets": [
|
||||
// Quotes
|
||||
{
|
||||
"name": "py_single_quote",
|
||||
"open": "u?r?((?:'')?')",
|
||||
"close": "((?:'')?')",
|
||||
"style": "single_quote",
|
||||
"scopes": ["string"],
|
||||
"language_filter": "whitelist",
|
||||
"language_list": ["Python"],
|
||||
"sub_bracket_search": "true",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "py_double_quote",
|
||||
"open": "u?r?((?:\"\")?\")",
|
||||
"close": "((?:\"\")?\")",
|
||||
"style": "double_quote",
|
||||
"scopes": ["string"],
|
||||
"language_filter": "whitelist",
|
||||
"language_list": ["Python"],
|
||||
"sub_bracket_search": "true",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "single_quote",
|
||||
"open": "(')",
|
||||
"close": "(')",
|
||||
"style": "single_quote",
|
||||
"scopes": ["string"],
|
||||
"language_filter": "blacklist",
|
||||
"language_list": ["Plain text"],
|
||||
"sub_bracket_search": "true",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "double_quote",
|
||||
"open": "(\")",
|
||||
"close": "(\")",
|
||||
"style": "double_quote",
|
||||
"scopes": ["string"],
|
||||
"language_filter": "blacklist",
|
||||
"language_list": ["Plain text"],
|
||||
"sub_bracket_search": "true",
|
||||
"enabled": true
|
||||
},
|
||||
// Regex for different Languages
|
||||
{
|
||||
"name": "jsregex",
|
||||
"open": " *(/)",
|
||||
"close": "(/)[igm]*",
|
||||
"style": "regex",
|
||||
"scopes": ["string"],
|
||||
"language_filter": "whitelist",
|
||||
"language_list": ["JavaScript"],
|
||||
"sub_bracket_search": "true",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "perlregex",
|
||||
"open": "(?:m|s|tr)(.|\n)",
|
||||
"close": "(.|\n)(?:[igmos]*)",
|
||||
"style": "regex",
|
||||
"scopes": ["string.regexp"],
|
||||
"language_filter": "whitelist",
|
||||
"language_list": ["Perl"],
|
||||
"sub_bracket_search": "true",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "rubyregex",
|
||||
"open": " *(/)",
|
||||
"close": "(/)[imxo]*",
|
||||
"style": "regex",
|
||||
"scopes": ["string"],
|
||||
"language_filter": "whitelist",
|
||||
"language_list": ["Ruby"],
|
||||
"sub_bracket_search": "true",
|
||||
"enabled": true
|
||||
},
|
||||
// Markdown
|
||||
{
|
||||
"name": "mditalic",
|
||||
"open": "(\\*|_)",
|
||||
"close": "(\\*|_)",
|
||||
"style": "default",
|
||||
"scopes": ["markup.italic"],
|
||||
"language_filter": "whitelist",
|
||||
"language_list": ["Markdown"],
|
||||
"sub_bracket_search": "true",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "mdbold",
|
||||
"open": "(\\*\\*|__)",
|
||||
"close": "(\\*\\*|__)",
|
||||
"style": "default",
|
||||
"scopes": ["markup.bold"],
|
||||
"language_filter": "whitelist",
|
||||
"language_list": ["Markdown"],
|
||||
"sub_bracket_search": "true",
|
||||
"enabled": true
|
||||
}
|
||||
],
|
||||
|
||||
// Rule definitions for finding and matching brackets.
|
||||
// Brackets are found by using regex and can use scope
|
||||
// qualifiers exclude certain matches.
|
||||
// Once all matches are found, the closest pair surrounding
|
||||
// the cursor are selected.
|
||||
"brackets": [
|
||||
// Basic brackets
|
||||
{
|
||||
"name": "curly",
|
||||
"open": "(\\{)",
|
||||
"close": "(\\})",
|
||||
"style": "curly",
|
||||
"scope_exclude": ["string", "comment"],
|
||||
"scope_exclude_exceptions": ["string.other.math.block.environment.latex"],
|
||||
"language_filter": "blacklist",
|
||||
"language_list": ["Plain text"],
|
||||
"find_in_sub_search": "true",
|
||||
"ignore_string_escape": true,
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "round",
|
||||
"open": "(\\()",
|
||||
"close": "(\\))",
|
||||
"style": "round",
|
||||
"scope_exclude_exceptions": ["string.other.math.block.environment.latex"],
|
||||
"scope_exclude": ["string", "comment"],
|
||||
"language_filter": "blacklist",
|
||||
"language_list": ["Plain text"],
|
||||
"find_in_sub_search": "true",
|
||||
"ignore_string_escape": true,
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "square",
|
||||
"open": "(\\[)",
|
||||
"close": "(\\])",
|
||||
"style": "square",
|
||||
"scope_exclude": ["string", "comment"],
|
||||
"scope_exclude_exceptions": ["string.other.math.block.environment.latex"],
|
||||
"language_filter": "blacklist",
|
||||
"language_list": ["Plain text"],
|
||||
"find_in_sub_search": "true",
|
||||
"ignore_string_escape": true,
|
||||
"enabled": true
|
||||
},
|
||||
// HTML
|
||||
{
|
||||
"name": "html",
|
||||
"open": "(<)(?=[\\w\\:\\-]+(?:(?:\\s+[\\w\\-:]+(?:\\s*=\\s*(?:\"[^\"]*\"|'[^']*'|[^>\\s]+))?)*)\\s*\\/?>|\\/[\\w\\:\\-]+[^>]*>)",
|
||||
"close": "(?<=<)(?:[\\w\\:\\-]+(?:(?:\\s+[\\w\\-:]+(?:\\s*=\\s*(?:\"[^\"]*\"|'[^']*'|[^>\\s]+))?)*)\\s*\\/?|\\/[\\w\\:\\-]+[^>]*)(>)",
|
||||
"style": "tag",
|
||||
"scope_exclude": ["string", "comment"],
|
||||
"language_filter": "whitelist",
|
||||
"language_list": ["HTML", "HTML 5", "XML", "PHP"],
|
||||
"plugin_library": "bh_modules.tags",
|
||||
"find_in_sub_search": "only",
|
||||
"enabled": false
|
||||
},
|
||||
// CFML
|
||||
{
|
||||
"name": "cfml",
|
||||
"open": "(<)(?=[\\w\\:\\-]+(?:(?:\\s+[\\w\\-\\.:]+(?:\\s*=\\s*(?:\"[^\"]*\"|'[^']*'|[^>\\s]+))?)*|(?:(?<=cfif)|(?<=cfelseif))[^>]+)\\s*\\/?>|\\/[\\w\\:\\-]+[^>]*>)",
|
||||
"close": "(?<=<)(?:[\\w\\:\\-]+(?:(?:\\s+[\\w\\-\\.:]+(?:\\s*=\\s*(?:\"[^\"]*\"|'[^']*'|[^>\\s]+))?)*|(?:(?<=cfif)|(?<=cfelseif))[^>]+)\\s*\\/?|\\/[\\w\\:\\-]+[^>]*)(>)",
|
||||
"style": "tag",
|
||||
"scope_exclude": ["string", "comment"],
|
||||
"language_filter": "whitelist",
|
||||
"language_list": ["HTML+CFML", "ColdFusion", "ColdFusionCFC"],
|
||||
"plugin_library": "bh_modules.tags",
|
||||
"find_in_sub_search": "only",
|
||||
"enabled": false
|
||||
},
|
||||
// Angle
|
||||
{
|
||||
"name": "angle",
|
||||
"open": "(<)",
|
||||
"close": "(>)",
|
||||
"style": "angle",
|
||||
"scope_exclude": ["string", "comment", "keyword.operator"],
|
||||
"language_filter": "whitelist",
|
||||
"language_list": ["HTML", "HTML 5", "XML", "PHP", "HTML+CFML", "ColdFusion", "ColdFusionCFC"],
|
||||
"plugin_library": "bh_modules.tags",
|
||||
"enabled": true
|
||||
},
|
||||
// CSSedit groups
|
||||
{
|
||||
"name": "cssedit_groups",
|
||||
"open": "(/\\* *@group .*\\*/)",
|
||||
"close": "(/\\* *@end *\\*/)",
|
||||
"style": "default",
|
||||
"scope_exclude": [],
|
||||
"language_filter": "whitelist",
|
||||
"language_list": ["CSS"],
|
||||
"enabled": true
|
||||
},
|
||||
// Ruby conditional statements
|
||||
{
|
||||
"name": "ruby",
|
||||
"open": "(^\\s*\\b(?:if|case|until|unless|while|begin|class|module|def\\b\\s*[a-zA-Z_\\d]+)|\\bdo)\\b",
|
||||
"close": "\\b(end)\\b",
|
||||
"style": "default",
|
||||
"scope_exclude": ["string", "comment"],
|
||||
"plugin_library": "bh_modules.rubykeywords",
|
||||
"language_filter": "whitelist",
|
||||
"language_list": ["Ruby", "Ruby on Rails", "HTML (Rails)"],
|
||||
"enabled": true
|
||||
},
|
||||
// C/C++ compile switches
|
||||
{
|
||||
"name": "c_compile_switch",
|
||||
"open": "(\\#(?:if|ifdef|ifndef))\\b",
|
||||
"close": "(\\#endif)\\b",
|
||||
"style": "default",
|
||||
"scope_exclude": ["string", "comment"],
|
||||
"language_filter": "whitelist",
|
||||
"language_list": ["C++", "C", "Objective-C"],
|
||||
"enabled": true
|
||||
},
|
||||
// PHP conditional keywords
|
||||
{
|
||||
"name": "php_keywords",
|
||||
"open": "(?:^\\s*|<\\?(?:php)?\\s*)?\\b(if|foreach|for|while|switch)\\b(?=.*:\\s*(?:\\?>\\s*)?$)",
|
||||
"close": "(?:^\\s*|<\\?(?:php)?\\s*)?\\b(endif|endfor|endforeach|endwhile|endswitch)\\b(?=\\s*;\\s*(?:\\?>\\s*)?$)",
|
||||
"style": "default",
|
||||
"language_filter": "whitelist",
|
||||
"scope_exclude": ["string", "comment"],
|
||||
"plugin_library": "bh_modules.phpkeywords",
|
||||
"language_list": ["HTML", "HTML 5", "XML", "PHP", "HTML+CFML", "ColdFusion", "ColdFusionCFC"],
|
||||
"enabled": true
|
||||
},
|
||||
// Erlang conditional statements
|
||||
{
|
||||
"name": "erlang",
|
||||
"open": "\\s*(\\b(?:if|case|begin|try|fun(?=\\s*\\()|receive)\\b)",
|
||||
"close": "\\b(end)\\b",
|
||||
"style": "default",
|
||||
"scope_exclude": ["string", "comment"],
|
||||
"language_filter": "whitelist",
|
||||
"language_list": ["Erlang", "HTML (Erlang)"],
|
||||
"enabled": true
|
||||
}
|
||||
],
|
||||
|
||||
// Define region highlight styles
|
||||
"bracket_styles": {
|
||||
// "default" and "unmatched" styles are special
|
||||
// styles. If they are not defined here,
|
||||
// they will be generated internally with
|
||||
// internal defaults.
|
||||
|
||||
// "default" style defines attributes that
|
||||
// will be used for any style that does not
|
||||
// explicitly define that attribute. So if
|
||||
// a style does not define a color, it will
|
||||
// use the color from the "default" style.
|
||||
"default": {
|
||||
"icon": "dot",
|
||||
"color": "brackethighlighter.default",
|
||||
"style": "underline"
|
||||
},
|
||||
|
||||
// This particular style is used to highlight
|
||||
// unmatched bracekt pairs. It is a special
|
||||
// style.
|
||||
"unmatched": {
|
||||
"icon": "question",
|
||||
// "color": "brackethighlighter.unmatched",
|
||||
"style": "outline"
|
||||
},
|
||||
// User defined region styles
|
||||
"curly": {
|
||||
"icon": "curly_bracket"
|
||||
// "color": "brackethighlighter.curly",
|
||||
// "style": "underline"
|
||||
},
|
||||
"round": {
|
||||
"icon": "round_bracket"
|
||||
// "color": "brackethighlighter.round",
|
||||
// "style": "underline"
|
||||
},
|
||||
"square": {
|
||||
"icon": "square_bracket"
|
||||
// "color": "brackethighlighter.square",
|
||||
// "style": "underline"
|
||||
},
|
||||
"angle": {
|
||||
"icon": "angle_bracket"
|
||||
// "color": "brackethighlighter.angle",
|
||||
// "style": "underline"
|
||||
},
|
||||
"tag": {
|
||||
"icon": "tag",
|
||||
// "color": "brackethighlighter.tag",
|
||||
"style": "outline"
|
||||
},
|
||||
"single_quote": {
|
||||
"icon": "single_quote"
|
||||
// "color": "brackethighlighter.quote",
|
||||
// "style": "underline"
|
||||
},
|
||||
"double_quote": {
|
||||
"icon": "double_quote"
|
||||
// "color": "brackethighlighter.quote",
|
||||
// "style": "underline"
|
||||
},
|
||||
"regex": {
|
||||
"icon": "regex"
|
||||
// "color": "brackethighlighter.quote",
|
||||
// "style": "underline"
|
||||
}
|
||||
},
|
||||
|
||||
/* Plugin settings */
|
||||
|
||||
// Style to use for matched tags
|
||||
"tag_style": "tag",
|
||||
|
||||
// Scopes to exclude from tag searches
|
||||
"tag_scope_exclude": ["string", "comment"],
|
||||
|
||||
// Determine which style of tag-matching to use in which syntax
|
||||
"tag_mode": {
|
||||
"xhtml": ["XML"],
|
||||
"html": ["HTML", "HTML 5", "PHP"],
|
||||
"cfml": ["HTML+CFML", "ColdFusion", "ColdFusionCFC"]
|
||||
}
|
||||
}
|
@@ -0,0 +1 @@
|
||||
|
@@ -0,0 +1,41 @@
|
||||
import bh_plugin
|
||||
import re
|
||||
import sublime
|
||||
|
||||
|
||||
class BracketRemove(bh_plugin.BracketPluginCommand):
|
||||
def decrease_indent_level(self, edit, row_first, row_last):
|
||||
tab_size = self.view.settings().get("tab_size", 4)
|
||||
indents = re.compile(r"^(?:\t| {%d}| *)((?:\t| {%d}| )*)([\s\S]*)" % (tab_size, tab_size))
|
||||
if not self.single_line:
|
||||
for x in reversed(range(row_first, row_last + 1)):
|
||||
line = self.view.full_line(self.view.text_point(x, 0))
|
||||
text = self.view.substr(line)
|
||||
m = indents.match(text)
|
||||
if m:
|
||||
self.view.replace(edit, line, m.group(1) + m.group(2))
|
||||
|
||||
def run(self, edit, name, remove_content=False, remove_indent=False, remove_block=False):
|
||||
if remove_content:
|
||||
self.view.replace(edit, sublime.Region(self.left.begin, self.right.end), "")
|
||||
else:
|
||||
row_first = self.view.rowcol(self.left.end)[0] + 1
|
||||
row_last = self.view.rowcol(self.right.begin)[0] - 1
|
||||
self.single_line = not row_first <= row_last
|
||||
if remove_block and not self.single_line:
|
||||
self.view.replace(edit, self.view.full_line(self.right.toregion()), "")
|
||||
else:
|
||||
self.view.replace(edit, self.right.toregion(), "")
|
||||
if remove_indent:
|
||||
self.decrease_indent_level(edit, row_first, row_last)
|
||||
if remove_block and not self.single_line:
|
||||
self.view.replace(edit, self.view.full_line(self.left.toregion()), "")
|
||||
else:
|
||||
self.view.replace(edit, self.left.toregion(), "")
|
||||
|
||||
self.left = None
|
||||
self.right = None
|
||||
|
||||
|
||||
def plugin():
|
||||
return BracketRemove
|
@@ -0,0 +1,33 @@
|
||||
import bh_plugin
|
||||
import sublime
|
||||
|
||||
DEFAULT_TAGS = ["cfml", "html", "angle"]
|
||||
|
||||
|
||||
class SelectBracket(bh_plugin.BracketPluginCommand):
|
||||
def run(self, edit, name, select='', tags=DEFAULT_TAGS):
|
||||
left, right = self.left, self.right
|
||||
first, last = left.end, right.begin
|
||||
if select == 'left':
|
||||
if name in tags and left.size() > 1:
|
||||
first, last = left.begin + 1, left.begin + 1
|
||||
else:
|
||||
first, last = left.end, left.end
|
||||
elif select == 'right':
|
||||
if left.end != right.end:
|
||||
if name in tags and left.size() > 1:
|
||||
first, last = right.begin + 1, right.begin + 1
|
||||
else:
|
||||
first, last = right.begin, right.begin
|
||||
else:
|
||||
# There is no second bracket, so just select the first
|
||||
if name in tags and left.size() > 1:
|
||||
first, last = left.begin + 1, left.begin + 1
|
||||
else:
|
||||
first, last = right.end, right.end
|
||||
|
||||
self.selection = [sublime.Region(first, last)]
|
||||
|
||||
|
||||
def plugin():
|
||||
return SelectBracket
|
@@ -0,0 +1,16 @@
|
||||
import bh_plugin
|
||||
import sublime
|
||||
|
||||
|
||||
class FoldBrackets(bh_plugin.BracketPluginCommand):
|
||||
def run(self, edit, name):
|
||||
content = sublime.Region(self.left.end, self.right.begin)
|
||||
new_content = [content]
|
||||
if content.size > 0:
|
||||
if self.view.fold(content) == False:
|
||||
new_content = self.view.unfold(content)
|
||||
self.selection = new_content
|
||||
|
||||
|
||||
def plugin():
|
||||
return FoldBrackets
|
@@ -0,0 +1,2 @@
|
||||
def compare(name, first, second, bfr):
|
||||
return "end" + bfr[first.begin:first.end].lower() == bfr[second.begin:second.end].lower()
|
@@ -0,0 +1,12 @@
|
||||
import re
|
||||
|
||||
|
||||
def post_match(view, name, style, first, second, center, bfr, threshold):
|
||||
if first is not None:
|
||||
# Strip whitespace from the beginning of first bracket
|
||||
open_bracket = bfr[first.begin:first.end]
|
||||
if open_bracket != "do":
|
||||
m = re.match(r"^(\s*\b)[\w\W]*", open_bracket)
|
||||
if m:
|
||||
first = first.move(first.begin + m.end(1), first.end)
|
||||
return first, second, style
|
@@ -0,0 +1,14 @@
|
||||
import sublime
|
||||
from bh_plugin import ImportModule as ImpMod
|
||||
BracketRemove = ImpMod.import_from("bh_modules.bracketremove", "BracketRemove")
|
||||
|
||||
|
||||
class SwapBrackets(BracketRemove):
|
||||
def run(self, edit, name, remove_content=False, remove_indent=False, remove_block=False):
|
||||
offset = self.left.toregion().size()
|
||||
self.selection = [sublime.Region(self.left.begin, self.right.begin - offset)]
|
||||
super(SwapBrackets, self).run(edit, name)
|
||||
|
||||
|
||||
def plugin():
|
||||
return SwapBrackets
|
@@ -0,0 +1,46 @@
|
||||
import bh_plugin
|
||||
import sublime
|
||||
|
||||
|
||||
class SwapQuotes(bh_plugin.BracketPluginCommand):
|
||||
def escaped(self, idx):
|
||||
view = self.view
|
||||
escaped = False
|
||||
while idx >= 0 and view.substr(idx) == '\\':
|
||||
escaped = ~escaped
|
||||
idx -= 1
|
||||
return escaped
|
||||
|
||||
def run(self, edit, name):
|
||||
view = self.view
|
||||
quote = view.substr(self.left.begin)
|
||||
if quote != "'" and quote != '"':
|
||||
return
|
||||
new = "'" if (quote == '"') else '"'
|
||||
old = quote
|
||||
begin = self.left.end
|
||||
end = self.right.begin
|
||||
content_end = self.right.begin
|
||||
|
||||
view.replace(edit, self.left.toregion(), view.substr(self.left.toregion()).replace(old, new))
|
||||
view.replace(edit, self.right.toregion(), view.substr(self.right.toregion()).replace(old, new))
|
||||
|
||||
offset = 0
|
||||
while begin < end + offset:
|
||||
char = view.substr(begin)
|
||||
if char == old and self.escaped(begin - 1):
|
||||
view.replace(edit, sublime.Region(begin - 1, begin), '')
|
||||
offset -= 1
|
||||
content_end -= 1
|
||||
elif char == new and not self.escaped(begin - 1):
|
||||
view.insert(edit, begin, "\\")
|
||||
offset += 1
|
||||
content_end += 1
|
||||
begin += 1
|
||||
|
||||
self.right = self.right.move(content_end, end + offset)
|
||||
self.selection = [sublime.Region(content_end)]
|
||||
|
||||
|
||||
def plugin():
|
||||
return SwapQuotes
|
@@ -0,0 +1,54 @@
|
||||
import bh_plugin
|
||||
|
||||
|
||||
class SelectAttr(bh_plugin.BracketPluginCommand):
|
||||
def run(self, edit, name, direction='right'):
|
||||
if self.left.size() <= 1:
|
||||
return
|
||||
tag_name = r'[\w\:\-]+'
|
||||
attr_name = r'''([\w\-\.:]+)(?:\s*=\s*(?:(?:"((?:\.|[^"])*)")|(?:'((?:\.|[^'])*)')|([^>\s]+)))?'''
|
||||
tname = self.view.find(tag_name, self.left.begin)
|
||||
current = self.selection[0].b
|
||||
region = self.view.find(attr_name, tname.b)
|
||||
selection = self.selection
|
||||
|
||||
if direction == 'left':
|
||||
last = None
|
||||
|
||||
# Keep track of last attr
|
||||
if region != None and current <= region.b and region.b < self.left.end:
|
||||
last = region
|
||||
|
||||
while region != None and region.b < self.left.end:
|
||||
# Select attribute until you have closest to the left of selection
|
||||
if current > region.b:
|
||||
selection = [region]
|
||||
last = None
|
||||
# Update last attr
|
||||
elif last != None:
|
||||
last = region
|
||||
region = self.view.find(attr_name, region.b)
|
||||
# Wrap right
|
||||
if last != None:
|
||||
selection = [last]
|
||||
else:
|
||||
first = None
|
||||
# Keep track of first attr
|
||||
if region != None and region.b < self.left.end:
|
||||
first = region
|
||||
|
||||
while region != None and region.b < self.left.end:
|
||||
# Select closest attr to the right of the selection
|
||||
if current < region.b:
|
||||
selection = [region]
|
||||
first = None
|
||||
break
|
||||
region = self.view.find(attr_name, region.b)
|
||||
# Wrap left
|
||||
if first != None:
|
||||
selection = [first]
|
||||
self.selection = selection
|
||||
|
||||
|
||||
def plugin():
|
||||
return SelectAttr
|
@@ -0,0 +1,14 @@
|
||||
import bh_plugin
|
||||
|
||||
|
||||
class TagNameSelect(bh_plugin.BracketPluginCommand):
|
||||
def run(self, edit, name):
|
||||
if self.left.size() > 1:
|
||||
tag_name = '[\w\:\-]+'
|
||||
region1 = self.view.find(tag_name, self.left.begin)
|
||||
region2 = self.view.find(tag_name, self.right.begin)
|
||||
self.selection = [region1, region2]
|
||||
|
||||
|
||||
def plugin():
|
||||
return TagNameSelect
|
@@ -0,0 +1,243 @@
|
||||
import re
|
||||
from collections import namedtuple
|
||||
import sublime
|
||||
from os.path import basename
|
||||
|
||||
FLAGS = re.MULTILINE | re.IGNORECASE
|
||||
HTML_START = re.compile(r'''<([\w\:\-]+)((?:\s+[\w\-:]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^>\s]+))?)*)\s*(\/?)>''', FLAGS)
|
||||
CFML_START = re.compile(r'''<([\w\:\-]+)((?:\s+[\w\-\.:]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^>\s]+))?)*|(?:(?<=cfif)|(?<=cfelseif))[^>]+)\s*(\/?)>''', FLAGS)
|
||||
START_TAG = {
|
||||
"html": HTML_START,
|
||||
"xhtml": HTML_START,
|
||||
"cfml": CFML_START
|
||||
}
|
||||
END_TAG = re.compile(r'<\/([\w\:\-]+)[^>]*>', FLAGS)
|
||||
|
||||
self_closing_tags = set("colgroup dd dt li options p td tfoot th thead tr".split())
|
||||
single_tags = set("area base basefont br col frame hr img input isindex link meta param embed".split())
|
||||
|
||||
|
||||
class TagEntry(namedtuple('TagEntry', ['begin', 'end', 'name', 'self_closing', 'single'], verbose=False)):
|
||||
def move(self, begin, end):
|
||||
return self._replace(begin=begin, end=end)
|
||||
|
||||
|
||||
def compare_languge(language, lang_list):
|
||||
found = False
|
||||
for l in lang_list:
|
||||
if language == l.lower():
|
||||
found = True
|
||||
break
|
||||
return found
|
||||
|
||||
|
||||
def get_tag_mode(view, tag_mode_config):
|
||||
default_mode = None
|
||||
syntax = view.settings().get('syntax')
|
||||
language = basename(syntax).replace('.tmLanguage', '').lower() if syntax != None else "plain text"
|
||||
for mode in ["html", "xhtml", "cfml"]:
|
||||
if compare_languge(language, tag_mode_config.get(mode, [])):
|
||||
return mode
|
||||
return default_mode
|
||||
|
||||
|
||||
def post_match(view, name, style, first, second, center, bfr, threshold):
|
||||
left, right = first, second
|
||||
threshold = [0, len(bfr)] if threshold is None else threshold
|
||||
tag_settings = sublime.load_settings("bh_core.sublime-settings")
|
||||
tag_mode = get_tag_mode(view, tag_settings.get("tag_mode", {}))
|
||||
tag_style = tag_settings.get("tag_style", "angle")
|
||||
bracket_style = style
|
||||
|
||||
if first is not None and tag_mode is not None:
|
||||
matcher = TagMatch(view, bfr, threshold, first, second, center, tag_mode)
|
||||
left, right = matcher.match()
|
||||
if not matcher.no_tag:
|
||||
bracket_style = tag_style
|
||||
|
||||
return left, right, bracket_style
|
||||
|
||||
|
||||
class TagSearch(object):
|
||||
def __init__(self, view, bfr, window, center, pattern, match_type):
|
||||
self.start = window[0]
|
||||
self.end = window[1]
|
||||
self.center = center
|
||||
self.pattern = pattern
|
||||
self.match_type = match_type
|
||||
self.bfr = bfr
|
||||
self.prev_match = None
|
||||
self.return_prev = False
|
||||
self.done = False
|
||||
self.view = view
|
||||
self.scope_exclude = sublime.load_settings("bh_core.sublime-settings").get("tag_scope_exclude")
|
||||
|
||||
def scope_check(self, pt):
|
||||
illegal_scope = False
|
||||
for exclude in self.scope_exclude:
|
||||
illegal_scope |= bool(self.view.score_selector(pt, exclude))
|
||||
return illegal_scope
|
||||
|
||||
def reset_end_state(self):
|
||||
self.done = False
|
||||
self.prev_match = None
|
||||
self.return_prev = False
|
||||
|
||||
def remember(self):
|
||||
self.return_prev = True
|
||||
self.done = False
|
||||
|
||||
def get_tags(self, bracket_code):
|
||||
if self.done:
|
||||
return
|
||||
if self.return_prev:
|
||||
self.return_prev = False
|
||||
yield self.prev_match
|
||||
for m in self.pattern.finditer(self.bfr, self.start, self.end):
|
||||
name = m.group(1).lower()
|
||||
if not self.match_type:
|
||||
single = bool(m.group(3) != "" or name in single_tags)
|
||||
self_closing = name in self_closing_tags or name.startswith("cf")
|
||||
else:
|
||||
single = False
|
||||
self_closing = False
|
||||
start = m.start(0)
|
||||
end = m.end(0)
|
||||
if not self.scope_check(start):
|
||||
self.prev_match = TagEntry(start, end, name, self_closing, single)
|
||||
self.start = end
|
||||
yield self.prev_match
|
||||
self.done = True
|
||||
|
||||
|
||||
class TagMatch(object):
|
||||
def __init__(self, view, bfr, threshold, first, second, center, mode):
|
||||
self.view = view
|
||||
self.bfr = bfr
|
||||
self.mode = mode
|
||||
tag, tag_type, tag_end = self.get_first_tag(first[0])
|
||||
self.left, self.right = None, None
|
||||
self.window = None
|
||||
self.no_tag = False
|
||||
if tag and first[0] < center < tag_end:
|
||||
if tag.single:
|
||||
self.left = tag
|
||||
self.right = tag
|
||||
else:
|
||||
if tag_type == "open":
|
||||
self.left = tag
|
||||
self.window = (tag_end, len(bfr) if threshold is None else threshold[1])
|
||||
else:
|
||||
self.right = tag
|
||||
self.window = (0 if threshold is None else threshold[0], first[0])
|
||||
else:
|
||||
self.left = first
|
||||
self.right = second
|
||||
self.no_tag = True
|
||||
|
||||
def get_first_tag(self, offset):
|
||||
tag = None
|
||||
tag_type = None
|
||||
self_closing = False
|
||||
single = False
|
||||
m = START_TAG[self.mode].match(self.bfr[offset:])
|
||||
end = None
|
||||
if m:
|
||||
name = m.group(1).lower()
|
||||
single = bool(m.group(3) != "" or name in single_tags)
|
||||
if self.mode == "html":
|
||||
self_closing = name in self_closing_tags
|
||||
elif self.mode == "cfml":
|
||||
self_closing = name in self_closing_tags or name.startswith("cf")
|
||||
start = m.start(0) + offset
|
||||
end = m.end(0) + offset
|
||||
tag = TagEntry(start, end, name, self_closing, single)
|
||||
tag_type = "open"
|
||||
self.center = end
|
||||
else:
|
||||
m = END_TAG.match(self.bfr[offset:])
|
||||
if m:
|
||||
name = m.group(1).lower()
|
||||
start = m.start(0) + offset
|
||||
end = m.end(0) + offset
|
||||
tag = TagEntry(start, end, name, self_closing, single)
|
||||
tag_type = "close"
|
||||
self.center = offset
|
||||
return tag, tag_type, end
|
||||
|
||||
def compare_tags(self, left, right):
|
||||
return left.name == right.name
|
||||
|
||||
def resolve_self_closing(self, stack, c):
|
||||
found_tag = None
|
||||
b = stack[-1]
|
||||
if self.compare_tags(b, c):
|
||||
found_tag = b
|
||||
stack.pop()
|
||||
else:
|
||||
while b is not None and b.self_closing:
|
||||
stack.pop()
|
||||
if len(stack):
|
||||
b = stack[-1]
|
||||
if self.compare_tags(b, c):
|
||||
found_tag = b
|
||||
stack.pop()
|
||||
break
|
||||
else:
|
||||
b = None
|
||||
return found_tag
|
||||
|
||||
def match(self):
|
||||
stack = []
|
||||
|
||||
# No tags to search for
|
||||
if self.no_tag or (self.left and self.right):
|
||||
return self.left, self.right
|
||||
|
||||
# Init tag matching objects
|
||||
osearch = TagSearch(self.view, self.bfr, self.window, self.center, START_TAG[self.mode], 0)
|
||||
csearch = TagSearch(self.view, self.bfr, self.window, self.center, END_TAG, 1)
|
||||
|
||||
# Searching for opening or closing tag to match
|
||||
match_type = 0 if self.right else 1
|
||||
|
||||
# Match the tags
|
||||
for c in csearch.get_tags(match_type):
|
||||
if len(stack) and osearch.done:
|
||||
if self.resolve_self_closing(stack, c):
|
||||
continue
|
||||
for o in osearch.get_tags(match_type):
|
||||
if o.end <= c.begin:
|
||||
if not o.single:
|
||||
stack.append(o)
|
||||
continue
|
||||
else:
|
||||
osearch.remember()
|
||||
break
|
||||
|
||||
if len(stack):
|
||||
if self.resolve_self_closing(stack, c):
|
||||
continue
|
||||
elif match_type == 0 and not osearch.done:
|
||||
continue
|
||||
if match_type == 1:
|
||||
if self.left is None or self.compare_tags(self.left, c):
|
||||
self.right = c
|
||||
elif self.left.self_closing:
|
||||
self.right = self.left
|
||||
break
|
||||
|
||||
if match_type == 0:
|
||||
# Find the rest of the the unmatched left side open brackets
|
||||
# approaching the cursor if all closing brackets were matched
|
||||
# Select the most recent open bracket on the stack.
|
||||
for o in osearch.get_tags(0):
|
||||
if not o.single:
|
||||
stack.append(o)
|
||||
if len(stack):
|
||||
self.left = self.resolve_self_closing(stack, self.right)
|
||||
elif self.right is None and self.left is not None and self.left.self_closing:
|
||||
# Account for the opening tag that was found being a self closing
|
||||
self.right = self.left
|
||||
|
||||
return self.left, self.right
|
@@ -0,0 +1,140 @@
|
||||
import sublime
|
||||
from os.path import normpath, join
|
||||
import imp
|
||||
from collections import namedtuple
|
||||
import sys
|
||||
import traceback
|
||||
import warnings
|
||||
|
||||
|
||||
class BracketRegion (namedtuple('BracketRegion', ['begin', 'end'], verbose=False)):
|
||||
"""
|
||||
Bracket Regions for plugins
|
||||
"""
|
||||
|
||||
def move(self, begin, end):
|
||||
"""
|
||||
Move bracket region to different points
|
||||
"""
|
||||
|
||||
return self._replace(begin=begin, end=end)
|
||||
|
||||
def size(self):
|
||||
"""
|
||||
Get the size of the region
|
||||
"""
|
||||
|
||||
return abs(self.begin - self.end)
|
||||
|
||||
def toregion(self):
|
||||
"""
|
||||
Convert to sublime region
|
||||
"""
|
||||
|
||||
return sublime.Region(self.begin, self.end)
|
||||
|
||||
|
||||
def is_bracket_region(obj):
|
||||
"""
|
||||
Check if object is a BracketRegion
|
||||
"""
|
||||
|
||||
return isinstance(obj, BracketRegion)
|
||||
|
||||
|
||||
class ImportModule(object):
|
||||
@classmethod
|
||||
def import_module(cls, module_name, loaded=None):
|
||||
# Pull in built-in and custom plugin directory
|
||||
if module_name.startswith("bh_modules."):
|
||||
path_name = join(sublime.packages_path(), "BracketHighlighter", normpath(module_name.replace('.', '/')))
|
||||
else:
|
||||
path_name = join(sublime.packages_path(), normpath(module_name.replace('.', '/')))
|
||||
path_name += ".py"
|
||||
if loaded is not None and module_name in loaded:
|
||||
module = sys.modules[module_name]
|
||||
else:
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
# Ignore warnings about plugin folder not being a python package
|
||||
warnings.simplefilter("always")
|
||||
module = imp.new_module(module_name)
|
||||
sys.modules[module_name] = module
|
||||
source = None
|
||||
with open(path_name) as f:
|
||||
source = f.read().replace('\r', '')
|
||||
cls.__execute_module(source, module_name)
|
||||
w = filter(lambda i: issubclass(i.category, UserWarning), w)
|
||||
return module
|
||||
|
||||
@classmethod
|
||||
def __execute_module(cls, source, module_name):
|
||||
exec(compile(source, module_name, 'exec'), sys.modules[module_name].__dict__)
|
||||
|
||||
@classmethod
|
||||
def import_from(cls, module_name, attribute):
|
||||
return getattr(cls.import_module(module_name), attribute)
|
||||
|
||||
|
||||
class BracketPlugin(object):
|
||||
"""
|
||||
Class for preparing and running plugins
|
||||
"""
|
||||
|
||||
def __init__(self, plugin, loaded):
|
||||
"""
|
||||
Load plugin module
|
||||
"""
|
||||
|
||||
self.enabled = False
|
||||
self.args = plugin['args'] if ("args" in plugin) else {}
|
||||
self.plugin = None
|
||||
if 'command' in plugin:
|
||||
plib = plugin['command']
|
||||
try:
|
||||
module = ImportModule.import_module(plib, loaded)
|
||||
self.plugin = getattr(module, 'plugin')()
|
||||
loaded.add(plib)
|
||||
self.enabled = True
|
||||
except Exception:
|
||||
print 'BracketHighlighter: Load Plugin Error: %s\n%s' % (plugin['command'], traceback.format_exc())
|
||||
|
||||
def is_enabled(self):
|
||||
"""
|
||||
Check if plugin is enabled
|
||||
"""
|
||||
|
||||
return self.enabled
|
||||
|
||||
def run_command(self, view, name, left, right, selection):
|
||||
"""
|
||||
Load arguments into plugin and run
|
||||
"""
|
||||
|
||||
plugin = self.plugin()
|
||||
setattr(plugin, "left", left)
|
||||
setattr(plugin, "right", right)
|
||||
setattr(plugin, "view", view)
|
||||
setattr(plugin, "selection", selection)
|
||||
edit = view.begin_edit()
|
||||
self.args["edit"] = edit
|
||||
self.args["name"] = name
|
||||
try:
|
||||
plugin.run(**self.args)
|
||||
left, right, selection = plugin.left, plugin.right, plugin.selection
|
||||
except Exception:
|
||||
print "BracketHighlighter: Plugin Run Error:\n%s" % str(traceback.format_exc())
|
||||
view.end_edit(edit)
|
||||
return left, right, selection
|
||||
|
||||
|
||||
class BracketPluginCommand(object):
|
||||
"""
|
||||
Bracket Plugin base class
|
||||
"""
|
||||
|
||||
def run(self, bracket, content, selection):
|
||||
"""
|
||||
Runs the plugin class
|
||||
"""
|
||||
|
||||
pass
|
@@ -0,0 +1,51 @@
|
||||
import sublime_plugin
|
||||
from collections import namedtuple
|
||||
|
||||
MENU = namedtuple("Menu", "simple content block block_indent")(
|
||||
"Remove Brackets",
|
||||
"Remove Brackets and Content",
|
||||
"Remove Brackets: Block",
|
||||
"Remove Brackets: Indented Block"
|
||||
)
|
||||
|
||||
|
||||
class BhRemoveBracketsCommand(sublime_plugin.WindowCommand):
|
||||
"""
|
||||
Command to remove current highlighted brackets and optionally content
|
||||
"""
|
||||
|
||||
def remove_brackets(self, value):
|
||||
"""
|
||||
Perform removal of brackets
|
||||
"""
|
||||
|
||||
if value != -1:
|
||||
menu_item = MENU[value]
|
||||
indent = menu_item == MENU.block_indent
|
||||
block = menu_item == MENU.block or menu_item == MENU.block_indent
|
||||
content = menu_item == MENU.content
|
||||
|
||||
self.window.run_command(
|
||||
"bh_key",
|
||||
{
|
||||
"plugin": {
|
||||
"type": ["__all__"],
|
||||
"command": "bh_modules.bracketremove",
|
||||
"args": {
|
||||
"remove_indent": indent,
|
||||
"remove_block": block,
|
||||
"remove_content": content
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
def run(self):
|
||||
"""
|
||||
Show menu of removal options
|
||||
"""
|
||||
|
||||
self.window.show_quick_panel(
|
||||
list(MENU),
|
||||
self.remove_brackets
|
||||
)
|
@@ -0,0 +1,44 @@
|
||||
import sublime_plugin
|
||||
import bh_wrapping
|
||||
|
||||
|
||||
class SwapBrackets(bh_wrapping.WrapBrackets):
|
||||
def wrap(self, wrap_entry):
|
||||
if wrap_entry < 0:
|
||||
return
|
||||
|
||||
self._style = ["inline"]
|
||||
|
||||
self.brackets = self._brackets[wrap_entry]
|
||||
self.wrap_brackets(0)
|
||||
|
||||
|
||||
class SwapBracketsCommand(sublime_plugin.WindowCommand):
|
||||
def swap_brackets(self, value):
|
||||
if value < 0:
|
||||
return
|
||||
|
||||
self.brackets = self.wrap._brackets[value]
|
||||
|
||||
self.window.run_command(
|
||||
"bh_key",
|
||||
{
|
||||
"plugin": {
|
||||
"type": ["__all__"],
|
||||
"command": "bh_modules.swapbrackets"
|
||||
}
|
||||
}
|
||||
)
|
||||
self.wrap.wrap(value)
|
||||
|
||||
def run(self):
|
||||
view = self.window.active_view()
|
||||
if view is None:
|
||||
return
|
||||
self.wrap = SwapBrackets(view, "bh_swapping.sublime-settings", "swapping")
|
||||
|
||||
if len(self.wrap._menu):
|
||||
self.window.show_quick_panel(
|
||||
self.wrap._menu,
|
||||
self.swap_brackets
|
||||
)
|
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"swapping": [
|
||||
{
|
||||
"enabled": true, "language_list": [], "language_filter": "whitelist", "entries": [
|
||||
{"name": "<> Angle", "brackets": ["<", ">${BH_SEL}"]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"enabled": true, "language_list": ["Plain text"], "language_filter": "blacklist", "entries": [
|
||||
{"name": "{} Curly", "brackets": ["{", "}${BH_SEL}"]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"enabled": true, "language_list": ["Plain text"], "language_filter": "blacklist", "entries": [
|
||||
{"name": "() Round", "brackets": ["(", ")${BH_SEL}"]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"enabled": true, "language_list": ["Plain text"], "language_filter": "blacklist", "entries": [
|
||||
{"name": "[] Square", "brackets": ["[", "]${BH_SEL}"]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"enabled": true, "language_list": ["HTML", "HTML 5", "XML", "PHP", "HTML+CFML", "ColdFusion", "ColdFusionCFC"], "language_filter": "whitelist", "entries": [
|
||||
{"name": "HTML/XML Tag", "brackets": ["<${BH_SEL:NAME}>", "</${BH_SEL:NAME}>"]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"enabled": true, "language_list": ["Markdown"], "language_filter": "whitelist", "entries": [
|
||||
{"name": "Mardown: Bold", "brackets": ["**", "**${BH_SEL}"]},
|
||||
{"name": "Mardown: Italic", "brackets": ["_", "_${BH_SEL}"]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"enabled": true, "language_list": ["C++", "C"], "language_filter": "whitelist", "entries": [
|
||||
{"name": "C/C++: #if", "brackets": ["#if ${BH_SEL}", "#endif"]},
|
||||
{"name": "C/C++: #if, #else", "brackets": ["#if${BH_SEL}", "#else\n${BH_TAB:/* CODE */}\n#endif"]},
|
||||
{"name": "C/C++: #if, #elif", "brackets": ["#if${BH_SEL}", "#elif ${BH_TAB:/* CONDITION */}\n${BH_TAB:/* CODE */}\n#endif"]},
|
||||
{"name": "C/C++: #ifdef", "brackets": ["#ifdef${BH_SEL}", "#endif"]},
|
||||
{"name": "C/C++: #ifdef, #else", "brackets": ["#ifdef${BH_SEL}", "#else\n${BH_TAB:/* CODE */}\n#endif"]},
|
||||
{"name": "C/C++: #ifndef", "brackets": ["#ifndef${BH_SEL}", "#endif"]},
|
||||
{"name": "C/C++: #ifndef, #else", "brackets": ["#ifndef${BH_SEL}", "#else\n${BH_TAB:/* CODE */}\n#endif"]}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
@@ -0,0 +1,368 @@
|
||||
import sublime
|
||||
import sublime_plugin
|
||||
from os.path import basename
|
||||
import re
|
||||
|
||||
|
||||
BH_TABSTOPS = re.compile(r"(\$\{BH_(SEL|TAB)(?:\:([^\}]+))?\})")
|
||||
TAB_REGION = "bh_plugin_wrapping_tabstop"
|
||||
SEL_REGION = "bh_plugin_wrapping_select"
|
||||
OUT_REGION = "bh_plugin_wrapping_outlier"
|
||||
|
||||
VALID_INSERT_STYLES = (
|
||||
("inline", "Inline Insert"),
|
||||
("block", "Block Insert"),
|
||||
("indent_block", "Indented Block Insert")
|
||||
)
|
||||
|
||||
|
||||
def exclude_entry(enabled, filter_type, language_list, language):
|
||||
"""
|
||||
Exclude bracket wrapping entry by filter
|
||||
"""
|
||||
|
||||
exclude = True
|
||||
if enabled:
|
||||
# Black list languages
|
||||
if filter_type == 'blacklist':
|
||||
exclude = False
|
||||
if language != None:
|
||||
for item in language_list:
|
||||
if language == item.lower():
|
||||
exclude = True
|
||||
break
|
||||
#White list languages
|
||||
elif filter_type == 'whitelist':
|
||||
if language != None:
|
||||
for item in language_list:
|
||||
if language == item.lower():
|
||||
exclude = False
|
||||
break
|
||||
return exclude
|
||||
|
||||
|
||||
class TextInsertion(object):
|
||||
"""
|
||||
Wrapper class for inserting text
|
||||
"""
|
||||
|
||||
def __init__(self, view, edit):
|
||||
"""
|
||||
Store view and edit objects
|
||||
"""
|
||||
|
||||
self.view = view
|
||||
self.edit = edit
|
||||
|
||||
def insert(self, pt, text):
|
||||
"""
|
||||
Peform insertion
|
||||
"""
|
||||
|
||||
return self.view.insert(self.edit, pt, text)
|
||||
|
||||
|
||||
class WrapBrackets(object):
|
||||
"""
|
||||
Wrap the current selection(s) with the defined wrapping options
|
||||
"""
|
||||
|
||||
def __init__(self, view, setting_file, attribute):
|
||||
self.view = view
|
||||
self._menu = []
|
||||
self._brackets = []
|
||||
self._insert = []
|
||||
self._style = []
|
||||
self.read_wrap_entries(setting_file, attribute)
|
||||
|
||||
def inline(self, edit, sel):
|
||||
"""
|
||||
Inline wrap
|
||||
"""
|
||||
|
||||
ti = TextInsertion(self.view, edit)
|
||||
|
||||
offset1 = ti.insert(sel.begin(), self.brackets[0])
|
||||
self.insert_regions.append(sublime.Region(sel.begin(), sel.begin() + offset1))
|
||||
offset2 = ti.insert(sel.end() + offset1, self.brackets[1])
|
||||
self.insert_regions.append(sublime.Region(sel.end() + offset1, sel.end() + offset1 + offset2))
|
||||
|
||||
def block(self, edit, sel, indent=False):
|
||||
"""
|
||||
Wrap brackets around selection and block off the content
|
||||
"""
|
||||
|
||||
# Calculate number of lines between brackets
|
||||
self.calculate_lines(sel)
|
||||
# Calculate the current indentation of first bracket
|
||||
self.calculate_indentation(sel)
|
||||
|
||||
ti = TextInsertion(self.view, edit)
|
||||
|
||||
line_offset = 0
|
||||
first_end = 0
|
||||
second_end = 0
|
||||
second_start = sel.end()
|
||||
|
||||
for b in reversed(self.brackets[1].split('\n')):
|
||||
second_end += ti.insert(sel.end(), "\n" + self.indent_to_col + b)
|
||||
num_open_lines = self.brackets[0].count('\n')
|
||||
for b in reversed(self.brackets[0].split('\n')):
|
||||
if line_offset == num_open_lines:
|
||||
line = b + "\n"
|
||||
else:
|
||||
line = self.indent_to_col + b + "\n"
|
||||
first_end += ti.insert(sel.begin(), line)
|
||||
line_offset += 1
|
||||
self.insert_regions.append(sublime.Region(sel.begin(), sel.begin() + first_end))
|
||||
|
||||
if indent:
|
||||
second_start += self.indent_content(ti, line_offset)
|
||||
else:
|
||||
pt = self.view.text_point(self.first_line + line_offset, 0)
|
||||
second_start += ti.insert(pt, self.indent_to_col)
|
||||
|
||||
self.insert_regions.append(sublime.Region(first_end + second_start, first_end + second_start + second_end))
|
||||
|
||||
def indent_content(self, ti, line_offset):
|
||||
"""
|
||||
Indent the block content
|
||||
"""
|
||||
|
||||
first = True
|
||||
offset = 0
|
||||
for l in range(line_offset, self.total_lines + line_offset):
|
||||
pt = self.view.text_point(self.first_line + l, 0)
|
||||
if first:
|
||||
offset += ti.insert(pt, self.indent_to_col + "\t")
|
||||
first = False
|
||||
else:
|
||||
offset += ti.insert(pt, "\t")
|
||||
return offset
|
||||
|
||||
def calculate_lines(self, sel):
|
||||
"""
|
||||
Calculate lines between brackets
|
||||
"""
|
||||
|
||||
self.first_line, self.col_position = self.view.rowcol(sel.begin())
|
||||
last_line = self.view.rowcol(sel.end())[0]
|
||||
self.total_lines = last_line - self.first_line + 1
|
||||
|
||||
def calculate_indentation(self, sel):
|
||||
"""
|
||||
Calculate how much lines should be indented
|
||||
"""
|
||||
|
||||
tab_size = self.view.settings().get("tab_size", 4)
|
||||
tab_count = self.view.substr(sublime.Region(sel.begin() - self.col_position, sel.begin())).count('\t')
|
||||
spaces = self.col_position - tab_count
|
||||
self.indent_to_col = "\t" * tab_count + "\t" * (spaces / tab_size) + " " * (spaces % tab_size if spaces >= tab_size else spaces)
|
||||
|
||||
def select(self, edit):
|
||||
"""
|
||||
Select defined regions after wrapping
|
||||
"""
|
||||
|
||||
self.view.sel().clear()
|
||||
map(lambda x: self.view.sel().add(x), self.insert_regions)
|
||||
|
||||
final_sel = []
|
||||
initial_sel = []
|
||||
for s in self.view.sel():
|
||||
string = self.view.substr(s)
|
||||
matches = [m for m in BH_TABSTOPS.finditer(string)]
|
||||
multi_offset = 0
|
||||
if matches:
|
||||
for m in matches:
|
||||
r = sublime.Region(s.begin() + multi_offset + m.start(1), s.begin() + multi_offset + m.end(1))
|
||||
if m.group(3):
|
||||
replace = m.group(3)
|
||||
self.view.erase(edit, r)
|
||||
added = self.view.insert(edit, r.begin(), replace)
|
||||
final_sel.append(sublime.Region(s.begin() + multi_offset + m.start(1), s.begin() + multi_offset + m.start(1) + added))
|
||||
multi_offset += added - r.size()
|
||||
else:
|
||||
self.view.erase(edit, r)
|
||||
final_sel.append(sublime.Region(s.begin() + multi_offset + m.start(1)))
|
||||
multi_offset -= r.size()
|
||||
if m.group(2) == "SEL":
|
||||
initial_sel.append(final_sel[-1])
|
||||
|
||||
if len(initial_sel) != len(final_sel):
|
||||
self.view.add_regions(TAB_REGION, final_sel, "", "", sublime.HIDDEN)
|
||||
|
||||
# Re-position cursor
|
||||
self.view.sel().clear()
|
||||
if len(initial_sel):
|
||||
map(lambda x: self.view.sel().add(x), initial_sel)
|
||||
elif len(final_sel):
|
||||
self.view.sel().add(final_sel[0])
|
||||
|
||||
def read_wrap_entries(self, setting_file, attribute):
|
||||
"""
|
||||
Read wrap entries from the settings file
|
||||
"""
|
||||
|
||||
settings = sublime.load_settings(setting_file)
|
||||
syntax = self.view.settings().get('syntax')
|
||||
language = basename(syntax).replace('.tmLanguage', '').lower() if syntax != None else "plain text"
|
||||
wrapping = settings.get(attribute, [])
|
||||
for i in wrapping:
|
||||
if not exclude_entry(i["enabled"], i["language_filter"], i["language_list"], language):
|
||||
for j in i.get("entries", []):
|
||||
try:
|
||||
menu_entry = j["name"]
|
||||
bracket_entry = j["brackets"]
|
||||
insert_style = j.get("insert_style", ["inline"])
|
||||
self._menu.append(menu_entry)
|
||||
self._brackets.append(bracket_entry)
|
||||
self._insert.append(insert_style)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def wrap_brackets(self, value):
|
||||
"""
|
||||
Wrap selection(s) with defined brackets
|
||||
"""
|
||||
|
||||
if value < 0:
|
||||
return
|
||||
|
||||
# Use new edit object since the main run has already exited
|
||||
# and the old edit is more than likely closed now
|
||||
edit = self.view.begin_edit()
|
||||
|
||||
# Wrap selections with brackets
|
||||
style = self._style[value]
|
||||
self.insert_regions = []
|
||||
|
||||
for sel in self.view.sel():
|
||||
# Determine indentation style
|
||||
if style == "indent_block":
|
||||
self.block(edit, sel, True)
|
||||
elif style == "block":
|
||||
self.block(edit, sel)
|
||||
else:
|
||||
self.inline(edit, sel)
|
||||
|
||||
self.select(edit)
|
||||
|
||||
self.view.end_edit(edit)
|
||||
|
||||
def wrap_style(self, value):
|
||||
"""
|
||||
Choose insert style for wrapping.
|
||||
"""
|
||||
|
||||
if value < 0:
|
||||
return
|
||||
|
||||
style = []
|
||||
|
||||
self.brackets = self._brackets[value]
|
||||
for s in VALID_INSERT_STYLES:
|
||||
if s[0] in self._insert[value]:
|
||||
self._style.append(s[0])
|
||||
style.append(s[1])
|
||||
|
||||
if len(style) > 1:
|
||||
self.view.window().show_quick_panel(
|
||||
style,
|
||||
self.wrap_brackets
|
||||
)
|
||||
else:
|
||||
self.wrap_brackets(0)
|
||||
|
||||
|
||||
class WrapBracketsCommand(sublime_plugin.TextCommand, WrapBrackets):
|
||||
def run(self, edit):
|
||||
"""
|
||||
Display the wrapping menu
|
||||
"""
|
||||
|
||||
self._menu = []
|
||||
self._brackets = []
|
||||
self._insert = []
|
||||
self._style = []
|
||||
self.read_wrap_entries("bh_wrapping.sublime-settings", "wrapping")
|
||||
|
||||
if len(self._menu):
|
||||
self.view.window().show_quick_panel(
|
||||
self._menu,
|
||||
self.wrap_style
|
||||
)
|
||||
|
||||
|
||||
class BhNextWrapSelCommand(sublime_plugin.TextCommand):
|
||||
"""
|
||||
Navigate wrapping tab stop regions
|
||||
"""
|
||||
|
||||
def run(self, edit):
|
||||
"""
|
||||
Look for the next wrapping tab stop region
|
||||
"""
|
||||
|
||||
regions = self.view.get_regions(SEL_REGION) + self.view.get_regions(OUT_REGION)
|
||||
if len(regions):
|
||||
self.view.sel().clear()
|
||||
map(lambda x: self.view.sel().add(x), regions)
|
||||
|
||||
# Clean up unneed sections
|
||||
self.view.erase_regions(SEL_REGION)
|
||||
self.view.erase_regions(OUT_REGION)
|
||||
|
||||
|
||||
class BhWrapListener(sublime_plugin.EventListener):
|
||||
"""
|
||||
Listen for wrapping tab stop tabbing
|
||||
"""
|
||||
|
||||
def on_query_context(self, view, key, operator, operand, match_all):
|
||||
"""
|
||||
Mark the next regions to navigate to.
|
||||
"""
|
||||
|
||||
accept_query = False
|
||||
if key == "bh_wrapping":
|
||||
select = []
|
||||
outlier = []
|
||||
regions = view.get_regions(TAB_REGION)
|
||||
tabstop = []
|
||||
sels = view.sel()
|
||||
|
||||
if len(regions) == 0:
|
||||
return False
|
||||
|
||||
for s in sels:
|
||||
count = 0
|
||||
found = False
|
||||
for r in regions[:]:
|
||||
if found:
|
||||
select.append(r)
|
||||
tabstop.append(r)
|
||||
del regions[count]
|
||||
break
|
||||
if r.begin() <= s.begin() <= r.end():
|
||||
del regions[count]
|
||||
found = True
|
||||
continue
|
||||
count += 1
|
||||
if not found:
|
||||
outlier.append(s)
|
||||
tabstop += regions
|
||||
|
||||
if len(tabstop) == len(select):
|
||||
if len(tabstop):
|
||||
tabstop = []
|
||||
accept_query = True
|
||||
elif len(tabstop) != 0:
|
||||
accept_query = True
|
||||
|
||||
# Mark regions to make the "next" command aware of what to do
|
||||
view.add_regions(SEL_REGION, select, "", "", sublime.HIDDEN)
|
||||
view.add_regions(OUT_REGION, outlier, "", "", sublime.HIDDEN)
|
||||
view.add_regions(TAB_REGION, tabstop, "", "", sublime.HIDDEN)
|
||||
|
||||
return accept_query
|
@@ -0,0 +1,71 @@
|
||||
{
|
||||
"wrapping": [
|
||||
{
|
||||
"enabled": true, "language_list": [], "language_filter": "whitelist", "entries": [
|
||||
{"name": "<> Angle", "brackets": ["<", ">${BH_SEL}"]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"enabled": true, "language_list": ["Plain text"], "language_filter": "blacklist", "entries": [
|
||||
{"name": "{} Curly", "brackets": ["{", "}${BH_SEL}"]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"enabled": true, "language_list": ["Plain text"], "language_filter": "blacklist", "entries": [
|
||||
{"name": "() Round", "brackets": ["(", ")${BH_SEL}"]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"enabled": true, "language_list": ["Plain text"], "language_filter": "blacklist", "entries": [
|
||||
{"name": "[] Square", "brackets": ["[", "]${BH_SEL}"]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"enabled": true, "language_list": ["Plain text"], "language_filter": "blacklist", "entries": [
|
||||
{"name": "'' Single Quotes", "brackets": ["'", "'${BH_SEL}"], "insert_style": ["inline"]},
|
||||
{"name": "\"\" Double Quotes", "brackets": ["\"", "\"${BH_SEL}"], "insert_style": ["inline"]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"enabled": true, "language_list": ["Python"], "language_filter": "whitelist", "entries": [
|
||||
{"name": "'''''' Triple Single Quotes", "brackets": ["'''", "'''${BH_SEL}"], "insert_style": ["inline", "block"]},
|
||||
{"name": "\"\"\"\"\"\" Triple Double Quotes", "brackets": ["\"\"\"", "\"\"\"${BH_SEL}"], "insert_style": ["inline", "block"]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"enabled": true, "language_list": ["HTML", "HTML 5", "XML", "PHP", "HTML+CFML", "ColdFusion", "ColdFusionCFC"], "language_filter": "whitelist", "entries": [
|
||||
{"name": "HTML/XML Tag", "brackets": ["<${BH_SEL:NAME}>", "</${BH_SEL:NAME}>"], "insert_style": ["inline", "block", "indent_block"]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"enabled": true, "language_list": ["Markdown"], "language_filter": "whitelist", "entries": [
|
||||
{"name": "Mardown: Bold", "brackets": ["**", "**${BH_SEL}"]},
|
||||
{"name": "Mardown: Italic", "brackets": ["_", "_${BH_SEL}"]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"enabled": true, "language_list": ["C++", "C"], "language_filter": "whitelist", "entries": [
|
||||
{"name": "C/C++: #if", "brackets": ["#if ${BH_SEL:/* CONDITION */}", "#endif"], "insert_style": ["block"]},
|
||||
{"name": "C/C++: #if, #else", "brackets": ["#if ${BH_SEL:/* CONDITION */}", "#else\n${BH_TAB:/* CODE */}\n#endif"], "insert_style": ["block"]},
|
||||
{"name": "C/C++: #if, #elif", "brackets": ["#if ${BH_SEL:/* CONDITION */}", "#elif ${BH_TAB:/* CONDITION */}\n${BH_TAB:/* CODE */}\n#endif"], "insert_style": ["block"]},
|
||||
{"name": "C/C++: #ifdef", "brackets": ["#ifdef ${BH_SEL:/* DEFINE */}", "#endif"], "insert_style": ["block"]},
|
||||
{"name": "C/C++: #ifdef, #else", "brackets": ["#ifdef ${BH_SEL:/* DEFINE */}", "#else\n${BH_TAB:/* CODE */}\n#endif"], "insert_style": ["block"]},
|
||||
{"name": "C/C++: #ifndef", "brackets": ["#ifndef ${BH_SEL:/* DEFINE */}", "#endif"], "insert_style": ["block"]},
|
||||
{"name": "C/C++: #ifndef, #else", "brackets": ["#ifndef ${BH_SEL:/* DEFINE */}", "#else\n${BH_TAB:/* CODE */}\n#endif"], "insert_style": ["block"]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"enabled": true, "language_list": ["Ruby"], "language_filter": "whitelist", "entries": [
|
||||
{"name": "Ruby: if", "brackets": ["if ${BH_SEL:CONDITION}", "end"], "insert_style": ["indent_block"]},
|
||||
{"name": "Ruby: until", "brackets": ["until ${BH_SEL:CONDITION}", "end"], "insert_style": ["indent_block"]},
|
||||
{"name": "Ruby: while", "brackets": ["while ${BH_SEL:CONDITION}", "end"], "insert_style": ["indent_block"]},
|
||||
{"name": "Ruby: def", "brackets": ["def ${BH_SEL:NAME}", "end"], "insert_style": ["indent_block"]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"enabled": true, "language_list": ["CSS"], "language_filter": "whitelist", "entries": [
|
||||
{"name": "CSS: @group", "brackets": ["/* @group ${BH_SEL:NAME} */", "/* @end */"], "insert_style": ["block"]}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
After Width: | Height: | Size: 217 B |
After Width: | Height: | Size: 155 B |
After Width: | Height: | Size: 143 B |
After Width: | Height: | Size: 155 B |
After Width: | Height: | Size: 138 B |
After Width: | Height: | Size: 191 B |
After Width: | Height: | Size: 108 B |
After Width: | Height: | Size: 118 B |
After Width: | Height: | Size: 220 B |
After Width: | Height: | Size: 215 B |
After Width: | Height: | Size: 242 B |
After Width: | Height: | Size: 173 B |
After Width: | Height: | Size: 156 B |
After Width: | Height: | Size: 173 B |
After Width: | Height: | Size: 145 B |
After Width: | Height: | Size: 211 B |
After Width: | Height: | Size: 167 B |
After Width: | Height: | Size: 148 B |
After Width: | Height: | Size: 158 B |
After Width: | Height: | Size: 125 B |
After Width: | Height: | Size: 131 B |
After Width: | Height: | Size: 163 B |
After Width: | Height: | Size: 133 B |
After Width: | Height: | Size: 134 B |
After Width: | Height: | Size: 169 B |
After Width: | Height: | Size: 133 B |
After Width: | Height: | Size: 134 B |
After Width: | Height: | Size: 167 B |
After Width: | Height: | Size: 176 B |
After Width: | Height: | Size: 158 B |
After Width: | Height: | Size: 125 B |
After Width: | Height: | Size: 131 B |
After Width: | Height: | Size: 270 B |
After Width: | Height: | Size: 188 B |
After Width: | Height: | Size: 148 B |
After Width: | Height: | Size: 190 B |
After Width: | Height: | Size: 147 B |
After Width: | Height: | Size: 206 B |
After Width: | Height: | Size: 137 B |
After Width: | Height: | Size: 111 B |
After Width: | Height: | Size: 104 B |
After Width: | Height: | Size: 141 B |
After Width: | Height: | Size: 114 B |
After Width: | Height: | Size: 103 B |
After Width: | Height: | Size: 124 B |
After Width: | Height: | Size: 114 B |
After Width: | Height: | Size: 103 B |
After Width: | Height: | Size: 124 B |
After Width: | Height: | Size: 101 B |
After Width: | Height: | Size: 97 B |
After Width: | Height: | Size: 111 B |
After Width: | Height: | Size: 98 B |
After Width: | Height: | Size: 112 B |
After Width: | Height: | Size: 127 B |
After Width: | Height: | Size: 244 B |
After Width: | Height: | Size: 166 B |
After Width: | Height: | Size: 306 B |
After Width: | Height: | Size: 215 B |