feat(SublimeText2.WebPackages): cache packages

This commit is contained in:
Iristyle
2013-04-04 08:54:25 -04:00
parent 590d7a44f9
commit 1e6f643a1b
1026 changed files with 79077 additions and 0 deletions

View File

@@ -0,0 +1,30 @@
*.py[co]
*.tmLanguage.cache
# Packages
*.egg
*.egg-info
dist
build
eggs
parts
bin
var
sdist
develop-eggs
.installed.cfg
# Installer logs
pip-log.txt
# Unit test / coverage reports
.coverage
.tox
#Translations
*.mo
#Mr Developer
.mr.developer.cfg
.DS_Store

View File

@@ -0,0 +1,518 @@
// This file is automatically generated with misc/generate-keymap.py script
[
{
"keys": [
"shift+ctrl+y"
],
"args": {
"action": "evaluate_math_expression"
},
"command": "run_emmet_action",
"context": [
{
"key": "emmet_action_enabled.evaluate_math_expression"
}
]
},
{
"keys": [
"shift+ctrl+;"
],
"args": {
"action": "remove_tag"
},
"command": "run_emmet_action",
"context": [
{
"key": "emmet_action_enabled.remove_tag"
}
]
},
{
"keys": [
"ctrl+up"
],
"args": {
"action": "increment_number_by_1"
},
"command": "run_emmet_action",
"context": [
{
"key": "emmet_action_enabled.increment_number_by_1"
}
]
},
{
"keys": [
"ctrl+shift+forward_slash"
],
"args": {
"action": "toggle_comment"
},
"command": "run_emmet_action",
"context": [
{
"operand": "source.css - source.css.less, text.xml, text.html - source",
"operator": "equal",
"match_all": true,
"key": "selector"
},
{
"match_all": true,
"key": "emmet_action_enabled.toggle_comment"
}
]
},
{
"keys": [
"shift+ctrl+."
],
"args": {
"action": "select_next_item"
},
"command": "run_emmet_action",
"context": [
{
"key": "emmet_action_enabled.select_next_item"
}
]
},
{
"keys": [
"ctrl+alt+enter"
],
"command": "expand_as_you_type",
"context": [
{
"operand": false,
"operator": "equal",
"match_all": true,
"key": "setting.is_widget"
},
{
"match_all": true,
"key": "emmet_action_enabled.expand_as_you_type"
}
]
},
{
"keys": [
"alt+down"
],
"args": {
"action": "decrement_number_by_01"
},
"command": "run_emmet_action",
"context": [
{
"key": "emmet_action_enabled.decrement_number_by_01"
}
]
},
{
"keys": [
"ctrl+'"
],
"args": {
"action": "encode_decode_data_url"
},
"command": "run_emmet_action",
"context": [
{
"key": "emmet_action_enabled.encode_decode_data_url"
}
]
},
{
"keys": [
"ctrl+shift+0"
],
"args": {
"action": "match_pair_inward"
},
"command": "run_emmet_action",
"context": [
{
"key": "emmet_action_enabled.match_pair_inward"
}
]
},
{
"keys": [
"shift+alt+up"
],
"args": {
"action": "increment_number_by_10"
},
"command": "run_emmet_action",
"context": [
{
"key": "emmet_action_enabled.increment_number_by_10"
}
]
},
{
"keys": [
"shift+ctrl+r"
],
"args": {
"action": "reflect_css_value"
},
"command": "run_emmet_action",
"context": [
{
"key": "emmet_action_enabled.reflect_css_value"
}
]
},
{
"keys": [
"ctrl+alt+left"
],
"args": {
"action": "prev_edit_point"
},
"command": "run_emmet_action",
"context": [
{
"key": "emmet_action_enabled.prev_edit_point"
}
]
},
{
"keys": [
"shift+ctrl+,"
],
"args": {
"action": "select_previous_item"
},
"command": "run_emmet_action",
"context": [
{
"key": "emmet_action_enabled.select_previous_item"
}
]
},
{
"keys": [
"ctrl+,"
],
"args": {
"action": "match_pair_outward"
},
"command": "run_emmet_action",
"context": [
{
"key": "emmet_action_enabled.match_pair_outward"
}
]
},
{
"keys": [
"ctrl+u"
],
"args": {
"action": "update_image_size"
},
"command": "run_emmet_action",
"context": [
{
"key": "emmet_action_enabled.update_image_size"
}
]
},
{
"keys": [
"ctrl+alt+right"
],
"args": {
"action": "next_edit_point"
},
"command": "run_emmet_action",
"context": [
{
"key": "emmet_action_enabled.next_edit_point"
}
]
},
{
"keys": [
"shift+ctrl+`"
],
"args": {
"action": "split_join_tag"
},
"command": "run_emmet_action",
"context": [
{
"key": "emmet_action_enabled.split_join_tag"
}
]
},
{
"keys": [
"shift+alt+down"
],
"args": {
"action": "decrement_number_by_10"
},
"command": "run_emmet_action",
"context": [
{
"key": "emmet_action_enabled.decrement_number_by_10"
}
]
},
{
"keys": [
"shift+ctrl+g"
],
"command": "wrap_as_you_type",
"context": [
{
"operand": false,
"operator": "equal",
"match_all": true,
"key": "setting.is_widget"
},
{
"match_all": true,
"key": "emmet_action_enabled.wrap_as_you_type"
}
]
},
{
"keys": [
"shift+ctrl+'"
],
"command": "rename_tag",
"context": [
{
"key": "emmet_action_enabled.rename_tag"
}
]
},
{
"keys": [
"alt+up"
],
"args": {
"action": "increment_number_by_01"
},
"command": "run_emmet_action",
"context": [
{
"key": "emmet_action_enabled.increment_number_by_01"
}
]
},
{
"keys": [
"ctrl+alt+j"
],
"args": {
"action": "matching_pair"
},
"command": "run_emmet_action",
"context": [
{
"key": "emmet_action_enabled.matching_pair"
}
]
},
{
"keys": [
"ctrl+down"
],
"args": {
"action": "decrement_number_by_1"
},
"command": "run_emmet_action",
"context": [
{
"key": "emmet_action_enabled.decrement_number_by_1"
}
]
},
{
"keys": [
"ctrl+e"
],
"args": {
"action": "expand_abbreviation"
},
"command": "run_emmet_action",
"context": [
{
"key": "emmet_action_enabled.expand_abbreviation"
}
]
},
{
"keys": [
"tab"
],
"command": "expand_abbreviation_by_tab",
"context": [
{
"operand": "source.css, source.sass, source.less, source.scss, source.stylus, text.xml, text.html, text.haml, text.scala.html, source string",
"operator": "equal",
"match_all": true,
"key": "selector"
},
{
"operand": "text.html source.php, text.html source.js, storage.type.templatetag.django",
"operator": "not_equal",
"match_all": true,
"key": "selector"
},
{
"match_all": true,
"key": "selection_empty"
},
{
"operator": "equal",
"operand": false,
"match_all": true,
"key": "has_next_field"
},
{
"operator": "equal",
"operand": false,
"match_all": true,
"key": "setting.disable_tab_abbreviations"
},
{
"operand": false,
"operator": "equal",
"match_all": true,
"key": "auto_complete_visible"
},
{
"match_all": true,
"key": "is_abbreviation"
}
]
},
{
"keys": [
"tab"
],
"command": "expand_abbreviation_by_tab",
"context": [
{
"operand": "source.css, source.sass, source.less, source.scss, source.stylus, text.xml, text.html, text.haml, text.scala.html, source string",
"operator": "equal",
"match_all": true,
"key": "selector"
},
{
"operand": "text.html source.php, text.html source.js, storage.type.templatetag.django",
"operator": "not_equal",
"match_all": true,
"key": "selector"
},
{
"match_all": true,
"key": "selection_empty"
},
{
"operator": "equal",
"operand": false,
"match_all": true,
"key": "has_next_field"
},
{
"operator": "equal",
"operand": true,
"match_all": true,
"key": "auto_complete_visible"
},
{
"operator": "equal",
"operand": false,
"match_all": true,
"key": "setting.disable_tab_abbreviations_on_auto_complete"
},
{
"match_all": true,
"key": "is_abbreviation"
}
]
},
{
"keys": [
"enter"
],
"args": {
"contents": "\n\t${0}\n"
},
"command": "insert_snippet",
"context": [
{
"operand": "meta.scope.between-tag-pair.html, meta.scope.between-tag-pair.xml",
"match_all": true,
"key": "selector"
},
{
"operand": false,
"match_all": true,
"key": "auto_complete_visible"
},
{
"match_all": true,
"key": "clear_fields_on_enter_key"
},
{
"operand": false,
"match_all": true,
"key": "setting.disable_formatted_linebreak"
}
]
},
{
"keys": [
"#"
],
"args": {
"attribute": "id"
},
"command": "emmet_insert_attribute",
"context": [
{
"operand": "text.html meta.tag -string -punctuation.definition.tag.begin.html -meta.scope.between-tag-pair.html -source -meta.tag.template.value.twig",
"operator": "equal",
"match_all": true,
"key": "selector"
},
{
"operator": "equal",
"operand": true,
"key": "setting.auto_id_class"
}
]
},
{
"keys": [
"."
],
"args": {
"attribute": "class"
},
"command": "emmet_insert_attribute",
"context": [
{
"operand": "text.html meta.tag -string -punctuation.definition.tag.begin.html -meta.scope.between-tag-pair.html -source -meta.tag.template.value.twig",
"operator": "equal",
"match_all": true,
"key": "selector"
},
{
"operator": "equal",
"operand": true,
"key": "setting.auto_id_class"
}
]
}
]

View File

@@ -0,0 +1,518 @@
// This file is automatically generated with misc/generate-keymap.py script
[
{
"keys": [
"shift+super+y"
],
"args": {
"action": "evaluate_math_expression"
},
"command": "run_emmet_action",
"context": [
{
"key": "emmet_action_enabled.evaluate_math_expression"
}
]
},
{
"keys": [
"super+'"
],
"args": {
"action": "remove_tag"
},
"command": "run_emmet_action",
"context": [
{
"key": "emmet_action_enabled.remove_tag"
}
]
},
{
"keys": [
"ctrl+up"
],
"args": {
"action": "increment_number_by_1"
},
"command": "run_emmet_action",
"context": [
{
"key": "emmet_action_enabled.increment_number_by_1"
}
]
},
{
"keys": [
"alt+shift+forward_slash"
],
"args": {
"action": "toggle_comment"
},
"command": "run_emmet_action",
"context": [
{
"operand": "source.css - source.css.less, text.xml, text.html - source",
"operator": "equal",
"match_all": true,
"key": "selector"
},
{
"match_all": true,
"key": "emmet_action_enabled.toggle_comment"
}
]
},
{
"keys": [
"shift+super+."
],
"args": {
"action": "select_next_item"
},
"command": "run_emmet_action",
"context": [
{
"key": "emmet_action_enabled.select_next_item"
}
]
},
{
"keys": [
"ctrl+alt+enter"
],
"command": "expand_as_you_type",
"context": [
{
"operand": false,
"operator": "equal",
"match_all": true,
"key": "setting.is_widget"
},
{
"match_all": true,
"key": "emmet_action_enabled.expand_as_you_type"
}
]
},
{
"keys": [
"alt+down"
],
"args": {
"action": "decrement_number_by_01"
},
"command": "run_emmet_action",
"context": [
{
"key": "emmet_action_enabled.decrement_number_by_01"
}
]
},
{
"keys": [
"shift+ctrl+d"
],
"args": {
"action": "encode_decode_data_url"
},
"command": "run_emmet_action",
"context": [
{
"key": "emmet_action_enabled.encode_decode_data_url"
}
]
},
{
"keys": [
"ctrl+j"
],
"args": {
"action": "match_pair_inward"
},
"command": "run_emmet_action",
"context": [
{
"key": "emmet_action_enabled.match_pair_inward"
}
]
},
{
"keys": [
"alt+super+up"
],
"args": {
"action": "increment_number_by_10"
},
"command": "run_emmet_action",
"context": [
{
"key": "emmet_action_enabled.increment_number_by_10"
}
]
},
{
"keys": [
"shift+super+r"
],
"args": {
"action": "reflect_css_value"
},
"command": "run_emmet_action",
"context": [
{
"key": "emmet_action_enabled.reflect_css_value"
}
]
},
{
"keys": [
"ctrl+alt+left"
],
"args": {
"action": "prev_edit_point"
},
"command": "run_emmet_action",
"context": [
{
"key": "emmet_action_enabled.prev_edit_point"
}
]
},
{
"keys": [
"shift+super+,"
],
"args": {
"action": "select_previous_item"
},
"command": "run_emmet_action",
"context": [
{
"key": "emmet_action_enabled.select_previous_item"
}
]
},
{
"keys": [
"ctrl+d"
],
"args": {
"action": "match_pair_outward"
},
"command": "run_emmet_action",
"context": [
{
"key": "emmet_action_enabled.match_pair_outward"
}
]
},
{
"keys": [
"shift+ctrl+i"
],
"args": {
"action": "update_image_size"
},
"command": "run_emmet_action",
"context": [
{
"key": "emmet_action_enabled.update_image_size"
}
]
},
{
"keys": [
"ctrl+alt+right"
],
"args": {
"action": "next_edit_point"
},
"command": "run_emmet_action",
"context": [
{
"key": "emmet_action_enabled.next_edit_point"
}
]
},
{
"keys": [
"shift+super+'"
],
"args": {
"action": "split_join_tag"
},
"command": "run_emmet_action",
"context": [
{
"key": "emmet_action_enabled.split_join_tag"
}
]
},
{
"keys": [
"alt+super+down"
],
"args": {
"action": "decrement_number_by_10"
},
"command": "run_emmet_action",
"context": [
{
"key": "emmet_action_enabled.decrement_number_by_10"
}
]
},
{
"keys": [
"ctrl+w"
],
"command": "wrap_as_you_type",
"context": [
{
"operand": false,
"operator": "equal",
"match_all": true,
"key": "setting.is_widget"
},
{
"match_all": true,
"key": "emmet_action_enabled.wrap_as_you_type"
}
]
},
{
"keys": [
"super+shift+k"
],
"command": "rename_tag",
"context": [
{
"key": "emmet_action_enabled.rename_tag"
}
]
},
{
"keys": [
"alt+up"
],
"args": {
"action": "increment_number_by_01"
},
"command": "run_emmet_action",
"context": [
{
"key": "emmet_action_enabled.increment_number_by_01"
}
]
},
{
"keys": [
"ctrl+shift+t"
],
"args": {
"action": "matching_pair"
},
"command": "run_emmet_action",
"context": [
{
"key": "emmet_action_enabled.matching_pair"
}
]
},
{
"keys": [
"ctrl+down"
],
"args": {
"action": "decrement_number_by_1"
},
"command": "run_emmet_action",
"context": [
{
"key": "emmet_action_enabled.decrement_number_by_1"
}
]
},
{
"keys": [
"ctrl+e"
],
"args": {
"action": "expand_abbreviation"
},
"command": "run_emmet_action",
"context": [
{
"key": "emmet_action_enabled.expand_abbreviation"
}
]
},
{
"keys": [
"tab"
],
"command": "expand_abbreviation_by_tab",
"context": [
{
"operand": "source.css, source.sass, source.less, source.scss, source.stylus, text.xml, text.html, text.haml, text.scala.html, source string",
"operator": "equal",
"match_all": true,
"key": "selector"
},
{
"operand": "text.html source.php, text.html source.js, storage.type.templatetag.django",
"operator": "not_equal",
"match_all": true,
"key": "selector"
},
{
"match_all": true,
"key": "selection_empty"
},
{
"operator": "equal",
"operand": false,
"match_all": true,
"key": "has_next_field"
},
{
"operator": "equal",
"operand": false,
"match_all": true,
"key": "setting.disable_tab_abbreviations"
},
{
"operand": false,
"operator": "equal",
"match_all": true,
"key": "auto_complete_visible"
},
{
"match_all": true,
"key": "is_abbreviation"
}
]
},
{
"keys": [
"tab"
],
"command": "expand_abbreviation_by_tab",
"context": [
{
"operand": "source.css, source.sass, source.less, source.scss, source.stylus, text.xml, text.html, text.haml, text.scala.html, source string",
"operator": "equal",
"match_all": true,
"key": "selector"
},
{
"operand": "text.html source.php, text.html source.js, storage.type.templatetag.django",
"operator": "not_equal",
"match_all": true,
"key": "selector"
},
{
"match_all": true,
"key": "selection_empty"
},
{
"operator": "equal",
"operand": false,
"match_all": true,
"key": "has_next_field"
},
{
"operator": "equal",
"operand": true,
"match_all": true,
"key": "auto_complete_visible"
},
{
"operator": "equal",
"operand": false,
"match_all": true,
"key": "setting.disable_tab_abbreviations_on_auto_complete"
},
{
"match_all": true,
"key": "is_abbreviation"
}
]
},
{
"keys": [
"enter"
],
"args": {
"contents": "\n\t${0}\n"
},
"command": "insert_snippet",
"context": [
{
"operand": "meta.scope.between-tag-pair.html, meta.scope.between-tag-pair.xml",
"match_all": true,
"key": "selector"
},
{
"operand": false,
"match_all": true,
"key": "auto_complete_visible"
},
{
"match_all": true,
"key": "clear_fields_on_enter_key"
},
{
"operand": false,
"match_all": true,
"key": "setting.disable_formatted_linebreak"
}
]
},
{
"keys": [
"#"
],
"args": {
"attribute": "id"
},
"command": "emmet_insert_attribute",
"context": [
{
"operand": "text.html meta.tag -string -punctuation.definition.tag.begin.html -meta.scope.between-tag-pair.html -source -meta.tag.template.value.twig",
"operator": "equal",
"match_all": true,
"key": "selector"
},
{
"operator": "equal",
"operand": true,
"key": "setting.auto_id_class"
}
]
},
{
"keys": [
"."
],
"args": {
"attribute": "class"
},
"command": "emmet_insert_attribute",
"context": [
{
"operand": "text.html meta.tag -string -punctuation.definition.tag.begin.html -meta.scope.between-tag-pair.html -source -meta.tag.template.value.twig",
"operator": "equal",
"match_all": true,
"key": "selector"
},
{
"operator": "equal",
"operand": true,
"key": "setting.auto_id_class"
}
]
}
]

View File

@@ -0,0 +1,518 @@
// This file is automatically generated with misc/generate-keymap.py script
[
{
"keys": [
"shift+ctrl+y"
],
"args": {
"action": "evaluate_math_expression"
},
"command": "run_emmet_action",
"context": [
{
"key": "emmet_action_enabled.evaluate_math_expression"
}
]
},
{
"keys": [
"shift+ctrl+;"
],
"args": {
"action": "remove_tag"
},
"command": "run_emmet_action",
"context": [
{
"key": "emmet_action_enabled.remove_tag"
}
]
},
{
"keys": [
"ctrl+up"
],
"args": {
"action": "increment_number_by_1"
},
"command": "run_emmet_action",
"context": [
{
"key": "emmet_action_enabled.increment_number_by_1"
}
]
},
{
"keys": [
"ctrl+shift+forward_slash"
],
"args": {
"action": "toggle_comment"
},
"command": "run_emmet_action",
"context": [
{
"operand": "source.css - source.css.less, text.xml, text.html - source",
"operator": "equal",
"match_all": true,
"key": "selector"
},
{
"match_all": true,
"key": "emmet_action_enabled.toggle_comment"
}
]
},
{
"keys": [
"shift+ctrl+."
],
"args": {
"action": "select_next_item"
},
"command": "run_emmet_action",
"context": [
{
"key": "emmet_action_enabled.select_next_item"
}
]
},
{
"keys": [
"ctrl+alt+enter"
],
"command": "expand_as_you_type",
"context": [
{
"operand": false,
"operator": "equal",
"match_all": true,
"key": "setting.is_widget"
},
{
"match_all": true,
"key": "emmet_action_enabled.expand_as_you_type"
}
]
},
{
"keys": [
"alt+down"
],
"args": {
"action": "decrement_number_by_01"
},
"command": "run_emmet_action",
"context": [
{
"key": "emmet_action_enabled.decrement_number_by_01"
}
]
},
{
"keys": [
"ctrl+'"
],
"args": {
"action": "encode_decode_data_url"
},
"command": "run_emmet_action",
"context": [
{
"key": "emmet_action_enabled.encode_decode_data_url"
}
]
},
{
"keys": [
"ctrl+shift+0"
],
"args": {
"action": "match_pair_inward"
},
"command": "run_emmet_action",
"context": [
{
"key": "emmet_action_enabled.match_pair_inward"
}
]
},
{
"keys": [
"shift+alt+up"
],
"args": {
"action": "increment_number_by_10"
},
"command": "run_emmet_action",
"context": [
{
"key": "emmet_action_enabled.increment_number_by_10"
}
]
},
{
"keys": [
"shift+ctrl+r"
],
"args": {
"action": "reflect_css_value"
},
"command": "run_emmet_action",
"context": [
{
"key": "emmet_action_enabled.reflect_css_value"
}
]
},
{
"keys": [
"ctrl+alt+left"
],
"args": {
"action": "prev_edit_point"
},
"command": "run_emmet_action",
"context": [
{
"key": "emmet_action_enabled.prev_edit_point"
}
]
},
{
"keys": [
"shift+ctrl+,"
],
"args": {
"action": "select_previous_item"
},
"command": "run_emmet_action",
"context": [
{
"key": "emmet_action_enabled.select_previous_item"
}
]
},
{
"keys": [
"ctrl+,"
],
"args": {
"action": "match_pair_outward"
},
"command": "run_emmet_action",
"context": [
{
"key": "emmet_action_enabled.match_pair_outward"
}
]
},
{
"keys": [
"ctrl+u"
],
"args": {
"action": "update_image_size"
},
"command": "run_emmet_action",
"context": [
{
"key": "emmet_action_enabled.update_image_size"
}
]
},
{
"keys": [
"ctrl+alt+right"
],
"args": {
"action": "next_edit_point"
},
"command": "run_emmet_action",
"context": [
{
"key": "emmet_action_enabled.next_edit_point"
}
]
},
{
"keys": [
"shift+ctrl+`"
],
"args": {
"action": "split_join_tag"
},
"command": "run_emmet_action",
"context": [
{
"key": "emmet_action_enabled.split_join_tag"
}
]
},
{
"keys": [
"shift+alt+down"
],
"args": {
"action": "decrement_number_by_10"
},
"command": "run_emmet_action",
"context": [
{
"key": "emmet_action_enabled.decrement_number_by_10"
}
]
},
{
"keys": [
"shift+ctrl+g"
],
"command": "wrap_as_you_type",
"context": [
{
"operand": false,
"operator": "equal",
"match_all": true,
"key": "setting.is_widget"
},
{
"match_all": true,
"key": "emmet_action_enabled.wrap_as_you_type"
}
]
},
{
"keys": [
"shift+ctrl+'"
],
"command": "rename_tag",
"context": [
{
"key": "emmet_action_enabled.rename_tag"
}
]
},
{
"keys": [
"alt+up"
],
"args": {
"action": "increment_number_by_01"
},
"command": "run_emmet_action",
"context": [
{
"key": "emmet_action_enabled.increment_number_by_01"
}
]
},
{
"keys": [
"ctrl+alt+j"
],
"args": {
"action": "matching_pair"
},
"command": "run_emmet_action",
"context": [
{
"key": "emmet_action_enabled.matching_pair"
}
]
},
{
"keys": [
"ctrl+down"
],
"args": {
"action": "decrement_number_by_1"
},
"command": "run_emmet_action",
"context": [
{
"key": "emmet_action_enabled.decrement_number_by_1"
}
]
},
{
"keys": [
"ctrl+e"
],
"args": {
"action": "expand_abbreviation"
},
"command": "run_emmet_action",
"context": [
{
"key": "emmet_action_enabled.expand_abbreviation"
}
]
},
{
"keys": [
"tab"
],
"command": "expand_abbreviation_by_tab",
"context": [
{
"operand": "source.css, source.sass, source.less, source.scss, source.stylus, text.xml, text.html, text.haml, text.scala.html, source string",
"operator": "equal",
"match_all": true,
"key": "selector"
},
{
"operand": "text.html source.php, text.html source.js, storage.type.templatetag.django",
"operator": "not_equal",
"match_all": true,
"key": "selector"
},
{
"match_all": true,
"key": "selection_empty"
},
{
"operator": "equal",
"operand": false,
"match_all": true,
"key": "has_next_field"
},
{
"operator": "equal",
"operand": false,
"match_all": true,
"key": "setting.disable_tab_abbreviations"
},
{
"operand": false,
"operator": "equal",
"match_all": true,
"key": "auto_complete_visible"
},
{
"match_all": true,
"key": "is_abbreviation"
}
]
},
{
"keys": [
"tab"
],
"command": "expand_abbreviation_by_tab",
"context": [
{
"operand": "source.css, source.sass, source.less, source.scss, source.stylus, text.xml, text.html, text.haml, text.scala.html, source string",
"operator": "equal",
"match_all": true,
"key": "selector"
},
{
"operand": "text.html source.php, text.html source.js, storage.type.templatetag.django",
"operator": "not_equal",
"match_all": true,
"key": "selector"
},
{
"match_all": true,
"key": "selection_empty"
},
{
"operator": "equal",
"operand": false,
"match_all": true,
"key": "has_next_field"
},
{
"operator": "equal",
"operand": true,
"match_all": true,
"key": "auto_complete_visible"
},
{
"operator": "equal",
"operand": false,
"match_all": true,
"key": "setting.disable_tab_abbreviations_on_auto_complete"
},
{
"match_all": true,
"key": "is_abbreviation"
}
]
},
{
"keys": [
"enter"
],
"args": {
"contents": "\n\t${0}\n"
},
"command": "insert_snippet",
"context": [
{
"operand": "meta.scope.between-tag-pair.html, meta.scope.between-tag-pair.xml",
"match_all": true,
"key": "selector"
},
{
"operand": false,
"match_all": true,
"key": "auto_complete_visible"
},
{
"match_all": true,
"key": "clear_fields_on_enter_key"
},
{
"operand": false,
"match_all": true,
"key": "setting.disable_formatted_linebreak"
}
]
},
{
"keys": [
"#"
],
"args": {
"attribute": "id"
},
"command": "emmet_insert_attribute",
"context": [
{
"operand": "text.html meta.tag -string -punctuation.definition.tag.begin.html -meta.scope.between-tag-pair.html -source -meta.tag.template.value.twig",
"operator": "equal",
"match_all": true,
"key": "selector"
},
{
"operator": "equal",
"operand": true,
"key": "setting.auto_id_class"
}
]
},
{
"keys": [
"."
],
"args": {
"attribute": "class"
},
"command": "emmet_insert_attribute",
"context": [
{
"operand": "text.html meta.tag -string -punctuation.definition.tag.begin.html -meta.scope.between-tag-pair.html -source -meta.tag.template.value.twig",
"operator": "equal",
"match_all": true,
"key": "selector"
},
{
"operator": "equal",
"operand": true,
"key": "setting.auto_id_class"
}
]
}
]

View File

@@ -0,0 +1,192 @@
[
{
"caption": "Emmet: Expand Abbreviation",
"command": "run_emmet_action",
"args": {
"action": "expand_abbreviation"
}
},
{
"caption": "Emmet: Wrap With Abbreviation",
"command": "wrap_as_you_type"
},
{
"caption": "Emmet: Match Pair (outward)",
"command": "run_emmet_action",
"args": {
"action": "match_pair_outward"
}
},
{
"caption": "Emmet: Match Pair (inward)",
"command": "run_emmet_action",
"args": {
"action": "match_pair_inward"
}
},
{
"caption": "Emmet: Go to Matching Pair",
"command": "run_emmet_action",
"args": {
"action": "matching_pair"
}
},
{
"caption": "Emmet: Next Edit Point",
"command": "run_emmet_action",
"args": {
"action": "next_edit_point"
}
},
{
"caption": "Emmet: Previous Edit Point",
"command": "run_emmet_action",
"args": {
"action": "prev_edit_point"
}
},
{
"caption": "Emmet: Merge Lines",
"command": "run_emmet_action",
"args": {
"action": "merge_lines"
}
},
{
"caption": "Emmet: Toggle Comment",
"command": "run_emmet_action",
"args": {
"action": "toggle_comment"
}
},
{
"caption": "Emmet: Split\\Join Tag",
"command": "run_emmet_action",
"args": {
"action": "split_join_tag"
}
},
{
"caption": "Emmet: Remove Tag",
"command": "run_emmet_action",
"args": {
"action": "remove_tag"
}
},
{
"caption": "Emmet: Evaluate Math Expression",
"command": "run_emmet_action",
"args": {
"action": "evaluate_math_expression"
}
},
{
"caption": "Emmet: Increment Number by 1",
"command": "run_emmet_action",
"args": {
"action": "increment_number_by_1"
}
},
{
"caption": "Emmet: Decrement Number by 1",
"command": "run_emmet_action",
"args": {
"action": "decrement_number_by_1"
}
},
{
"caption": "Emmet: Increment Number by 0.1",
"command": "run_emmet_action",
"args": {
"action": "increment_number_by_01"
}
},
{
"caption": "Emmet: Decrement Number by 0.1",
"command": "run_emmet_action",
"args": {
"action": "decrement_number_by_01"
}
},
{
"caption": "Emmet: Increment Number by 10",
"command": "run_emmet_action",
"args": {
"action": "increment_number_by_10"
}
},
{
"caption": "Emmet: Decrement Number by 10",
"command": "run_emmet_action",
"args": {
"action": "decrement_number_by_10"
}
},
{
"caption": "Emmet: Select Next Item",
"command": "run_emmet_action",
"args": {
"action": "select_next_item"
}
},
{
"caption": "Emmet: Select Previous Item",
"command": "run_emmet_action",
"args": {
"action": "select_previous_item"
}
},
{
"caption": "Emmet: Reflect CSS Value",
"command": "run_emmet_action",
"args": {
"action": "reflect_css_value"
}
},
{
"caption": "Emmet: Encode\\Decode Image to data:URL",
"command": "run_emmet_action",
"args": {
"action": "encode_decode_data_url"
}
},
{
"caption": "Emmet: Update Image Size",
"command": "run_emmet_action",
"args": {
"action": "update_image_size"
}
},
{
"caption": "Emmet: Rename Tag",
"command": "rename_tag"
},
{
"caption": "Emmet: Reload Extensions",
"command": "emmet_reset_context"
}
]

View File

@@ -0,0 +1,114 @@
{
// Copy any modified settings to `User/Emmet.sublime-settings`
// otherwise modifications will not survive updates.
// Path to folder where Emmet should look for extensions
// http://docs.emmet.io/customization/
"extensions_path": "~/emmet",
// Disable completions of HTML attributes
// with this option disabled, you can get attribute list completions
// inside opening HTML tags.
// WARNING: with this option disabled, Tab key expander will not
// work inside opening HTML attributes
"disable_completions": false,
// With this option enabled, all Emmet's CSS snippets
// will be available in standard auto-complete popup
"show_css_completions": true,
// List of scopes where Emmet CSS completions should be available
"css_completions_scope": "source.css - meta.selector.css - meta.property-value.css, source.scss - meta.selector.scss - meta.property-value.scss",
// Remove default HTML tag completions on plugin start
// You should restart editor after changing this option
"remove_html_completions": false,
// A comma-separated list of scopes where Emmets Tab key
// abbreviation expander should be disabled
"disable_tab_abbreviations_for_scopes": "",
// A regexp for scope name: if it matches, Tab handler wont work
// The reason to use this preference is that ST2 has buggy scope matcher
// which may still trigger Tab handler even if it's restricted by context
"disable_tab_abbreviations_for_regexp": "source\\.(?!css).+?\\stext\\.html",
// Exit tabstop mode when enter key is pressed
"clear_fields_on_enter_key": true,
// A comma-separated list of disabled action names.
// Listed action will not be triggered by default keyboard
// shortcut.
// Use "all" value to disable all shortcuts at once
"disabled_keymap_actions": "",
// By default, Emmet overrides Tab key to effectively expand abbreviations.
// The downside of this approach is that you cant expand regular ST2
// snippets (like `php`). Since its not currently possible to get a list
// of ST2 snippets via API, you can provide a list of scopes where Emmets
// Tab trigger should be disabled when expanding simple abbreviation.
// If entered abbreviation (like `php`) wasnt found in Emmet snippets list
// or "known_html_tags" preference, Tab handler will not be triggered.
// Leave this setting blank to disable this feature
"disabled_single_snippet_for_scopes": "text.html",
// A space-separated list of single snippets that should be
// forcilbly disabled (not handled) for Emmet even if it
// has such abbreviation.
// This option is useful if you wish the enumerated snippets
// should be handled by Sublime Text.
// Example value: "script style html"
"disabled_single_snippets": "",
// A space separated list of all known HTML tags,
// used together with "disabled_on_single_snippets" option
"known_html_tags": "html head title base link meta style script noscript body section nav article aside h1 h2 h3 h4 h5 h6 hgroup header footer address p hr pre blockquote ol ul li dl dt dd figure figcaption div a em strong small s cite q dfn abbr data time code var samp kbd sub sup i b u mark ruby rt rp bdi bdo span br wbr ins del img iframe embed object param video audio source track canvas map area svg math table caption colgroup col tbody thead tfoot tr td th form fieldset legend label input button select datalist optgroup option textarea keygen output progress meter details summary command menu",
"empty_elements": "area base basefont br col frame hr img input isindex link meta param embed",
// If set to `true`, Emmet will automatically insert final tabstop
// at the end of expanded abbreviation
"insert_final_tabstop": false,
// Try to automatically detect XHTML dialect in HTML documents.
// With this option enabled, your custom profile for HTML documents may not work.
"autodetect_xhtml": true,
// Use old Tab handler to exand abbreviations.
// With this option enabled, editor may better handle Tab key
// (especially with other plugins that overrides Tab key),
// but will spit "slow plugin" message
"use_old_tab_handler": false,
///////////////////////////////
// Emmet customization
// Each section has the same meaning as the same-named JSON file
// described here:
// http://docs.emmet.io/customization/
///////////////////////////////
// Custom snippets definitions, as per https://github.com/emmetio/emmet/blob/master/snippets.json
"snippets": {
// "html": {
// "abbreviations": {
// "example": "<div class='example' title='Custom element example'>"
// }
// }
},
// Emmet preferences
// List of all available preferences:
// http://docs.emmet.io/customization/preferences/
"preferences": {
// "css.valueSeparator": ": ",
// "css.propertyEnd": ";"
},
// Output profiles for syntaxes
// http://docs.emmet.io/customization/syntax-profiles/
"syntaxProfiles": {
// Enable XHTML dialect for HTML syntax
// "html": "xhtml"
}
}

View File

@@ -0,0 +1,333 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>comment</key>
<string>Emmet abbreviation syntax by sublimator|castle_made_of_sand</string>
<key>fileTypes</key>
<array>
<string>em</string>
</array>
<key>name</key>
<string>Emmet</string>
<key>patterns</key>
<array>
<dict>
<key>include</key>
<string>#css_snippets</string>
</dict>
<dict>
<key>include</key>
<string>#html_abbrevs</string>
</dict>
<dict>
<key>include</key>
<string>#expandos</string>
</dict>
<dict>
<key>include</key>
<string>#html_elements</string>
</dict>
<dict>
<key>include</key>
<string>#filter</string>
</dict>
<dict>
<key>include</key>
<string>#element</string>
</dict>
<dict>
<key>include</key>
<string>#class</string>
</dict>
<dict>
<key>include</key>
<string>#operator</string>
</dict>
<dict>
<key>include</key>
<string>#id</string>
</dict>
<dict>
<key>include</key>
<string>#repeater</string>
</dict>
<dict>
<key>include</key>
<string>#repeat_quantifier</string>
</dict>
<dict>
<key>begin</key>
<string>\[</string>
<key>beginCaptures</key>
<dict>
<key>0</key>
<dict>
<key>name</key>
<string>punctuation.definition.begin.#30d556d0518a11e1bd8ab482fe507f0e</string>
</dict>
</dict>
<key>end</key>
<string>\]</string>
<key>endCaptures</key>
<dict>
<key>0</key>
<dict>
<key>name</key>
<string>punctuation.definition.end.#30d556d1518a11e1ab2fb482fe507f0e</string>
</dict>
</dict>
<key>name</key>
<string>meta.tag.attributes.#30d556cf518a11e1afd8b482fe507f0e</string>
<key>patterns</key>
<array>
<dict>
<key>include</key>
<string>#attribute-value</string>
</dict>
<dict>
<key>include</key>
<string>#attribute-name</string>
</dict>
<dict>
<key>include</key>
<string>#double-string</string>
</dict>
<dict>
<key>include</key>
<string>#single-string</string>
</dict>
</array>
</dict>
<dict>
<key>begin</key>
<string>\{</string>
<key>beginCaptures</key>
<dict>
<key>0</key>
<dict>
<key>name</key>
<string>punctuation.#30d556d4518a11e1baa6b482fe507f0e</string>
</dict>
</dict>
<key>contentName</key>
<string>string.#30d556d3518a11e1babab482fe507f0e</string>
<key>end</key>
<string>\}</string>
<key>endCaptures</key>
<dict>
<key>0</key>
<dict>
<key>name</key>
<string>punctuation.#30d556d5518a11e1860bb482fe507f0e</string>
</dict>
</dict>
<key>name</key>
<string>string.#30d556d2518a11e1bccfb482fe507f0e</string>
<key>patterns</key>
<array>
</array>
</dict>
</array>
<key>repository</key>
<dict>
<key>attribute-name</key>
<dict>
<key>match</key>
<string>[a-zA-Z0-9:]+</string>
<key>name</key>
<string>meta.tag entity.other.attribute-name.#30d556dd518a11e19355b482fe507f0e</string>
</dict>
<key>attribute-value</key>
<dict>
<key>captures</key>
<dict>
<key>1</key>
<dict>
<key>name</key>
<string>meta.tag entity.other.attribute-name.#30d556df518a11e18855b482fe507f0e</string>
</dict>
<key>2</key>
<dict>
<key>name</key>
<string></string>
</dict>
<key>3</key>
<dict>
<key>name</key>
<string>string.#30d556e0518a11e1949eb482fe507f0e</string>
</dict>
</dict>
<key>match</key>
<string>([a-zA-Z0-9:]+)(=)([^"'\] ]+)</string>
<key>name</key>
<string>meta.tag.#30d556de518a11e195ecb482fe507f0e</string>
</dict>
<key>class</key>
<dict>
<key>match</key>
<string>\.[0-9a-zA-Z-_-]+</string>
<key>name</key>
<string>entity.class.#30d556e4518a11e1a731b482fe507f0e</string>
</dict>
<key>css_snippets</key>
<dict>
<key>captures</key>
<dict>
<key>1</key>
<dict>
<key>name</key>
<string></string>
</dict>
</dict>
<key>match</key>
<string>(d:tbc|wow:n|wow:u|wow:s|d:tbr|list:lr|bdl\+|bdf:c|bgbk:bb|bdbi:n|bdf:r|to:n|fst:ee|fst:ec|bgcp:cb|lisp:o|lisp:i|d:tbclg|@f|d:rbt|@i|@m|fef:eb|fef:eg|te:c|te:b|q:n|te:n|bdbs:n|bg:ie|d:li|tj:k|bd\+|fems:ac|fst:n|fst:c|fst:e|cur:t|cur:p|cur:m|maw:n|fw:n|bdtri:n|fw:b|bdtri:c|cur:a|oc:i|cur:c|bdls:n|tw:u|va:sub|tw:s|pgbi:av|tj:t|pgbi:au|va:sup|va:bl|tw:n|va:t|va:m|bds:dt|va:b|tsh\+|cps:t|cps:b|list:dclz|f\+|bd:n|!|bdl:n|bdl:a|td:u|tw:no|whs:nw|va:tb|h:a|d:ib|bgo:cb|d:i|va:tt|fef:o|wow:nm|ct:noq|pgba:al|bdli:n|d:tbhg|bga:s|fst:se|fst:sc|fsm:a|bga:f|fsm:n|tbl:f|tbl:a|bdci:n|whsc:k|bdci:c|whsc:l|bgi:n|bdb:n|bdbk:c|pgba:r|te:ac|l:a|bdr:n|whsc:ba|whsc:bs|b:a|bdt\+|ta:c|bdf:sp|ovy:a|bdb\+|d:tb|bdf:st|ti:-|ovy:h|ta:l|ovy:s|ta:r|bdf:sc|ovy:v|bdts:n|bdf:of|fl:l|fl:n|bdf:ow|fl:r|tt:c|tt:n|ec:s|tt:l|ec:h|tt:u|bdti:n|bgz:cv|bgz:ct|d:cp|fef:n|bdt:n|to\+|bdbri:n|bdbri:c|tsh:n|fv:sc|r:a|fems:ds|fems:dt|op:ms|bds:dtds|bgcp:nc|ct:ncq|bg:n|bdrs:n|ml:a|bds:dtdtds|ff:s|d:rbb|tj:d|tj:a|ff:f|fems:c|ff:c|d:itb|fems:n|ff:m|pgba:au|bdri:n|mt:a|wob:l|td:n|td:o|td:l|bxz:bb|bxsh:n|bxsh:m|bxsh:w|fw:br|ovs:p|ovs:s|w:a|fv:n|ovs:a|m:a|bgcp:pb|ovs:m|fsm:aw|pgbb:au|m:4|m:0|m:2|m:3|op:ie|fst:ue|fst:uc|pgbb:al|bdtli:n|bdtli:c|list:ur|tr:n|bgbk:c|ov:a|te:a|ov:h|ov:v|ov:s|cp:r|cp:a|lisi:n|rz:v|rz:n|rz:h|mb:a|rz:b|d:rb|d:ri|bds:db|d:tbfg|bds:ds|lis:n|d:b|tal:a|tal:c|tal:l|bgbk:eb|d:n|tal:r|tj:iw|bgr:x|bgr:y|bgr:n|list:c|list:d|bdbli:c|bdbli:n|list:n|list:s|mah:n|th:t|d:rbtg|th:f|th:a|ct:cq|ct:cs|th:m|bxz:cb|whs:p|wob:bs|fw:lr|whsc:n|te:ds|te:dt|whs:n|wob:ba|list:dc|d:tbrg|mr:a|q:en|ovs:mq|p:4|bgz:a|p:0|p:3|p:2|whs:pw|bg\+|bdcl:s|bdcl:c|wob:n|wob:k|tj:ic|tj:ii|t:a|bgcp:bb|ff:ss|cl:r|q:ru|cl:n|cl:l|cl:b|fs:o|fs:n|bds:h|bds:i|bds:n|bds:o|fs:i|ct:oq|bds:g|bds:r|bds:s|bds:w|z:a|ct:c|ct:a|pgbb:r|bgo:bb|ct:n|bdr\+|pgbb:l|d:tbcl|ovx:a|whs:pl|ovx:h|ovx:v|ovx:s|cur:d|d:tbcp|d:rbbg|femp:a|femp:b|o:n|pgba:l|pos:s|pos:r|bdi:m|bdi:n|pos:f|pos:a|bdi:w|fza:n|v:h|v:c|cur:he|cur:ha|bgo:pb|v:v)</string>
<key>name</key>
<string>support.zen.css.snippet.#30d556d9518a11e18531b482fe507f0e</string>
</dict>
<key>double-string</key>
<dict>
<key>begin</key>
<string>"</string>
<key>beginCaptures</key>
<dict>
<key>0</key>
<dict>
<key>name</key>
<string>punctuation.definition.begin.#30d556e7518a11e18d8eb482fe507f0e</string>
</dict>
</dict>
<key>end</key>
<string>"</string>
<key>endCaptures</key>
<dict>
<key>0</key>
<dict>
<key>name</key>
<string>punctuation.definition.end.#30d556e8518a11e19ddeb482fe507f0e</string>
</dict>
</dict>
<key>name</key>
<string>string.quoted.double.#30d556e6518a11e1aa37b482fe507f0e</string>
<key>patterns</key>
<array>
</array>
</dict>
<key>element</key>
<dict>
<key>match</key>
<string>[a-zA-Z-:]+</string>
<key>name</key>
<string>meta.tag.#30d556dc518a11e1833ab482fe507f0e</string>
</dict>
<key>expandos</key>
<dict>
<key>match</key>
<string>(colgroup\+|optg\+|table\+|ol\+|tr\+|optgroup\+|dl\+|ul\+|select\+|colg\+|map\+)$</string>
<key>name</key>
<string>support.zen.html.expandos.#30d556d7518a11e18b1ab482fe507f0e</string>
</dict>
<key>filter</key>
<dict>
<key>captures</key>
<dict>
<key>1</key>
<dict>
<key>name</key>
<string>keyword.pipe.#30d556da518a11e18e9cb482fe507f0e</string>
</dict>
<key>2</key>
<dict>
<key>name</key>
<string>entity.filter.#30d556db518a11e1947fb482fe507f0e</string>
</dict>
</dict>
<key>match</key>
<string>(\|)([a-zA-Z]+)</string>
</dict>
<key>html_abbrevs</key>
<dict>
<key>match</key>
<string>(?:a:link|input:datetime-local|input:reset|colg|style|adr|img|bdo:l|param|form:post|bdo:r|fig|input:radio|link:print|opt|input:i|input:h|input:f|input:c|input:b|abbr|input:t|input:p|input:s|input:r|ifr|emb|cmd|link:atom|art|input:search|area:r|area:p|input:date|video|input:button|area:d|area:c|out|ftr|dlg|script:src|form:get|meta:utf|label|input:time|link:favicon|menu:toolbar|prog|input:email|str|leg|acronym|base|bq|src|obj|script|acr|input:password|input:file|tarea|select|input:number|input:range|area|input:image|input:month|fset|meta:win|menu:t|form|menu:c|link|input|link:rss|hdr|cap|det|link:touch|iframe|link:css|input:week|embed|optg|input:datetime|datag|option|html:xml|btn|input:url|menu:context|map|input:color|meta:compat|input:hidden|object|a:mail|a|datal|kg|textarea|input:submit|input:text|input:checkbox|fst|sect|audio|bdo)</string>
<key>name</key>
<string>entity.name.tag support.zen.html.abbrev.#30d556d6518a11e18a88b482fe507f0e</string>
<key>patterns</key>
<array>
<dict>
<key>match</key>
<string>:</string>
<key>name</key>
<string>fuck</string>
</dict>
</array>
</dict>
<key>html_elements</key>
<dict>
<key>match</key>
<string>\b(comment|bgsound|code|h2|h3|h1|h6|ilayer|h4|blink|header|table|font|u|select|noframes|noscript|style|span|img|area|mark|tt|var|tr|param|legend|source|dfn|tfoot|th|time|strike|input|td|xmp|cite|thead|dl|blockquote|fieldset|option|form|hr|big|dd|nobr|link|abbr|optgroup|li|dt|h5|ruby|noembed|pre|b|wbr|colgroup|button|isindex|keygen|p|applet|del|iframe|section|small|output|div|dir|em|frameset|layer|figure|datalist|frame|head|hgroup|meta|video|meter|summary|!DOCTYPE|rt|kbd|canvas|rp|sub|ul|tbody|bdo|aside|label|basefont|html|nav|details|sup|progress|samp|math|body|map|object|ins|acronym|marquee|figcaption|xml|base|br|address|article|strong|embed|a|ol|center|textarea|footer|i|svg|script|q|caption|s|command|menu|title|audio|col)\b</string>
<key>name</key>
<string>entity.name.tag support.zen.html.element.#30d556d8518a11e195e7b482fe507f0e</string>
</dict>
<key>id</key>
<dict>
<key>match</key>
<string>#[a-zA-Z-_]+</string>
<key>name</key>
<string>entity.id.#30d556e5518a11e1a0d0b482fe507f0e</string>
</dict>
<key>operator</key>
<dict>
<key>match</key>
<string>&gt;|\*|\+|:|\^</string>
<key>name</key>
<string>keyword.#30d556e1518a11e1983ab482fe507f0e</string>
</dict>
<key>repeat_quantifier</key>
<dict>
<key>match</key>
<string>\d</string>
<key>name</key>
<string>keyword.quantifier.#30d556e3518a11e18aefb482fe507f0e</string>
</dict>
<key>repeater</key>
<dict>
<key>match</key>
<string>\$</string>
<key>name</key>
<string>keyword.repeater.#30d556e2518a11e18320b482fe507f0e</string>
</dict>
<key>single-string</key>
<dict>
<key>begin</key>
<string>'</string>
<key>beginCaptures</key>
<dict>
<key>0</key>
<dict>
<key>name</key>
<string>punctuation.definition.begin.#30d556ea518a11e1baedb482fe507f0e</string>
</dict>
</dict>
<key>end</key>
<string>'</string>
<key>endCaptures</key>
<dict>
<key>0</key>
<dict>
<key>name</key>
<string>punctuation.definition.end.#30d556eb518a11e19d9ab482fe507f0e</string>
</dict>
</dict>
<key>name</key>
<string>string.quoted.single.#30d556e9518a11e190e7b482fe507f0e</string>
<key>patterns</key>
<array>
</array>
</dict>
</dict>
<key>scopeName</key>
<string>source.zen.5a454e6772616d6d6172</string>
<key>uuid</key>
<string>ffb80ea1-4cf0-11e1-b0dc-b482fe507f0e</string>
</dict>
</plist>

View File

@@ -0,0 +1,89 @@
[
{
"caption": "Preferences",
"mnemonic": "n",
"id": "preferences",
"children":
[
{
"caption": "Package Settings",
"mnemonic": "P",
"id": "package-settings",
"children":
[
{
"caption": "Emmet",
"children":
[
{
"command": "open_file", "args":
{
"file": "${packages}/Emmet/Emmet.sublime-settings"
},
"caption": "Settings Default"
},
{
"command": "open_file", "args":
{
"file": "${packages}/User/Emmet.sublime-settings"
},
"caption": "Settings User"
},
{ "caption": "-" },
{ "caption": "-" },
{
"command": "open_file",
"args": {
"file": "${packages}/Emmet/Default (OSX).sublime-keymap",
"platform": "OSX"
},
"caption": "Key Bindings Default"
},
{
"command": "open_file",
"args": {
"file": "${packages}/Emmet/Default (Linux).sublime-keymap",
"platform": "Linux"
},
"caption": "Key Bindings Default"
},
{
"command": "open_file",
"args": {
"file": "${packages}/Emmet/Default (Windows).sublime-keymap",
"platform": "Windows"
},
"caption": "Key Bindings Default"
},
{
"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"
},
{
"command": "open_file",
"args": {
"file": "${packages}/User/Default (Windows).sublime-keymap",
"platform": "Windows"
},
"caption": "Key Bindings User"
},
{ "caption": "-" }
]
}
]
}
]
}
]

View File

@@ -0,0 +1,30 @@
{
// --------------------------- README -----------------------------------
// Copy these key/values to User/Preferences.sublime-settings
// They have NO effect here
// If `true` will disable bindings like ctrl+alt+n etc
// Handy for our italian friends :)
"alt_gr": false,
// If `true` will insert id="$1" snippet on pressing '#', similar on '.'
// Useful for `raw html`, but annoying for some templating langs.
"auto_id_class": false,
// disable expanding abbreviation by Tab key
"disable_tab_abbreviations": false,
// disable insertion of formatted linebreak when
// Enter key is pressed between opening and closing HTML tags
"disable_formatted_linebreak": false,
// Enables default Emmet keymap. Many users complain that Emmet actions
// (especially ones that bound to Alt key) behave incorrectly in
// non-English keyboard layouts. Set this setting to `false` in
// Userss Preferences.sublime-settings to disable all default
// keybindings at once
"enable_emmet_keymap": true,
// disable expanding abbreviation by Tab key when autocomplete popup is visible
"disable_tab_abbreviations_on_auto_complete": true
}

View File

@@ -0,0 +1,112 @@
# Emmet for Sublime Text 2 plugin
Official [Emmet](http://emmet.io) plugin (previously called _Zen Coding_) for Sublime Text 2.
* [How to install](#how-to-install)
* [Available actions](#available-actions)
* [Extensions support](#extensions-support)
* [Overriding keyboard shortcuts](#overriding-keyboard-shortcuts)
* [Tab key handler](#tab-key-handler)
## How to install
*Warning:* this plugin may not work at all in some OSes since it written in JavaScript and uses [PyV8](http://code.google.com/p/pyv8/) and [Google V8](https://developers.google.com/v8/) binaries to run. If you experience problems or editor crashes please [fill an issue](https://github.com/sergeche/emmet-sublime/issues).
1. Clone or [download](https://github.com/sergeche/emmet-sublime/archive/master.zip) git repo into your packages folder (in ST2, find Browse Packages... menu item to open this folder)
2. Restart ST2 editor (if required)
Or with [Package Control](http://wbond.net/sublime_packages/package_control):
1. Run “Package Control: Install Package” command, find and install `Emmet` plugin.
2. Restart ST2 editor (if required)
--------------
**WARNING**: When plugin is installed, it will automatically download required PyV8 binary so you have to wait a bit (see _Loading PyV8 binary_ message on status bar). If you experience issues with automatic PyV8 loader, try to [install it manually](https://github.com/emmetio/pyv8-binaries).
## New features of Emmet (compared with old Zen Coding)
* [Dynamic CSS abbreviations](http://docs.emmet.io/css-abbreviations/), automatic [vendor prefixes](http://docs.emmet.io/css-abbreviations/vendor-prefixes/) and [gradient generator](http://docs.emmet.io/css-abbreviations/gradients/).
* [“Lorem Ipsum” generator](http://docs.emmet.io/abbreviations/lorem-ipsum/)
* [Implicit tag names](http://docs.emmet.io/abbreviations/implicit-names/)
* New [Yandexs BEM filter](http://docs.emmet.io/filters/bem/)
* [Extensions support](http://docs.emmet.io/customization/)
* New [^ operator](http://docs.emmet.io/abbreviations/syntax/)
* Various fixes and improvements
## Available actions ##
* [Expand Abbreviation](http://docs.emmet.io/actions/expand-abbreviation/) <kbd>Tab</kbd> or <kbd>Ctrl+E</kbd>
* Interactive “Expand Abbreviation” — <kbd>Ctrl+Alt+Enter</kbd>
* [Match Tag Pair Outward](http://docs.emmet.io/actions/match-pair/) <kbd>⌃D</kbd> (Mac) / <kbd>Ctrl+,</kbd> (PC)
* [Match Tag Pair Inward](http://docs.emmet.io/actions/match-pair/) <kbd>⌃J</kbd> / <kbd>Shift+Ctrl+0</kbd>
* [Go to Matching Pair](http://docs.emmet.io/actions/go-to-pair/) <kbd>⇧⌃T</kbd> / <kbd>Ctrl+Alt+J</kbd>
* [Wrap With Abbreviation](http://docs.emmet.io/actions/wrap-with-abbreviation/) — <kbd>⌃W</kbd> / <kbd>Shift+Ctrl+G</kbd>
* [Go to Edit Point](http://docs.emmet.io/actions/go-to-edit-point/) — <kbd>Ctrl+Alt+→</kbd> or <kbd>Ctrl+Alt+←</kbd>
* [Select Item](http://docs.emmet.io/actions/select-item/) <kbd>⇧⌘.</kbd> or <kbd>⇧⌘,</kbd> / <kbd>Shift+Ctrl+.</kbd> or <kbd>Shift+Ctrl+,</kbd>
* [Toggle Comment](http://docs.emmet.io/actions/toggle-comment/) — <kbd>⇧⌥/</kbd> / <kbd>Shift+Ctrl+/</kbd>
* [Split/Join Tag](http://docs.emmet.io/actions/split-join-tag/) — <kbd>⇧⌘'</kbd> / <kbd>Shift+Ctrl+`</kbd>
* [Remove Tag](http://docs.emmet.io/actions/remove-tag/) <kbd>⌘'</kbd> / <kbd>Shift+Ctrl+;</kbd>
* [Update Image Size](http://docs.emmet.io/actions/update-image-size/) — <kbd>⇧⌃I</kbd> / <kbd>Ctrl+U</kbd>
* [Evaluate Math Expression](http://docs.emmet.io/actions/evaluate-math/) — <kbd>⇧⌘Y</kbd> / <kbd>Shift+Ctrl+Y</kbd>
* [Reflect CSS Value](http://docs.emmet.io/actions/reflect-css-value/) <kbd>⇧⌘R</kbd> / <kbd>Shift+Ctrl+R</kbd>
* [Encode/Decode Image to data:URL](http://docs.emmet.io/actions/base64/) <kbd>⇧⌃D</kbd> / <kbd>Ctrl+'</kbd>
* Rename Tag <kbd>⇧⌘K</kbd> / <kbd>Shift+Ctrl+'</kbd>
[Increment/Decrement Number](http://docs.emmet.io/actions/inc-dec-number/) actions:
* Increment by 1: <kbd>Ctrl+↑</kbd>
* Decrement by 1: <kbd>Ctrl+↓</kbd>
* Increment by 0.1: <kbd>Alt+↑</kbd>
* Decrement by 0.1: <kbd>Alt+↓</kbd>
* Increment by 10: <kbd>⌥⌘↑</kbd> / <kbd>Shift+Alt+↑</kbd>
* Decrement by 10: <kbd>⌥⌘↓</kbd> / <kbd>Shift+Alt+↓</kbd>
## Extensions support ##
You can easily [extend](http://docs.emmet.io/customization/) Emmet with new actions and filters or customize existing ones. In `Emmet.sublime-settings`, define `extensions_path` setting and Emmet will load all `.js` and `.json` files in specified folder at startup.
The default value of `extensions_path` is `~/emmet`, which points to _emmet_ folder inside your OS users home folder.
Also, you can create sections named as extension files (e.g. `snippets`, `preferences` and `syntaxProfiles`) inside users `Emmet.sublime-settings` file and write your customizations there. See [original settings file](https://github.com/sergeche/emmet-sublime/blob/master/Emmet.sublime-settings#L61) for examples.
## Overriding keyboard shortcuts ##
Sublime Text 2 is a great text editor with lots of features and actions. Most of these actions are bound to keyboard shortcuts so its nearly impossible to provide convenient plugin shortcuts for third-party plugins.
If youre unhappy with default keymap, you can disable individual keyboard shortcuts with `disabled_keymap_actions` preference of `Emmet.sublime-settings` file.
Use a comma-separated list of action names which default keyboard shortcuts should be disabled. For example, if you want to release <kbd>Ctrl+E</kbd> (“Expand Abbreviation”) and <kbd>Ctrl+U</kbd> (“Update Image Size”) shortcuts, your must set the following value:
"disabled_keymap_actions": "expand_abbreviation, update_image_size"
You should refer `Default (Your-OS-Name).sublime-keymap` file to get action ids (look for `args/action` key).
To disable all default shortcuts, set value to `all`:
"disabled_keymap_actions": "all"
Not that if you disabled any action like so and youre create your own keyboard shortcut, you **should not** use `emmet_action_enabled.ACTION_NAME` context since this is the key that disables action.
### Tab key handler ###
Emmet plugin allows you to expand abbreviations with <kbd>Tab</kbd> key, just like regular snippets. On the other hand, due to dynamic nature and extensive syntax, sometimes you may get unexpected results. This section describes how Tab handler works and how you can fine-tune it.
By default, Tab handler works in a limited _syntax scopes_: HTML, XML, HAML, CSS, SASS/SCSS, LESS and _strings in programming languages_ (like JavaScript, Python, Ruby etc.). It means:
* You have to switch your document to one of the syntaxes listed above to expand abbreviations by Tab key.
* With <kbd>Ctrl-E</kbd> shortcut, you can expand abbreviations everywhere, its scope is not limited.
* When you expand abbreviation inside strings of programming languages, the output is generated with special [output profile](http://docs.emmet.io/customization/syntax-profiles/) named `line` that generates output as a single line.
To fine-tune Tab key handler, you can use the following settings in users `Emmet.sublime-settings` file:
* `disable_tab_abbreviations_for_scopes` — a comma-separated list of syntax scopes where Tab key handler should be disabled. For example, if you want disable handler inside strings of programming languages and HAML syntax, your setting will look like this:
```json
"disable_tab_abbreviations_for_scopes": "text.haml, string"
```
* `disabled_single_snippet_for_scopes` — a comma-separated list of syntax scopes where Tab handler should be disabled when expanding a single abbreviation. Currently, ST2 doesnt provide API for getting list of native snippets. So, for example, if you try to expand a `php` abbreviation, it will be passed to Emmet which outputs `<php></php>` instead of PHP block as defined in native ST2 snippets. As a workaround, if youre trying to expand a single abbreviation inside scope defined in `disabled_single_snippet_for_scopes` setting Emmet will look for its name inside its own [snippets catalog](http://docs.emmet.io/cheat-sheet/) first, inside `known_html_tags` setting second and if its not found, it allows ST2 to handle it and expand native abbreviation, if matched.
* `known_html_tags` — a space-separated list of all known HTML tags used for lookup as described above.
If youre unhappy with Emmet tab handler behavior, you can disable it: just add `"disable_tab_abbreviations": true` into users `Preferences.sublime-settings` file.

View File

@@ -0,0 +1,323 @@
function activeView() {
return sublime.active_window().active_view();
}
var editorProxy = emmet.exec(function(require, _) {
return {
getSelectionRange: function() {
var view = activeView();
var sel = view.sel()[0];
return {
start: sel.begin(),
end: sel.end()
};
},
createSelection: function(start, end) {
var view = activeView();
view.sel().clear();
view.sel().add(new sublime.Region(start, end || start));
view.show(view.sel());
},
getCurrentLineRange: function() {
var view = activeView();
var selection = view.sel()[0];
var line = view.line(selection);
return {
start: line.begin(),
end: line.end()
};
},
getCaretPos: function() {
var view = activeView();
var sel = view.sel();
return sel && sel[0] ? sel[0].begin() : 0;
},
setCaretPos: function(pos){
this.createSelection(pos, pos);
},
getCurrentLine: function() {
var view = activeView();
return view.substr(view.line(view.sel()[0]));
},
replaceContent: function(value, start, end, noIndent) {
if (_.isUndefined(end))
end = _.isUndefined(start) ? this.getContent().length : start;
if (_.isUndefined(start)) start = 0;
// update tabstops: make sure all caret placeholder are unique
// by default, abbreviation parser generates all unlinked (un-mirrored)
// tabstops as ${0}, so we have upgrade all caret tabstops with unique
// positions but make sure that all other tabstops are not linked accidentally
value = pyPreprocessText(value);
sublimeReplaceSubstring(start, end, value, !!noIndent);
},
getContent: function() {
var view = activeView();
return view.substr(new sublime.Region(0, view.size()));
},
getSyntax: function() {
return pyGetSyntax();
},
getProfileName: function() {
var view = activeView();
var pos = this.getCaretPos();
if (view.match_selector(pos, 'text.html')
&& sublimeGetOption('autodetect_xhtml', false)
&& require('actionUtils').isXHTML(this)) {
return 'xhtml';
}
if (view.match_selector(pos, 'string.quoted.double.block.python')
|| view.match_selector(pos, 'source.coffee string')
|| view.match_selector(pos, 'string.unquoted.heredoc')) {
// use html's default profile for:
// * Python's multiline block
// * CoffeeScript string
// * PHP heredoc
return pyDetectProfile();
}
if (view.score_selector(pos, 'source string')) {
return 'line';
}
return pyDetectProfile();
},
prompt: function(title) {
return pyEditor.prompt();
},
getSelection: function() {
var view = activeView();
return view.sel() ? view.substr(view.sel()[0]) : '';
},
getFilePath: function() {
return activeView().file_name();
}
};
});
var _completions = {};
function require(name) {
return emmet.require(name);
}
function pyPreprocessText(value) {
var base = 1000;
var zeroBase = 0;
var lastZero = null;
var range = require('range');
var ts = require('tabStops');
var tabstopOptions = {
tabstop: function(data) {
var group = parseInt(data.group, 10);
var isZero = group === 0;
if (isZero)
group = ++zeroBase;
else
group += base;
var placeholder = data.placeholder;
if (placeholder) {
// recursively update nested tabstops
placeholder = ts.processText(placeholder, tabstopOptions);
}
var result = '${' + group + (placeholder ? ':' + placeholder : '') + '}';
if (isZero) {
lastZero = range.create(data.start, result);
}
return result
},
escape: function(ch) {
if (ch == '$') {
return '\\$';
}
if (ch == '\\') {
return '\\\\';
}
return ch;
}
};
value = ts.processText(value, tabstopOptions);
if (sublimeGetOption('insert_final_tabstop', false) && !/\$\{0\}$/.test(value)) {
value += '${0}';
} else if (lastZero) {
value = require('utils').replaceSubstring(value, '${0}', lastZero);
}
return value;
}
function pyExpandAbbreviationAsYouType(abbr) {
var info = require('editorUtils').outputInfo(editorProxy);
try {
var result = emmet.expandAbbreviation(abbr, info.syntax, info.profile,
require('actionUtils').captureContext(editorProxy));
return pyPreprocessText(result);
} catch (e) {
return '';
}
}
function pyWrapAsYouType(abbr, content) {
var info = require('editorUtils').outputInfo(editorProxy);
content = require('utils').escapeText(content);
var ctx = require('actionUtils').captureContext(editorProxy);
try {
var result = require('wrapWithAbbreviation').wrap(abbr, content, info.syntax, info.profile, ctx);
return pyPreprocessText(result);
} catch(e) {
return '';
}
}
function pyCaptureWrappingRange() {
var info = require('editorUtils').outputInfo(editorProxy);
var range = editorProxy.getSelectionRange();
var startOffset = range.start;
var endOffset = range.end;
if (startOffset == endOffset) {
// no selection, find tag pair
var match = require('htmlMatcher').find(info.content, startOffset);
if (!match) {
// nothing to wrap
return null;
}
/** @type Range */
var utils = require('utils');
var narrowedSel = utils.narrowToNonSpace(info.content, match.range);
startOffset = narrowedSel.start;
endOffset = narrowedSel.end;
}
return [startOffset, endOffset];
}
function pyGetTagNameRanges(pos) {
var ranges = [];
var info = require('editorUtils').outputInfo(editorProxy);
// search for tag
try {
var tag = require('htmlMatcher').tag(info.content, pos);
if (tag) {
var open = tag.open.range;
var tagName = /^<([\w\-\:]+)/i.exec(open.substring(info.content))[1];
ranges.push([open.start + 1, open.start + 1 + tagName.length]);
if (tag.close) {
ranges.push([tag.close.range.start + 2, tag.close.range.start + 2 + tagName.length]);
}
}
} catch (e) {}
return ranges;
}
function pyGetTagRanges() {
var ranges = [];
var info = require('editorUtils').outputInfo(editorProxy);
// search for tag
try {
var tag = require('htmlMatcher').tag(info.content, editorProxy.getCaretPos());
if (tag) {
ranges.push(tag.open.range.toArray());
if (tag.close) {
ranges.push(tag.close.range.toArray());
}
}
} catch (e) {}
return ranges;
}
function pyExtractAbbreviation() {
return require('expandAbbreviation').findAbbreviation(editorProxy);
}
function pyHasSnippet(name) {
return !!emmet.require('resources').findSnippet(editorProxy.getSyntax(), name);
}
/**
* Get all available CSS completions. This method is optimized for CSS
* only since it should contain snippets only so it's not required
* to do extra parsing
*/
function pyGetCSSCompletions(dialect) {
dialect = dialect || pyGetSyntax();
if (!_completions[dialect]) {
var all = require('resources').getAllSnippets(dialect);
var css = require('cssResolver');
_completions[dialect] = _.map(all, function(v, k) {
var snippetValue = typeof v.parsedValue == 'object'
? v.parsedValue.data
: v.value;
var snippet = css.transformSnippet(snippetValue, false, dialect);
return {
k: v.nk,
label: snippet.replace(/\:\s*\$\{0\}\s*;?$/, ''),
v: css.expandToSnippet(v.nk, dialect)
};
});
}
return _completions[dialect];
}
/**
* Returns current syntax name
* @return {String}
*/
function pyGetSyntax() {
var view = activeView();
var pt = view.sel()[0].begin();
var scope = 'scope_name' in view ? view.scope_name(pt) : view.syntax_name(pt);
if (~scope.indexOf('xsl')) {
return 'xsl';
}
var syntax = 'html';
// detect CSS-like syntaxes independently,
// since it may cause collisions with some highlighters
if (/\b(less|scss|sass|css|stylus)\b/.test(scope)) {
syntax = RegExp.$1;
} else if (/\b(html|xml|haml)\b/.test(scope)) {
syntax = RegExp.$1;
}
return require('actionUtils').detectSyntax(editorProxy, syntax);
}
function pyDetectProfile(argument) {
return require('actionUtils').detectProfile(editorProxy);
}

View File

@@ -0,0 +1,711 @@
import sublime
import sublime_plugin
import re
import imp
import json
import sys
import os.path
import traceback
BASE_PATH = os.path.abspath(os.path.dirname(__file__))
PACKAGES_PATH = sublime.packages_path() or os.path.dirname(BASE_PATH)
# EMMET_GRAMMAR = os.path.join(BASE_PATH, 'Emmet.tmLanguage')
EMMET_GRAMMAR = 'Packages/%s/Emmet.tmLanguage' % os.path.basename(BASE_PATH)
sys.path += [BASE_PATH] + [os.path.join(BASE_PATH, f) for f in ['emmet_completions', 'emmet']]
# Make sure all dependencies are reloaded on upgrade
if 'emmet.reloader' in sys.modules:
imp.reload(sys.modules['emmet.reloader'])
import emmet.reloader
# import completions as cmpl
import emmet.pyv8loader as pyv8loader
import emmet_completions as cmpl
from emmet_completions.meta import HTML_ELEMENTS_ATTRIBUTES, HTML_ATTRIBUTES_VALUES
from emmet.context import Context
from emmet.context import js_file_reader as _js_file_reader
from emmet.pyv8loader import LoaderDelegate
__version__ = '1.1'
__core_version__ = '1.0'
__authors__ = ['"Sergey Chikuyonok" <serge.che@gmail.com>'
'"Nicholas Dudfield" <ndudfield@gmail.com>']
is_python3 = sys.version_info[0] > 2
# JS context
ctx = None
# Emmet Settings
settings = None
# Default ST settings
user_settings = None
def is_st3():
return sublime.version()[0] == '3'
def js_file_reader(file_path, use_unicode=True):
if hasattr(sublime, 'load_resource'):
rel_path = file_path
for prefix in [sublime.packages_path(), sublime.installed_packages_path()]:
if rel_path.startswith(prefix):
rel_path = os.path.join('Packages', rel_path[len(prefix) + 1:])
break
rel_path = rel_path.replace('.sublime-package', '')
# for Windows we have to replace slashes
rel_path = rel_path.replace('\\', '/')
return sublime.load_resource(rel_path)
return _js_file_reader(file_path, use_unicode)
def init():
"Init Emmet plugin"
# load settings
globals()['user_settings'] = sublime.load_settings('Preferences.sublime-settings')
globals()['settings'] = sublime.load_settings('Emmet.sublime-settings')
settings.add_on_change('extensions_path', update_settings)
# setup environment for PyV8 loading
pyv8_paths = [
os.path.join(PACKAGES_PATH, 'PyV8'),
os.path.join(PACKAGES_PATH, 'PyV8', pyv8loader.get_arch()),
os.path.join(PACKAGES_PATH, 'PyV8', 'pyv8-%s' % pyv8loader.get_arch())
]
sys.path += pyv8_paths
# unpack recently loaded binary, is exists
for p in pyv8_paths:
pyv8loader.unpack_pyv8(p)
# provide some contributions to JS
contrib = {
'sublime': sublime,
'sublimeReplaceSubstring': replace_substring,
'sublimeGetOption': settings.get
}
# create JS environment
delegate = SublimeLoaderDelegate()
globals()['ctx'] = Context(
files=['../editor.js'],
ext_path=settings.get('extensions_path', None),
contrib=contrib,
logger=delegate.log,
reader=js_file_reader
)
update_settings()
pyv8loader.load(pyv8_paths[1], delegate)
if settings.get('remove_html_completions', False):
sublime.set_timeout(cmpl.remove_html_completions, 2000)
class SublimeLoaderDelegate(LoaderDelegate):
def __init__(self, settings=None):
if settings is None:
settings = {}
for k in ['http_proxy', 'https_proxy', 'timeout']:
if user_settings.has(k):
settings[k] = user_settings.get(k, None)
LoaderDelegate.__init__(self, settings)
self.state = None
self.message = 'Loading PyV8 binary, please wait'
self.i = 0
self.addend = 1
self.size = 8
def on_start(self, *args, **kwargs):
self.state = 'loading'
def on_progress(self, *args, **kwargs):
if kwargs['progress'].is_background:
return
before = self.i % self.size
after = (self.size - 1) - before
msg = '%s [%s=%s]' % (self.message, ' ' * before, ' ' * after)
if not after:
self.addend = -1
if not before:
self.addend = 1
self.i += self.addend
sublime.set_timeout(lambda: sublime.status_message(msg), 0)
def on_complete(self, *args, **kwargs):
self.state = 'complete'
if kwargs['progress'].is_background:
return
sublime.set_timeout(lambda: sublime.status_message('PyV8 binary successfully loaded'), 0)
def on_error(self, exit_code=-1, thread=None):
self.state = 'error'
sublime.set_timeout(lambda: show_pyv8_error(exit_code), 0)
def setting(self, name, default=None):
"Returns specified setting name"
return self.settings.get(name, default)
def log(self, message):
print('Emmet: %s' % message)
def show_pyv8_error(exit_code):
if 'PyV8' not in sys.modules:
sublime.error_message('Error while loading PyV8 binary: exit code %s \nTry to manually install PyV8 from\nhttps://github.com/emmetio/pyv8-binaries' % exit_code)
def active_view():
return sublime.active_window().active_view()
def check_context(verbose=False):
"Checks if JS context is completely available"
if not ctx.js():
if verbose:
sublime.message_dialog('Please wait a bit while PyV8 binary is being downloaded')
return False
return True
def replace_substring(start, end, value, no_indent=False):
view = active_view()
view.sel().clear()
view.sel().add(sublime.Region(start, end or start))
if not is_python3:
value = value.decode('utf-8')
# XXX a bit naive indentation control. It handles most common
# `no_indent` usages like replacing CSS rule content, but may not
# produce expected result in all possible situations
if no_indent:
line = view.substr(view.line(view.sel()[0]))
value = unindent_text(value, get_line_padding(line))
view.run_command('insert_snippet', {'contents': value})
def unindent_text(text, pad):
"""
Removes padding at the beginning of each text's line
@type text: str
@type pad: str
"""
lines = text.splitlines()
for i,line in enumerate(lines):
if line.startswith(pad):
lines[i] = line[len(pad):]
return '\n'.join(lines)
def get_line_padding(line):
"""
Returns padding of current editor's line
@return str
"""
m = re.match(r'^(\s+)', line)
return m and m.group(0) or ''
def update_settings():
ctx.set_ext_path(settings.get('extensions_path', None))
keys = ['snippets', 'preferences', 'syntaxProfiles', 'profiles']
payload = {}
for k in keys:
data = settings.get(k, None)
if data:
payload[k] = data
ctx.reset()
ctx.load_user_data(json.dumps(payload))
ctx.js()
def get_scope(view, pt=-1):
if pt == -1:
# use current caret position
pt = view.sel()[0].begin()
if hasattr(view, 'scope_name'):
return view.scope_name(pt)
return view.syntax_name(pt)
def should_perform_action(name, view=None):
if not view:
view = active_view()
# fallback to old check
if not view.settings().get('enable_emmet_keymap', True):
return False
disabled_actions = settings.get('disabled_keymap_actions', '')
if not disabled_actions: # no disabled actions
return True
if disabled_actions == 'all': # disable all actions
return False
return name not in re.split(r'\s*,\s*', disabled_actions.strip())
def should_handle_tab_key(syntax=None):
view = active_view()
scopes = settings.get('disabled_single_snippet_for_scopes', None)
cur_scope = get_scope(view)
if sublime.score_selector(cur_scope, 'source.css'):
return True
if not scopes or not sublime.score_selector(cur_scope, scopes):
return True
abbr = ctx.js().locals.pyExtractAbbreviation()
disabled_snippets = settings.get('disabled_single_snippets', '').split()
if disabled_snippets and abbr in disabled_snippets:
return False
if not re.match(r'^[\w\:%]+$', abbr):
# it's a complex expression
return True
if re.match(r'^(lorem|lipsum)([a-z]{2})?\d*$', abbr):
# hardcoded Lorem Ipsum generator
return True
# detect inline CSS
if syntax is None:
syntax = ctx.js().locals.pyGetSyntax();
if syntax == 'css':
return True
known_tags = settings.get('known_html_tags', '').split()
if abbr in known_tags or ctx.js().locals.pyHasSnippet(abbr):
return True
return False
def log(message):
if settings.get('debug', False):
print('Emmet: %s' % message)
class RunEmmetAction(sublime_plugin.TextCommand):
def run(self, edit, action=None, **kw):
run_action(lambda i, sel: ctx.js().locals.pyRunAction(action))
# ctx.js().locals.pyRunAction(action)
class ActionContextHandler(sublime_plugin.EventListener):
def on_query_context(self, view, key, op, operand, match_all):
if not key.startswith('emmet_action_enabled.'):
return None
prefix, name = key.split('.')
return should_perform_action(name, view)
def get_edit(view, edit_token=None):
edit = None
try:
edit = view.begin_edit()
except:
pass
if not edit and edit_token:
try:
edit = view.begin_edit(edit_token, 'Emmet')
except Exception as e:
pass
return edit
def run_action(action, view=None):
if not check_context(True):
return
"Runs Emmet action in multiselection mode"
if not view:
view = active_view()
region_key = '__emmet__'
sels = list(view.sel())
r = ctx.js().locals.pyRunAction
result = False
# edit = get_edit(view, edit_token)
max_sel_ix = len(sels) - 1
try:
for i, sel in enumerate(reversed(sels)):
view.sel().clear()
view.sel().add(sel)
# run action
# result = r(name) or result
result = action(max_sel_ix - i, sel) or result
# remember resulting selections
view.add_regions(region_key,
(view.get_regions(region_key) + list(view.sel())) , '')
except Exception as e:
view.erase_regions(region_key)
print(traceback.format_exc())
return
# output all saved regions as selection
view.sel().clear()
for sel in view.get_regions(region_key):
view.sel().add(sel)
view.erase_regions(region_key)
# if edit:
# view.end_edit(edit)
return result
class TabAndCompletionsHandler():
def correct_syntax(self, view, syntax='html'):
return syntax == 'html' and view.match_selector( view.sel()[0].b, cmpl.EMMET_SCOPE )
def completion_handler(self, view):
"Returns completions handler fo current caret position"
black_list = settings.get('completions_blacklist', [])
# A mapping of scopes, sub scopes and handlers, first matching of which
# is used.
COMPLETIONS = (
(cmpl.HTML_INSIDE_TAG, self.html_elements_attributes),
(cmpl.HTML_INSIDE_TAG_ATTRIBUTE, self.html_attributes_values)
)
pos = view.sel()[0].b
# Try to find some more specific contextual abbreviation
for sub_selector, handler in COMPLETIONS:
h_name = handler.__name__
if not black_list or h_name in black_list: continue
if (view.match_selector(pos, sub_selector) or
view.match_selector(pos - 1, sub_selector)):
return handler
return None
def html_elements_attributes(self, view, prefix, pos):
tag = cmpl.find_tag_name(view, pos)
values = HTML_ELEMENTS_ATTRIBUTES.get(tag, [])
return [(v, '%s\t@%s' % (v,v), '%s="$1"' % v) for v in values]
def html_attributes_values(self, view, prefix, pos):
attr = cmpl.find_attribute_name(view, pos)
values = HTML_ATTRIBUTES_VALUES.get(attr, [])
return [(v, '%s\t@=%s' % (v,v), v) for v in values]
def expand_by_tab(self, view):
if not check_context():
return False;
syntax = ctx.js().locals.pyGetSyntax();
if not should_handle_tab_key(syntax):
return False
# we need to filter out attribute completions if
# 'disable_completions' option is not active
if (not settings.get('disable_completions', False) and
self.correct_syntax(view, syntax) and
self.completion_handler(view)):
return None
caret_pos = view.sel()[0].begin()
cur_scope = get_scope(view)
# let's see if Tab key expander should be disabled for current scope
banned_scopes = settings.get('disable_tab_abbreviations_for_scopes', '')
if banned_scopes and view.score_selector(caret_pos, banned_scopes):
return None
# Sometimes ST2 matcher may incorrectly filter scope context,
# check it against special regexp
banned_regexp = settings.get('disable_tab_abbreviations_for_regexp', None)
if banned_regexp and re.search(banned_regexp, cur_scope):
return None
return run_action(lambda i, sel: ctx.js().locals.pyRunAction('expand_abbreviation'))
# view.run_command('run_emmet_action',
# {'action':'expand_abbreviation'})
class ExpandAbbreviationByTab(sublime_plugin.TextCommand):
def run(self, edit, **kw):
if settings.get('use_old_tab_handler', False):
return
view = active_view()
h = TabAndCompletionsHandler()
if not h.expand_by_tab(view):
# try to mimic default Tab behaviour of Sublime Text
view.run_command('insert_best_completion', {
'default': '\t',
'exact': user_settings.get('tab_completion', True)
})
class TabExpandHandler(sublime_plugin.EventListener):
def on_query_context(self, view, key, op, operand, match_all):
if key != 'is_abbreviation':
return None
if settings.get('use_old_tab_handler', False):
h = TabAndCompletionsHandler()
return h.expand_by_tab(view)
return check_context()
def on_query_completions(self, view, prefix, locations):
h = TabAndCompletionsHandler()
if view.match_selector(locations[0], settings.get('css_completions_scope', '')) and check_context():
l = []
if settings.get('show_css_completions', False):
completions = ctx.js().locals.pyGetCSSCompletions()
if completions:
for p in completions:
l.append(('%s\t%s' % (p['k'], p['label']), p['v']))
if not l:
return []
return (l, sublime.INHIBIT_WORD_COMPLETIONS | sublime.INHIBIT_EXPLICIT_COMPLETIONS)
if not h.correct_syntax(view) or settings.get('disable_completions', False):
return []
handler = h.completion_handler(view)
if handler:
pos = view.sel()[0].b
completions = handler(view, prefix, pos)
return completions
return []
class CommandsAsYouTypeBase(sublime_plugin.TextCommand):
input_message = "Enter Input"
default_input = ""
process_panel_input = lambda s, i: i.title()
# Note that this must be of form `Packages/$Package/Emmet.tmLanguage` on ST3
# NOT an absolute path!
panel_grammar = EMMET_GRAMMAR
def is_enabled(self):
return True
def run_command(self, edit, view, processed_input):
if '\n' in processed_input:
for sel in view.sel():
trailing = sublime.Region(sel.end(), view.line(sel).end())
if view.substr(trailing).isspace():
view.erase(edit, trailing)
if not is_python3:
processed_input = processed_input.decode('utf-8')
view.run_command('insert_snippet', { 'contents': processed_input })
def on_panel_change(self, abbr):
if not abbr and self.erase:
self.undo()
self.erase = False
return
def inner_insert():
self.view.run_command(self.name(), dict(panel_input=abbr))
# self.view.run_command('hide_auto_complete')
self.undo()
sublime.set_timeout(inner_insert, 0)
def undo(self):
if self.erase:
sublime.set_timeout(lambda: self.view.run_command('undo'), 0)
def remember_sels(self, view):
self._sels = list(view.sel())
self._sel_items = []
for sel in self._sels:
# selection should be unindented in order to get desired result
line = view.substr(view.line(sel))
s = view.substr(sel)
self._sel_items.append(unindent_text(s, get_line_padding(line)))
def on_panel_done(self, abbr):
pass
def run(self, edit, panel_input=None, **kwargs):
if panel_input is None:
self.setup(edit, self.view, **kwargs)
self.erase = False
panel = self.view.window().show_input_panel (
self.input_message,
self.default_input,
self.on_panel_done, # on_done
self.on_panel_change, # on_change
self.undo) # on_cancel
panel.sel().clear()
panel.sel().add(sublime.Region(0, panel.size()))
if self.panel_grammar:
panel.set_syntax_file(self.panel_grammar)
panel_setting = panel.settings().set
panel_setting('line_numbers', False)
panel_setting('gutter', False)
panel_setting('auto_complete', False)
panel_setting('tab_completion', False)
else:
self.run_on_input(edit, self.view, panel_input)
def setup(self, edit, view, **kwargs):
pass
def run_on_input(self, edit, view, panel_input):
view = self.view
cmd_input = self.process_panel_input(panel_input) or ''
try:
self.erase = self.run_command(edit, view, cmd_input) is not False
except:
pass
class WrapAsYouType(CommandsAsYouTypeBase):
default_input = 'div'
_prev_output = ''
input_message = "Enter Wrap Abbreviation: "
def setup(self, edit, view, **kwargs):
self._prev_output = ''
if len(view.sel()) == 1:
# capture wrapping context (parent HTML element)
# if there is only one selection
r = ctx.js().locals.pyCaptureWrappingRange()
if r:
view.sel().clear()
view.sel().add(sublime.Region(r[0], r[1]))
view.show(view.sel())
self.remember_sels(view)
# override method to correctly wrap abbreviations
def run_on_input(self, edit, view, abbr):
# def _real_insert(self, abbr):
# view = self.view
# self.edit = get_edit(view, self.edit_token)
self.erase = True
# restore selections
view.sel().clear()
for sel in self._sels:
view.sel().add(sel)
def ins(i, sel):
try:
self._prev_output = ctx.js().locals.pyWrapAsYouType(abbr, self._sel_items[i])
# self.run_command(view, output)
except Exception:
"dont litter the console"
self.run_command(edit, view, self._prev_output)
run_action(ins, view)
# if self.edit:
# view.end_edit(self.edit)
class ExpandAsYouType(WrapAsYouType):
default_input = 'div'
input_message = "Enter Abbreviation: "
def setup(self, edit, view, **kwargs):
# adjust selection to non-space bounds
sels = []
for s in view.sel():
text = view.substr(s)
a = s.a + len(text) - len(text.lstrip())
b = s.b - len(text) + len(text.rstrip())
sels.append(sublime.Region(a, b))
view.sel().clear()
for s in sels:
view.sel().add(s)
self.remember_sels(active_view())
class EnterKeyHandler(sublime_plugin.EventListener):
def on_query_context(self, view, key, op, operand, match_all):
if key != 'clear_fields_on_enter_key':
return None
if settings.get('clear_fields_on_enter_key', False):
view.run_command('clear_fields')
return True
class RenameTag(sublime_plugin.TextCommand):
def run(self, edit, **kw):
if not check_context(True):
return
view = active_view()
sels = list(view.sel())
sel_cleared = False
for s in sels:
ranges = ctx.js().locals.pyGetTagNameRanges(s.begin())
if ranges:
if not sel_cleared:
view.sel().clear()
sel_cleared = True
for r in ranges:
view.sel().add(sublime.Region(r[0], r[1]))
view.show(view.sel())
class EmmetInsertAttribute(sublime_plugin.TextCommand):
def run(self, edit, attribute=None, **kw):
if not attribute:
return
view = active_view()
prefix = ''
if view.sel():
sel = view.sel()[0]
if not view.substr(sublime.Region(sel.begin() - 1, sel.begin())).isspace():
prefix = ' '
view.run_command('insert_snippet', {'contents': '%s%s="$1"' % (prefix, attribute)})
class EmmetResetContext(sublime_plugin.TextCommand):
def run(self, edit, **kw):
update_settings()
def plugin_loaded():
sublime.set_timeout(init, 200)
##################
# Init plugin
if not is_python3:
init()

View File

@@ -0,0 +1,228 @@
# coding=utf-8
import sys
import os
import os.path
import codecs
import json
import gc
import imp
import re
from file import File
BASE_PATH = os.path.abspath(os.path.dirname(__file__))
is_python3 = sys.version_info[0] > 2
core_files = ['emmet-app.js', 'python-wrapper.js']
def should_use_unicode():
"""
WinXP unable to eval JS in unicode object (while other OSes requires it)
This function checks if we have to use unicode when reading files
"""
ctx = PyV8.JSContext()
ctx.enter()
use_unicode = True
try:
ctx.eval(u'(function(){return;})()')
except:
use_unicode = False
ctx.leave()
return use_unicode
def make_path(filename):
return os.path.normpath(os.path.join(BASE_PATH, filename))
def js_log(message):
print(message)
def js_file_reader(file_path, use_unicode=True):
if use_unicode:
f = codecs.open(file_path, 'r', 'utf-8')
else:
f = open(file_path, 'r')
content = f.read()
f.close()
return content
def import_pyv8():
# Importing non-existing modules is a bit tricky in Python:
# if we simply call `import PyV8` and module doesn't exists,
# Python will cache this failed import and will always
# throw exception even if this module appear in PYTHONPATH.
# To prevent this, we have to manually test if
# PyV8.py(c) exists in PYTHONPATH before importing PyV8
if 'PyV8' in sys.modules:
# PyV8 was loaded by ST2, create global alias
if 'PyV8' not in globals():
globals()['PyV8'] = __import__('PyV8')
return
loaded = False
f, pathname, description = imp.find_module('PyV8')
bin_f, bin_pathname, bin_description = imp.find_module('_PyV8')
if f:
try:
imp.acquire_lock()
globals()['_PyV8'] = imp.load_module('_PyV8', bin_f, bin_pathname, bin_description)
globals()['PyV8'] = imp.load_module('PyV8', f, pathname, description)
imp.release_lock()
loaded = True
finally:
# Since we may exit via an exception, close fp explicitly.
if f:
f.close()
if bin_f:
bin_f.close()
if not loaded:
raise ImportError('No PyV8 module found')
class Context():
"""
Creates Emmet JS core context.
Before instantiating this class, make sure PyV8
is available in `sys.path`
@param files: Additional files to load with JS core
@param path: Path to Emmet extensions
@param contrib: Python objects to contribute to JS execution context
@param pyv8_path: Location of PyV8 binaries
"""
def __init__(self, files=[], ext_path=None, contrib=None, logger=None, reader=js_file_reader):
self.logger = logger
self.reader = reader
try:
import_pyv8()
except ImportError as e:
pass
self._ctx = None
self._contrib = contrib
self._should_load_extension = True
# detect reader encoding
self._use_unicode = None
self._core_files = [] + core_files + files
self._ext_path = None
self.set_ext_path(ext_path)
self._user_data = None
def log(self, message):
if self.logger:
self.logger(message)
def get_ext_path(self):
return self._ext_path
def set_ext_path(self, val):
try:
if val and val[:1] == '~':
val = os.path.expanduser(val)
val = os.path.abspath(val)
except Exception as e:
return
if val == self._ext_path:
return
self._ext_path = val
self.reset()
def load_extensions(self, path=None):
if path is None:
path = self._ext_path;
if path and os.path.isdir(path):
ext_files = []
self.log('Loading Emmet extensions from %s' % self._ext_path)
for dirname, dirnames, filenames in os.walk(self._ext_path):
for filename in filenames:
if filename[0] != '.':
ext_files.append(os.path.join(dirname, filename))
self.js().locals.pyLoadExtensions(ext_files)
def js(self):
"Returns JS context"
if not self._ctx:
try:
import_pyv8()
except ImportError as e:
return None
if 'PyV8' not in sys.modules:
# Binary is not available yet
return None
if self._use_unicode is None:
self._use_unicode = should_use_unicode()
glue = u'\n' if self._use_unicode else '\n'
core_src = [self.read_js_file(make_path(f)) for f in self._core_files]
self._ctx = PyV8.JSContext()
self._ctx.enter()
self._ctx.eval(glue.join(core_src))
# for f in self._core_files:
# self._ctx.eval(self.read_js_file(make_path(f)), name=f, line=0, col=0)
# load default snippets
self._ctx.locals.pyLoadSystemSnippets(self.read_js_file(make_path('snippets.json')))
# expose some methods
self._ctx.locals.log = js_log
self._ctx.locals.pyFile = File()
if self._contrib:
for k in self._contrib:
self._ctx.locals[k] = self._contrib[k]
else:
self._ctx.enter()
if self._should_load_extension:
self._ctx.locals.pyResetUserData()
self._should_load_extension = False
self.load_extensions()
if self._user_data:
self._ctx.locals.pyLoadUserData(self._user_data)
self._user_data = None
return self._ctx
def load_user_data(self, data):
"Loads user data payload from JSON"
self._user_data = data
# self.js().locals.pyLoadUserData(data)
def reset(self):
"Resets JS execution context"
if self._ctx:
self._ctx.leave()
self._ctx = None
try:
PyV8.JSEngine.collect()
gc.collect()
except:
pass
self._should_load_extension = True
def read_js_file(self, file_path):
return self.reader(file_path, self._use_unicode)
def eval(self, source):
self.js().eval(source)
def eval_js_file(self, file_path):
self.eval(self.read_js_file(file_path))

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,159 @@
'''
@author Sergey Chikuyonok (serge.che@gmail.com)
@link http://chikuyonok.ru
'''
import sys
import os.path
import re
is_python3 = sys.version_info[0] > 2
try:
if is_python3:
import urllib.request as urllib2
else:
import urllib2
except Exception as e:
pass
def is_url(path):
return re.match(r'^https?://', path, re.IGNORECASE)
def read_http(url, size=-1, mode=None):
response = urllib2.urlopen(url, timeout=5)
return response.read(size)
def read_file(path, size=-1, mode='rb'):
kwargs = {}
if is_python3 and 'b' not in mode:
kwargs['encoding'] = 'utf-8'
with open(path, mode, **kwargs) as fp:
return fp.read(size)
class File():
def __init__(self):
pass
def _read(self, path, size, mode='rb'):
reader = is_url(path) and read_http or read_file
return reader(path, size, mode)
def read(self, path, size, callback=None):
"""
Read file content and return it
@param path: File's relative or absolute path
@type path: str
@return: str
"""
try:
content = self._read(path, size)
# return as array of character codes since PyV8 may corrupt
# binary data when python string is translated into JS string
if is_python3:
content = [ch for ch in content]
else:
content = [ord(ch) for ch in content]
except Exception as e:
return callback(str(e), None)
callback(None, content)
def read_text(self, path, size, callback=None):
"""
Read file content and return it
@param path: File's relative or absolute path
@type path: str
@return: str
"""
try:
content = self._read(path, size, 'r')
if not is_python3:
content = content.decode('utf-8')
except Exception as e:
return callback(str(e), None)
callback(None, content)
def locate_file(self, editor_file, file_name):
"""
Locate <code>file_name</code> file that relates to <code>editor_file</code>.
File name may be absolute or relative path
@type editor_file: str
@type file_name: str
@return String or None if <code>file_name</code> cannot be located
"""
if is_url(file_name):
return file_name
result = None
previous_parent = ''
parent = os.path.dirname(editor_file)
while parent and os.path.exists(parent) and parent != previous_parent:
tmp = self.create_path(parent, file_name)
if os.path.exists(tmp):
result = tmp
break
previous_parent = parent
parent = os.path.dirname(parent)
return result
def create_path(self, parent, file_name):
"""
Creates absolute path by concatenating <code>parent</code> and <code>file_name</code>.
If <code>parent</code> points to file, its parent directory is used
@type parent: str
@type file_name: str
@return: str
"""
result = ''
file_name = file_name.lstrip('/')
if os.path.exists(parent):
if os.path.isfile(parent):
parent = os.path.dirname(parent)
result = os.path.normpath(os.path.join(parent, file_name))
return result
def save(self, file, content):
"""
Saves <code>content</code> as <code>file</code>
@param file: File's asolute path
@type file: str
@param content: File content
@type content: str
"""
try:
fp = open(file, 'wb')
except:
fdirs, fname = os.path.split(file)
if fdirs:
os.makedirs(fdirs)
fp = open(file, 'wb')
fp.write(content)
fp.close()
def get_ext(self, file):
"""
Returns file extention in lower case
@type file: str
@return: str
"""
ext = os.path.splitext(file)[1]
if ext:
ext = ext[1:]
return ext.lower()

View File

@@ -0,0 +1,97 @@
var console = {
log: function(msg) {
log(msg);
}
};
/**
* Simple function alias to run Emmet action.
* <code>editorProxy</code> object should be defined
* in concrete plugin implementation.
*/
function pyRunAction(name) {
return emmet.require('actions').run(name, editorProxy);
}
function pyLoadSystemSnippets(data) {
emmet.require('bootstrap').loadSystemSnippets(data);
}
function pyLoadUserData(data) {
emmet.require('bootstrap').loadUserData(data);
}
function pyLoadExtensions(fileList) {
fileList = _.toArray(fileList);
emmet.require('bootstrap').loadExtensions(fileList);
}
function pyResetUserData() {
emmet.require('bootstrap').resetUserData();
}
emmet.define('file', function(require, _) {
return {
_parseParams: function(args) {
var params = {
path: args[0],
size: -1
};
args = _.rest(args);
params.callback = _.last(args);
args = _.initial(args);
if (args.length) {
params.size = args[0];
}
return params;
},
read: function(path, size, callback) {
var params = this._parseParams(arguments);
try {
pyFile.read(params.path, params.size, function(err, content) {
if (err) {
return params.callback(err, content);
}
content = _.map(content || [], function(b) {
return String.fromCharCode(b);
}).join('');
params.callback(null, content);
});
} catch(e) {
params.callback(e);
}
},
readText: function() {
var params = this._parseParams(arguments);
try {
pyFile.read_text(params.path, params.size, params.callback);
} catch(e) {
params.callback(e);
}
},
locateFile: function(editorFile, fileName) {
return pyFile.locate_file(editorFile, fileName);
},
createPath: function(parent, fileName) {
return pyFile.create_path(parent, fileName);
},
save: function(file, content) {
return pyFile.save(file, content);
},
getExt: function(file) {
var m = (file || '').match(/\.([\w\-]+)$/);
return m ? m[1].toLowerCase() : '';
}
};
});

View File

@@ -0,0 +1,591 @@
# coding=utf-8
import os
import os.path
import sys
import json
import re
import threading
import subprocess
import tempfile
import collections
import platform
import semver
import time
import zipfile
is_python3 = sys.version_info[0] > 2
if is_python3:
import urllib.request as url_req
import urllib.error as url_err
import urllib.parse as url_parse
else:
import urllib
import urllib2
url_req = urllib2
url_err = urllib2
url_parse = urllib2
CHECK_INTERVAL = 60 * 60 * 24
# PACKAGES_URL = 'https://api.github.com/repos/emmetio/pyv8-binaries/downloads'
PACKAGES_URL = 'https://api.github.com/repos/emmetio/pyv8-binaries/contents'
def load(dest_path, delegate=None):
"""
Main function that attempts to load or update PyV8 binary.
First, it loads list of available PyV8 modules and check if
PyV8 should be downloaded or updated.
@param dest_path: Path where PyV8 lib should be downloaded
@param delegate: instance of LoaderDelegate that will receive
loader progress events
@returns: `True` if download progress was initiated
"""
if delegate is None:
delegate = LoaderDelegate()
config = get_loader_config(dest_path)
if 'PyV8' in sys.modules and (config['skip_update'] or time.time() < config['last_update'] + CHECK_INTERVAL):
# No need to load anything: user already has PyV8 binary
# or decided to disable update process
delegate.log('No need to update PyV8')
return False
def on_complete(result, *args, **kwargs):
if result is not None:
# Most recent version was downloaded
config['last_id'] = result
if 'PyV8' not in sys.modules:
# PyV8 is not loaded yet, we can safely unpack it
unpack_pyv8(dest_path)
config['last_update'] = time.time()
save_loader_config(dest_path, config)
delegate.on_complete(*args, **kwargs)
# try to download most recent version of PyV8
# As PyV8 for Sublime Text spreads the world, it's possible
# that multiple distinct PyV8Loader's may start doing the same
# job at the same time. In this case, we should check if there's
# already a thread that load PyV8 and hook on existing thread
# rather that creating a new one
thread = None
thread_exists = False
for t in threading.enumerate():
if hasattr(t, 'is_pyv8_thread'):
print('PyV8: Reusing thread')
thread = t
thread_exists = True
break
if not thread:
print('PyV8: Creating new thread')
thread = PyV8Loader(get_arch(), dest_path, config, delegate=delegate)
thread.start()
delegate.on_start()
# watch on download progress
prog = ThreadProgress(thread, delegate, thread_exists)
prog.on('complete', on_complete if not thread_exists else delegate.on_complete)
prog.on('error', delegate.on_error)
def get_arch():
"Returns architecture name for PyV8 binary"
suffix = is_python3 and '-p3' or ''
p = lambda a: '%s%s' % (a, suffix)
is_64bit = sys.maxsize > 2**32
system_name = platform.system()
if system_name == 'Darwin':
if semver.match(platform.mac_ver()[0], '<10.7.0'):
return p('mac106')
return p('osx')
if system_name == 'Windows':
return p('win64') if is_64bit else p('win32')
if system_name == 'Linux':
return p('linux64') if is_64bit else p('linux32')
def get_loader_config(path):
config = {
"last_id": 0,
"last_update": 0,
"skip_update": False
}
config_path = os.path.join(path, 'config.json')
if os.path.exists(config_path):
with open(config_path) as fd:
for k,v in json.load(fd).items():
config[k] = v
return config
def save_loader_config(path, data):
config_path = os.path.join(path, 'config.json')
if not os.path.exists(path):
os.makedirs(path)
fp = open(config_path, 'w')
fp.write(json.dumps(data))
fp.close()
def clean_old_data():
for f in os.listdir('.'):
if f.lower() != 'config.json' and f.lower() != 'pack.zip':
try:
os.remove(f)
except Exception as e:
pass
def unpack_pyv8(package_dir):
f = os.path.join(package_dir, 'pack.zip')
if not os.path.exists(f):
return
package_zip = zipfile.ZipFile(f, 'r')
root_level_paths = []
last_path = None
for path in package_zip.namelist():
last_path = path
if path.find('/') in [len(path) - 1, -1]:
root_level_paths.append(path)
if path[0] == '/' or path.find('../') != -1 or path.find('..\\') != -1:
raise 'The PyV8 package contains files outside of the package dir and cannot be safely installed.'
if last_path and len(root_level_paths) == 0:
root_level_paths.append(last_path[0:last_path.find('/') + 1])
prev_dir = os.getcwd()
os.chdir(package_dir)
clean_old_data()
# Here we don't use .extractall() since it was having issues on OS X
skip_root_dir = len(root_level_paths) == 1 and \
root_level_paths[0].endswith('/')
extracted_paths = []
for path in package_zip.namelist():
dest = path
if not is_python3:
try:
if not isinstance(dest, unicode):
dest = unicode(dest, 'utf-8', 'strict')
except UnicodeDecodeError:
dest = unicode(dest, 'cp1252', 'replace')
if os.name == 'nt':
regex = ':|\*|\?|"|<|>|\|'
if re.search(regex, dest) != None:
print ('%s: Skipping file from package named %s due to ' +
'an invalid filename') % (__name__, path)
continue
# If there was only a single directory in the package, we remove
# that folder name from the paths as we extract entries
if skip_root_dir:
dest = dest[len(root_level_paths[0]):]
if os.name == 'nt':
dest = dest.replace('/', '\\')
else:
dest = dest.replace('\\', '/')
dest = os.path.join(package_dir, dest)
def add_extracted_dirs(dir):
while dir not in extracted_paths:
extracted_paths.append(dir)
dir = os.path.dirname(dir)
if dir == package_dir:
break
if path.endswith('/'):
if not os.path.exists(dest):
os.makedirs(dest)
add_extracted_dirs(dest)
else:
dest_dir = os.path.dirname(dest)
if not os.path.exists(dest_dir):
os.makedirs(dest_dir)
add_extracted_dirs(dest_dir)
extracted_paths.append(dest)
try:
open(dest, 'wb').write(package_zip.read(path))
except (IOError, UnicodeDecodeError):
print ('%s: Skipping file from package named %s due to ' +
'an invalid filename') % (__name__, path)
package_zip.close()
os.chdir(prev_dir)
os.remove(f)
class LoaderDelegate():
"""
Abstract class used to display PyV8 binary download progress,
and provide some settings for downloader
"""
def __init__(self, settings={}):
self.settings = settings
def on_start(self, *args, **kwargs):
"Invoked when download process is initiated"
pass
def on_progress(self, *args, **kwargs):
"Invoked on download progress"
pass
def on_complete(self, *args, **kwargs):
"Invoked when download process was finished successfully"
pass
def on_error(self, *args, **kwargs):
"Invoked when error occured during download process"
pass
def setting(self, name, default=None):
"Returns specified setting name"
return self.settings[name] if name in self.settings else default
def log(self, message):
pass
class ThreadProgress():
def __init__(self, thread, delegate, is_background=False):
self.thread = thread
self.delegate = delegate
self.is_background = is_background
self._callbacks = {}
threading.Timer(0, self.run).start()
def run(self):
if not self.thread.is_alive():
if self.thread.exit_code != 0:
return self.trigger('error', exit_code=self.thread.exit_code, progress=self)
return self.trigger('complete', result=self.thread.result, progress=self)
self.trigger('progress', progress=self)
threading.Timer(0.1, self.run).start()
def on(self, event_name, callback):
if event_name not in self._callbacks:
self._callbacks[event_name] = []
if isinstance(callback, collections.Callable):
self._callbacks[event_name].append(callback)
return self
def trigger(self, event_name, *args, **kwargs):
if event_name in self._callbacks:
for c in self._callbacks[event_name]:
c(*args, **kwargs)
if self.delegate and hasattr(self.delegate, 'on_%s' % event_name):
getattr(self.delegate, 'on_%s' % event_name)(*args, **kwargs)
return self
class BinaryNotFoundError(Exception):
pass
class NonCleanExitError(Exception):
def __init__(self, returncode):
self.returncode = returncode
def __str__(self):
return repr(self.returncode)
class CliDownloader():
def __init__(self, settings):
self.settings = settings
def find_binary(self, name):
for dir in os.environ['PATH'].split(os.pathsep):
path = os.path.join(dir, name)
if os.path.exists(path):
return path
raise BinaryNotFoundError('The binary %s could not be located' % name)
def execute(self, args):
proc = subprocess.Popen(args, stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
output = proc.stdout.read()
returncode = proc.wait()
if returncode != 0:
error = NonCleanExitError(returncode)
error.output = output
raise error
return output
class WgetDownloader(CliDownloader):
def __init__(self, settings):
self.settings = settings
self.wget = self.find_binary('wget')
def clean_tmp_file(self):
os.remove(self.tmp_file)
def download(self, url, error_message, timeout, tries):
if not self.wget:
return False
self.tmp_file = tempfile.NamedTemporaryFile().name
command = [self.wget, '--connect-timeout=' + str(int(timeout)), '-o',
self.tmp_file, '-O', '-', '-U', 'Emmet PyV8 Loader',
'--no-check-certificate']
command.append(url)
if self.settings.get('http_proxy'):
os.putenv('http_proxy', self.settings.get('http_proxy'))
if not self.settings.get('https_proxy'):
os.putenv('https_proxy', self.settings.get('http_proxy'))
if self.settings.get('https_proxy'):
os.putenv('https_proxy', self.settings.get('https_proxy'))
while tries > 0:
tries -= 1
try:
result = self.execute(command)
self.clean_tmp_file()
return result
except NonCleanExitError as e:
error_line = ''
with open(self.tmp_file) as f:
for line in list(f):
if re.search('ERROR[: ]|failed: ', line):
error_line = line
break
if e.returncode == 8:
regex = re.compile('^.*ERROR (\d+):.*', re.S)
if re.sub(regex, '\\1', error_line) == '503':
# GitHub and BitBucket seem to rate limit via 503
print('%s: Downloading %s was rate limited, trying again' % (__name__, url))
continue
error_string = 'HTTP error ' + re.sub('^.*? ERROR ', '',
error_line)
elif e.returncode == 4:
error_string = re.sub('^.*?failed: ', '', error_line)
# GitHub and BitBucket seem to time out a lot
if error_string.find('timed out') != -1:
print('%s: Downloading %s timed out, trying again' % (__name__, url))
continue
else:
error_string = re.sub('^.*?(ERROR[: ]|failed: )', '\\1',
error_line)
error_string = re.sub('\\.?\s*\n\s*$', '', error_string)
print('%s: %s %s downloading %s.' % (__name__, error_message,
error_string, url))
self.clean_tmp_file()
break
return False
class CurlDownloader(CliDownloader):
def __init__(self, settings):
self.settings = settings
self.curl = self.find_binary('curl')
def download(self, url, error_message, timeout, tries):
if not self.curl:
return False
command = [self.curl, '-f', '--user-agent', 'Emmet PyV8 Loader',
'--connect-timeout', str(int(timeout)), '-sS']
command.append(url)
if self.settings.get('http_proxy'):
os.putenv('http_proxy', self.settings.get('http_proxy'))
if not self.settings.get('https_proxy'):
os.putenv('HTTPS_PROXY', self.settings.get('http_proxy'))
if self.settings.get('https_proxy'):
os.putenv('HTTPS_PROXY', self.settings.get('https_proxy'))
while tries > 0:
tries -= 1
try:
return self.execute(command)
except NonCleanExitError as e:
if e.returncode == 22:
code = re.sub('^.*?(\d+)\s*$', '\\1', e.output)
if code == '503':
# GitHub and BitBucket seem to rate limit via 503
print('%s: Downloading %s was rate limited, trying again' % (__name__, url))
continue
error_string = 'HTTP error ' + code
elif e.returncode == 6:
error_string = 'URL error host not found'
elif e.returncode == 28:
# GitHub and BitBucket seem to time out a lot
print('%s: Downloading %s timed out, trying again' % (__name__, url))
continue
else:
error_string = e.output.rstrip()
print('%s: %s %s downloading %s.' % (__name__, error_message, error_string, url))
break
return False
class UrlLib2Downloader():
def __init__(self, settings):
self.settings = settings
def download(self, url, error_message, timeout, tries):
http_proxy = self.settings.get('http_proxy')
https_proxy = self.settings.get('https_proxy')
if http_proxy or https_proxy:
proxies = {}
if http_proxy:
proxies['http'] = http_proxy
if not https_proxy:
proxies['https'] = http_proxy
if https_proxy:
proxies['https'] = https_proxy
proxy_handler = url_req.ProxyHandler(proxies)
else:
proxy_handler = url_req.ProxyHandler()
handlers = [proxy_handler]
# secure_url_match = re.match('^https://([^/]+)', url)
# if secure_url_match != None:
# secure_domain = secure_url_match.group(1)
# bundle_path = self.check_certs(secure_domain, timeout)
# if not bundle_path:
# return False
# handlers.append(VerifiedHTTPSHandler(ca_certs=bundle_path))
url_req.install_opener(url_req.build_opener(*handlers))
while tries > 0:
tries -= 1
try:
request = url_req.Request(url, headers={"User-Agent":
"Emmet PyV8 Loader"})
http_file = url_req.urlopen(request, timeout=timeout)
return http_file.read()
except url_err.HTTPError as e:
# Bitbucket and Github ratelimit using 503 a decent amount
if str(e.code) == '503':
print('%s: Downloading %s was rate limited, trying again' % (__name__, url))
continue
print('%s: %s HTTP error %s downloading %s.' % (__name__, error_message, str(e.code), url))
except url_err.URLError as e:
# Bitbucket and Github timeout a decent amount
if str(e.reason) == 'The read operation timed out' or \
str(e.reason) == 'timed out':
print('%s: Downloading %s timed out, trying again' % (__name__, url))
continue
print('%s: %s URL error %s downloading %s.' % (__name__, error_message, str(e.reason), url))
break
return False
class PyV8Loader(threading.Thread):
def __init__(self, arch, download_path, config, delegate=None):
self.arch = arch
self.config = config
self.download_path = download_path
self.exit_code = 0
self.result = None
self.delegate = delegate or LoaderDelegate()
self.is_pyv8_thread = True
threading.Thread.__init__(self)
self.delegate.log('Creating thread')
def download_url(self, url, error_message):
# TODO add settings
has_ssl = 'ssl' in sys.modules and hasattr(url_req, 'HTTPSHandler')
is_ssl = re.search('^https://', url) != None
if (is_ssl and has_ssl) or not is_ssl:
downloader = UrlLib2Downloader(self.delegate.settings)
else:
for downloader_class in [CurlDownloader, WgetDownloader]:
try:
downloader = downloader_class(self.delegate.settings)
break
except BinaryNotFoundError:
pass
if not downloader:
self.delegate.log('Unable to download PyV8 binary due to invalid downloader')
return False
timeout = self.delegate.settings.get('timeout', 60)
# timeout = 3
return downloader.download(url.replace(' ', '%20'), error_message, timeout, 3)
def run(self):
# get list of available packages first
self.delegate.log('Loading %s' % PACKAGES_URL)
try:
packages = self.download_url(PACKAGES_URL, 'Unable to download packages list.')
except Exception as e:
self.delegate.log('Unable to download file: %s' % e)
self.exit_code = 4
return
if not packages:
self.exit_code = 1
return
if isinstance(packages, bytes):
packages = packages.decode('utf-8')
files = json.loads(packages)
# find package for current architecture
cur_item = None
bundle_name = 'pyv8-%s.zip' % self.arch
for item in files:
if bundle_name == item['name']:
cur_item = item
break
if not cur_item:
self.delegate.log('Unable to find binary for %s architecture' % self.arch)
self.exit_code = 2
return
if cur_item['sha'] == self.config['last_id']:
self.delegate.log('You have the most recent PyV8 binary')
return
url = 'https://raw.github.com/emmetio/pyv8-binaries/master/%s' % cur_item['name']
self.delegate.log('Loading PyV8 binary from %s' % url)
package = self.download_url(url, 'Unable to download package from %s' % url)
if not package:
self.exit_code = 3
return
# we should only save downloaded package and delegate module
# loading/unloading to main thread since improper PyV8 unload
# may cause editor crash
try:
os.makedirs(self.download_path)
except Exception as e:
pass
fp = open(os.path.join(self.download_path, 'pack.zip'), 'wb')
fp.write(package)
fp.close()
self.result = cur_item['sha']
# Done!

View File

@@ -0,0 +1,25 @@
import sys
import imp
# Dependecy reloader for Emmet plugin
# The original idea is borrowed from
# https://github.com/wbond/sublime_package_control/blob/master/package_control/reloader.py
reload_mods = []
for mod in sys.modules:
if mod.startswith('emmet') and sys.modules[mod] != None:
reload_mods.append(mod)
mods_load_order = [
'emmet.semver',
'emmet.pyv8loader',
'emmet_completions.trackers',
'emmet_completions.meta',
'emmet_completions',
'emmet.file',
'emmet.context'
]
for mod in mods_load_order:
if mod in reload_mods:
imp.reload(sys.modules[mod])

View File

@@ -0,0 +1,83 @@
# -*- coding: utf-8 -*-
import re
_REGEX = re.compile('^(?P<major>[0-9]+)'
'\.(?P<minor>[0-9]+)'
'\.(?P<patch>[0-9]+)'
'(\-(?P<prerelease>[0-9A-Za-z]+(\.[0-9A-Za-z]+)*))?'
'(\+(?P<build>[0-9A-Za-z]+(\.[0-9A-Za-z]+)*))?$')
if 'cmp' not in __builtins__:
cmp = lambda a,b: (a > b) - (a < b)
def parse(version):
"""
Parse version to major, minor, patch, pre-release, build parts.
"""
match = _REGEX.match(version)
if match is None:
raise ValueError('%s is not valid SemVer string' % version)
verinfo = match.groupdict()
verinfo['major'] = int(verinfo['major'])
verinfo['minor'] = int(verinfo['minor'])
verinfo['patch'] = int(verinfo['patch'])
return verinfo
def compare(ver1, ver2):
def nat_cmp(a, b):
a, b = a or '', b or ''
convert = lambda text: text.isdigit() and int(text) or text.lower()
alphanum_key = lambda key: [convert(c) for c in re.split('([0-9]+)', key)]
return cmp(alphanum_key(a), alphanum_key(b))
def compare_by_keys(d1, d2):
for key in ['major', 'minor', 'patch']:
v = cmp(d1.get(key), d2.get(key))
if v:
return v
rc1, rc2 = d1.get('prerelease'), d2.get('prerelease')
build1, build2 = d1.get('build'), d2.get('build')
rccmp = nat_cmp(rc1, rc2)
buildcmp = nat_cmp(build1, build2)
if not (rc1 or rc2):
return buildcmp
elif not rc1:
return 1
elif not rc2:
return -1
return rccmp or buildcmp or 0
v1, v2 = parse(ver1), parse(ver2)
return compare_by_keys(v1, v2)
def match(version, match_expr):
prefix = match_expr[:2]
if prefix in ('>=', '<=', '=='):
match_version = match_expr[2:]
elif prefix and prefix[0] in ('>', '<', '='):
prefix = prefix[0]
match_version = match_expr[1:]
else:
raise ValueError("match_expr parameter should be in format <op><ver>, "
"where <op> is one of ['<', '>', '==', '<=', '>=']. "
"You provided: %r" % match_expr)
possibilities_dict = {
'>': (1,),
'<': (-1,),
'==': (0,),
'>=': (0, 1),
'<=': (-1, 0)
}
possibilities = possibilities_dict[prefix]
cmp_res = compare(version, match_version)
return cmp_res in possibilities

View File

@@ -0,0 +1,846 @@
{
"variables": {
"lang": "en",
"locale": "en-US",
"charset": "UTF-8",
"indentation": "\t",
"newline": "\n"
},
"css": {
"filters": "html",
"snippets": {
"@i": "@import url(|);",
"@import": "@import url(|);",
"@m": "@media ${1:screen} {\n\t|\n}",
"@media": "@media ${1:screen} {\n\t|\n}",
"@f": "@font-face {\n\tfont-family:|;\n\tsrc:url(|);\n}",
"@f+": "@font-face {\n\tfont-family: '${1:FontName}';\n\tsrc: url('${2:FileName}.eot');\n\tsrc: url('${2:FileName}.eot?#iefix') format('embedded-opentype'),\n\t\t url('${2:FileName}.woff') format('woff'),\n\t\t url('${2:FileName}.ttf') format('truetype'),\n\t\t url('${2:FileName}.svg#${1:FontName}') format('svg');\n\tfont-style: ${3:normal};\n\tfont-weight: ${4:normal};\n}",
"@kf": "@-webkit-keyframes ${1:identifier} {\n\t${2:from} { ${3} }${6}\n\t${4:to} { ${5} }\n}\n@-o-keyframes ${1:identifier} {\n\t${2:from} { ${3} }${6}\n\t${4:to} { ${5} }\n}\n@-moz-keyframes ${1:identifier} {\n\t${2:from} { ${3} }${6}\n\t${4:to} { ${5} }\n}\n@keyframes ${1:identifier} {\n\t${2:from} { ${3} }${6}\n\t${4:to} { ${5} }\n}",
"anim": "animation:|;",
"anim-": "animation:${1:name} ${2:duration} ${3:timing-function} ${4:delay} ${5:iteration-count} ${6:direction} ${7:fill-mode};",
"animdel": "animation-delay:${1:time};",
"animdir": "animation-direction:${1:normal};",
"animdir:n": "animation-direction:normal;",
"animdir:r": "animation-direction:reverse;",
"animdir:a": "animation-direction:alternate;",
"animdir:ar": "animation-direction:alternate-reverse;",
"animdur": "animation-duration:${1:0}s;",
"animfm": "animation-fill-mode:${1:both};",
"animfm:f": "animation-fill-mode:forwards;",
"animfm:b": "animation-fill-mode:backwards;",
"animfm:bt": "animation-fill-mode:both;",
"animfm:bh": "animation-fill-mode:both;",
"animic": "animation-iteration-count:${1:1};",
"animic:i": "animation-iteration-count:infinite;",
"animn": "animation-name:${1:none};",
"animps": "animation-play-state:${1:running};",
"animps:p": "animation-play-state:paused;",
"animps:r": "animation-play-state:running;",
"animtf": "animation-timing-function:${1:linear};",
"animtf:e": "animation-timing-function:ease;",
"animtf:ei": "animation-timing-function:ease-in;",
"animtf:eo": "animation-timing-function:ease-out;",
"animtf:eio": "animation-timing-function:ease-in-out;",
"animtf:l": "animation-timing-function:linear;",
"animtf:cb": "animation-timing-function:cubic-bezier(${1:0.1}, ${2:0.7}, ${3:1.0}, ${3:0.1});",
"ap": "appearance:${none};",
"!": "!important",
"pos": "position:${1:relative};",
"pos:s": "position:static;",
"pos:a": "position:absolute;",
"pos:r": "position:relative;",
"pos:f": "position:fixed;",
"t": "top:|;",
"t:a": "top:auto;",
"r": "right:|;",
"r:a": "right:auto;",
"b": "bottom:|;",
"b:a": "bottom:auto;",
"l": "left:|;",
"l:a": "left:auto;",
"z": "z-index:|;",
"z:a": "z-index:auto;",
"fl": "float:${1:left};",
"fl:n": "float:none;",
"fl:l": "float:left;",
"fl:r": "float:right;",
"cl": "clear:${1:both};",
"cl:n": "clear:none;",
"cl:l": "clear:left;",
"cl:r": "clear:right;",
"cl:b": "clear:both;",
"colm": "columns:|;",
"colmc": "column-count:|;",
"colmf": "column-fill:|;",
"colmg": "column-gap:|;",
"colmr": "column-rule:|;",
"colmrc": "column-rule-color:|;",
"colmrs": "column-rule-style:|;",
"colmrw": "column-rule-width:|;",
"colms": "column-span:|;",
"colmw": "column-width:|;",
"d": "display:${1:block};",
"d:n": "display:none;",
"d:b": "display:block;",
"d:i": "display:inline;",
"d:ib": "display:inline-block;",
"d:li": "display:list-item;",
"d:ri": "display:run-in;",
"d:cp": "display:compact;",
"d:tb": "display:table;",
"d:itb": "display:inline-table;",
"d:tbcp": "display:table-caption;",
"d:tbcl": "display:table-column;",
"d:tbclg": "display:table-column-group;",
"d:tbhg": "display:table-header-group;",
"d:tbfg": "display:table-footer-group;",
"d:tbr": "display:table-row;",
"d:tbrg": "display:table-row-group;",
"d:tbc": "display:table-cell;",
"d:rb": "display:ruby;",
"d:rbb": "display:ruby-base;",
"d:rbbg": "display:ruby-base-group;",
"d:rbt": "display:ruby-text;",
"d:rbtg": "display:ruby-text-group;",
"v": "visibility:${1:hidden};",
"v:v": "visibility:visible;",
"v:h": "visibility:hidden;",
"v:c": "visibility:collapse;",
"ov": "overflow:${1:hidden};",
"ov:v": "overflow:visible;",
"ov:h": "overflow:hidden;",
"ov:s": "overflow:scroll;",
"ov:a": "overflow:auto;",
"ovx": "overflow-x:${1:hidden};",
"ovx:v": "overflow-x:visible;",
"ovx:h": "overflow-x:hidden;",
"ovx:s": "overflow-x:scroll;",
"ovx:a": "overflow-x:auto;",
"ovy": "overflow-y:${1:hidden};",
"ovy:v": "overflow-y:visible;",
"ovy:h": "overflow-y:hidden;",
"ovy:s": "overflow-y:scroll;",
"ovy:a": "overflow-y:auto;",
"ovs": "overflow-style:${1:scrollbar};",
"ovs:a": "overflow-style:auto;",
"ovs:s": "overflow-style:scrollbar;",
"ovs:p": "overflow-style:panner;",
"ovs:m": "overflow-style:move;",
"ovs:mq": "overflow-style:marquee;",
"zoo": "zoom:1;",
"zm": "zoom:1;",
"cp": "clip:|;",
"cp:a": "clip:auto;",
"cp:r": "clip:rect(${1:top} ${2:right} ${3:bottom} ${4:left});",
"bxz": "box-sizing:${1:border-box};",
"bxz:cb": "box-sizing:content-box;",
"bxz:bb": "box-sizing:border-box;",
"bxsh": "box-shadow:${1:inset }${2:hoff} ${3:voff} ${4:blur} ${5:color};",
"bxsh:r": "box-shadow:${1:inset }${2:hoff} ${3:voff} ${4:blur} ${5:spread }rgb(${6:0}, ${7:0}, ${8:0});",
"bxsh:ra": "box-shadow:${1:inset }${2:h} ${3:v} ${4:blur} ${5:spread }rgba(${6:0}, ${7:0}, ${8:0}, .${9:5});",
"bxsh:n": "box-shadow:none;",
"m": "margin:|;",
"m:a": "margin:auto;",
"mt": "margin-top:|;",
"mt:a": "margin-top:auto;",
"mr": "margin-right:|;",
"mr:a": "margin-right:auto;",
"mb": "margin-bottom:|;",
"mb:a": "margin-bottom:auto;",
"ml": "margin-left:|;",
"ml:a": "margin-left:auto;",
"p": "padding:|;",
"pt": "padding-top:|;",
"pr": "padding-right:|;",
"pb": "padding-bottom:|;",
"pl": "padding-left:|;",
"w": "width:|;",
"w:a": "width:auto;",
"h": "height:|;",
"h:a": "height:auto;",
"maw": "max-width:|;",
"maw:n": "max-width:none;",
"mah": "max-height:|;",
"mah:n": "max-height:none;",
"miw": "min-width:|;",
"mih": "min-height:|;",
"mar": "max-resolution:${1:res};",
"mir": "min-resolution:${1:res};",
"ori": "orientation:|;",
"ori:l": "orientation:landscape;",
"ori:p": "orientation:portrait;",
"ol": "outline:|;",
"ol:n": "outline:none;",
"olo": "outline-offset:|;",
"olw": "outline-width:|;",
"ols": "outline-style:|;",
"olc": "outline-color:#${1:000};",
"olc:i": "outline-color:invert;",
"bd": "border:|;",
"bd+": "border:${1:1px} ${2:solid} ${3:#000};",
"bd:n": "border:none;",
"bdbk": "border-break:${1:close};",
"bdbk:c": "border-break:close;",
"bdcl": "border-collapse:|;",
"bdcl:c": "border-collapse:collapse;",
"bdcl:s": "border-collapse:separate;",
"bdc": "border-color:#${1:000};",
"bdc:t": "border-color:transparent;",
"bdi": "border-image:url(|);",
"bdi:n": "border-image:none;",
"bdti": "border-top-image:url(|);",
"bdti:n": "border-top-image:none;",
"bdri": "border-right-image:url(|);",
"bdri:n": "border-right-image:none;",
"bdbi": "border-bottom-image:url(|);",
"bdbi:n": "border-bottom-image:none;",
"bdli": "border-left-image:url(|);",
"bdli:n": "border-left-image:none;",
"bdci": "border-corner-image:url(|);",
"bdci:n": "border-corner-image:none;",
"bdci:c": "border-corner-image:continue;",
"bdtli": "border-top-left-image:url(|);",
"bdtli:n": "border-top-left-image:none;",
"bdtli:c": "border-top-left-image:continue;",
"bdtri": "border-top-right-image:url(|);",
"bdtri:n": "border-top-right-image:none;",
"bdtri:c": "border-top-right-image:continue;",
"bdbri": "border-bottom-right-image:url(|);",
"bdbri:n": "border-bottom-right-image:none;",
"bdbri:c": "border-bottom-right-image:continue;",
"bdbli": "border-bottom-left-image:url(|);",
"bdbli:n": "border-bottom-left-image:none;",
"bdbli:c": "border-bottom-left-image:continue;",
"bdf": "border-fit:${1:repeat};",
"bdf:c": "border-fit:clip;",
"bdf:r": "border-fit:repeat;",
"bdf:sc": "border-fit:scale;",
"bdf:st": "border-fit:stretch;",
"bdf:ow": "border-fit:overwrite;",
"bdf:of": "border-fit:overflow;",
"bdf:sp": "border-fit:space;",
"bdlen": "border-length:|;",
"bdlen:a": "border-length:auto;",
"bdsp": "border-spacing:|;",
"bds": "border-style:|;",
"bds:n": "border-style:none;",
"bds:h": "border-style:hidden;",
"bds:dt": "border-style:dotted;",
"bds:ds": "border-style:dashed;",
"bds:s": "border-style:solid;",
"bds:db": "border-style:double;",
"bds:dtds": "border-style:dot-dash;",
"bds:dtdtds": "border-style:dot-dot-dash;",
"bds:w": "border-style:wave;",
"bds:g": "border-style:groove;",
"bds:r": "border-style:ridge;",
"bds:i": "border-style:inset;",
"bds:o": "border-style:outset;",
"bdw": "border-width:|;",
"bdtw": "border-top-width:|;",
"bdrw": "border-right-width:|;",
"bdbw": "border-bottom-width:|;",
"bdlw": "border-left-width:|;",
"bdt": "border-top:|;",
"bt": "border-top:|;",
"bdt+": "border-top:${1:1px} ${2:solid} ${3:#000};",
"bdt:n": "border-top:none;",
"bdts": "border-top-style:|;",
"bdts:n": "border-top-style:none;",
"bdtc": "border-top-color:#${1:000};",
"bdtc:t": "border-top-color:transparent;",
"bdr": "border-right:|;",
"br": "border-right:|;",
"bdr+": "border-right:${1:1px} ${2:solid} ${3:#000};",
"bdr:n": "border-right:none;",
"bdrst": "border-right-style:|;",
"bdrst:n": "border-right-style:none;",
"bdrc": "border-right-color:#${1:000};",
"bdrc:t": "border-right-color:transparent;",
"bdb": "border-bottom:|;",
"bb": "border-bottom:|;",
"bdb+": "border-bottom:${1:1px} ${2:solid} ${3:#000};",
"bdb:n": "border-bottom:none;",
"bdbs": "border-bottom-style:|;",
"bdbs:n": "border-bottom-style:none;",
"bdbc": "border-bottom-color:#${1:000};",
"bdbc:t": "border-bottom-color:transparent;",
"bdl": "border-left:|;",
"bl": "border-left:|;",
"bdl+": "border-left:${1:1px} ${2:solid} ${3:#000};",
"bdl:n": "border-left:none;",
"bdls": "border-left-style:|;",
"bdls:n": "border-left-style:none;",
"bdlc": "border-left-color:#${1:000};",
"bdlc:t": "border-left-color:transparent;",
"bdrs": "border-radius:|;",
"bdtrrs": "border-top-right-radius:|;",
"bdtlrs": "border-top-left-radius:|;",
"bdbrrs": "border-bottom-right-radius:|;",
"bdblrs": "border-bottom-left-radius:|;",
"bg": "background:|;",
"bg+": "background:${1:#fff} url(${2}) ${3:0} ${4:0} ${5:no-repeat};",
"bg:n": "background:none;",
"bg:ie": "filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${1:x}.png',sizingMethod='${2:crop}');",
"bgc": "background-color:#${1:fff};",
"bgc:t": "background-color:transparent;",
"bgi": "background-image:url(|);",
"bgi:n": "background-image:none;",
"bgr": "background-repeat:|;",
"bgr:n": "background-repeat:no-repeat;",
"bgr:x": "background-repeat:repeat-x;",
"bgr:y": "background-repeat:repeat-y;",
"bgr:sp": "background-repeat:space;",
"bgr:rd": "background-repeat:round;",
"bga": "background-attachment:|;",
"bga:f": "background-attachment:fixed;",
"bga:s": "background-attachment:scroll;",
"bgp": "background-position:${1:0} ${2:0};",
"bgpx": "background-position-x:|;",
"bgpy": "background-position-y:|;",
"bgbk": "background-break:|;",
"bgbk:bb": "background-break:bounding-box;",
"bgbk:eb": "background-break:each-box;",
"bgbk:c": "background-break:continuous;",
"bgcp": "background-clip:${1:padding-box};",
"bgcp:bb": "background-clip:border-box;",
"bgcp:pb": "background-clip:padding-box;",
"bgcp:cb": "background-clip:content-box;",
"bgcp:nc": "background-clip:no-clip;",
"bgo": "background-origin:|;",
"bgo:pb": "background-origin:padding-box;",
"bgo:bb": "background-origin:border-box;",
"bgo:cb": "background-origin:content-box;",
"bgsz": "background-size:|;",
"bgsz:a": "background-size:auto;",
"bgsz:ct": "background-size:contain;",
"bgsz:cv": "background-size:cover;",
"c": "color:#${1:000};",
"c:r": "color:rgb(${1:0}, ${2:0}, ${3:0});",
"c:ra": "color:rgba(${1:0}, ${2:0}, ${3:0}, .${4:5});",
"cm": "/* |${child} */",
"cnt": "content:'|';",
"cnt:n": "content:normal;",
"cnt:oq": "content:open-quote;",
"cnt:noq": "content:no-open-quote;",
"cnt:cq": "content:close-quote;",
"cnt:ncq": "content:no-close-quote;",
"cnt:a": "content:attr(|);",
"cnt:c": "content:counter(|);",
"cnt:cs": "content:counters(|);",
"tbl": "table-layout:|;",
"tbl:a": "table-layout:auto;",
"tbl:f": "table-layout:fixed;",
"cps": "caption-side:|;",
"cps:t": "caption-side:top;",
"cps:b": "caption-side:bottom;",
"ec": "empty-cells:|;",
"ec:s": "empty-cells:show;",
"ec:h": "empty-cells:hide;",
"lis": "list-style:|;",
"lis:n": "list-style:none;",
"lisp": "list-style-position:|;",
"lisp:i": "list-style-position:inside;",
"lisp:o": "list-style-position:outside;",
"list": "list-style-type:|;",
"list:n": "list-style-type:none;",
"list:d": "list-style-type:disc;",
"list:c": "list-style-type:circle;",
"list:s": "list-style-type:square;",
"list:dc": "list-style-type:decimal;",
"list:dclz": "list-style-type:decimal-leading-zero;",
"list:lr": "list-style-type:lower-roman;",
"list:ur": "list-style-type:upper-roman;",
"lisi": "list-style-image:|;",
"lisi:n": "list-style-image:none;",
"q": "quotes:|;",
"q:n": "quotes:none;",
"q:ru": "quotes:'\\00AB' '\\00BB' '\\201E' '\\201C';",
"q:en": "quotes:'\\201C' '\\201D' '\\2018' '\\2019';",
"ct": "content:|;",
"ct:n": "content:normal;",
"ct:oq": "content:open-quote;",
"ct:noq": "content:no-open-quote;",
"ct:cq": "content:close-quote;",
"ct:ncq": "content:no-close-quote;",
"ct:a": "content:attr(|);",
"ct:c": "content:counter(|);",
"ct:cs": "content:counters(|);",
"coi": "counter-increment:|;",
"cor": "counter-reset:|;",
"va": "vertical-align:${1:top};",
"va:sup": "vertical-align:super;",
"va:t": "vertical-align:top;",
"va:tt": "vertical-align:text-top;",
"va:m": "vertical-align:middle;",
"va:bl": "vertical-align:baseline;",
"va:b": "vertical-align:bottom;",
"va:tb": "vertical-align:text-bottom;",
"va:sub": "vertical-align:sub;",
"ta": "text-align:${1:left};",
"ta:l": "text-align:left;",
"ta:c": "text-align:center;",
"ta:r": "text-align:right;",
"ta:j": "text-align:justify;",
"ta-lst": "text-align-last:|;",
"tal:a": "text-align-last:auto;",
"tal:l": "text-align-last:left;",
"tal:c": "text-align-last:center;",
"tal:r": "text-align-last:right;",
"td": "text-decoration:${1:none};",
"td:n": "text-decoration:none;",
"td:u": "text-decoration:underline;",
"td:o": "text-decoration:overline;",
"td:l": "text-decoration:line-through;",
"te": "text-emphasis:|;",
"te:n": "text-emphasis:none;",
"te:ac": "text-emphasis:accent;",
"te:dt": "text-emphasis:dot;",
"te:c": "text-emphasis:circle;",
"te:ds": "text-emphasis:disc;",
"te:b": "text-emphasis:before;",
"te:a": "text-emphasis:after;",
"th": "text-height:|;",
"th:a": "text-height:auto;",
"th:f": "text-height:font-size;",
"th:t": "text-height:text-size;",
"th:m": "text-height:max-size;",
"ti": "text-indent:|;",
"ti:-": "text-indent:-9999px;",
"tj": "text-justify:|;",
"tj:a": "text-justify:auto;",
"tj:iw": "text-justify:inter-word;",
"tj:ii": "text-justify:inter-ideograph;",
"tj:ic": "text-justify:inter-cluster;",
"tj:d": "text-justify:distribute;",
"tj:k": "text-justify:kashida;",
"tj:t": "text-justify:tibetan;",
"tov": "text-overflow:${ellipsis};",
"tov:e": "text-overflow:ellipsis;",
"tov:c": "text-overflow:clip;",
"to": "text-outline:|;",
"to+": "text-outline:${1:0} ${2:0} ${3:#000};",
"to:n": "text-outline:none;",
"tr": "text-replace:|;",
"tr:n": "text-replace:none;",
"tt": "text-transform:${1:uppercase};",
"tt:n": "text-transform:none;",
"tt:c": "text-transform:capitalize;",
"tt:u": "text-transform:uppercase;",
"tt:l": "text-transform:lowercase;",
"tw": "text-wrap:|;",
"tw:n": "text-wrap:normal;",
"tw:no": "text-wrap:none;",
"tw:u": "text-wrap:unrestricted;",
"tw:s": "text-wrap:suppress;",
"tsh": "text-shadow:${1:hoff} ${2:voff} ${3:blur} ${4:#000};",
"tsh:r": "text-shadow:${1:h} ${2:v} ${3:blur} rgb(${4:0}, ${5:0}, ${6:0});",
"tsh:ra": "text-shadow:${1:h} ${2:v} ${3:blur} rgba(${4:0}, ${5:0}, ${6:0}, .${7:5});",
"tsh+": "text-shadow:${1:0} ${2:0} ${3:0} ${4:#000};",
"tsh:n": "text-shadow:none;",
"trf": "transform:|;",
"trf:skx": "transform: skewX(${1:angle});",
"trf:sky": "transform: skewY(${1:angle});",
"trf:sc": "transform: scale(${1:x}, ${2:y});",
"trf:scx": "transform: scaleX(${1:x});",
"trf:scy": "transform: scaleY(${1:y});",
"trf:r": "transform: rotate(${1:angle});",
"trf:t": "transform: translate(${1:x}, ${2:y});",
"trf:tx": "transform: translateX(${1:x});",
"trf:ty": "transform: translateY(${1:y});",
"trfo": "transform-origin:|;",
"trfs": "transform-style:${1:preserve-3d};",
"trs": "transition:${1:prop} ${2:time};",
"trsde": "transition-delay:${1:time};",
"trsdu": "transition-duration:${1:time};",
"trsp": "transition-property:${1:prop};",
"trstf": "transition-timing-function:${1:tfunc};",
"lh": "line-height:|;",
"whs": "white-space:|;",
"whs:n": "white-space:normal;",
"whs:p": "white-space:pre;",
"whs:nw": "white-space:nowrap;",
"whs:pw": "white-space:pre-wrap;",
"whs:pl": "white-space:pre-line;",
"whsc": "white-space-collapse:|;",
"whsc:n": "white-space-collapse:normal;",
"whsc:k": "white-space-collapse:keep-all;",
"whsc:l": "white-space-collapse:loose;",
"whsc:bs": "white-space-collapse:break-strict;",
"whsc:ba": "white-space-collapse:break-all;",
"wob": "word-break:|;",
"wob:n": "word-break:normal;",
"wob:k": "word-break:keep-all;",
"wob:l": "word-break:loose;",
"wob:bs": "word-break:break-strict;",
"wob:ba": "word-break:break-all;",
"wos": "word-spacing:|;",
"wow": "word-wrap:|;",
"wow:nm": "word-wrap:normal;",
"wow:n": "word-wrap:none;",
"wow:u": "word-wrap:unrestricted;",
"wow:s": "word-wrap:suppress;",
"lts": "letter-spacing:|;",
"f": "font:|;",
"f+": "font:${1:1em} ${2:Arial,sans-serif};",
"fw": "font-weight:|;",
"fw:n": "font-weight:normal;",
"fw:b": "font-weight:bold;",
"fw:br": "font-weight:bolder;",
"fw:lr": "font-weight:lighter;",
"fs": "font-style:${italic};",
"fs:n": "font-style:normal;",
"fs:i": "font-style:italic;",
"fs:o": "font-style:oblique;",
"fv": "font-variant:|;",
"fv:n": "font-variant:normal;",
"fv:sc": "font-variant:small-caps;",
"fz": "font-size:|;",
"fza": "font-size-adjust:|;",
"fza:n": "font-size-adjust:none;",
"ff": "font-family:|;",
"ff:s": "font-family:serif;",
"ff:ss": "font-family:sans-serif;",
"ff:c": "font-family:cursive;",
"ff:f": "font-family:fantasy;",
"ff:m": "font-family:monospace;",
"fef": "font-effect:|;",
"fef:n": "font-effect:none;",
"fef:eg": "font-effect:engrave;",
"fef:eb": "font-effect:emboss;",
"fef:o": "font-effect:outline;",
"fem": "font-emphasize:|;",
"femp": "font-emphasize-position:|;",
"femp:b": "font-emphasize-position:before;",
"femp:a": "font-emphasize-position:after;",
"fems": "font-emphasize-style:|;",
"fems:n": "font-emphasize-style:none;",
"fems:ac": "font-emphasize-style:accent;",
"fems:dt": "font-emphasize-style:dot;",
"fems:c": "font-emphasize-style:circle;",
"fems:ds": "font-emphasize-style:disc;",
"fsm": "font-smooth:|;",
"fsm:a": "font-smooth:auto;",
"fsm:n": "font-smooth:never;",
"fsm:aw": "font-smooth:always;",
"fst": "font-stretch:|;",
"fst:n": "font-stretch:normal;",
"fst:uc": "font-stretch:ultra-condensed;",
"fst:ec": "font-stretch:extra-condensed;",
"fst:c": "font-stretch:condensed;",
"fst:sc": "font-stretch:semi-condensed;",
"fst:se": "font-stretch:semi-expanded;",
"fst:e": "font-stretch:expanded;",
"fst:ee": "font-stretch:extra-expanded;",
"fst:ue": "font-stretch:ultra-expanded;",
"op": "opacity:|;",
"op:ie": "filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=100);",
"op:ms": "-ms-filter:'progid:DXImageTransform.Microsoft.Alpha(Opacity=100)';",
"rsz": "resize:|;",
"rsz:n": "resize:none;",
"rsz:b": "resize:both;",
"rsz:h": "resize:horizontal;",
"rsz:v": "resize:vertical;",
"cur": "cursor:${pointer};",
"cur:a": "cursor:auto;",
"cur:d": "cursor:default;",
"cur:c": "cursor:crosshair;",
"cur:ha": "cursor:hand;",
"cur:he": "cursor:help;",
"cur:m": "cursor:move;",
"cur:p": "cursor:pointer;",
"cur:t": "cursor:text;",
"pgbb": "page-break-before:|;",
"pgbb:au": "page-break-before:auto;",
"pgbb:al": "page-break-before:always;",
"pgbb:l": "page-break-before:left;",
"pgbb:r": "page-break-before:right;",
"pgbi": "page-break-inside:|;",
"pgbi:au": "page-break-inside:auto;",
"pgbi:av": "page-break-inside:avoid;",
"pgba": "page-break-after:|;",
"pgba:au": "page-break-after:auto;",
"pgba:al": "page-break-after:always;",
"pgba:l": "page-break-after:left;",
"pgba:r": "page-break-after:right;",
"orp": "orphans:|;",
"us": "user-select:${none};",
"wid": "widows:|;",
"wfsm": "-webkit-font-smoothing:${antialiased};",
"wfsm:a": "-webkit-font-smoothing:antialiased;",
"wfsm:s": "-webkit-font-smoothing:subpixel-antialiased;",
"wfsm:sa": "-webkit-font-smoothing:subpixel-antialiased;",
"wfsm:n": "-webkit-font-smoothing:none;"
}
},
"html": {
"filters": "html",
"profile": "html",
"snippets": {
"!!!": "<!doctype html>",
"!!!4t": "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">",
"!!!4s": "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">",
"!!!xt": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">",
"!!!xs": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">",
"!!!xxs": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">",
"c": "<!-- |${child} -->",
"cc:ie6": "<!--[if lte IE 6]>\n\t${child}|\n<![endif]-->",
"cc:ie": "<!--[if IE]>\n\t${child}|\n<![endif]-->",
"cc:noie": "<!--[if !IE]><!-->\n\t${child}|\n<!--<![endif]-->"
},
"abbreviations": {
"!": "html:5",
"a": "<a href=\"\">",
"a:link": "<a href=\"http://|\">",
"a:mail": "<a href=\"mailto:|\">",
"abbr": "<abbr title=\"\">",
"acronym": "<acronym title=\"\">",
"base": "<base href=\"\" />",
"basefont": "<basefont/>",
"br": "<br/>",
"frame": "<frame/>",
"hr": "<hr/>",
"bdo": "<bdo dir=\"\">",
"bdo:r": "<bdo dir=\"rtl\">",
"bdo:l": "<bdo dir=\"ltr\">",
"col": "<col/>",
"link": "<link rel=\"stylesheet\" href=\"\" />",
"link:css": "<link rel=\"stylesheet\" href=\"${1:style}.css\" />",
"link:print": "<link rel=\"stylesheet\" href=\"${1:print}.css\" media=\"print\" />",
"link:favicon": "<link rel=\"shortcut icon\" type=\"image/x-icon\" href=\"${1:favicon.ico}\" />",
"link:touch": "<link rel=\"apple-touch-icon\" href=\"${1:favicon.png}\" />",
"link:rss": "<link rel=\"alternate\" type=\"application/rss+xml\" title=\"RSS\" href=\"${1:rss.xml}\" />",
"link:atom": "<link rel=\"alternate\" type=\"application/atom+xml\" title=\"Atom\" href=\"${1:atom.xml}\" />",
"meta": "<meta/>",
"meta:utf": "<meta http-equiv=\"Content-Type\" content=\"text/html;charset=UTF-8\" />",
"meta:win": "<meta http-equiv=\"Content-Type\" content=\"text/html;charset=windows-1251\" />",
"meta:vp": "<meta name=\"viewport\" content=\"width=${1:device-width}, user-scalable=${2:no}, initial-scale=${3:1.0}, maximum-scale=${4:1.0}, minimum-scale=${5:1.0}\" />",
"meta:compat": "<meta http-equiv=\"X-UA-Compatible\" content=\"${1:IE=7}\" />",
"style": "<style>",
"script": "<script>",
"script:src": "<script src=\"\">",
"img": "<img src=\"\" alt=\"\" />",
"iframe": "<iframe src=\"\" frameborder=\"0\">",
"embed": "<embed src=\"\" type=\"\" />",
"object": "<object data=\"\" type=\"\">",
"param": "<param name=\"\" value=\"\" />",
"map": "<map name=\"\">",
"area": "<area shape=\"\" coords=\"\" href=\"\" alt=\"\" />",
"area:d": "<area shape=\"default\" href=\"\" alt=\"\" />",
"area:c": "<area shape=\"circle\" coords=\"\" href=\"\" alt=\"\" />",
"area:r": "<area shape=\"rect\" coords=\"\" href=\"\" alt=\"\" />",
"area:p": "<area shape=\"poly\" coords=\"\" href=\"\" alt=\"\" />",
"form": "<form action=\"\">",
"form:get": "<form action=\"\" method=\"get\">",
"form:post": "<form action=\"\" method=\"post\">",
"label": "<label for=\"\">",
"input": "<input type=\"${1:text}\" />",
"inp": "<input type=\"${1:text}\" name=\"\" id=\"\" />",
"input:hidden": "input[type=hidden name]",
"input:h": "input:hidden",
"input:text": "inp",
"input:t": "inp",
"input:search": "inp[type=search]",
"input:email": "inp[type=email]",
"input:url": "inp[type=url]",
"input:password": "inp[type=password]",
"input:p": "input:password",
"input:datetime": "inp[type=datetime]",
"input:date": "inp[type=date]",
"input:datetime-local": "inp[type=datetime-local]",
"input:month": "inp[type=month]",
"input:week": "inp[type=week]",
"input:time": "inp[type=time]",
"input:number": "inp[type=number]",
"input:color": "inp[type=color]",
"input:checkbox": "inp[type=checkbox]",
"input:c": "input:checkbox",
"input:radio": "inp[type=radio]",
"input:r": "input:radio",
"input:range": "inp[type=range]",
"input:file": "inp[type=file]",
"input:f": "input:file",
"input:submit": "<input type=\"submit\" value=\"\" />",
"input:s": "input:submit",
"input:image": "<input type=\"image\" src=\"\" alt=\"\" />",
"input:i": "input:image",
"input:button": "<input type=\"button\" value=\"\" />",
"input:b": "input:button",
"isindex": "<isindex/>",
"input:reset": "input:button[type=reset]",
"select": "<select name=\"\" id=\"\">",
"option": "<option value=\"\">",
"textarea": "<textarea name=\"\" id=\"\" cols=\"${1:30}\" rows=\"${2:10}\">",
"menu:context": "menu[type=context]>",
"menu:c": "menu:context",
"menu:toolbar": "menu[type=toolbar]>",
"menu:t": "menu:toolbar",
"video": "<video src=\"\">",
"audio": "<audio src=\"\">",
"html:xml": "<html xmlns=\"http://www.w3.org/1999/xhtml\">",
"keygen": "<keygen/>",
"command": "<command/>",
"bq": "blockquote",
"acr": "acronym",
"fig": "figure",
"figc": "figcaption",
"ifr": "iframe",
"emb": "embed",
"obj": "object",
"src": "source",
"cap": "caption",
"colg": "colgroup",
"fst": "fieldset",
"btn": "button",
"btn:b": "button[type=button]",
"btn:r": "button[type=reset]",
"btn:s": "button[type=submit]",
"optg": "optgroup",
"opt": "option",
"tarea": "textarea",
"leg": "legend",
"sect": "section",
"art": "article",
"hdr": "header",
"ftr": "footer",
"adr": "address",
"dlg": "dialog",
"str": "strong",
"prog": "progress",
"fset": "fieldset",
"datag": "datagrid",
"datal": "datalist",
"kg": "keygen",
"out": "output",
"det": "details",
"cmd": "command",
"doc": "html>(head>meta[charset=UTF-8]+title{${1:Document}})+body",
"doc4": "html>(head>meta[http-equiv=\"Content-Type\" content=\"text/html;charset=${charset}\"]+title{${1:Document}})+body",
"html:4t": "!!!4t+doc4[lang=${lang}]",
"html:4s": "!!!4s+doc4[lang=${lang}]",
"html:xt": "!!!xt+doc4[xmlns=http://www.w3.org/1999/xhtml xml:lang=${lang}]",
"html:xs": "!!!xs+doc4[xmlns=http://www.w3.org/1999/xhtml xml:lang=${lang}]",
"html:xxs": "!!!xxs+doc4[xmlns=http://www.w3.org/1999/xhtml xml:lang=${lang}]",
"html:5": "!!!+doc[lang=${lang}]",
"ol+": "ol>li",
"ul+": "ul>li",
"dl+": "dl>dt+dd",
"map+": "map>area",
"table+": "table>tr>td",
"colgroup+": "colgroup>col",
"colg+": "colgroup>col",
"tr+": "tr>td",
"select+": "select>option",
"optgroup+": "optgroup>option",
"optg+": "optgroup>option"
}
},
"xml": {
"extends": "html",
"profile": "xml",
"filters": "html"
},
"xsl": {
"extends": "html",
"profile": "xml",
"filters": "html, xsl",
"abbreviations": {
"tm": "<xsl:template match=\"\" mode=\"\">",
"tmatch": "tm",
"tn": "<xsl:template name=\"\">",
"tname": "tn",
"call": "<xsl:call-template name=\"\"/>",
"ap": "<xsl:apply-templates select=\"\" mode=\"\"/>",
"api": "<xsl:apply-imports/>",
"imp": "<xsl:import href=\"\"/>",
"inc": "<xsl:include href=\"\"/>",
"ch": "<xsl:choose>",
"xsl:when": "<xsl:when test=\"\">",
"wh": "xsl:when",
"ot": "<xsl:otherwise>",
"if": "<xsl:if test=\"\">",
"par": "<xsl:param name=\"\">",
"pare": "<xsl:param name=\"\" select=\"\"/>",
"var": "<xsl:variable name=\"\">",
"vare": "<xsl:variable name=\"\" select=\"\"/>",
"wp": "<xsl:with-param name=\"\" select=\"\"/>",
"key": "<xsl:key name=\"\" match=\"\" use=\"\"/>",
"elem": "<xsl:element name=\"\">",
"attr": "<xsl:attribute name=\"\">",
"attrs": "<xsl:attribute-set name=\"\">",
"cp": "<xsl:copy select=\"\"/>",
"co": "<xsl:copy-of select=\"\"/>",
"val": "<xsl:value-of select=\"\"/>",
"each": "<xsl:for-each select=\"\">",
"for": "each",
"tex": "<xsl:text></xsl:text>",
"com": "<xsl:comment>",
"msg": "<xsl:message terminate=\"no\">",
"fall": "<xsl:fallback>",
"num": "<xsl:number value=\"\"/>",
"nam": "<namespace-alias stylesheet-prefix=\"\" result-prefix=\"\"/>",
"pres": "<xsl:preserve-space elements=\"\"/>",
"strip": "<xsl:strip-space elements=\"\"/>",
"proc": "<xsl:processing-instruction name=\"\">",
"sort": "<xsl:sort select=\"\" order=\"\"/>",
"choose+": "xsl:choose>xsl:when+xsl:otherwise",
"xsl": "!!!+xsl:stylesheet[version=1.0 xmlns:xsl=http://www.w3.org/1999/XSL/Transform]>{\n|}"
},
"snippets": {
"!!!": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
}
},
"haml": {
"filters": "haml",
"extends": "html",
"profile": "xml"
},
"scss": {
"extends": "css"
},
"sass": {
"extends": "css"
},
"less": {
"extends": "css"
},
"stylus": {
"extends": "css"
}
}

View File

@@ -0,0 +1,52 @@
import sys
import sublime
import sublime_plugin
from trackers import back_track, track_regex, track_scope
__authors__ = ['"Sergey Chikuyonok" <serge.che@gmail.com>'
'"Nicholas Dudfield" <ndudfield@gmail.com>']
HTML = 'text.html - source'
XML = 'text.xml'
HTML_INSIDE_TAG_ANYWHERE = 'text.html meta.tag'
HTML_INSIDE_TAG = ( 'text.html meta.tag - string - '
'meta.scope.between-tag-pair.html '
'-punctuation.definition.tag.begin.html')
HTML_INSIDE_TAG_ATTRIBUTE = 'text.html meta.tag string'
HTML_NOT_INSIDE_TAG = 'text.html - meta.tag'
NO_PLUG = sublime.INHIBIT_EXPLICIT_COMPLETIONS
NO_BUF = sublime.INHIBIT_WORD_COMPLETIONS
EMMET_SCOPE = ', '.join([HTML, XML])
def find_tag_start(view, start_pt):
regions = back_track(view, start_pt, track_regex('<', False) )
return regions[-1].begin()
def find_tag_name(view, start_pt):
tag_region = view.find('[a-zA-Z:]+', find_tag_start(view, start_pt))
name = view.substr( tag_region )
return name
def find_attribute_name(view, start_pt):
conds = track_scope('string'), track_regex('\s|='), track_regex('\S')
regions = back_track(view, start_pt, *conds)
return view.substr(regions[-1])
def remove_html_completions():
for completer in "TagCompletions", "HtmlCompletions":
try:
import html_completions
cm = getattr(html_completions, completer)
except (ImportError, AttributeError):
continue
completions = sublime_plugin.all_callbacks['on_query_completions']
for i, instance in enumerate (completions):
if isinstance(instance, cm):
del completions[i]

View File

@@ -0,0 +1,66 @@
#!/usr/bin/env python
#coding: utf8
#################################### IMPORTS ###################################
# Std Libs
import re
# Sublime Libs
import sublime
import sublime_plugin
from collections import defaultdict
################################### CONSTANTS ##################################
# Directions for tracker
BACK = -1
FORWARD = 1
###################### VIEW TRACKERS ( CONTEXT SCANNERS ) ######################
def pt_range(view, start_pt, direction):
end_pt = direction
if end_pt != -1: end_pt = view.size()
return xrange(start_pt, end_pt, direction)
def region_from_pt_list(l):
if l:
l = sorted(l)
return sublime.Region(l[0], l[-1]+1)
def view_tracker(view, start_pt, *conds):
pts = defaultdict(list)
failed = False
for i, (direction, condition) in enumerate(conds):
for pt in pt_range(view, start_pt, direction):
if failed: break
if not condition(view, pt):
if not pts[i]: failed = True
start_pt = pt
break
if len(pts[i]) < 2:
pts[i].append(pt)
else:
pts[i][-1] = pt
return [ region_from_pt_list(pt_list) for pt_list in pts.values() ]
def tracker_success(regions):
return all(r is not None for r in regions)
def back_track(view, start_pt, *conds):
return view_tracker(view, start_pt -1, *((BACK, c) for c in conds))
################################### TRACKERS ###################################
def track_regex(r, cond=True):
return lambda v, p: bool(re.match(r, v.substr(p))) is cond
def track_scope(s, cond=True):
return lambda v, p: bool(v.match_selector(p, s)) is cond
################################################################################

View File

@@ -0,0 +1,4 @@
{
"install": "messages/install.txt",
"2013.02.27.00.00.00": "messages/official1.0.txt"
}

View File

@@ -0,0 +1,28 @@
New features:
Fuzzy search for CSS abbreviations
==================================
Emmet now supports fuzzy searching of unknowns CSS abbreviations.
For example, instead of using ov:h abbreviation to get overflow: hidden, you can write, ov-h, ovh or even oh.
Read more about fuzzy search feature:
http://docs.emmet.io/css-abbreviations/fuzzy-search/
Emmet CSS snippets in auto-complete popup
=========================================
All Emmet snippets are displayed in standard auto-complete popup,
so you don't need to remember them all: just start typing first
letters of required CSS snippet and let editor do the rest
(works with fuzzy search too).
To disable Emmet completions, set
"show_css_completions": false
preference in user's Emmet.sublime-settings
------------------------------
Follow me on Twitter: @emmetio
------------------------------

View File

@@ -0,0 +1,36 @@
Thank you for installing Emmet -- a toolkit that can greatly improve your workflow. Note that this plugin automatically downloads and installs PyV8 binary (see status bar message).
******************************
Please restart editor
to finish installation process
after PyV8 was downloaded.
******************************
Tab key handler
==========================
By default, Emmet allows you to expand abbreviations with Tab key in HTML, XML, HAML and CSS/SASS/LESS/Stylus documents. As a side effect, you cant use some of your ST2 snippets.
Please read https://github.com/sergeche/emmet-sublime#tab-key-handler about how Tab handler works and how to tweak its behavior to match your needs.
Enter key
==========================
In HTML and XML documents, Emmet overrides Enter key to insert formatted line breaks between opening and closing tags. In some cases it will break character input (for example, in Japanese language).
To disable Enter key handler, simply add the following option in your user's Preferences file:
"disable_formatted_linebreak": true
Actions shortcuts
==========================
Emmet has a number of actions with keyboard shortcuts that may override ones you're using commonly (for example, Ctrl-E or Ctrl-Down). Please read the project main page to get list of available actions and keyboard shortcuts and how to disable them:
https://github.com/sergeche/emmet-sublime
Documentation and examples:
http://emmet.io
------------------------------
Follow me on Twitter: @emmetio
------------------------------

View File

@@ -0,0 +1,16 @@
Emmet v1.0 is out!
==================
Check out features you might miss since beta release:
http://emmet.io/blog/emmet-v1/
If you like Emmet and wish to support further development,
any donations are highly appreciated:
http://emmet.io/donate/
------------------------------
Follow me on Twitter: @emmetio
------------------------------

View File

@@ -0,0 +1,253 @@
import os.path
import json
import copy
keymap = {
"expand_abbreviation": "ctrl+e",
"match_pair_outward": {"mac": "ctrl+d", "pc": "ctrl+,"},
"match_pair_inward": {"mac": "ctrl+j", "pc": "ctrl+shift+0"},
"matching_pair": {"mac": "ctrl+shift+t", "pc": "ctrl+alt+j"},
"next_edit_point": "ctrl+alt+right",
"prev_edit_point": "ctrl+alt+left",
"toggle_comment": {
"mac": "alt+shift+forward_slash",
"pc": "ctrl+shift+forward_slash",
"context": [{
"key": "selector",
"operand": "source.css - source.css.less, text.xml, text.html - source",
"operator": "equal"
}]
},
"split_join_tag": {"mac": "shift+super+'", "pc": "shift+ctrl+`"},
"remove_tag": {"mac": "super+'", "pc": "shift+ctrl+;"},
"evaluate_math_expression": {"mac": "shift+super+y", "pc": "shift+ctrl+y"},
"increment_number_by_1": "ctrl+up",
"decrement_number_by_1": "ctrl+down",
"increment_number_by_01": "alt+up",
"decrement_number_by_01": "alt+down",
"increment_number_by_10": {"mac": "alt+super+up", "pc": "shift+alt+up"},
"decrement_number_by_10": {"mac": "alt+super+down", "pc": "shift+alt+down"},
"select_next_item": {"mac": "shift+super+.", "pc": "shift+ctrl+."},
"select_previous_item": {"mac": "shift+super+,", "pc": "shift+ctrl+,"},
"reflect_css_value": {"mac": "shift+super+r", "pc": "shift+ctrl+r"},
"rename_tag": {"mac": "super+shift+k", "pc": "shift+ctrl+'"},
"encode_decode_data_url": {"mac": "shift+ctrl+d", "pc": "ctrl+'"},
"update_image_size": {"mac": "shift+ctrl+i", "pc": "ctrl+u"},
"expand_as_you_type": {
"keys": ["ctrl+alt+enter"],
"context": [{
"key": "setting.is_widget",
"operand": False,
"operator": "equal"
}]
},
"wrap_as_you_type": {
"mac": "ctrl+w",
"pc": "shift+ctrl+g",
"context": [{
"key": "setting.is_widget",
"operand": False,
"operator": "equal"
}]
}
}
# additional "raw" ST2 actions definition
addon = [
{
"keys": ["tab"],
"command": "expand_abbreviation_by_tab",
"context": [
{
"key": "selector",
"match_all": True,
"operand": "source.css, source.sass, source.less, source.scss, source.stylus, text.xml, text.html, text.haml, text.scala.html, source string",
"operator": "equal"
}, {
"key": "selector",
"operand": "text.html source.php, text.html source.js, storage.type.templatetag.django",
"operator": "not_equal",
"match_all": True
}, {
"key": "selection_empty",
"match_all": True
}, {
"key": "has_next_field",
"operator": "equal",
"operand": False,
"match_all": True
}, {
"key": "setting.disable_tab_abbreviations",
"operator": "equal",
"operand": False,
"match_all": True
}, {
"key": "auto_complete_visible",
"operand": False,
"operator": "equal",
"match_all": True
}, {
"key": "is_abbreviation",
"match_all": True
}
]
},
# behaviour of tab key when autocomplete popup is visible
{
"keys": ["tab"],
"command": "expand_abbreviation_by_tab",
"context": [
{
"key": "selector",
"match_all": True,
"operand": "source.css, source.sass, source.less, source.scss, source.stylus, text.xml, text.html, text.haml, text.scala.html, source string",
"operator": "equal"
}, {
"key": "selector",
"operand": "text.html source.php, text.html source.js, storage.type.templatetag.django",
"operator": "not_equal",
"match_all": True
}, {
"key": "selection_empty",
"match_all": True
}, {
"key": "has_next_field",
"operator": "equal",
"operand": False,
"match_all": True
}, {
"key": "auto_complete_visible",
"operator": "equal",
"operand": True,
"match_all": True
}, {
"key": "setting.disable_tab_abbreviations_on_auto_complete",
"operator": "equal",
"operand": False,
"match_all": True
}, {
"key": "is_abbreviation",
"match_all": True
}
]
},
# insert linebreak with formatting
{
"keys": ["enter"],
"command": "insert_snippet",
"args": {"contents": "\n\t${0}\n"},
"context": [
{
"key": "selector",
"operand": "meta.scope.between-tag-pair.html, meta.scope.between-tag-pair.xml",
"match_all": True
}, {
"key": "auto_complete_visible",
"operand": False,
"match_all": True
}, {
"key": "clear_fields_on_enter_key",
"match_all": True
}, {
"key": "setting.disable_formatted_linebreak",
"operand": False,
"match_all": True
}
]
},
{
"keys": ["#"],
"command": "emmet_insert_attribute",
"args": {"attribute": "id"},
"context": [
{
"key": "selector",
"match_all": True,
"operand": "text.html meta.tag -string -punctuation.definition.tag.begin.html -meta.scope.between-tag-pair.html -source -meta.tag.template.value.twig",
"operator": "equal"
}, {
"key": "setting.auto_id_class",
"operator": "equal",
"operand": True
}
]
},
{
"keys": ["."],
"command": "emmet_insert_attribute",
"args": {"attribute": "class"},
"context": [
{
"key": "selector",
"match_all": True,
"operand": "text.html meta.tag -string -punctuation.definition.tag.begin.html -meta.scope.between-tag-pair.html -source -meta.tag.template.value.twig",
"operator": "equal"
}, {
"key": "setting.auto_id_class",
"operator": "equal",
"operand": True
}
]
}
]
# header of generated file
header = "// This file is automatically generated with misc/generate-keymap.py script\n\n"
_dir = os.path.dirname(os.path.abspath(__file__))
standalone_actions = ["wrap_as_you_type", "expand_as_you_type", "rename_tag"]
def create_record(k, v, os_type):
if isinstance(v, basestring):
v = {"keys": [v]}
else:
v = copy.deepcopy(v)
if os_type in v:
v['keys'] = [v[os_type]]
if 'pc' in v:
del v['pc']
if 'mac' in v:
del v['mac']
if k in standalone_actions:
v['command'] = k
else:
v['command'] = 'run_emmet_action'
v['args'] = {"action": k}
if 'context' not in v:
v['context'] = []
v['context'].append({'key': 'emmet_action_enabled.%s' % k})
if len(v['context']) > 1:
for ctx in v['context']:
ctx['match_all'] = True
return v
def generate_keymap_file(path):
os_type = 'mac' if '(OSX)' in path else 'pc'
path = os.path.abspath(os.path.join(_dir, path))
print('Generate %s (%s)' % (path, os_type))
editor_keymap = [create_record(k, v, os_type) for k, v in keymap.items()] + addon
content = json.dumps(editor_keymap, indent=4)
f = open(path, 'w')
f.write(header + content)
f.close()
for path in ['../Default (OSX).sublime-keymap', '../Default (Windows).sublime-keymap', '../Default (Linux).sublime-keymap']:
generate_keymap_file(path)

View File

@@ -0,0 +1 @@
{"url": "http://emmet.io", "version": "2013.04.03.07.24.20", "description": "Emmet (ex-Zen Coding) for Sublime Text 2 plugin"}