ctrl+shift+p filters: :st2 :st3 :win :osx :linux
Browse

Formatter

by bitst0rm ST3 Trending

πŸ§œβ€β™€οΈ A Sublime Text plugin to beautify and minify source code: CSS, SCSS, Sass, HTML, XML, SVG, JavaScript, JSON, GraphQL, Markdown, TypeScript, Vue, Lua, YAML, Go, Perl, PHP, Python, Ruby, Rust, Haskell, Dart, Swift, Crystal, Bash, Shell, SQL, CSV, C, C++, C#, Objective-C, D, Java, Pawn, VALA, Proto, LaTeX, D2, Graphviz, Mermaid, PlantUML, etc.

Details

Installs

  • Total 123K
  • Win 71K
  • Mac 33K
  • Linux 19K
Apr 27 Apr 26 Apr 25 Apr 24 Apr 23 Apr 22 Apr 21 Apr 20 Apr 19 Apr 18 Apr 17 Apr 16 Apr 15 Apr 14 Apr 13 Apr 12 Apr 11 Apr 10 Apr 9 Apr 8 Apr 7 Apr 6 Apr 5 Apr 4 Apr 3 Apr 2 Apr 1 Mar 31 Mar 30 Mar 29 Mar 28 Mar 27 Mar 26 Mar 25 Mar 24 Mar 23 Mar 22 Mar 21 Mar 20 Mar 19 Mar 18 Mar 17 Mar 16 Mar 15 Mar 14 Mar 13
Windows 15 40 42 34 35 41 18 22 34 49 57 37 32 19 15 29 25 34 32 28 29 13 26 39 26 24 49 10 17 39 38 51 34 24 20 24 28 45 34 37 29 23 23 48 40 40
Mac 18 28 44 30 27 35 22 18 25 28 34 37 36 17 12 20 32 25 29 21 13 11 24 12 20 25 29 7 15 17 22 29 36 21 5 18 22 24 28 27 20 7 9 15 22 27
Linux 8 18 22 30 17 10 12 14 15 15 15 18 31 10 3 3 6 6 6 6 5 4 8 10 9 6 8 4 14 8 12 13 14 7 9 4 14 5 17 9 7 8 6 11 11 13

Readme

Source
raw.​githubusercontent.​com

πŸ§œβ€β™€οΈ Formatter

Formatter is a simple config-file-driven plugin for Sublime Text 3 & 4 to beautify and minify source code.

Key features:

  • Supports more than 70 major programming languages.
  • Includes over 80 preset adapters for various plugins.
  • Formats text in various ways:
    • Text-to-Text (Text diagramms, ASCII art, etc.)
    • Text-to-Image (Image diagramms, QR-code images, etc.)
  • Capable to format entire files, single or multiple selections.
  • Capable to format entire folder recursively.
  • Operates based on syntax scope, not file extension.
  • Works with both saved and unsaved files.
  • Unified settings across different systems.
  • Supports auto-detect formatting.
  • Supports per-project formatting.
  • Capable to format on Save.
  • Capable to format on Paste.
  • Shared config files available for each 3rd-party plugin.
  • Displays real-time word and character counts.
  • Automatically remembers and restores text position.
  • Customizable and extendable through 2 methods to add your custom plugins:
    • Generic: Adding a portion JSON settings (no coding needed). see Configuration
    • Modules: Integration of your own modules. see Development
  • Zero dependencies for installation.
  • Open source and works offline.

Limitations:

  • Text-to-Image: Third-party plugins often rely on a headless browser to render images, making the process time-consuming. Consequently:

    • "recursive_folder_format" will not be implemented or is disabled.
    • "new_file_on_format" will not be implemented or is disabled.
    • Third-party plugins must support exporting PNG format as Sublime Text only supports PNG, JPG, and GIF images.

Formatter in action: Text-to-Text…

Formatter

Formatter in action: Text-to-Image…

Formatter

Guides

Plugins

Formatter is useless without third-party plugins. It relies on external plugins in order to format code. These plugins need to be installed by the end-user. This means, Formatter is not responsible for:

  • The quality of formatted code.
  • The speed of the formatting process.

The complete list of supported plugins: Need more? see: Configuration and Development to add your own.

  • This table does not contain the complete languages that each plugin does support. For example, prettydiff supports 45 languages, that would blow up the frame of this list here.
  • Languages such as Svelte or Prisma are not listed here, but can be used through the prettier plugin. deno and dprint should have the similar concept.
  • build-in = do not need to install by end-users.
  • None = mostly standalone binary.
  • Req. = Requirements might not be up-to-date.
Languages Beautify Minify Graphic Req. Config
Angular prettier, prettierd – – Node.js –
Arduino uncrustify[1], clang-format[2], artistic style – – None [1], [2]
Assembly asmfmt, nasmfmt – – None –
Astro prettier, prettierd – – Node.js –
BibTeX bibtex-tidy[1] – – Node.js 12.0+ [1]
C, C++, C#, Objective-C uncrustify[1], clang-format[2], artistic style – – None [1], [2]
Cabal cabal-fmt – – Haskell –
Caddyfile caddy-fmt – – None –
Clojure cljfmt, zprint – – None, (Java) –
CMake cmake-format – – Python –
Crystal crystal tool format – – None –
CSS, SCSS, Sass, Less, SugarSS stylelint[1], js-beautifier, prettier, prettierd, prettydiff[2], csscomb, stylefmt cleancss CLI, prettydiff[2] – Node.js [1], [2]
CSV, TSV, DSV, Text prettytable (build-in), prettydiff[1][2] – – Python, Node.js[2] [1]
D uncrustify[1] – – None [1]
D2 d2 fmt – d2 None –
Dart dart-format – – Dart –
Dhall dhall format – – None –
Dockerfile dockfmt – – None –
Drawio – – draw.io None –
Elixir mix format – – Erlang –
Elm elm-format – – None –
Erlang erlfmt[1], efmt – – rebar3[1], None –
Fortran fprettify – – Python –
Gleam gleam format – – None –
GLSL clang-format[1] – – None [1]
Go gofmt, goimports, gofumpt – – None –
GraphQL prettier, prettierd – – Node.js –
Graphviz – – graphviz None –
Haskell ormolu, fourmolu[1], hindent, stylish-haskell, floskell – – Haskell [1]
HCL hclfmt – – None –
HTML, XHTML, XML js-beautifier, prettier, prettierd, prettydiff[1], html-tidy html-minifier, prettydiff[1] – Node.js [1]
Java google java format[1], uncrustify[2], clang-format[3], artistic style – – Java[1], None [2], [3]
JavaScript eslint, eslint_d, js-beautifier, prettier, prettierd, standard js, standardx js, semistandard js, prettydiff, clang-format[1][2], deno[2], dprint[2] terser, prettydiff – Node.js, None[2] [1]
JSON js-beautifier, prettier, prettierd, prettydiff[1], deno[2], topiary[2], dprint[2], jsonmax (build-in) prettydiff[1], jsonmin (build-in) – Node.js, None[2] [1]
Kotlin ktlint – – Java –
LaTeX latexindent – – Perl, None –
Lua stylua, luaformatter – – None –
Markdown prettier, prettierd, deno[1], dprint[1] – – Node.js, None[1] –
Mermaid – – mermaid[1] Node.js [1]
Nginx nginxfmt – – Python 3.4+ –
Nickel topiary – – None –
OCaml ocamlformat, ocp-indent, topiary – – None –
Perl perltidy – – Perl –
Pawn uncrustify[1] – – None [1]
PHP php-cs-fixer[1], php_codesniffer – – PHP 7.4+[1] [1]
Plantuml plantumlascii – plantuml Java –
Proto clang-format[1] – – None[1] [1]
Python ruff, yapf, black[1], autopep8, isort, docformatter, pyment python-minifier[2] – Python 3.7+[1] [2]
R styler, formatR[1] – – R [1]
Racket raco fmt – – Racket 8.0+ –
Ruby rubocop[1], rubyfmt, standardrb, rufo[1] – – Ruby[1], None –
Rust rustfmt – – Rust 1.24+ –
Scala scalafmt, scalariform[1] – – None, Java[1] –
Shell, Bash beautysh[1], shfmt, shellcheck shfmt – Python[1], None –
SQL, SQL dialects, PostgreSQL sql-formatter[1], pg_format[2], sqlparse[3] sqlmin (build-in) – Node.js[1], Perl[2], Python 3.6+[3] [1], [2]
Swift apple swift-format, swiftformat – – None –
SVG svgo max svgo min – Node.js –
TableGen clang-format[1] – – None [1]
Terraform terraform fmt – – None –
TextProto clang-format[1] – – None [1]
TOML taplo, topiary, dprint – – None –
TypeScript prettier, prettierd, js-beautifier, ts-standard, prettydiff[1], tsfmt, deno, dprint prettydiff[1] – Node.js [1]
VALA uncrustify[1] – – None [1]
Verilog clang-format[1] – – None [1]
Vue prettier, prettierd, js-beautifier – – Node.js –
YAML prettier, prettierd – – Node.js –
Zig zigfmt – – None –

πŸ’‘ Tips:

  • prettier and stylelint and can collaborate to format CSS

    Config example

    stylelint_rc.json:
    {"extends":["stylelint-config-recommended","stylelint-config-standard"],"plugins":["stylelint-group-selectors","stylelint-no-indistinguishable-colors","@double-great/stylelint-a11y","stylelint-prettier"],"rules":{"plugin/stylelint-group-selectors":true,"plugin/stylelint-no-indistinguishable-colors":true,"a11y/content-property-no-static-value":false,"a11y/font-size-is-readable":false,"a11y/line-height-is-vertical-rhythmed":[true,{"severity":"warning"}],"a11y/media-prefers-color-scheme":false,"a11y/media-prefers-reduced-motion":false,"a11y/no-display-none":false,"a11y/no-obsolete-attribute":[true,{"severity":"warning"}],"a11y/no-obsolete-element":[true,{"severity":"warning"}],"a11y/no-outline-none":false,"a11y/no-spread-text":false,"a11y/no-text-align-justify":false,"a11y/selector-pseudo-class-focus":false,"prettier/prettier":[true,{"parser":"css","printWidth":120,"semi":true,"singleQuote":false,"tabWidth":4,"useTabs":false}]}}
    
    Then in Formatter settings > "stylelint": { ... "args": ["--config-basedir", "/absolute/path/to/javascript/node_modules"] ... }
    

  • prettier and eslint can collaborate to format JS

    Config example

    eslint_rc.json:
    {"env":{"es2022":true,"node":true,"browser":true},"parserOptions":{"ecmaVersion":13,"sourceType":"module","ecmaFeatures":{"jsx":true}},"extends":["../javascript/node_modules/eslint-config-prettier","../javascript/node_modules/eslint-config-airbnb-base"],"plugins":["eslint-plugin-prettier"],"rules":{"prettier/prettier":["error",{"bracketSpacing":true,"jsxSingleQuote":true,"parser":"babel","printWidth":120,"semi":true,"singleQuote":true,"tabWidth":4,"useTabs":false},{"usePrettierrc":false}],"indent":["error",4]}}
    

Installation

  • Using Package Control: run Package Control: Install Package and select Formatter
  • or Download: the latest source from GitHub to your sublime Packages directory and rename it to Formatter

The Packages directory is located in:

  • MacOSX: ~/Library/Application Support/Sublime Text 3/Packages/
  • Linux: ~/.config/sublime-text-3/Packages/
  • Windows: %APPDATA%/Sublime Text 3/Packages/

Configuration

This section is the head of Formatter. While the configuration is easy and self-explained, it still needs a detailed explanation of the underlying principles and context. Hold on for a long text.

Formatter stores third-party plugin config files in:

Sublime Text > Packages > User > formatter.assets > config

You can use these files directly or place them in a location of your choice. Formatter provides only a set of default (original) config files to illustrate how it works. You might want to tweak and refine them to fit your needs. The full list of supported options and parameters can be found on plugins dev websites.
Note: Do not use files with the suffix .master. as they serve as reference(example) files for your final configuration and could be overwritten by any package updates: Some exotic plugins do not support input config file, while others do not understand stdio. To overcome this limitation, you will need these example files as reference to configure them.
It is recommended to explore this folder, as it may contain additional config files for the same plugin.

Formatter settings can be accessed from: Preferences > Package Settings > Formatter > Settings

The following setting details - along with their default values and examples - are provided to guide you on how to set it up. Options are flexible, you do not need to take the whole set of options. Just take the ones you need, but keep the json structure be intact.

Starting from version 1.2.0, Formatter provides 2 methods to add third-party plugins:

  • Generic: simple, no need coding, using just a simple portion of JSON dict.
  • Modules: advanced, more powerful but needs writing and integrating python modules to hack deeper.

Both methods with examples are in this settings guide:

πŸ’‘ Tips:

  • You are not forced to use the preset modules. Instead, you can create a new one using a different UID key through either of these methods.
  • Not all syntax highlighting plugins for a specific language exist; syntaxes like "text" or "plain" work just as well as a workaround.
{
    // Enable debug mode to view errors in the console.
    // Accepted values: true (verbose), false, OR "status" (minimal info)
    "debug": false,

    // Auto open the console panel whenever formatting failed.
    // This is useful when combined with "debug": "status" or true
    "open_console_on_failure": false,

    // Timeout to abort subprocess in seconds.
    // Default to 10 seconds. Set to false to disable the timeout.
    "timeout": 10,

    // Integrate your custom modules into the Formatter ecosystem.
    // This option ensures that your own modules won't be automatically removed
    // from Packages Control during any release updates. It also spares you the trouble
    // of having to submit pull requests to get your own modules integrated.
    // For security reasons, Formatter never communicates over the Internet:
    // All paths to files and folders must be local.
    "custom_modules": {
        "config": ["/path/to/foo_rc.json", "/path/to/bar_rc.cfg"],
        "modules": ["/path/to/formatter_foo.py", "/path/to/formatter_bar.py"],
        "libs": ["/path/to/foolib", "/path/to/mylib"]
    },

    // Display results in the status bar.
    // The displayed abbreviation for the current settings mode:
    // PUS: Persistent User Settings
    // PQO: Persistent Quick Options
    // TQO: Temporary Quick Options
    "show_statusbar": true,

    // Display a real-time word and character count in the status bar.
    // By default, whitespace is not included in the character count.
    "show_words_count": {
        "enable": true,
        "ignore_whitespace_char": true
    },

    // Remember and restore cursor position, selections and bookmarks
    // each time a file is closed and re-opened.
    // This is helpful to resume your work from where you left off.
    // It does not remember the whole session as name might suggest.
    "remember_session": true,

    // Configure the layout when opening new files.
    // This setting takes effect when the "new_file_on_format" option is enabled.
    // Available choices include 2-columns, 2-rows or single layout.
    // To revert to the Sublime default layout:
    // View > Layout > Single
    // Accepted values: "2cols", "2rows", "single" OR false
    "layout": {
        "enable": "2cols",
        "sync_scroll": true
    },

    // A set of directories where executable programs are located.
    // It can be absolute paths to module directories, python zipfiles.
    // Any environment variables like PATH, PYTHONPATH, GEM_PATH, GOPATH,
    // GOROOT, GOBIN, TMPDIR, WHATEVER, etc. can be added here.
    // This option is similar to running 'export PYTHONPATH="/path/to/my/site-packages"'
    // from terminal. But it is only temporary in the memory and will only apply
    // for the current formatting session. Your system environment remains untouched.
    // Non-existent environment directories and files will be silently ignored.
    // This option can be ommitted, but for python, ruby and erlang you probably need
    // to add it. In debug mode, Formatter will display your current system environments
    // to assist you in configuration. On Windows, you can use either escaped
    // backslashes (e.g., "C:\\a\\b\\c") or forward slashes (e.g., "C:/a/b/c")
    // as path separators for all other options in this file as well.
    "environ": {
        "PATH": ["/path/to/erlang@22/bin:$PATH", "$PATH:/path/to/elixir/bin", "/path/to/.cache/rebar3/bin:$PATH"],
        "GEM_PATH": ["${HOME}/to/my/ruby"],
        "PYTHONPATH": ["${packages}/User/MyFolder/python/lib/python3.7/site-packages"],
        "OLALA": ["$HOME/.cabal/bin:$PATH", "~/.olala/bin:$PATH"]
    },

    // This option addresses the syntaxes conflict described in "format_on_save".
    // It serves as a takeover and only applies to the following options:
    // 1. "format_on_save"
    // 2. "format_on_paste"
    // Syntaxes in this option always take precedence over the syntaxes specified there.
    // All syntaxes must be unique without any duplicates.
    "format_on_unique": {
        "enable": false,
        "csscomb": ["css"],
        "jsbeautifier": ["js"]
    },

    // This option enables auto-detect formatting for file with a single command.
    // You can configure it either here and/or by using the dot files in your working folder.
    // If you use both methods, the config from the dot files will override the one embedded here.
    // More about this feature and its structure: see README.md > Auto-detect Formatting
    "auto_format": {
        "config": {
            "format_on_save": false,
            "format_on_paste": false
        },
        "json": {
            "uid": "jsbeautifier"
        },
        "html": {
            "uid": "jsbeautifier",
            "exclude_syntaxes": {
                "html": ["markdown"]
            }
        },
        "python": {
            "uid": "autopep8"
        }
    },

    // THIRD-PARTY PLUGINS LEVEL
    "formatters": {
        "examplegeneric": { // GENERIC METHOD
            // Formatter provides 2 methods to add custom plugins:
            // - Generic: this one, you design the bridge yourself. Suitable for simple tasks.
            // - Modules: hacking deeper where generic cannot, needs writing python modules.
            // Note: Generic method requires an Sublime Text restart after adding or changing
            // the keys: "name" and "type". Also avoid using the same existing uid key in JSON.

            // Capitalized Plugin name. REQUIRED! REQUIRED! REQUIRED!
            // This will appear on the sublime menu and on other important commands.
            "name": "Example Generic",

            // Plugin type. REQUIRED! REQUIRED! REQUIRED!
            // This will be assigned to a category. Accepted values:
            // "beautifier" OR "minifier" OR "converter" OR "graphic" OR any string of your choice.
            "type": "beautifier",

            // This will activate the option "args_extended" for type graphic
            // to generate extended files like SVG to download.
            "render_extended": false,

            // The exit code of the third-party plugin.
            // This option can be omitted. Type integer, default to 0.
            "success_code": 0,

            // Same as examplemodule options.
            "enable": false,
            // Same as examplemodule options.
            "format_on_save": false,
            // Same as examplemodule options.
            "format_on_paste": false,
            // Same as examplemodule options. (disabled/unused for type graphic)
            "new_file_on_format": false,
            // Same as examplemodule options. (disabled/unused for type graphic)
            "recursive_folder_format": {},
            // Same as examplemodule options.
            "syntaxes": ["css", "html", "js", "php"],
            // Same as examplemodule options.
            "exclude_syntaxes": {},
            // Same as examplemodule options.
            "interpreter_path": ["${HOME}/example/path/to\\$my/php.exe"],
            // Same as examplemodule options.
            "executable_path": ["${HOME}/example/path/to\\$my/php-cs-fixer.phar"],
            // Same as examplemodule options.
            "config_path": {
                "css": "${packages}/User/formatter.assets/config/only_css_rc.json",
                "php": "${packages}/User/formatter.assets/config/only_php_rc.json",
                "default": "${packages}/User/formatter.assets/config/css_plus_js_plus_php_rc.json"
            },

            // These are the main commands to trigger the formatting process.
            // You can either pass the paths directly or use variable substitution for the following options:
            // - "interpreter_path"   : "{{i}}"
            // - "executable_path"    : "{{e}}", "{{e=node}}" (to auto resolve the local executable with runtime type node)
            // - "config_path"        : "{{c}}"
            // - SPECIAL CASE GRAPHIC : "{{o}}" (output PNG image, e.g: "args": [... "--output", "{{o}}"])
            // Variable substitution offers more advanced mechanisms such as auto-search path, auto-config, etc.
            // Requirements to use the SPECIAL CASE GRAPHIC:
            // 1. Third-party plugins MUST support exporting PNG format.
            // 2. The hardcoded "{{o}}" MUST ALWAYS be set inside "args".
            //    You might regret using your own path instead of "{{o}}" or daring to omit "{{o}}" in this case.
            // In all other cases, output may not be as a file; use "-" or "--" instead.
            "args": ["{{i}}", "{{e=node}}", "--config", "{{c}}", "--basedir", "./example/my/foo", "--"],

            // This is for the SPECIAL CASE GRAPHIC to offer downloading extended graphic files.
            // To use this, the trigger option "render_extended" above must be activated.
            // Sublime Text only supports PNG, JPG, and GIF images. Formatter uses PNG to display
            // image in view and generates the same image in various formats for you.
            // WARNING: Formatter will loop subprocess to render extended files. This means, process
            // will takes more time. This option might be useful for the final step to production.
            // "key":["value",..], where key is the output file extension, value is the command arguments.
            "args_extended": {
                "svg": ["{{e}}", "--config", "{{c}}", "--blabla-format", "svgv5", "--output", "{{o}}"],
                "pdf": ["{{e}}", "--config", "{{c}}", "--blabla-format", "pdf2001", "--output", "{{o}}"]
            }
        },
        "examplemodule": { // MODULE METHOD
            // Plugin activation.
            // By default, all plugins are disabled and disappear from the menu.
            "enable": false,

            // Auto formatting whenever the current file/view is being saved.
            // This option should be used for plugins with unique syntaxes.
            // For multi plugins with the same syntaxes, the first plugin takes precedence.
            // Remove the identical syntaxes from one of the plugins to avoid conflicts.
            // For example:
            // Plugin A (enabled): syntaxes ["css", "js"]
            // Plugin B (enabled): syntaxes ["html", "css"]
            // In the case you want to use Plugin B with "css", then you should remove
            // the "css" from plugin A or just disable it, as there is no guarantee of the
            // execution order between the two, and determining your favorist is not possible.
            // Solution: Use the "format_on_unique" option to workaround this.
            "format_on_save": false,

            // Auto formatting whenever code is pasted into the current file/view.
            // This option is affected by the same syntax conflict, so its solutions
            // are identical to those mentioned above for the "format_on_save" option.
            "format_on_paste": false,

            // Create a new file containing formatted codes.
            // The value of this option is the suffix of the new file being renamed.
            // Suffix must be of type string. =true, =false and all other types imply =false
            // Note: It will overwrite any existing file that has the same new name in
            // the same location.
            // For example:
            // "new_file_on_format": "min", will create a new file:
            // myfile.raw.js -> myfile.raw.min.js
            "new_file_on_format": false,

            // Recursively format the entire folder with unlimited depth.
            // This option requires an existing and currently opened file
            // to serve as the starting point. Files will be opened and closed.
            // For the sake of convenience, two new folders will be created at
            // the same level as the file, which will contain all failed and
            // successfully formatted files. The "new_file_on_format" option
            // can be used to rename files if needed.
            // The "format_on_save" option above, which applies only to
            // single files, does not take effect here.
            // All none-text files (binary) will be automatically ignored.
            // Note: Placing files directly on the Desktop or elsewhere without
            // enclosing them within a folder can lead to accidental formatting.
            // Any literal "$" must be escaped to "\\$" to distinguish it from
            // the variable expansion "${...}". This important rule applies
            // to the entire content of this settings file!
            "recursive_folder_format": {
                "enable": false,
                "exclude_folders_regex": ["Spotlight-V100", "temp", "cache", "logs", "^_.*foo\\$"],
                "exclude_files_regex": ["^._.*$", ".*bar.exe"],
                "exclude_extensions": ["DS_Store", "localized", "TemporaryItems", "Trashes", "db", "ini", "git", "svn", "tmp", "bak"],
                "exclude_syntaxes": []
            },

            // Syntax support based on the scope name, not file extension.
            // Syntax name is part of the scope name and can be retrieved from:
            // Tools > Developer > Show Scope Name
            // End-users are advised to consult plugin documentation to add more syntaxes.
            "syntaxes": ["css", "html", "js", "php"],

            // Exclude a list of syntaxes for an individual syntax key.
            // A list of excluded syntaxes can be applied to all syntax definitions.
            // In this case, the key must be named: "all".
            // This option is useful to exclude part of the scope selector.
            // For example: text.html.markdown, want html but wish to filter out html.markdown.
            "exclude_syntaxes": {
                "html": ["markdown"],
                "all": ["markdown"]
            },

            // Path to the interpreter to run the third-party plugin.
            // Just for the sake of completeness, but it is unlikely that you will ever need
            // to use this option. Most of the programs you have installed are usually set
            // to run in the global environment, such as Python, Node.js, Ruby, PHP, etc.
            // Formatter is able to detect and automatically set them for you.
            // However, if you do need to use a specific interpreter, you can provide the path.
            // Alternatively, you can set the basename as the interpreter name to search on
            // PATH, similar to how it is done with the "executable_path" option.
            "interpreter_path": ["${HOME}/example/path/to\\$my/java.exe"],

            // Path to the third-party plugin executable to process formatting.
            // This option can be either a string or a list of executable paths.
            // - If this option is omitted or set to null, then the global executable
            //   on PATH will be used, if automatically found.
            // - If this option is exactly the basename, then it will be used as the
            //   executable name and searched for on the PATH.
            //   Basename can be with or without dot.extension as both variants are the same.
            //   For example: "fiLe.exe" (Windows only), "fiLe" (Windows + Unix + Linux)
            // System variable expansions like ${HOME}, ${USER} etc. and the Sublime Text
            // specific ${packages} can be used to assign paths.
            // Note: Again, any literal "$" must be escaped to "\\$" to distinguish
            // it from the variable expansion "${...}".
            "executable_path": ["${HOME}/example/path/to\\$my/php-cs-fixer.phar"],

            // Path to the config file for each individual syntaxes.
            // Syntax keys must match those in the "syntaxes" option above.
            // A single config file can be used to assign to all syntaxes.
            // In this case, the key must be named: "default"
            // Tips: You can choose another config file format as the standard one
            // provided by Formatter if the third-party plugin supports it.
            // Formatter provides a set of default config files under
            // "formatter.assets/config" folder for your personal use.
            // Do not use the reference files with suffix '.master.' directly.
            // These files could be overwritten by any release updates.
            // Note: Options from this config file always have precedence over
            // the options from any local project (per-project config file).
            // To disable this option in favor of the local project config:
            // 1. Set the config path of this option to null, OR
            // 2. Use the Quick Options: Ignore Config Path, OR
            // 3. Place an '.sublimeformatter.cfgignore.json' file inside
            //    the working root folder. The structure of this file is
            //    descripted in README.md > Auto-detect Formatting
            // Formatter will start to search up the file tree until a
            // '.sublimeformatter.cfgignore' file is found to bypass this option.
            "config_path": {
                "css": "${packages}/User/formatter.assets/config/only_css_rc.json",
                "php": "${packages}/User/formatter.assets/config/only_php_rc.json",
                "default": "${packages}/User/formatter.assets/config/css_plus_js_plus_php_rc.json"
            },

            // Array of additional arguments for the command line.
            "args": ["--basedir", "./example/my/foo", "--show-bar", "yes"],

            // This option is specifically designed for type graphic.
            // It enables SVG image generation for download.
            // Enable it if you need SVG image at the cost of processing time.
            // Unlike the generic method, this method only supports SVG generation.
            "render_extended": false,

            // Manipulate hardcoded command-line arguments.
            // This option allow you to modify hardcoded parameters, values and
            // their positions without digging into the source code.
            // This feature is primarily intended to temporarily fix bugs until
            // an official solution is implemented.
            // Note: Hardcoded args can be changed (rarely) by any release updates.
            // Enable debug mode will help to find all current hardcoded args.
            // Use "args" option above to add, this option to remove or manipulate.
            // Using regex: Again, any literal "$" must be escaped to "\\$" to
            // distinguish it from the variable expansion "${...}". Accepted args:
            // [search, [replace, [index, count, new position]]], where:
            // - search:   @type:str (regex)
            // - replace:  @type:str
            // - index:    @type:int (the number is known as a list index); required!
            // - count:    @type:int (the matching occurrences per index, 0 = all); required!
            // - position: @type:int (move old index pos. to new/old one, -1 = delete index); required!
            "fix_commands": [
                ["--autocorrect", "--autocorrect-all", 4, 0, 4], // no index pos change
                ["^.*?auto.*\\$", "--with", 4, 1, 5], // using escaped "\\$" regex, move index 4 to pos 5
                ["${packages}/to/old", "${packages}/to/new", 3, 0, 3], // variable expansion, no escaped "$"
                ["css", 5, 0, 7], // replace the value in index 5 with "css", move it to pos 7
                [3, 0, 4], // just move index 3 to the new pos 4. (count 0 irrelevant)
                [2, 0, -1], // just delete the index 2. (count 0 irrelevant)
                ["--show-bar", "xxx", 2, 0, -1] // enough bar, pop it out. ("xxx", 2, 0 irrelevant)
            ]
        },
        // -- END of explanation --

        "stylelint": {  // EXAMPLE: MODULE METHOD
            "info": "https://github.com/stylelint/stylelint",
            "enable": true,
            "format_on_paste": false,
            "format_on_save": false,
            "new_file_on_format": false,
            "recursive_folder_format": {
                "enable": false,
                "exclude_folders_regex": ["Spotlight-V100", "temp", "cache", "logs", "^_.*foo\\$"],
                "exclude_files_regex": ["^._.*$", ".*bar.exe"],
                "exclude_extensions": ["DS_Store", "localized", "TemporaryItems", "Trashes", "db", "ini", "git", "svn", "tmp", "bak"],
                "exclude_syntaxes": []
            },
            "syntaxes": ["css", "scss", "sass", "less", "sss", "sugarss"],
            "executable_path": ["${packages}/User/myjs/node_modules/.bin/stylelint"],
            "args": ["--config-basedir", "/path/to/js/node_modules"],
            "config_path": {
                "default": "${packages}/User/formatter.assets/config/stylelint_rc.json"
            }
        },
        "uncrustify": {  // EXAMPLE: GENERIC METHOD: Text-to-Text. Restart ST.
            "name": "Uncrustify",
            "type": "beautifier",
            "success_code": 0,
            "args": ["{{e}}", " --style=file:{{c}} ", "--"],

            "info": "https://github.com/uncrustify/uncrustify",
            "enable": true,
            "format_on_save": false,
            // "new_file_on_format": false, // Add this, if needed
            // "recursive_folder_format": {...} // Add this, if needed
            "syntaxes": ["c", "c++", "cs", "objc", "objc++", "d", "java", "pawn", "vala"],
            "executable_path": ["${HOME}/path/to/bin/uncrustify"],
            "config_path": {
                "objc": "${packages}/User/formatter.assets/config/uncrustify_objc_rc.cfg",
                "objc++": "${packages}/User/formatter.assets/config/uncrustify_objc_rc.cfg",
                "java": "${packages}/User/formatter.assets/config/uncrustify_sun_java_rc.cfg",
                "default": "${packages}/User/formatter.assets/config/uncrustify_rc.cfg"
            }
        },
        "d2": {  // EXAMPLE: GENERIC METHOD: Text-to-Image. Restart ST.
          "name": "D2",
          "type": "graphic",
          "success_code": 0,
          "render_extended": true,

          "info": "https://github.com/terrastruct/d2",
          "enable": true,
          "format_on_save": false,
          "format_on_paste": false,
          "syntaxes": ["d2"],
          "args": ["{{e}}", "--theme", "300", "--dark-theme", "200", "-l", "elk", "--pad", "0", "-", "{{o}}"],
          "args_extended": {
              "svg": ["{{e}}", "--theme", "300", "--dark-theme", "200", "-l", "elk", "--pad", "0", "-", "{{o}}"],
              "pdf": ["{{e}}", "--theme", "300", "--dark-theme", "200", "-l", "elk", "--pad", "0", "-", "{{o}}"]
          },
          "executable_path": "/path/to/bin/d2",
          "config_path": {
              "default": "${packages}/User/formatter.assets/config/d2_rc.yaml"
          }
        },
        ...
    }
}

Auto-detect Formatting

Starting from version 1.4.0, Formatter introduces a configuration mechanism to auto-detect formatter for itself (Special thanks to @midrare for ideas, tests and suggestions). There are 2 methods to achieve this:

  • Using embedded settings in your User Formatter.sublime-settings
  • Placing dot files inside the working folder, similar to per-project basis.

Formatter will start to search up the file tree inside the working folder until a following file is found: .sublimeformatter.json OR .sublimeformatter

.sublimeformatter.json

{
    // Comments are allowed.
    "json": {
        "uid": "jsbeautifier"
    },
    "html": {
        "uid": "jsbeautifier",
        "exclude_syntaxes": {
            "html": ["markdown"]
        }
    },
    "python": {
        "uid": "autopep8"
    }
}

User-specific config options can be set using .sublimeformatter.user.json OR .sublimeformatter-user

.sublimeformatter.user.json

{
    "format_on_save": true,
    "format_on_paste": false
}

To ignore a specific syntax assigned to your User's "config_path": settings, you can use .sublimeformatter.cfgignore.json OR .sublimeformatter.cfgignore
For example, if you prefer to use the standard .prettierrc in your working folder instead of the custom Formatter "config_path":

.sublimeformatter.cfgignore.json

{
    "json": ["jsbeautifier", "deno"],
    "python": ["autopep8"],
    "default": ["scalafmt", "stylelint"]
}

Alternatively, you can embed your auto-detect config within your User Formatter.sublime-settings. In cases where both the dot files and embedded methods coexist, then the config from dot files will take precedence over the embedded one.

Formatter.sublime-settings

{
    "debug": "status",

    "auto_format": {
        "config": {
            "format_on_save": false,
            "format_on_paste": false
        },
        "json": {
            "uid": "jsbeautifier"
        },
        "html": {
            "uid": "jsbeautifier",
            "exclude_syntaxes": {
                "html": ["markdown"]
            }
        },
        "python": {
            "uid": "autopep8"
        }
    },

    "formatters": {}
}

This is a one-command/one-keybinding feature. Both the app and context menu will now indicate whether a current folder is ready for Formatter with a new item: Auto Format File

Per-project Formatting

Formatter is able to add and override any setting on per-project basis using .sublime-project files.
You might want to restart Sublime Text to apply the changes to the .sublime-project file.

.sublime-project

{
    "folders": [
        {
            "path": "/path/to/my/project"
        }
    ],

    "settings": {
        "Formatter": {
            "debug": "status",
            "formatters": {
                "htmltidy": {
                    "format_on_save": true
                },
                "jsbeautifier": {
                    "config_path": {
                        "default": "${HOME}/path/to/new/jsbeautify_rc.json"
                    }
                }
            }
        }
    }
}

Usage

Formatter has been designed to detect the syntax of files according to file scopes, not file extension. In the most cases, Sublime Text already does this job for you when you open a file. For the rest, you must explicit assign the syntax via the syntax menu in the righ-hand bottom corner or via:

Sublime Text > View > Syntax

Setting wrong syntax when formatting code will cause error:

Syntax out of the scope.

Formatting actions can be triggered in different ways:

  • Tools > Command Palette (Cmd+Shift+P or Ctrl+Shift+P) and type Formatter.
  • Tools > Formatter
  • Right-click > Context-Menu > Formatter
  • Settings > Key Bindings

The Quick Options

This feature is designed to help users quickly access and switch between options, without the need to navigate the Settings file. It comprises 3 modes:

  • Temporary Quick Options (TQO): By default, all options are temporary and only take effect during the current Sublime session. They will be automatically reset when you close Sublime.
  • Persistent User Settings (PUS): Clicking the Reset option will reset all current Temporary Quick Options and switch to using your User Settings from Formatter.sublime-settings.
  • Persistent Quick Options (PQO): Clicking the Save option will make all current Temporary Quick Options persistently. This means that closing and reopening Sublime will retain these options. To exit this mode just clicking the Reset option.

Summary:

  • The Reset option is the exclusive method to exit any mode.
  • Clicking on the same selected item will remove it from the list.
  • None of the modes will ever modify your Settings file.
  • The current mode is indicated on the status bar for your reference.

Development:

Starting from version 1.0.6, you now are able to create your own module for a third-party plugin that hasn't yet been integrated into Formatter. This allows you to extend your individual needs. In theory, you can use Formatter as a platform to convert any form of text, as long as third-party plugins operate in a text-to-text manner, such as Text-to-QR code, text-to-ASCII image conversion.

1. Prerequisite:

  1. Create a config file specific to your third-party plugin if needed. Config files for third-party plugins must be placed in the following folder:

    Formatter > config
    
  2. Activate the debug mode with the secret key dev in your Formatter settings. The dev key should never be used in a production environment.

Formatter.sublime-settings

{
    "debug": true,  // controls printing error messages
    "dev": true     // controls modules reloading to update modified files
    ...
}

2. Creating a module:

Developing a module for Formatter is straightforward. All you need to do is creating a python file with just a few lines of code as below:

  1. Create a file with the file name pattern formatter_thisismyfirstpluginmodule.py inside the Formatter > modules folder. Ensure to follow these conventions:
  • Create only one file per plugin in the Formatter > modules folder:
    • All functions and other necessary components should reside inside this file.
  • The file name is all lowercase and contains only alphanumeric characters (no spaces or underscores):
    • Prefix: formatter_ (indicating that it's a module for a third-party plugin)
    • Suffix: thisismyfirstpluginmodule (serving as the unique Formatter ID, also known as uid)
    • Extension: .py
  • External libraries that the third-party plugin relies on should be placed in the folder: Formatter > libs
    • Libraries must not contain proprietary elements, including the LICENSE file or license notices.
    • No communication over the Internet.
  1. The content of this module file should follow the structure outlined below:

formatter_thisismyfirstpluginmodule.py

#!/usr/bin/env python3

INTERPRETERS = []                                           # optional: Fallback list of interpreter names
EXECUTABLES = []                                            # REQUIRED: Fallback list of executable names
MODULE_CONFIG = {}                                          # REQUIRED: template to create several sublime config files

class ThisismyfirstpluginmoduleFormatter(common.Module):    # REQUIRED: the Capitalized of uid and the Capitalized word "Formatter", nothing else!
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)                   # REQUIRED: initialize the module APIs from common.Module

    def get_cmd(self):                                      # optional: get commands, e.g get the "config_path", "executable_path" etc...

    def format(self):                                       # REQUIRED: the entry point, predefined function name exact as written

Details as an example:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# @copyright    you
# @link         you
# @license      The MIT License (MIT)

import logging                                              # REQUIRED: logging system for debugging this file
from ..core import common                                   # REQUIRED: a collection of APIs to assist in running this file

log = logging.getLogger(__name__)                           # REQUIRED: logger setup
INTERPRETERS = ['node']                                     # optional: case-sensitive fallback names (without extension) if interpreter is not found
EXECUTABLES = ['terser']                                    # optional: case-sensitive fallback names (without extension) if executable is not found
MODULE_CONFIG = {                                           # REQUIRED: template to create several sublime config files
    'source': 'https://thirdparty-plugin.com',              # REQUIRED: info on where the user can download the plugin
    'name': 'My First Plugin',                              # REQUIRED: a Capitalized plugin name of your choice, preferably short and comprehensive
    'uid': 'thisismyfirstpluginmodule',                     # REQUIRED: must match the suffix of "formatter_thisismyfirstpluginmodule.py"
    'type': 'minifier',                                     # REQUIRED: "beautifier" OR "minifier" OR "converter" OR "graphic",
                                                            #           OR any string of your choice (for private purposes).
    'syntaxes': ['js', 'html'],                             # REQUIRED: array of syntaxes, obtained from: Tools > Developer > Show Scope Name
    'exclude_syntaxes': {                                   # optional: blacklist syntaxes per syntax or None to omit it.
        'html': ['markdown']
    },
    "interpreter_path": ["/path/to/bin/node"],              # optional: use an empty string "" to include this key in config files or None to omit it
    "executable_path": ["/path/to/bin/terser"],             # optional: use an empty string "" to include this key in config files or None to omit it
    'args': None,                                           # optional: an array ['arg1', 'args2', ...] to include this key in config files or None to omit it
    'config_path': {                                        # optional: a dictionary to include this key in config files or None to omit it
        'js': 'my_first_plugin_js_rc.json'                  # optional: a key-value pair or just omit it. See Formatter.sublime-settings for explanation
        'default': 'my_first_plugin_rc.json'                # optional: a key-value pair or just omit it. See Formatter.sublime-settings for explanation
    },
    'comment': 'build-in, no executable'                    # optional: a single short comment, limited to 200 chars or just omit it
}


class ThisismyfirstpluginmoduleFormatter(common.Module):    # REQUIRED: the Capitalized of uid and the Capitalized word "Formatter", nothing else!
    def __init__(self, *args, **kwargs):                    # REQUIRED: initialization
        super().__init__(*args, **kwargs)                   # REQUIRED: initialize the module APIs from common.Module

    def get_cmd(self):                                      # optional: get commands e.g get the "config_path", "executable_path" etc...
        cmd = self.get_combo_cmd(runtime_type='node')       # See API below
        if not cmd:
            return None

        path = self.get_config_path()                       # See API below
        if path:
            cmd.extend(['--config-file', path])             # an array of args to run the third-party plugin

        cmd.extend(['--compress', '--mangle', '--'])

        # cmd.extend(['--output', self.get_output_image()]) # REQUIRED: only for special case of "type": "graphic"

        log.debug('Current arguments: %s', cmd)             # REQUIRED: to debug the input command
        cmd = self.fix_cmd(cmd)                             # REQUIRED: to finally process the "fix_commands" option, just right before the return

        return cmd

    def format(self):                                       # REQUIRED: the entry point, predefined function name exact as written
        cmd = self.get_cmd()
        if not self.is_valid_cmd(cmd):                      # REQUIRED: is command ok?
            return None

        try:
            exitcode, stdout, stderr = self.exec_cmd(cmd)   # REQUIRED: process command

            if exitcode > 0:                                # REQUIRED: please consult the plugin documentation for the exit codes
                self.print_exiterr(exitcode, stderr)
            else:
                # if self.is_render_extended():             # is render extended mode activated?
                #     cmd = self.all_png_to_svg_cmd(cmd)
                #     try:
                #         self.exec_cmd(cmd)                # REQUIRED: only for special case of "type": "graphic" to generate SVG image.
                #     except Exception as e:
                #         log.error('Error: %s', e)

                return stdout                               # REQUIRED: return the formatted code on success
        except OSError:
            self.print_oserr(cmd)

        return None                                         # REQUIRED: return None to indicate failure

That's all. Happy coding o_O

Restart Sublime Text.
New keys will be automatically created in the Default settings.
Do not forget to update/adjust your User settings:
Preferences > Package Settings > Formatter > Settings

3. Integrating modules:

You have the choice to either submit a pull request or integrate your modules yourself using:

"custom_modules": {
        "config": ["/path/to/foo_rc.json", "/path/to/bar_rc.cfg"],
        "modules": ["/path/to/formatter_foo.py", "/path/to/formatter_bar.py"],
        "libs": ["/path/to/foolib", "/path/to/mylib"]
    },

4. APIs:

The entire set of Formatter APIs can be found in the file: core > common.py
Responsible for handling plugin modules is the class: class Module(object):

  • Essentially for the def get_cmd(self) function:
# An alias for get_interpreter(), get_executable() and get_args() together.
# Set runtime_type=(None|'node'|'python'|'perl'|'ruby') to enable local executable search.
# Currently only None|node makes sense. 'python'|'perl'|'ruby' are just placeholder for future.
cmd = self.get_combo_cmd(runtime_type=None)

# Get the interpreter path or None.
interpreter = self.get_interpreter()

# Get the executable path or None.
# Set runtime_type=(None|'node'|'python'|'perl'|'ruby') to enable local executable search.
executable = self.get_executable(runtime_type=None)

# Get the input arguments "args" from the User settings or None.
args = self.get_args()

# Get the input "config_path" from the User settings or None.
path = self.get_config_path()

# Get the detected syntax of the current file or None.
syntax = self.get_assigned_syntax()

# Get the path to the output PNG image. Applicable only to the special case of type: graphic
output_image = self.get_output_image()

# Get a dictionary of file path components:
# {'path':, 'cwd':, 'base':, 'stem':, 'suffix':, 'ext':} or None.
components = self.get_pathinfo()

# Create and get the temp file path.
# Useful for plugins lacking a built-in mechanism to fix files inplace.
tmp_file = self.create_tmp_file(suffix=None)

# Remove temp file.
self.remove_tmp_file(tmp_file)

# To finally process the "fix_commands" option, just right before exec_cmd().
cmd = self.fix_cmd(cmd)
  • Essentially for the def format(self) function:
# To quickly test the command.
is_valid = self.is_valid_cmd(cmd)

# To replace cmd list items to generate SVG file for download.
# It is applicable only to the special case of type: graphic.
# Note: extended_cmd MUST be executed right before return stdout (=success)!
extended_cmd = self.ext_png_to_svg_cmd(cmd)  # replace extension .png -> .svg
extended_cmd = self.all_png_to_svg_cmd(cmd)  # replace all occurred png -> svg

# To process the formatting with all input (fixed) arguments.
# stdout as PIPE. 99% of plugins use this way.
exitcode, stdout, stderr = self.exec_cmd(cmd)

# stdout as file. 1% are just retarded.
exitcode, stdout, stderr = self.exec_cmd(cmd, outfile='/path/to/save/outfile')

# To print formatting exit error.
self.print_exiterr(exitcode, stderr)

# To print executing commands error.
self.print_oserr(cmd)

License

Formatter is licensed under the MIT license.