├── .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" : "|\\*}|\\?>", 6 | 7 | // the contents of these tag blocks will be indented (add/remove as desired) 8 | "tag_indent": 9 | "\\{% (if|for|block|else|spaceless)|||||||||||||||||||||", 22 | 23 | // example (li): 24 | //
    25 | //
  • inline
  • 26 | //
  • 27 | //

    expanded

    28 | //
  • 29 | //
30 | 31 | // these tags use raw code and should flatten to column 1 32 | // tabs will be removed inside these tags! use spaces for spacing if needed! 33 | // example: " 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 |

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 |
  • inline
  • 55 |
  • 56 |

    expanded

    57 |
  • 58 |
59 | 60 | 61 | 62 |

text

63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 |
74 |
75 |

text

76 | 77 |
78 | 79 | 80 | 81 |
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 here
89 | 90 | 91 |
92 | 93 | 94 |
    95 |
  • one

  • 96 | 97 |
  • three
  • 98 |
99 | 105 | 106 | 109 |
110 | 111 |

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, 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.

114 | 115 |

Header Level 2

116 |
117 |
    118 |
  1. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
  2. 119 |
  3. Aliquam tincidunt mauris eu risus.
  4. 120 |
121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 |
132 |

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 |
144 | 145 |

Header Level 3

146 | 147 |
    148 |
  • Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
  • 149 |
  • Aliquam tincidunt mauris eu risus.
  • 150 |
151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # HTMLBeautify for Sublime Text 2 | HTMLBeautify for Sublime Text by Ross A. Reyman is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License. 3 | 4 | --- 5 | ## You are free: 6 | * to Share — to copy, distribute and transmit the work 7 | * to Remix — to adapt the work 8 | * to make commercial use of the work 9 | 10 | --- 11 | ## Under the following conditions: 12 | * Attribution — You must attribute the work in the manner specified by the author or licensor (but not in any way that suggests that they endorse you or your use of the work). 13 | * Share Alike — If you alter, transform, or build upon this work, you may distribute the resulting work only under the same or similar license to this one. 14 | 15 | --- 16 | ## With the understanding that: 17 | * Waiver — Any of the above conditions can be waived if you get permission from the copyright holder. 18 | * Public Domain — Where the work or any of its elements is in the public domain under applicable law, that status is in no way affected by the license. 19 | * Other Rights — In no way are any of the following rights affected by the license: 20 | * Your fair dealing or fair use rights, or other applicable copyright exceptions and limitations; 21 | * The author's moral rights; 22 | * Rights other persons may have either in the work itself or in how the work is used, such as publicity or privacy rights. 23 | * Notice — For any reuse or distribution, you must make clear to others the license terms of this work. The best way to do this is with a link to this web page. 24 | 25 | --- 26 | 27 | [CCA License](http://creativecommons.org/licenses/by-sa/3.0/deed.en_US) 28 | -------------------------------------------------------------------------------- /Main.sublime-menu: -------------------------------------------------------------------------------- 1 | [{ 2 | "caption": "Edit", 3 | "mnemonic": "E", 4 | "id": "edit", 5 | "children": [{ 6 | "caption": "-" 7 | }, { 8 | "command": "html_beautify", 9 | "id": "html_beautify", 10 | "caption": "Beautify HTML" 11 | }] 12 | }, { 13 | "caption": "Preferences", 14 | "mnemonic": "n", 15 | "id": "preferences", 16 | "children": [{ 17 | "caption": "Package Settings", 18 | "mnemonic": "P", 19 | "id": "package-settings", 20 | "children": [{ 21 | "caption": "HTMLBeautify", 22 | "children": [{ 23 | "command": "open_file", 24 | "args": { 25 | "file": "${packages}/HTMLBeautify/HTMLBeautify.sublime-settings" 26 | }, 27 | "caption": "Settings – Default" 28 | }, { 29 | "command": "open_file", 30 | "args": { 31 | "file": "${packages}/User/HTMLBeautify.sublime-settings" 32 | }, 33 | "caption": "Settings – User" 34 | }] 35 | }] 36 | }] 37 | }] -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # HTMLBeautify v0.85 2 | ## SublimeText (version 2 & 3) 3 | - (Inspired by fhtml.pl by John Watson) 4 | - by Ross A. Reyman 5 | - 20 February 2015 6 | - url: [http://reyman.name/](http://reyman.name/) 7 | - e-mail: ross[at]reyman[dot]name 8 | 9 | --- 10 | 11 | A plugin for [Sublime Text ](http://sublimetext.com/), that formats (indents) HTML source code. 12 | It makes code easier for humans to read. 13 | 14 | --- 15 | 16 | ## Key Commands Reverted Back to Original 17 | Due to a conflict with other keymaps in Sublime Text, I am reverting the keymap back to the original setting: 18 | 19 | - Mac OS X: `Command-Option-Shift-F` 20 | - Windows: `Control-Alt-Shift-F` 21 | - Linux: `Control-Alt-Shift-F` 22 | 23 | (To change this, see instructions later in this README…) 24 | 25 | ## Notes 26 | - This script assumes an effort has been made by the user to expand tags to different lines. This script will **not** automatically expand minimized/compressed code—it will only try to “clean-up” code that needs to be re-indented 27 | - However, you can use multiple cursors ([Find All][1]) or use [Replace][2] on the beginning of a tag `<` to put every tag on a new line before applying beautify, which will help in this case. 28 | - Currently, this script chokes a bit with inline comments. 29 | - For example: 30 | 31 | `
` 32 | - So, a workaround is to keep comments on their own lines: 33 | 34 | `` 35 | 36 | `
` 37 | 38 | `` 39 | - (TODO: Fix this!) 40 | 41 | - This script uses `\t` characters to create indentation levels and spacing—ST appears to honor whether the user prefers spaces or tabs in ST settings and adjusts accordingly. 42 | - Use `tag_pos_inline` setting to define tags that _might_ appear on one line. 43 | - Windows Users: You **must** restart Sublime Text to complete the installation. 44 | 45 | ## Installation (Package Control) 46 | If you have [Package Control](http://wbond.net/sublime_packages/package_control/installation) installed in Sublime Text: 47 | 48 | - Open the Command Palette (Tools > Command Palette…) 49 | - Search for and choose "Package Control: Install Package" (give it a few seconds to return a list of available packages) 50 | - Search for "HTMLBeautify" and install. 51 | - Windows users will **need** to restart Sublime Text to finish the installation. 52 | 53 | ## Installation (Manual) 54 | - Download the zip, re-name resulting folder to: `HTMLBeautify`, then put the folder into your Sublime Text Packages folder. 55 | 56 | ## Usage 57 | - Open a file containing HTML. 58 | - Select HTML code you want to beautify. (If no selection is made the plugin will run on the whole file.) 59 | - Use the appropriate key command to run HTMLBeautify—or use HTMLBeautify from the Edit menu. 60 | - You can test the script with `HTMLBeautifyTest.html`: an HTML file with wacky indenting so you to see how this script works. 61 | 62 | ## Settings 63 | You can configure which tags should be processed with this script: 64 | 65 | - `ignored_tag_opening` : What are the opening tags that tell the script to ignore HTMLBeautify formatting? 66 | - `ignored_tag_closing` : What are the closing tags that tell the script to resume HTMLBeautify formatting? 67 | 68 | - `tag_indent` : If one of these opening tags is encountered, the contents (next line) will be indented by one level. 69 | - `tag_unindent` : If one of these closing tags is encountered, the next line will be un-indented one level. 70 | - `tag_unindent_line` : If one of these closing tags is encountered, this line is un-indented one level. 71 | 72 | - `tag_pos_inline` : These are special “one line” tags that open and close on the same line, so indenting should be ignored. 73 | 74 | - `remove_extraline` : Set true to remove empty line. 75 | 76 | ## Changing the Key Binding 77 | You can create your own custom keymap (key command/macro) in your keymap file: `Packages/User/Default[OS].sublime-keymap` 78 | 79 |
 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 | --------------------------------------------------------------------------------