feat(SublimeText2.EditorPackages): cache packages

This commit is contained in:
Iristyle
2013-04-04 08:55:15 -04:00
parent d65666cdfc
commit c3efdad2c2
274 changed files with 26863 additions and 0 deletions

View File

@@ -0,0 +1,3 @@
*.pyc
.DS_Store

View File

@@ -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

View File

@@ -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"
}
]

View File

@@ -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"
}
]
}
]

View File

@@ -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"
}
]

View File

@@ -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": "-" }
]
}
]
}
]
}
]

View File

@@ -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"]
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -0,0 +1,2 @@
def compare(name, first, second, bfr):
return "end" + bfr[first.begin:first.end].lower() == bfr[second.begin:second.end].lower()

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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
)

View File

@@ -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
)

View File

@@ -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"]}
]
}
]
}

View File

@@ -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

View File

@@ -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"]}
]
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 217 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 191 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 220 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 215 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 242 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 145 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 211 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 167 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 167 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 176 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 270 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 190 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 244 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 166 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 306 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 215 B

View File

@@ -0,0 +1 @@
{"url": "https://github.com/facelessuser/BracketHighlighter", "version": "2013.03.27.09.00.08", "description": "Bracket and tag highlighter for Sublime Text 2"}

View File

@@ -0,0 +1,470 @@
# About
This is a fork of pyparadigm's _SublimeBrackets_ and _SublimeTagmatcher_ (both are no longer available). I forked this to fix some issues I had and to add some features I wanted. I also wanted to improve the efficiency of the matching. This cuts down on the parallel searching that is now streamlined in one search. Since then, I have rewritten the entire code base to bring more flexibility, speed, and features.
<img src="http://dl.dropbox.com/u/342698/BracketHighlighter/Example1.png" border="0">
## Sublime Text 3 Support?
ST3 support is found here (at the present time): https://github.com/facelessuser/BracketHighlighter/tree/BH2ST3
## Overview
Bracket Highlighter matches a variety of brackets such as: ```[]```, ```()```, ```{}```, ```""```, ```''```, ```<tag></tag>```, and even custom brackets.
# FeatureList
- Customizable to highlight almost any bracket
- Customizable bracket highlight style
- High visibility bracket highlight mode
- Selectively disable or enable specific matching of tags, brackets, or quotes
- Selectively whitelist or blacklist matching of specific tags, brackets, or quotes based on language
- When bound to a shortcut, allow option to show line count and char count between match in the status bar
- Highlight basic brackets within strings
- Works with multi-select
- Configurable custom gutter icons
- Toggle bracket escape mode for string brackets (regex|string)
- Bracket plugins that can jump between bracket ends, select content, remove brackets and/or content, wrap selectios with brackets, swap brackets, swap quotes (handling quote escaping between the main quotes), fold/unfold conent between brackets, toggle through tag attribute selecection, select both the opening and closing tag name to change both simultaneously.
# General Use
In general BracketHighligher (BH) will automatically highlight brackets (or defined bracket like start and end blocks) its between. By default, BH will but opening and closing icons in the gutter of the corresponding line containing open or closising bracket. BH, by default, will underline the closing and opening bracket as well.
## Built-in Supported brackets
Currently BH supports the following brackets out of the box:
- round
- square
- curly
- angle
- single and double quotes
- python single and double quotes (unicode and raw)
- python tripple single and double quotes (unicode and raw)
- Javascript regex
- Perl regex
- Ruby regex
- Markdown italic
- Markdown bold
- CSSedit groups
- Ruby conditional statements
- C/C++ compiler switches
- PHP conditional keywords
- Erlang conditional statements
- HTML/ColdFusion/XML tags
BH also supports highlighting basic sub brackets ```(), [], {}``` within supported regex and strings.
## Additional Features
BH has a couple of additonal features built-in.
### Toggle Global Enable (bh_toggle_enable)
This command enables and disables BH globally
### Toggle String Bracket Escape Mode (bh_toggle_string_escape_mode)
This toggles BH's recognition mode of escaped sub brackets in strings and regex. The modes are string escape mode and regex escape mode.
### Settings
When changing settings, you should copy the entire ```bh_core.sublime-settings``` to your ```User``` folder before changing. Style and color will be discussed in greater depth in the ```Configuring Highlight Style``` section.
These are the basic settings you can change:
```javascript
//Debug logging
"debug_enable": false,
// 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,
```
### Bracket Plugins
Bh is also extendable via plugins and provides an number of plugins by default. See ```Bracket Plugins``` to learn more about the included plugins.
## Bracket Plugin
BH provides a number of built in Bracket Plugins that take advantage of BH's matching to provide additional features. Most plugin features are available via the Tools->Packages->BracketHighlighter menu or the command palette. To see how to configure shortcuts, see the ```Example.sublime-settings``` file.
### Bracket Select Plugin
This plugin changes the selection inside between the brackets. It can select the content or move the bracket to the opening and closing bracket. Behavior is slightly modified for tags.
### Bracket Remove Plugin
Removes the surrounding brackets.
### Fold Bracket Plugin
Folds the content of the current surrounding brackets.
### Swap Quotes Plugin
Swap the quotes style of surrounding quotes from double to single or vice versa. It also handlings escaping and unescaping of sub quotes.
### Tag Plugin
Plugin used to help highlight tags
Additional tag settings found in ```bh_core.sublime-settings```:
```javascript
/* 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"]
}
```
### Tag Attribute Select Plugin
Cycle through selecting tag attributes of tags.
### Tag Name Select Plugin
Select the opening and closing tag name of current tag.
### Bracket Wrapping Plugin
Wrap the current selection with supported bracket of your choice. Wrapping definitions are configured in ```bh_wrapping.sublime-settings```.
### Bracket Swapping Plugin
Swap the current surrounding bracket with supported bracket of your choice. Swapping definitions are configured in ```bh_swapping.sublime-settings```.
## Shortcuts
By default BH provides no shortcuts to avoid shortcut conflicts, but you can view the included ```Example.sublime-keymaps``` file to get an idea how to set up your own.
# Customizing BracketHighligher
BH is extremely flexible and be customized and extended to fit a User's needs. The first step is to copy the ```bh_core.sublime-settings``` to your ```User``` folder.
## Configuring Brackets
BH has been written to allow users to define any brackets they would like to have highlighted. There are two kinds of brackets you can define ```scope_brackets``` (search file for scope regions and then use regex to test for opening and closing brackets) and ```brackets``` (use regex to find opening and closing brackets). ```bracket``` type should usually be the preferred type. ```scope_brackets``` are usually used for brackets whose opening and closing are the same and not distinguishable form one another by regex; scope brackets must be contained in a continuous scope region like string for quotes etc.
### Configuring Brackets
Brackets are defined under ```brackets``` in ```bh_core.sublime-settings```.
Angle and Curly bracket will be used as an eample (not all options may be shown in these examples):
```javascript
{
"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
},
{
"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**: the name of the bracket (should be unique)
- **open**: defines the opening bracket (one and only one captureing group must be present)
- **close**: defines the closing bracket (one and only one captureing group must be present)
- **style**: Name of style definition to be used to highlight the brackets. See ```Configuring Bracket Styles``` for more info.
- **scope_exclude**: Scopes where the opening and closing brackets should be ignored.
- **language_filter**: This works in conjunction with ```language_list```. It specifies whether ```language_list``` is a ```blacklist``` or ```whitelist```.
- **language_list**: an array of tmLanguage file names that should be avoided or included for highlighting. Looks to ```language_filter``` to determine if avoidance or inclusion is used.
- **enabled**: disable or enable rule
- **scope_exclude_exceptions (optional)***: used to ignore exluding of sub scopes such as in the curly example above where ```string``` is excluded, but not ```string.other.math.block.environment.latex```.
- **plugin_library (optional)**: defines plugin to use for determining matches (see Bracket Plugin API for more info on matching plugins)
- **find_in_sub_search (optional)**: this rule should be included when doing sub bracket matching in ```scope_brackets``` (like finding round brackets between quotes etc.). The setting must be as string and can be either (true|false|only); only means this bracket is only matched as a sub bracket of a ```scope_bracket```.
- **ignore_string_escape (optional)**: Do not ignore sub brackets found in strings and regex when escaped, but use internal escape logic to determine if the brackets should be ignored based on whether regex or string escape mode is set.
### Configuring Scope Brackets
Scope Brackets are defined under ```scope_brackets``` in ```bh_core.sublime-settings```.
Python Single Quote bracket will be used as an eample (not all options are shown in this example):
```javascript
{
"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**: the name of the bracket (should be unique)
- **open**: defines the opening bracket (one and only one captureing group must be present)
- **close**: defines the closing bracket (one and only one captureing group must be present)
- **style**: Name of style definition to be used to highlight the brackets. See ```Configuring Bracket Styles``` for more info.
- **scopes**: scope that should be searched to find the opening and closing brackets.
- **language_filter**: This works in conjunction with ```language_list```. It specifies whether ```language_list``` is a ```blacklist``` or ```whitelist```.
- **language_list**: an array of tmLanguage file names that should be avoided or included for highlighting. Looks to ```language_filter``` to determine if avoidance or inclusion is used.
- **sub_bracket_search**: should this scope bracket also search for sub brackets (like curly brackets in strings etc.).
- **enabled**: disable or enable rule
- **plugin_library (optional)**: defines plugin to use for determining matches (see Bracket Plugin API for more info on matching plugins)
## Configuring Highlight Style
Each bracket definition (described in ```Configuring Scope Brackets``` and ```Configuring Brackets```) has a ```style``` setting that you give a style definition to. Style definitions are defined under ```bracket_styles``` in ```bh_core.sublime-settings```.
There are two special style definitions whose names are reserved: ```default``` and ```unmatched```, but you can configure them. All other custom style definitions follow the same pattern (see ```curly``` below and compare to the special style defintions; format is the same) All custom styles follow this pattern. See description below:
```javascript
// "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"
},
```
- **icon**: icon to show in gutter. Available options are (angle|round|curly|square|tag|star|dot|bookmark|question|quote|double_quote|single_quote|single_quote_offset|double_quote_offset|none)
- **color**: scope to define color
- **style**: higlight style. Available options are (solid|outline|underline|none)
As shown in the example above, if an option is omitted, it will use the setting in ```default```. So ```curly```, in this example, defines ```icon```, but will use ```default``` for the ```color``` and ```style```.
To customize the color for ```curly``` you can create your own custom scope.
Add this to your color scheme:
```XML
<dict>
<key>name</key>
<string>Bracket Curly</string>
<key>scope</key>
<string>brackethighlighter.curly</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>#CC99CC</string>
</dict>
</dict>
```
And then use the scope:
```javascript
"curly": {
"icon": "curly_bracket"
"color": "brackethighlighter.curly",
// "style": "underline"
},
```
# Bracket Plugin API
There are two kinds of plugins that can be written ```definition``` plugins (plugins attached to bracket definitions via the ```plugin_library``` option) or ```run instance``` plugins (plugins that are that are fed in the BracketHighligher via the command parameter ```plugin```).
Bracket plugins use ```BracketRegions```. ```BracketRegions``` are simple objects containing a begin pt and end pt of a bracket.
Class:
- **BracketRegion(begin_pt, end_pt)**
Attributes of BracketRegion:
- **begin**: the start pt of the BracketRegion
- **end**: the end pt of the BracketRegion
Methods of BracketRegion:
- **size()**: returns size of region
- **move(begin_pt, end_pt)**: returns a new BracketRegion object with the points moved as specified by the parameters
- **toregion**: returns a sublime Region() object
## 'Defintion' Plugins
These are plugins that are attached to the bracket definition and aid in processing the brackets. These kids of plugins have two methods you can provide ```post_match``` and/or ```compare```.
### compare
```compare``` is run when comparing the opening bracket with closing brackets. This allows you to provide logic to accept or regect a the pairing of an opening bracket with a closing bracket. You should not change the text in the view during this operation.
The ```compare``` method receives the following paramters:
- **name**: the name of the bracket definition being evaluated
- **first**: a bracket region for the opening bracket
- **second**: a bracket region for the closing bracket
- **bfr**: the file buffer
Returns:
- **Boolean**: indicating whether the the comparison yields a suitable match
Example (from phphekywords.py):
```python
def compare(name, first, second, bfr):
return "end" + bfr[first.begin:first.end].lower() == bfr[second.begin:second.end].lower()
```
### post_match
```post_match``` is run after the brackets have been matched. You can do things like alter the highlighting region and change the bracket_style if needed. You should not change the text in the view during this operation.
The ```post_match``` method receives the following parameters:
- **name**: the name of the bracket definition being evaluated
- **style**: the style definition name that is to be used to highlight the region
- **first**: a bracket region for the opening bracket
- **second**: a bracket region for the closing bracket
- **center**: position (pt) of cursor (in retrospect, probably not the most intuitive name; not sure why I named it such)
- **bfr**: the file buffer
- **threshold**: the calculated search window of the buffer that is being searched
Returns:
- **BracketRegion**: opening bracket region
- **BracketRegion**: closing bracekt region
- **style**: the name of the style definition to use
Example (from rubykeywords.py):
```python
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
```
Example (snippet from tags.py)
```python
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
```
## Run Instance Plugins
```Run instance``` plugins are fed into the command executing a BracketHighlighter match via the ```plugin``` parameter.
Example of run instance plugin getting called:
```javascript
// 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"}
}
}
},
```
The ```plugin``` paramter is a dictionary that contains 3 parameters to define what plugin should get run, with what arguments, and on what bracket defintion.
- **type**: an array containing the bracket definition names that the plugin should be run on. Use ```__all__``` for all bracket definitions.
- **command**: the plugin to run. For internal plugins, they are referenced by ```bh_modules.<plugin name>```. For custom plugins, you should use the folder path releative to ```Packages```. So if I had a plugin called ```myplugin.py``` in my ```User``` folder, I would use ```User.myplugin```.
- **args**: a dictionary contianing the arguments to feed into the plugin.
You create ```run instance``` plugins by deriving a class from the ```BracketPluginCommand``` class. Then you provide a method called ```plugin``` that returns the class.
Class:
- **BracketPluginCommand()**
Parameters of BracketPluginCommand:
- **edit**: sublime edit object
- **name**: name of tag definition being evaluated
Attributes of BracketPluginCommand:
- **view**: the sublime view containg the bracket (don't change this)
- **left**: a bracket region for the opening bracket (can be changed)
- **right**: a bracket region for the closing bracket (can be changed)
- **selection**: an array containing the selection that triggered the match (can be changed)
Methods of BracketPluginCommand:
- **run(edit, name, <args>)**: (edit is a sublime edit object and name is the bracket definition being evaluated)
Example (from foldbracket.py):
```python
import BracketHighlighter.bh_plugin as 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
```
# Credits
- pyparadigm: for his original efforts with SublimeBrackets and SublimeTagmatcher which originally BracketHighlighter was built off of and the inspiration behind the current implementation.
- BoundInCode: for his Tag icon
# Version 2.0.0
- Re-write of BracketHighlighter
# Version Older
- See [Complete Changelog](https://github.com/facelessuser/BracketHighlighter/blob/BH2/CHANGELOG.md)