├── .gitignore ├── Default (Linux).sublime-keymap ├── Default (OSX).sublime-keymap ├── Default (Windows).sublime-keymap ├── Default.sublime-commands ├── HTMLBeautify.py ├── HTMLBeautify.sublime-settings ├── HTMLBeautifyTest.html ├── LICENSE.md ├── Main.sublime-menu └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | -------------------------------------------------------------------------------- /Default (Linux).sublime-keymap: -------------------------------------------------------------------------------- 1 | [{ 2 | "keys": ["ctrl+alt+shift+f"], 3 | "command": "html_beautify", 4 | "context": [{ 5 | "key": "selector", 6 | "operator": "equal", 7 | "operand": "text.html,text.html.twig,text.twig,source.html,source.html.twig,source.twig" 8 | }] 9 | }] -------------------------------------------------------------------------------- /Default (OSX).sublime-keymap: -------------------------------------------------------------------------------- 1 | [{ 2 | "keys": ["super+alt+shift+f"], 3 | "command": "html_beautify", 4 | "context": [{ 5 | "key": "selector", 6 | "operator": "equal", 7 | "operand": "text.html,text.html.twig,text.twig,source.html,source.html.twig,source.twig" 8 | }] 9 | }] -------------------------------------------------------------------------------- /Default (Windows).sublime-keymap: -------------------------------------------------------------------------------- 1 | [{ 2 | "keys": ["ctrl+alt+shift+f"], 3 | "command": "html_beautify", 4 | "context": [{ 5 | "key": "selector", 6 | "operator": "equal", 7 | "operand": "text.html,text.html.twig,text.twig,source.html,source.html.twig,source.twig" 8 | }] 9 | }] -------------------------------------------------------------------------------- /Default.sublime-commands: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "caption": "HTMLBeautify", 4 | "command": "html_beautify" 5 | } 6 | ] -------------------------------------------------------------------------------- /HTMLBeautify.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # HTMLBeautify (for Sublime Text 2 & 3) v0.85 (Antonio Gates Edition) 4 | # (Inspired by fhtml.pl by John Watson) 5 | # by Ross A. Reyman 6 | # 20 February 2015 7 | # url: http://reyman.name/ 8 | # e-mail: ross[at]reyman[dot]name 9 | 10 | import sublime, sublime_plugin, re 11 | 12 | settings = None 13 | def plugin_loaded(): 14 | global settings 15 | 16 | # this file contains the tags that will be indented/unindented, etc. 17 | settings = sublime.load_settings('HTMLBeautify.sublime-settings') 18 | 19 | class PreSaveFormatListener(sublime_plugin.EventListener): 20 | """Event listener to run HtmlBeautify during the presave event""" 21 | def on_pre_save(self, view): 22 | if settings.get('format_on_save') and view.file_name().lower().endswith('.html'): 23 | view.run_command('html_beautify') 24 | 25 | class HtmlBeautifyCommand(sublime_plugin.TextCommand): 26 | def run(self, edit): 27 | 28 | # the contents of these tags will not be indented 29 | ignored_tag_opening = settings.get('ignored_tag_opening') 30 | ignored_tag_closing = settings.get('ignored_tag_closing') 31 | 32 | # the content of these tags will be indented 33 | tag_indent = settings.get('tag_indent') 34 | 35 | # these tags will be un-indented 36 | tag_unindent = settings.get('tag_unindent') 37 | 38 | # the line will be un-indented and next line will be indented 39 | tag_unindent_line = settings.get('tag_unindent_line') 40 | 41 | # these tags may occur inline and should not indent/unindent 42 | tag_pos_inline = settings.get('tag_pos_inline') 43 | 44 | # remove extra line (empty) 45 | remove_extraline = settings.get('remove_extraline') 46 | 47 | # flatten tags and contents to column 1, removing tabs! 48 | tag_raw_flat_opening = settings.get('tag_raw_flat_opening') 49 | tag_raw_flat_closing = settings.get('tag_raw_flat_closing') 50 | 51 | # determine if applying to a selection or applying to the whole document 52 | if self.view.sel()[0].empty(): 53 | # nothing selected: process the entire file 54 | region = sublime.Region(0, self.view.size()) 55 | sublime.status_message('Beautifying Entire File') 56 | rawcode = self.view.substr(region) 57 | # print region 58 | else: 59 | # process only selected region 60 | region = self.view.line(self.view.sel()[0]) 61 | sublime.status_message('Beautifying Selection Only') 62 | rawcode = self.view.substr(self.view.sel()[0]) 63 | # print region 64 | 65 | # print rawcode 66 | 67 | # remove leading and trailing white space 68 | rawcode = rawcode.strip() 69 | # print rawcode 70 | 71 | # put each line into a list 72 | rawcode_list = re.split('\n', rawcode) 73 | # print rawcode_list 74 | 75 | # cycle through each list item (line of rawcode_list) 76 | rawcode_flat = "" 77 | is_block_ignored = False 78 | is_block_raw = False 79 | 80 | for item in rawcode_list: 81 | # print item.strip() 82 | # remove extra "spacer" lines 83 | if item == "" and remove_extraline: 84 | continue 85 | # ignore raw code 86 | if re.search(tag_raw_flat_closing, item, re.IGNORECASE): 87 | tmp = item.strip() 88 | is_block_raw = False 89 | elif re.search(tag_raw_flat_opening, item, re.IGNORECASE): 90 | tmp = item.strip() 91 | is_block_raw = True 92 | # find ignored blocks and retain indentation, otherwise: strip whitespace 93 | if re.search(ignored_tag_closing, item, re.IGNORECASE): 94 | tmp = item.strip() 95 | is_block_ignored = False 96 | elif re.search(ignored_tag_opening, item, re.IGNORECASE): 97 | # count tabs used in ignored tags (for use later) 98 | ignored_block_tab_count = item.count('\t') 99 | tmp = item.strip() 100 | is_block_ignored = True 101 | # not filtered so just output it 102 | else: 103 | if is_block_raw == True: 104 | # remove tabs from raw_flat content 105 | tmp = re.sub('\t', '', item) 106 | elif is_block_ignored == True: 107 | tab_count = item.count('\t') - ignored_block_tab_count 108 | tmp = '\t' * tab_count + item.strip() 109 | else: 110 | tmp = item.strip() 111 | 112 | rawcode_flat = rawcode_flat + tmp + '\n' 113 | 114 | # print rawcode_flat 115 | 116 | # put each line into a list (again) 117 | rawcode_flat_list = re.split('\n', rawcode_flat) 118 | # print rawcode_flat_list 119 | 120 | # cycle through each list item (line of rawode_flat_list) again - this time: add indentation! 121 | beautified_code = "" 122 | 123 | indent_level = 0 124 | is_block_ignored = False 125 | is_block_raw = False 126 | 127 | for item in rawcode_flat_list: 128 | # if a one-line, inline tag, just process it 129 | if re.search(tag_pos_inline, item, re.IGNORECASE): 130 | tmp = ("\t" * indent_level) + item 131 | # if unindent, move left 132 | elif re.search(tag_unindent, item, re.IGNORECASE): 133 | indent_level = indent_level - 1 134 | tmp = ("\t" * indent_level) + item 135 | elif re.search(tag_unindent_line, item, re.IGNORECASE): 136 | tmp = ("\t" * (indent_level - 1)) + item 137 | # if indent, move right 138 | elif re.search(tag_indent, item, re.IGNORECASE): 139 | tmp = ("\t" * indent_level) + item 140 | indent_level = indent_level + 1 141 | # if raw, flatten! no indenting! 142 | elif re.search(tag_raw_flat_opening, item, re.IGNORECASE): 143 | tmp = item 144 | is_block_raw = True 145 | elif re.search(tag_raw_flat_closing, item, re.IGNORECASE): 146 | tmp = item 147 | is_block_raw = False 148 | else: 149 | if is_block_raw == True: 150 | tmp = item 151 | # otherwise, just leave same level 152 | else: 153 | tmp = ("\t" * indent_level) + item 154 | 155 | beautified_code = beautified_code + tmp + '\n' 156 | 157 | # remove leading and trailing white space 158 | beautified_code = beautified_code.strip() 159 | 160 | # print beautified_code 161 | 162 | # replace the code in Sublime Text 163 | self.view.replace(edit, region, beautified_code) 164 | 165 | # done 166 | -------------------------------------------------------------------------------- /HTMLBeautify.sublime-settings: -------------------------------------------------------------------------------- 1 | { 2 | // indicates tags whose contents should be ignored (add more as needed) 3 | "ignored_tag_opening" : "|
expanded
28 | //2 | 3 | 4 | 5 |6 | 7 | 8 | 9 | 10 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 43 | 44 | 45 | 46 | 47 |110 | 111 |Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium. 48 |
49 | 50 | 51 | 52 | 53 |54 |
59 | 60 | 61 | 62 |- inline
55 |- 56 |
58 |expanded
57 |text
63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 |74 |92 | 93 | 94 |75 |78 | 79 | 80 | 81 |text
76 | 77 |This text has 82 | been formatted using 83 | the HTML pre tag. The brower should 84 | display all white space as it was entered. 85 | 86 | I used TABS here, which the script will remove 87 | I used SPACES here, which the script will not remove 88 | more text and finally, it is ok to close pre here89 | 90 | 91 |95 |
99 | 105 | 106 | 109 |- 96 | 97 |
one
- three
98 |Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
112 |
113 |Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo. Quisque sit amet est et sapien ullamcorper pharetra. Vestibulum erat wisi, condimentum sed,
114 | 115 |commodo vitae
, ornare sit amet, wisi. Aenean fermentum, elit eget tincidunt condimentum, eros ipsum rutrum orci, sagittis tempus lacus enim ac dui. Donec non enim in turpis pulvinar facilisis. Ut felis.Header Level 2
116 |
117 |118 |
121 | 122 | 123 | 124 |- Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
119 |- Aliquam tincidunt mauris eu risus.
120 |125 | 126 |
127 | 128 | 129 | 130 | 131 |
132 |144 | 145 |Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus magna. Cras in mi at felis aliquet congue. Ut a est eget ligula molestie gravida. Curabitur massa. Donec eleifend, libero at sagittis mollis, tellus est malesuada tellus, at luctus turpis elit sit amet quam. Vivamus pretium ornare est.
133 |134 | Alternate way to code paragraphs. 135 |
136 | 137 | 138 |
139 | 140 | 141 |
142 | 143 |Header Level 3
146 | 147 |
80 | { 81 | "keys": ["super+alt+shift+f"], // create your own key command combination here! 82 | "command": "html_beautify", // command that executes html_beautify 83 | "context": [{ 84 | // these options ensure that the command is executed in the right files/context 85 | "key": "selector", 86 | "operator": "equal", 87 | "operand": "text.html,text.html.twig,text.twig,source.html,source.html.twig,source.twig" 88 | }] 89 | } 90 |91 | 92 | For more details: [Sublime Text Unofficial Documentation: Key Bindings](http://sublime-text-unofficial-documentation.readthedocs.org/en/sublime-text-2/reference/key_bindings.html) 93 | 94 | 95 | ## Disclaimer 96 | This script has been tested for basic HTML coding situations, but your mileage may vary—use with caution if using this in a production environment. (Please report bugs or contribute corrections to the script!) Although the script does not remove or modify code directly (it only attempts to adjust indentation levels), be sure to test this script throughly to make sure it works as expected! The author is not responsible for any bugs that might be introduced to your HTML. :) 97 | 98 | [1]: https://www.sublimetext.com/docs/2/multiple_selection_with_the_keyboard.html 99 | [2]: http://sublime-text-unofficial-documentation.readthedocs.org/en/latest/search_and_replace/search_and_replace.html#replacing-text 100 | --------------------------------------------------------------------------------