├── .no-sublime-package ├── .gitattributes ├── Svgo.sublime-settings ├── test.svg ├── Svgo.sublime-commands ├── .editorconfig ├── .github └── dependabot.yml ├── package.json ├── Main.sublime-menu ├── svgo.mjs ├── node_bridge.py ├── license ├── readme.md └── Svgo.py /.no-sublime-package: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | -------------------------------------------------------------------------------- /Svgo.sublime-settings: -------------------------------------------------------------------------------- 1 | { 2 | "indent": 2 3 | } 4 | -------------------------------------------------------------------------------- /test.svg: -------------------------------------------------------------------------------- 1 | 2 | test 3 | 4 | -------------------------------------------------------------------------------- /Svgo.sublime-commands: -------------------------------------------------------------------------------- 1 | [{ 2 | "caption": "SVGO: Minify SVG", 3 | "command": "svgo_minify" 4 | }, { 5 | "caption": "SVGO: Prettify SVG", 6 | "command": "svgo_prettify" 7 | }] 8 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: npm 4 | directory: "/" 5 | schedule: 6 | interval: weekly 7 | time: "20:00" 8 | open-pull-requests-limit: 10 9 | ignore: 10 | - dependency-name: svgo 11 | versions: 12 | - 2.0.3 13 | - 2.1.0 14 | - 2.2.1 15 | - 2.2.2 16 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "7.0.0", 3 | "private": true, 4 | "type": "module", 5 | "scripts": { 6 | "postversion": "git push && git push --tags" 7 | }, 8 | "dependencies": { 9 | "get-stdin": "^9.0.0", 10 | "svgo": "^3.3.2" 11 | }, 12 | "engines": { 13 | "node": ">=20", 14 | "npm": ">=10" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Main.sublime-menu: -------------------------------------------------------------------------------- 1 | [{ 2 | "caption": "Preferences", 3 | "mnemonic": "n", 4 | "id": "preferences", 5 | "children": [{ 6 | "caption": "Package Settings", 7 | "mnemonic": "P", 8 | "id": "package-settings", 9 | "children": [{ 10 | "caption": "svgo", 11 | "children": [{ 12 | "command": "open_file", 13 | "args": { 14 | "file": "${packages}/svgo/Svgo.sublime-settings" 15 | }, 16 | "caption": "Settings – Default" 17 | }, { 18 | "command": "open_file", 19 | "args": { 20 | "file": "${packages}/User/Svgo.sublime-settings" 21 | }, 22 | "caption": "Settings – User" 23 | }, { 24 | "caption": "-" 25 | }] 26 | }] 27 | }] 28 | }] 29 | -------------------------------------------------------------------------------- /svgo.mjs: -------------------------------------------------------------------------------- 1 | import {Buffer} from 'node:buffer'; 2 | import getStdin from 'get-stdin'; 3 | import {optimize} from 'svgo'; 4 | 5 | getStdin() 6 | .then(data => minify(data)) 7 | .then(data => process.stdout.write(data)); 8 | 9 | function minify(data) { 10 | const options = JSON.parse(process.argv[2]); 11 | const svg = Buffer.isBuffer(data) ? data.toString() : data; 12 | const plugins = ['preset-default']; 13 | 14 | // Add user plugins 15 | for (const plugin of Object.keys(options.plugins || [])) { 16 | plugins.push({ 17 | [plugin]: options.plugins[plugin], 18 | }); 19 | } 20 | 21 | return optimize(svg, { 22 | js2svg: { 23 | pretty: options.pretty, 24 | indent: options.indent 25 | }, 26 | plugins, 27 | }).data; 28 | } 29 | -------------------------------------------------------------------------------- /node_bridge.py: -------------------------------------------------------------------------------- 1 | import os 2 | import platform 3 | import subprocess 4 | 5 | IS_MACOS = platform.system() == 'Darwin' 6 | IS_WINDOWS = platform.system() == 'Windows' 7 | 8 | def node_bridge(data, bin, args=[]): 9 | env = None 10 | startupinfo = None 11 | 12 | if IS_MACOS: 13 | env = os.environ.copy() 14 | env['PATH'] += ':/usr/local/bin' 15 | 16 | if IS_WINDOWS: 17 | startupinfo = subprocess.STARTUPINFO() 18 | startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW 19 | 20 | try: 21 | p = subprocess.Popen(['node', bin] + args, 22 | stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE, 23 | env=env, startupinfo=startupinfo) 24 | except OSError: 25 | raise Exception('Couldn\'t find Node.js. Make sure it\'s in your $PATH by running `node -v` in your command-line.') 26 | 27 | stdout, stderr = p.communicate(input=data.encode('utf-8')) 28 | stdout = stdout.decode('utf-8') 29 | stderr = stderr.decode('utf-8') 30 | 31 | if stderr: 32 | raise Exception('Error: %s' % stderr) 33 | else: 34 | return stdout 35 | -------------------------------------------------------------------------------- /license: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) Shogo Sensui (https://github.com/1000ch) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Sublime-svgo 2 | 3 | A plugin for [Sublime Text](https://www.sublimetext.com/) providing an interface to [SVGO](https://github.com/svg/svgo). 4 | 5 | ![demo](https://cloud.githubusercontent.com/assets/1800018/24616695/d7ce3a10-18cc-11e7-8398-24e966b62914.gif) 6 | 7 | ## Install 8 | 9 | You can install via with [Package Control](https://packagecontrol.io/) and restart Sublime. 10 | 11 | - **Install Package**: Search with `SVGO`. 12 | - **Add Repository**: Put URL `https://github.com/1000ch/Sublime-svgo`. 13 | 14 | Also you can install this extension locally by putting symbolic link from `~/Library/Application\ Support/Sublime\ Text/Packages/` to `~/path/to/this/repo` like below. 15 | 16 | ```bash 17 | $ ln -s ~/workspace/github.com/1000ch/Sublime-svgo ~/Library/Application\ Support/Sublime\ Text/Packages/SVGO 18 | ``` 19 | 20 | ### Prerequisite 21 | 22 | [SVGO](https://github.com/svg/svgo) requires Node.js as runtime. If you don't have Node.js, I recommend you to install Node.js using version managers like the followings. 23 | 24 | - Use [nodenv/nodenv](https://github.com/nodenv/nodenv) 25 | - Use [hokaccha/nodebrew](https://github.com/hokaccha/nodebrew) 26 | 27 | ## Usage 28 | 29 | In a SVG file, open the Command Palette (Cmd Shift P) and choose **Minify SVG** or **Prettify SVG**. 30 | 31 | ## Config 32 | 33 | You can configure following options from Preferences → Package Settings → Svgo → Settings - User. 34 | 35 | ### indent 36 | 37 | Indent size used on prettify. 38 | 39 | ## License 40 | 41 | [MIT](https://1000ch.mit-license.org) © [Shogo Sensui](https://github.com/1000ch) 42 | -------------------------------------------------------------------------------- /Svgo.py: -------------------------------------------------------------------------------- 1 | import sublime 2 | import sublime_plugin 3 | import json 4 | from os.path import dirname, realpath, join 5 | 6 | try: 7 | # Python 2 8 | from node_bridge import node_bridge 9 | except: 10 | from .node_bridge import node_bridge 11 | 12 | sublime.Region.totuple = lambda self: (self.a, self.b) 13 | sublime.Region.__iter__ = lambda self: self.totuple().__iter__() 14 | 15 | BIN_PATH = join(sublime.packages_path(), dirname(realpath(__file__)), 'svgo.mjs') 16 | 17 | def get_setting(view, key): 18 | settings = view.settings().get('Svgo') 19 | 20 | if settings is None: 21 | settings = sublime.load_settings('Svgo.sublime-settings') 22 | 23 | return settings.get(key) 24 | 25 | class SvgoMinifyCommand(sublime_plugin.TextCommand): 26 | def run(self, edit): 27 | region = sublime.Region(0, self.view.size()) 28 | buffer = self.view.substr(region) 29 | processed = self.minify(buffer) 30 | 31 | if processed: 32 | self.view.replace(edit, region, processed) 33 | 34 | def minify(self, data): 35 | try: 36 | return node_bridge(data, BIN_PATH, [json.dumps({ 37 | 'indent': get_setting(self.view, 'indent'), 38 | 'plugins': get_setting(self.view, 'plugins') 39 | })]) 40 | except Exception as e: 41 | sublime.error_message('svgo\n%s' % e) 42 | 43 | class SvgoPrettifyCommand(sublime_plugin.TextCommand): 44 | def run(self, edit): 45 | region = sublime.Region(0, self.view.size()) 46 | buffer = self.view.substr(region) 47 | processed = self.prettify(buffer) 48 | 49 | if processed: 50 | self.view.replace(edit, region, processed) 51 | 52 | def prettify(self, data): 53 | try: 54 | return node_bridge(data, BIN_PATH, [json.dumps({ 55 | 'pretty': True, 56 | 'indent': get_setting(self.view, 'indent'), 57 | 'plugins': get_setting(self.view, 'plugins') 58 | })]) 59 | except Exception as e: 60 | sublime.error_message('svgo\n%s' % e) 61 | --------------------------------------------------------------------------------