├── .gitignore ├── .travis.yml ├── LICENSE.txt ├── README.md ├── generate-menu.js ├── keymaps └── emmet.cson ├── lib ├── editor-proxy.coffee ├── emmet.coffee ├── interactive.js └── prompt.coffee ├── menus └── emmet.json ├── package.json ├── spec ├── emmet-spec.coffee └── fixtures │ ├── abbreviation │ ├── after │ │ ├── anchor-class-expand.html │ │ ├── css-abbrv.css │ │ ├── header-expand.html │ │ ├── html-abbrv.html │ │ ├── multi-line.html │ │ ├── php-in-html.php │ │ ├── sass-test.sass │ │ └── vanilla-php.php │ └── before │ │ ├── anchor-class-expand.html │ │ ├── css-abbrv.css │ │ ├── header-expand.html │ │ ├── html-abbrv.html │ │ ├── multi-line.html │ │ ├── php-in-html.php │ │ ├── sass-test.sass │ │ └── vanilla-php.php │ ├── balance │ └── sample.html │ ├── edit-points │ └── edit-points.html │ ├── encode-decode-data-url │ ├── after │ │ └── encode-decode-data-url.css │ ├── barrel.png │ └── before │ │ └── encode-decode-data-url.css │ ├── evaluate-math-expression │ └── evaluate-math-expression.html │ ├── increment-decrement-numbers │ └── increment-decrement-numbers.css │ ├── merge-lines │ ├── after │ │ └── merge-lines.html │ └── before │ │ └── merge-lines.html │ ├── reflect-css-value │ ├── after │ │ └── reflect-css-value.css │ └── before │ │ └── reflect-css-value.css │ ├── remove-tag │ ├── after │ │ ├── remove-tag-once.html │ │ └── remove-tag-twice.html │ └── before │ │ └── remove-tag.html │ ├── select-item │ ├── select-item.css │ └── select-item.html │ ├── split-join-tag │ └── split-join-tag.html │ ├── tabbing.html │ ├── update-image-size │ ├── after │ │ ├── update-image-size.css │ │ └── update-image-size.html │ ├── before │ │ ├── update-image-size.css │ │ └── update-image-size.html │ └── raptor_dunk.jpg │ ├── update-tag │ ├── after │ │ └── update-tag.html │ └── before │ │ └── update-tag.html │ └── wrap-with-abbreviation │ ├── after │ └── wrap-with-abbreviation.html │ └── before │ └── wrap-with-abbreviation.html └── styles └── emmet.less /.gitignore: -------------------------------------------------------------------------------- 1 | lib-cov 2 | *.seed 3 | *.log 4 | *.csv 5 | *.dat 6 | *.out 7 | *.pid 8 | *.gz 9 | 10 | pids 11 | logs 12 | results 13 | 14 | node_modules/ 15 | npm-debug.log 16 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: objective-c 2 | script: 'curl -s -H "Authorization: token $ATOM_ACCESS_TOKEN" -H "Accept: application/vnd.github.v3.raw" 3 | https://api.github.com/repos/atom/apm/contents/script/build-package | sh' 4 | env: 5 | global: 6 | secure: LrQO6c1B6B/6cAAf2qLc8qE+En43+m2yu+y5jghl2QEk3GCxUFrt25QLpbC0Uo2EPaERVt5E60pMcerjSyF0mQCeM8z5zjd+LxQJDruiJ6I9KDhSynGWEgcf6uYZmOyTiNyj8EzS7AHm5Ap3weHxsfi+TfhjNzL15PEFAOomjIY= 7 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Garen J. Torikian 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | 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, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Emmet plugin Atom editor 2 | 3 | [Emmet](http://emmet.io) support for [Atom](http://atom.io). 4 | 5 | ## Installation 6 | 7 | * In Atom, open *Preferences* (*Settings* on Windows) 8 | * Go to *Install* section 9 | * Search for `Emmet` package. Once it found, click `Install` button to install package. 10 | 11 | ### Manual installation 12 | 13 | You can install the latest Emmet version manually from console: 14 | 15 | ```bash 16 | cd ~/.atom/packages 17 | git clone https://github.com/emmetio/emmet-atom 18 | cd emmet-atom 19 | npm install 20 | ``` 21 | 22 | Then restart Atom editor. 23 | 24 | ## Features: 25 | 26 | * Expand abbreviations by Tab key. 27 | * Multiple cursor support: most [Emmet actions](http://docs.emmet.io/actions/) like Expand Abbreviation, Wrap with Abbreviation, Update Tag can run in multi-cursor mode. 28 | * Interactive actions (Interactive Expand Abbreviation, Wrap With Abbreviation, Update Tag) allows you to preview result real-time as you type. 29 | * Better tabstops in generated content: when abbreviation expanded, hit Tab key to quickly traverse between important code points. 30 | * [Emmet v1.1 core](http://emmet.io/blog/beta-v1-1/). 31 | 32 | Please report any problems at [issue tracker](https://github.com/emmetio/emmet-atom/issues). 33 | 34 | ## Tab key 35 | 36 | Currently, Emmet expands abbreviations by Tab key only for HTML, CSS, Sass/SCSS and LESS syntaxes. Tab handler scope is limited because it overrides default snippets. 37 | 38 | If you want to make Emmet expand abbreviations with Tab key for other syntaxes, you can do the following: 39 | 40 | 1. Use *Open Your Keymap* menu item to open your custom `keymap.cson` file. 41 | 2. Add the following section into it: 42 | 43 | ```coffee 44 | 'atom-text-editor[data-grammar="YOUR GRAMMAR HERE"]:not([mini])': 45 | 'tab': 'emmet:expand-abbreviation-with-tab' 46 | ``` 47 | 48 | Replace `YOUR GRAMMAR HERE` with actual grammar attribute value. The easiest way to get grammar name of currently opened editor is to open DevTools and find corresponding `` element: it will contain `data-grammar` attribute with value you need. For example, for HTML syntax it’s a `text html basic`. 49 | 50 | You can add as many sections as you like for different syntaxes. Note that default snippets will no longer work, but you can add [your own snippets in Emmet](http://docs.emmet.io/customization/). 51 | 52 | ## Default Keybindings 53 | 54 | You can change these in Preferences > Keybindings. 55 | 56 | Command | Darwin | Linux/Windows 57 | ------- | ------ | ------------- 58 | Expand Abbreviation | tab or shift + + e | tab or ctrl + e 59 | Expand Abbreviation (interactive) | alt + + enter | ctrl + alt + enter 60 | Wrap with Abbreviation | ctrl + w | ctrl + alt + w 61 | Balance (outward) | ctrl + d | ctrl + shift + e 62 | Balance (inward) | alt + d | ctrl + shift + 0 63 | Go to Matching Pair | ctrl + alt + j | ctrl + alt + j 64 | Next Edit Point | ctrl + | ctrl + alt + 65 | Previous Edit Point | ctrl + | ctrl + alt + 66 | Select Next Item | ctrl + shift + | ctrl + shift + . 67 | Select Previous Item | ctrl + shift + | ctrl + shift + , 68 | Toggle Comment | + / | ctrl + shift + / 69 | Split/Join Tag | shift + + j | ctrl + shift + ` 70 | Remove Tag | + ' | ctrl + shift + ; 71 | Evaluate Math Expression | shift + + y | ctrl + shift + y 72 | Increment Number by 0.1 | ctrl + alt + | alt + 73 | Decrement Number by 0.1 | ctrl + alt + | alt + 74 | Increment Number by 1 | ctrl + alt + + | ctrl + 75 | Decrement Number by 1 | ctrl + alt + + | ctrl + 76 | Increment Number by 10 | ctrl + alt + + shift + | shift + alt + 77 | Decrement Number by 10 | ctrl + alt + + shift + | shift + alt + 78 | Reflect CSS value | shift + + r | ctrl + shift + r 79 | Update Image Size | ctrl + i | ctrl + u 80 | Encode/Decode image to data:URL | ctrl + shift + i | ctrl + ' 81 | Update Tag | ctrl + shift + u | ctrl + shift + ' 82 | Merge Lines | shift + + m | ctrl + shift + m 83 | 84 | All actions and their keyboard shortcuts are available under Packages > Emmet menu item. 85 | 86 | ## Extensions support 87 | 88 | You can easily [extend](http://docs.emmet.io/customization/) Emmet with new actions and filters or customize existing ones. In Preferences > Emmet, set Extensions path to folder with Emmet extensions. By default, it’s `~/emmet`, e.g. `emmet` folder in your system HOME folder. 89 | -------------------------------------------------------------------------------- /generate-menu.js: -------------------------------------------------------------------------------- 1 | // Generates Atom menu file from Emmet action list 2 | var fs = require('fs'); 3 | var path = require('path'); 4 | var actions = require('emmet/lib/action/main'); 5 | 6 | function generateMenu(menu) { 7 | return menu.map(function(item) { 8 | if (item.type == 'action') { 9 | return { 10 | label: item.label, 11 | command: 'emmet:' + item.name.replace(/_/g, '-') 12 | }; 13 | } 14 | 15 | if (item.type == 'submenu') { 16 | return { 17 | label: item.name, 18 | submenu: generateMenu(item.items) 19 | }; 20 | } 21 | }); 22 | } 23 | 24 | var menu = { 25 | 'menu': [{ 26 | label: 'Packages', 27 | submenu: [{ 28 | label: 'Emmet', 29 | submenu: generateMenu(actions.getMenu()).concat([{ 30 | label: 'Interactive Expand Abbreviation', 31 | command: 'emmet:interactive-expand-abbreviation' 32 | }]) 33 | }] 34 | }] 35 | }; 36 | 37 | var menuFile = path.join(__dirname, 'menus', 'emmet.json'); 38 | fs.writeFileSync(menuFile, JSON.stringify(menu, null, '\t'), {encoding: 'utf8'}); 39 | 40 | console.log('Menu file "%s" generated successfully', menuFile); -------------------------------------------------------------------------------- /keymaps/emmet.cson: -------------------------------------------------------------------------------- 1 | 'atom-text-editor:not([mini])': 2 | 'ctrl-e': 'emmet:expand-abbreviation' 3 | 'ctrl-shift-e': 'emmet:balance-outward' 4 | 'ctrl-shift-0': 'emmet:balance-inward' 5 | 'ctrl-alt-j': 'emmet:matching-pair' 6 | 'ctrl-alt-right': 'emmet:next-edit-point' 7 | 'ctrl-alt-left': 'emmet:prev-edit-point' 8 | 'ctrl-shift-`': 'emmet:split-join-tag' 9 | 'ctrl-shift-;': 'emmet:remove-tag' 10 | 'ctrl-shift-y': 'emmet:evaluate-math-expression' 11 | 'alt-up': 'emmet:increment-number-by-01' 12 | 'alt-down': 'emmet:decrement-number-by-01' 13 | 'ctrl-up': 'emmet:increment-number-by-1' 14 | 'ctrl-down': 'emmet:decrement-number-by-1' 15 | 'alt-shift-up': 'emmet:increment-number-by-10' 16 | 'alt-shift-down': 'emmet:decrement-number-by-10' 17 | 'ctrl-shift-.': 'emmet:select-next-item' 18 | 'ctrl-shift-,': 'emmet:select-previous-item' 19 | 'ctrl-shift-r': 'emmet:reflect-css-value' 20 | 'ctrl-u': 'emmet:update-image-size' 21 | "ctrl-'": 'emmet:encode-decode-data-url' 22 | "ctrl-shift-'": 'emmet:update-tag' 23 | 'ctrl-shift-m': 'emmet:merge-lines' 24 | 'ctrl-alt-w': 'emmet:wrap-with-abbreviation' 25 | 'ctrl-alt-enter': 'emmet:interactive-expand-abbreviation' 26 | 27 | 'atom-pane atom-text-editor:not([mini])': 28 | 'ctrl-shift-/': 'emmet:toggle-comment' 29 | 30 | # Override Enter key for specific syntaxes only 31 | 'atom-pane atom-text-editor[data-grammar~="html"]:not([mini]):not(.autocomplete-active), atom-pane atom-text-editor[data-grammar~="xml"]:not([mini]):not(.autocomplete-active)': 32 | 'enter': 'emmet:insert-formatted-line-break-only' 33 | 34 | # language-specific Tab triggers 35 | # you can add more triggers by changing `grammar` attribute values 36 | 'atom-text-editor[data-grammar="text html basic"]:not([mini]), atom-text-editor[data-grammar~="angular"]:not([mini]), atom-text-editor[data-grammar~="erb"]:not([mini]), atom-text-editor[data-grammar~="jade"]:not([mini]), atom-text-editor[data-grammar~="css"]:not([mini]), atom-text-editor[data-grammar~="stylus"]:not([mini]), atom-text-editor[data-grammar~="sass"]:not([mini]), atom-text-editor[data-grammar~="scss"]:not([mini])': 37 | 'tab': 'emmet:expand-abbreviation-with-tab' 38 | 39 | '.platform-darwin atom-text-editor:not([mini])': 40 | 'cmd-shift-e': 'emmet:expand-abbreviation' 41 | 'ctrl-d': 'emmet:balance-outward' 42 | 'alt-d': 'emmet:balance-inward' 43 | 'ctrl-right': 'emmet:next-edit-point' 44 | 'ctrl-left': 'emmet:prev-edit-point' 45 | "cmd-shift-j": 'emmet:split-join-tag' 46 | "cmd-'": 'emmet:remove-tag' 47 | 'cmd-shift-y': 'emmet:evaluate-math-expression' 48 | 'ctrl-alt-up': 'emmet:increment-number-by-01' 49 | 'ctrl-alt-down': 'emmet:decrement-number-by-01' 50 | 'ctrl-alt-cmd-up': 'emmet:increment-number-by-1' 51 | 'ctrl-alt-cmd-down': 'emmet:decrement-number-by-1' 52 | 'ctrl-alt-cmd-shift-up': 'emmet:increment-number-by-10' 53 | 'ctrl-alt-cmd-shift-down': 'emmet:decrement-number-by-10' 54 | 'ctrl-shift-right': 'emmet:select-next-item' 55 | 'ctrl-shift-left': 'emmet:select-previous-item' 56 | 'cmd-shift-r': 'emmet:reflect-css-value' 57 | 'ctrl-i': 'emmet:update-image-size' 58 | "ctrl-shift-i": 'emmet:encode-decode-data-url' 59 | 'ctrl-shift-u': 'emmet:update-tag' 60 | 'cmd-shift-m': 'emmet:merge-lines' 61 | 'ctrl-w': 'emmet:wrap-with-abbreviation' 62 | 'alt-cmd-enter': 'emmet:interactive-expand-abbreviation' 63 | 64 | '.platform-darwin atom-pane atom-text-editor:not([mini])': 65 | 'cmd-/': 'emmet:toggle-comment' 66 | -------------------------------------------------------------------------------- /lib/editor-proxy.coffee: -------------------------------------------------------------------------------- 1 | {Point, Range} = require 'atom' 2 | path = require 'path' 3 | 4 | emmet = require 'emmet' 5 | utils = require 'emmet/lib/utils/common' 6 | tabStops = require 'emmet/lib/assets/tabStops' 7 | resources = require 'emmet/lib/assets/resources' 8 | editorUtils = require 'emmet/lib/utils/editor' 9 | actionUtils = require 'emmet/lib/utils/action' 10 | 11 | insertSnippet = (snippet, editor) -> 12 | atom.packages.getLoadedPackage('snippets')?.mainModule?.insert(snippet, editor) 13 | 14 | # Fetch expansions and assign to editor 15 | editor.snippetExpansion = atom.packages.getLoadedPackage('snippets')?.mainModule?.getExpansions(editor)[0] 16 | 17 | visualize = (str) -> 18 | str 19 | .replace(/\t/g, '\\t') 20 | .replace(/\n/g, '\\n') 21 | .replace(/\s/g, '\\s') 22 | 23 | # Normalizes text before it goes to editor: replaces indentation 24 | # and newlines with ones used in editor 25 | # @param {String} text Text to normalize 26 | # @param {Editor} editor Brackets editor instance 27 | # @return {String} 28 | normalize = (text, editor) -> 29 | editorUtils.normalize text, 30 | indentation: editor.getTabText(), 31 | newline: '\n' 32 | 33 | # Proprocess text data that should be used as snippet content 34 | # Currently, Atom’s snippets implementation has the following issues: 35 | # * multiple $0 are not treated as distinct final tabstops 36 | preprocessSnippet = (value) -> 37 | order = [] 38 | 39 | tabstopOptions = 40 | tabstop: (data) -> 41 | group = parseInt(data.group, 10) 42 | if group is 0 43 | order.push(-1) 44 | group = order.length 45 | else 46 | order.push(group) if order.indexOf(group) is -1 47 | group = order.indexOf(group) + 1 48 | 49 | placeholder = data.placeholder or '' 50 | if placeholder 51 | # recursively update nested tabstops 52 | placeholder = tabStops.processText(placeholder, tabstopOptions) 53 | 54 | if placeholder then "${#{group}:#{placeholder}}" else "${#{group}}" 55 | 56 | escape: (ch) -> 57 | if ch == '$' then '\\$' else ch 58 | 59 | tabStops.processText(value, tabstopOptions) 60 | 61 | module.exports = 62 | setup: (@editor, @selectionIndex=0) -> 63 | buf = @editor.getBuffer() 64 | bufRanges = @editor.getSelectedBufferRanges() 65 | @_selection = 66 | index: 0 67 | saved: new Array(bufRanges.length) 68 | bufferRanges: bufRanges 69 | indexRanges: bufRanges.map (range) -> 70 | start: buf.characterIndexForPosition(range.start) 71 | end: buf.characterIndexForPosition(range.end) 72 | 73 | # Executes given function for every selection 74 | exec: (fn) -> 75 | ix = @_selection.bufferRanges.length - 1 76 | @_selection.saved = [] 77 | success = true 78 | while ix >= 0 79 | @_selection.index = ix 80 | if fn(@_selection.index) is false 81 | success = false 82 | break 83 | ix-- 84 | 85 | if success and @_selection.saved.length > 1 86 | @_setSelectedBufferRanges(@_selection.saved) 87 | 88 | _setSelectedBufferRanges: (sels) -> 89 | filteredSels = sels.filter (s) -> !!s 90 | if filteredSels.length 91 | @editor.setSelectedBufferRanges(filteredSels) 92 | 93 | _saveSelection: (delta) -> 94 | @_selection.saved[@_selection.index] = @editor.getSelectedBufferRange() 95 | if delta 96 | i = @_selection.index 97 | delta = Point.fromObject([delta, 0]) 98 | while ++i < @_selection.saved.length 99 | range = @_selection.saved[i] 100 | if range 101 | @_selection.saved[i] = new Range(range.start.translate(delta), range.end.translate(delta)) 102 | 103 | selectionList: -> 104 | @_selection.indexRanges 105 | 106 | # Returns the current caret position. 107 | getCaretPos: -> 108 | @getSelectionRange().start 109 | 110 | # Sets the current caret position. 111 | setCaretPos: (pos) -> 112 | @createSelection(pos) 113 | 114 | # Fetches the character indexes of the selected text. 115 | # Returns an {Object} with `start` and `end` properties. 116 | getSelectionRange: -> 117 | @_selection.indexRanges[@_selection.index] 118 | 119 | getSelectionBufferRange: -> 120 | @_selection.bufferRanges[@_selection.index] 121 | 122 | # Creates a selection from the `start` to `end` character indexes. 123 | # 124 | # If `end` is ommited, this method should place a caret at the `start` index. 125 | # 126 | # start - A {Number} representing the starting character index 127 | # end - A {Number} representing the ending character index 128 | createSelection: (start, end=start) -> 129 | sels = @_selection.bufferRanges 130 | buf = @editor.getBuffer() 131 | sels[@_selection.index] = new Range(buf.positionForCharacterIndex(start), buf.positionForCharacterIndex(end)) 132 | @_setSelectedBufferRanges(sels) 133 | 134 | # Returns the currently selected text. 135 | getSelection: -> 136 | @editor.getTextInBufferRange(@getSelectionBufferRange()) 137 | 138 | # Fetches the current line's start and end indexes. 139 | # 140 | # Returns an {Object} with `start` and `end` properties 141 | getCurrentLineRange: -> 142 | sel = @getSelectionBufferRange() 143 | row = sel.getRows()[0] 144 | lineLength = @editor.lineTextForBufferRow(row).length 145 | index = @editor.getBuffer().characterIndexForPosition({row: row, column: 0}) 146 | return { 147 | start: index 148 | end: index + lineLength 149 | } 150 | 151 | # Returns the current line. 152 | getCurrentLine: -> 153 | sel = @getSelectionBufferRange() 154 | row = sel.getRows()[0] 155 | return @editor.lineTextForBufferRow(row) 156 | 157 | # Returns the editor content. 158 | getContent: -> 159 | return @editor.getText() 160 | 161 | # Replace the editor's content (or part of it, if using `start` to 162 | # `end` index). 163 | # 164 | # If `value` contains `caret_placeholder`, the editor puts a caret into 165 | # this position. If you skip the `start` and `end` arguments, the whole target's 166 | # content is replaced with `value`. 167 | # 168 | # If you pass just the `start` argument, the `value` is placed at the `start` string 169 | # index of thr current content. 170 | # 171 | # If you pass both `start` and `end` arguments, the corresponding substring of 172 | # the current target's content is replaced with `value`. 173 | # 174 | # value - A {String} of content you want to paste 175 | # start - The optional start index {Number} of the editor's content 176 | # end - The optional end index {Number} of the editor's content 177 | # noIdent - An optional {Boolean} which, if `true`, does not attempt to auto indent `value` 178 | replaceContent: (value, start, end, noIndent) -> 179 | unless end? 180 | end = unless start? then @getContent().length else start 181 | start = 0 unless start? 182 | 183 | value = normalize(value, @editor) 184 | buf = @editor.getBuffer() 185 | changeRange = new Range( 186 | Point.fromObject(buf.positionForCharacterIndex(start)), 187 | Point.fromObject(buf.positionForCharacterIndex(end)) 188 | ) 189 | 190 | oldValue = @editor.getTextInBufferRange(changeRange) 191 | buf.setTextInRange(changeRange, '') 192 | # Before inserting snippet we have to reset all available selections 193 | # to insert snippent right in required place. Otherwise snippet 194 | # will be inserted for each selection in editor 195 | 196 | # Right after that we should save first available selection as buffer range 197 | caret = buf.positionForCharacterIndex(start) 198 | @editor.setSelectedBufferRange(new Range(caret, caret)) 199 | insertSnippet preprocessSnippet(value), @editor 200 | @_saveSelection(utils.splitByLines(value).length - utils.splitByLines(oldValue).length) 201 | value 202 | 203 | getGrammar: -> 204 | @editor.getGrammar().scopeName.toLowerCase() 205 | 206 | # Returns the editor's syntax mode. 207 | getSyntax: -> 208 | scope = @getCurrentScope().join(' ') 209 | return 'xsl' if ~scope.indexOf('xsl') 210 | return 'jsx' if not /\bstring\b/.test(scope) && /\bsource\.(js|ts)x?\b/.test(scope) 211 | 212 | sourceSyntax = scope.match(/\bsource\.([\w\-]+)/)?[0] 213 | 214 | if not /\bstring\b/.test(scope) && sourceSyntax && resources.hasSyntax(sourceSyntax) 215 | syntax = sourceSyntax; 216 | else 217 | # probe syntax based on current selector 218 | m = scope.match(/\b(source|text)\.[\w\-\.]+/) 219 | syntax = m?[0].split('.').reduceRight (result, token) -> 220 | result or (token if resources.hasSyntax token) 221 | , null 222 | 223 | actionUtils.detectSyntax(@, syntax or 'html') 224 | 225 | getCurrentScope: -> 226 | range = @_selection.bufferRanges[@_selection.index] 227 | @editor.scopeDescriptorForBufferPosition(range.start).getScopesArray() 228 | 229 | # Returns the current output profile name 230 | # 231 | # See emmet.setupProfile for more information. 232 | getProfileName: -> 233 | return if @getCurrentScope().some((scope) -> /\bstring\.quoted\b/.test scope) then 'line' else actionUtils.detectProfile(@) 234 | 235 | # Returns the current editor's file path 236 | getFilePath: -> 237 | # is there a better way to get this? 238 | @editor.buffer.file.path 239 | -------------------------------------------------------------------------------- /lib/emmet.coffee: -------------------------------------------------------------------------------- 1 | path = require 'path' 2 | fs = require 'fs' 3 | {CompositeDisposable} = require 'atom' 4 | 5 | emmet = require 'emmet' 6 | emmetActions = require 'emmet/lib/action/main' 7 | resources = require 'emmet/lib/assets/resources' 8 | 9 | editorProxy = require './editor-proxy' 10 | # interactive = require './interactive' 11 | 12 | singleSelectionActions = [ 13 | 'prev_edit_point', 'next_edit_point', 'merge_lines', 14 | 'reflect_css_value', 'select_next_item', 'select_previous_item', 15 | 'wrap_with_abbreviation', 'update_tag' 16 | ] 17 | 18 | toggleCommentSyntaxes = ['html', 'css', 'less', 'scss'] 19 | 20 | for k, v of atom.config.get 'emmet.stylus' 21 | emmet.preferences.set('stylus.' + k, v); 22 | 23 | getUserHome = () -> 24 | if process.platform is 'win32' 25 | return process.env.USERPROFILE 26 | 27 | process.env.HOME 28 | 29 | isValidTabContext = () -> 30 | if editorProxy.getGrammar() is 'html' 31 | # HTML may contain embedded grammars 32 | scopes = editorProxy.getCurrentScope() 33 | contains = (regexp) -> scopes.filter((s) -> regexp.test s).length 34 | 35 | if contains /\.js\.embedded\./ 36 | # in JS, allow Tab expander only inside string 37 | return contains /^string\./ 38 | 39 | return true 40 | 41 | 42 | # Emmet action decorator: creates a command function 43 | # for Atom and executes Emmet action as single 44 | # undo command 45 | # @param {Object} action Action to perform 46 | # @return {Function} 47 | actionDecorator = (action) -> 48 | (evt) -> 49 | editorProxy.setup @getModel() 50 | editorProxy.editor.transact => 51 | runAction action, evt 52 | 53 | # Same as `actionDecorator()` but executes action 54 | # with multiple selections 55 | # @param {Object} action Action to perform 56 | # @return {Function} 57 | multiSelectionActionDecorator = (action) -> 58 | (evt) -> 59 | editorProxy.setup(@getModel()) 60 | editorProxy.editor.transact => 61 | editorProxy.exec (i) -> 62 | runAction action, evt 63 | return false if evt.keyBindingAborted 64 | 65 | runAction = (action, evt) -> 66 | syntax = editorProxy.getSyntax() 67 | if action is 'expand_abbreviation_with_tab' 68 | # do not handle Tab key if: 69 | # -1. syntax is unknown- (no longer valid, defined by keymap selector) 70 | # 2. there’s a selection (user wants to indent it) 71 | # 3. has expanded snippet (e.g. has tabstops) 72 | activeEditor = editorProxy.editor; 73 | if not isValidTabContext() or not activeEditor.getLastSelection().isEmpty() 74 | return evt.abortKeyBinding() 75 | if activeEditor.snippetExpansion 76 | # in case of snippet expansion: expand abbreviation if we currently on last 77 | # tabstop 78 | se = activeEditor.snippetExpansion 79 | if se.tabStopIndex + 1 >= se.tabStopMarkers.length 80 | se.destroy() 81 | else 82 | return evt.abortKeyBinding() 83 | 84 | if action is 'toggle_comment' and (toggleCommentSyntaxes.indexOf(syntax) is -1 or not atom.config.get 'emmet.useEmmetComments') 85 | return evt.abortKeyBinding() 86 | 87 | if action is 'insert_formatted_line_break_only' 88 | if not atom.config.get 'emmet.formatLineBreaks' 89 | return evt.abortKeyBinding() 90 | 91 | result = emmet.run action, editorProxy 92 | return if not result then evt.abortKeyBinding() else true 93 | 94 | emmet.run action, editorProxy 95 | 96 | atomActionName = (name) -> 97 | 'emmet:' + name.replace(/_/g, '-') 98 | 99 | registerInteractiveActions = (actions) -> 100 | for name in ['wrap_with_abbreviation', 'update_tag', 'interactive_expand_abbreviation'] 101 | do (name) -> 102 | atomAction = atomActionName name 103 | actions[atomAction] = (evt) -> 104 | editorProxy.setup(@getModel()) 105 | interactive = require './interactive' 106 | interactive.run(name, editorProxy) 107 | 108 | loadExtensions = () -> 109 | extPath = atom.config.get 'emmet.extensionsPath' 110 | console.log 'Loading Emmet extensions from', extPath 111 | return unless extPath 112 | 113 | if extPath[0] is '~' 114 | extPath = getUserHome() + extPath.substr 1 115 | 116 | if fs.existsSync extPath 117 | emmet.resetUserData() 118 | files = fs.readdirSync extPath 119 | files = files 120 | .map((item) -> path.join extPath, item) 121 | .filter((file) -> not fs.statSync(file).isDirectory()) 122 | 123 | emmet.loadExtensions(files) 124 | else 125 | console.warn 'Emmet: no such extension folder:', extPath 126 | 127 | module.exports = 128 | config: 129 | extensionsPath: 130 | type: 'string' 131 | default: '~/emmet' 132 | formatLineBreaks: 133 | type: 'boolean' 134 | default: true 135 | useEmmetComments: 136 | type: 'boolean' 137 | default: false 138 | description: 'disable to use atom native commenting system' 139 | 140 | activate: (@state) -> 141 | @subscriptions = new CompositeDisposable 142 | unless @actions 143 | @subscriptions.add atom.config.observe 'emmet.extensionsPath', loadExtensions 144 | @actions = {} 145 | registerInteractiveActions @actions 146 | for action in emmetActions.getList() 147 | atomAction = atomActionName action.name 148 | if @actions[atomAction]? 149 | continue 150 | cmd = if singleSelectionActions.indexOf(action.name) isnt -1 then actionDecorator(action.name) else multiSelectionActionDecorator(action.name) 151 | @actions[atomAction] = cmd 152 | 153 | @subscriptions.add atom.commands.add 'atom-text-editor', @actions 154 | 155 | deactivate: -> 156 | atom.config.transact => @subscriptions.dispose() 157 | -------------------------------------------------------------------------------- /lib/interactive.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition of interactive functions: the function 3 | * that require additional dialog prompt and update 4 | * editor content when user types data in prompt 5 | */ 6 | var utils = require('emmet/lib/utils/common'); 7 | var editorUtils = require('emmet/lib/utils/editor'); 8 | var actionUtils = require('emmet/lib/utils/action'); 9 | 10 | var range = require('emmet/lib/assets/range'); 11 | var htmlMatcher = require('emmet/lib/assets/htmlMatcher'); 12 | var parser = require('emmet/lib/parser/abbreviation'); 13 | var updateTag = require('emmet/lib/action/updateTag'); 14 | 15 | var atom = require('atom'); 16 | var PromptView = require('./prompt'); 17 | var Point = atom.Point; 18 | var Range = atom.Range; 19 | var prompt = new PromptView(); 20 | 21 | /** 22 | * Caches wrapping context for current selection in editor 23 | * @param {IEmmetEditor} editor 24 | * @param {Object} info Current editor info (content, syntax, etc.) 25 | * @return {Object} 26 | */ 27 | function selectionContext(editor, info) { 28 | info = info || editorUtils.outputInfo(editor); 29 | return editor.selectionList().map(function(sel, i) { 30 | var r = range(sel); 31 | var tag = htmlMatcher.tag(info.content, r.start); 32 | if (!r.length() && tag) { 33 | // no selection, use tag pair 34 | r = utils.narrowToNonSpace(info.content, tag.range); 35 | } 36 | 37 | var out = { 38 | selection: r, 39 | tag: tag, 40 | caret: r.start, 41 | syntax: info.syntax, 42 | profile: info.profile || null, 43 | counter: i + 1, 44 | contextNode: actionUtils.captureContext(editor, r.start) 45 | }; 46 | 47 | if (r.length()) { 48 | var pasted = utils.escapeText(r.substring(info.content)); 49 | out.pastedContent = editorUtils.unindent(editor, pasted); 50 | } 51 | 52 | return out; 53 | }); 54 | } 55 | 56 | function updateFinalCarets(selCtx, fromIndex, delta) { 57 | if (!delta) { 58 | return; 59 | } 60 | 61 | var offset = new Point(delta, 0); 62 | for (var i = fromIndex + 1, il = selCtx.length; i < il; i++) { 63 | selCtx[i].finalCaret = selCtx[i].finalCaret.translate(offset); 64 | } 65 | } 66 | 67 | /** 68 | * Returns current caret position for given editor 69 | * @param {Editor} editor Atom editor instance 70 | * @return {Number} Character index in editor 71 | */ 72 | function getCaret(editor) { 73 | // we can’t use default `getCursor()` method because it returns 74 | // the most recent (e.g. the latest) caret, but we need the first one 75 | return editor.getSelectedBufferRanges()[0].start; 76 | } 77 | 78 | function lineDelta(prev, cur) { 79 | return utils.splitByLines(cur).length - utils.splitByLines(prev).length; 80 | } 81 | 82 | function setFinalCarets(selCtx, editor) { 83 | if (selCtx && selCtx.length > 1) { 84 | editor.setSelectedBufferRanges(selCtx.map(function(ctx) { 85 | return new Range(ctx.finalCaret, ctx.finalCaret); 86 | })); 87 | } 88 | } 89 | 90 | module.exports = { 91 | run: function(cmd, editor) { 92 | if (cmd === 'wrap_with_abbreviation') { 93 | return this.wrapWithAbbreviation(editor); 94 | } 95 | 96 | if (cmd === 'update_tag') { 97 | return this.updateTag(editor); 98 | } 99 | 100 | if (cmd === 'interactive_expand_abbreviation') { 101 | return this.expandAbbreviation(editor); 102 | } 103 | }, 104 | 105 | expandAbbreviation: function(editor) { 106 | var info = editorUtils.outputInfo(editor); 107 | var selCtx = editor.selectionList().map(function(sel, i) { 108 | editor._selection.index = i; 109 | var r = range(sel); 110 | return { 111 | selection: r, 112 | selectedText: r.substring(info.content), 113 | caret: r.start, 114 | syntax: info.syntax, 115 | profile: info.profile || null, 116 | counter: i + 1, 117 | contextNode: actionUtils.captureContext(editor, r.start) 118 | }; 119 | }); 120 | 121 | return this.wrapWithAbbreviation(editor, selCtx); 122 | }, 123 | 124 | wrapWithAbbreviation: function(editor, selCtx) { 125 | selCtx = selCtx || selectionContext(editor); 126 | 127 | // show prompt dialog that will wrap each selection 128 | // on user typing 129 | prompt.show({ 130 | label: 'Enter Abbreviation', 131 | editor: editor.editor, 132 | editorView: editor.editorView, 133 | update: function(abbr) { 134 | var result, replaced; 135 | for (var i = selCtx.length - 1, ctx; i >= 0; i--) { 136 | ctx = selCtx[i]; 137 | result = ''; 138 | try { 139 | if (abbr) { 140 | result = parser.expand(abbr, ctx); 141 | } else { 142 | result = ctx.pastedContent; 143 | } 144 | } catch (e) { 145 | console.error(e); 146 | result = ctx.pastedContent; 147 | } 148 | 149 | editor._selection.index = i; 150 | replaced = editor.replaceContent(result, ctx.selection.start, ctx.selection.end); 151 | ctx.finalCaret = getCaret(editor.editor); 152 | updateFinalCarets(selCtx, i, lineDelta(ctx.selectedText, replaced)); 153 | } 154 | }, 155 | confirm: function() { 156 | setFinalCarets(selCtx, editor.editor); 157 | } 158 | }); 159 | }, 160 | 161 | updateTag: function(editor) { 162 | var info = editorUtils.outputInfo(editor); 163 | var selCtx = selectionContext(editor, info); 164 | 165 | // show prompt dialog that will update each 166 | // tag from selection 167 | prompt.show({ 168 | label: 'Enter Abbreviation', 169 | editor: editor.editor, 170 | editorView: editor.editorView, 171 | update: function(abbr) { 172 | var tag, replaced, delta; 173 | for (var i = selCtx.length - 1, ctx; i >= 0; i--) { 174 | ctx = selCtx[i]; 175 | tag = null; 176 | 177 | try { 178 | tag = updateTag.getUpdatedTag(abbr, {match: ctx.tag}, info.content, { 179 | counter: ctx.counter 180 | }); 181 | } catch (e) { 182 | console.error(e); 183 | } 184 | 185 | if (!tag) { 186 | continue; 187 | } 188 | 189 | replaced = [{ 190 | start: ctx.tag.open.range.start, 191 | end: ctx.tag.open.range.end, 192 | content: tag.source 193 | }]; 194 | 195 | if (tag.name() != ctx.tag.name && ctx.tag.close) { 196 | replaced.unshift({ 197 | start: ctx.tag.close.range.start, 198 | end: ctx.tag.close.range.end, 199 | content: '' 200 | }); 201 | } 202 | 203 | replaced.forEach(function(data) { 204 | editor.replaceContent(data.content, data.start, data.end); 205 | ctx.finalCaret = editor.editor.getBuffer().positionForCharacterIndex(data.start); 206 | }); 207 | } 208 | 209 | }, 210 | confirm: function() { 211 | setFinalCarets(selCtx, editor.editor); 212 | } 213 | }); 214 | } 215 | }; -------------------------------------------------------------------------------- /lib/prompt.coffee: -------------------------------------------------------------------------------- 1 | {$, TextEditorView, View} = require 'atom-space-pen-views' 2 | noop = -> 3 | 4 | method = (delegate, method) -> 5 | delegate?[method]?.bind(delegate) or noop 6 | 7 | module.exports = 8 | class PromptView extends View 9 | @attach: -> new PromptView 10 | 11 | @content: -> 12 | @div class: 'emmet-prompt tool-panel panel-bottom', => 13 | # @label class: 'emmet-prompt__label', outlet: 'label' 14 | @div class: 'emmet-prompt__input', => 15 | @subview 'panelInput', new TextEditorView(mini: true) 16 | 17 | initialize: () -> 18 | @panelEditor = @panelInput.getModel() 19 | @panelEditor.onDidStopChanging => 20 | return unless @attached 21 | @handleUpdate @panelEditor.getText() 22 | atom.commands.add @panelInput.element, 'core:confirm', => @confirm() 23 | atom.commands.add @panelInput.element, 'core:cancel', => @cancel() 24 | 25 | show: (@delegate={}) -> 26 | @editor = @delegate.editor 27 | @editorView = @delegate.editorView 28 | # @panelInput.setPlaceholderText @delegate.label or 'Enter abbreviation' 29 | @panelInput.element.setAttribute 'placeholder', @delegate.label or 'Enter abbreviation' 30 | @updated = no 31 | 32 | @attach() 33 | text = @panelEditor.getText() 34 | if text 35 | @panelEditor.selectAll() 36 | @handleUpdate text 37 | 38 | undo: -> 39 | @editor.undo() if @updated 40 | 41 | handleUpdate: (text) -> 42 | @undo() 43 | @updated = yes 44 | @editor.transact => 45 | method(@delegate, 'update')(text) 46 | 47 | confirm: -> 48 | @handleUpdate @panelEditor.getText() 49 | @trigger 'confirm' 50 | method(@delegate, 'confirm')() 51 | @detach() 52 | 53 | cancel: -> 54 | @undo() 55 | @trigger 'cancel' 56 | method(@delegate, 'cancel')() 57 | @detach() 58 | 59 | detach: -> 60 | return unless @hasParent() 61 | @detaching = true 62 | @prevPane?.activate() 63 | 64 | super 65 | @detaching = false 66 | @attached = false 67 | 68 | @trigger 'detach' 69 | method(@delegate, 'hide')() 70 | 71 | attach: -> 72 | @attached = true 73 | @prevPane = atom.workspace.getActivePane() 74 | atom.workspace.addBottomPanel(item: this, visible: true) 75 | @panelInput.focus() 76 | @trigger 'attach' 77 | method(@delegate, 'show')() 78 | -------------------------------------------------------------------------------- /menus/emmet.json: -------------------------------------------------------------------------------- 1 | { 2 | "menu": [ 3 | { 4 | "label": "Packages", 5 | "submenu": [ 6 | { 7 | "label": "Emmet", 8 | "submenu": [ 9 | { 10 | "label": "Encode\\Decode data:URL image", 11 | "command": "emmet:encode-decode-data-url" 12 | }, 13 | { 14 | "label": "Previous Edit Point", 15 | "command": "emmet:prev-edit-point" 16 | }, 17 | { 18 | "label": "Next Edit Point", 19 | "command": "emmet:next-edit-point" 20 | }, 21 | { 22 | "label": "Numbers", 23 | "submenu": [ 24 | { 25 | "label": "Evaluate Math Expression", 26 | "command": "emmet:evaluate-math-expression" 27 | }, 28 | { 29 | "label": "Increment number by 1", 30 | "command": "emmet:increment-number-by-1" 31 | }, 32 | { 33 | "label": "Decrement number by 1", 34 | "command": "emmet:decrement-number-by-1" 35 | }, 36 | { 37 | "label": "Increment number by 10", 38 | "command": "emmet:increment-number-by-10" 39 | }, 40 | { 41 | "label": "Decrement number by 10", 42 | "command": "emmet:decrement-number-by-10" 43 | }, 44 | { 45 | "label": "Increment number by 0.1", 46 | "command": "emmet:increment-number-by-01" 47 | }, 48 | { 49 | "label": "Decrement number by 0.1", 50 | "command": "emmet:decrement-number-by-01" 51 | } 52 | ] 53 | }, 54 | { 55 | "label": "Expand Abbreviation", 56 | "command": "emmet:expand-abbreviation" 57 | }, 58 | { 59 | "label": "Balance (inward)", 60 | "command": "emmet:balance-inward" 61 | }, 62 | { 63 | "label": "Balance (outward)", 64 | "command": "emmet:balance-outward" 65 | }, 66 | { 67 | "label": "HTML", 68 | "submenu": [ 69 | { 70 | "label": "Go To Matching Tag Pair", 71 | "command": "emmet:matching-pair" 72 | }, 73 | { 74 | "label": "Remove Tag", 75 | "command": "emmet:remove-tag" 76 | }, 77 | { 78 | "label": "Split\\Join Tag Declaration", 79 | "command": "emmet:split-join-tag" 80 | }, 81 | { 82 | "label": "Update Tag", 83 | "command": "emmet:update-tag" 84 | } 85 | ] 86 | }, 87 | { 88 | "label": "Merge Lines", 89 | "command": "emmet:merge-lines" 90 | }, 91 | { 92 | "label": "CSS", 93 | "submenu": [ 94 | { 95 | "label": "Reflect Value", 96 | "command": "emmet:reflect-css-value" 97 | } 98 | ] 99 | }, 100 | { 101 | "label": "Select Next Item", 102 | "command": "emmet:select-next-item" 103 | }, 104 | { 105 | "label": "Select Previous Item", 106 | "command": "emmet:select-previous-item" 107 | }, 108 | { 109 | "label": "Toggle Comment", 110 | "command": "emmet:toggle-comment" 111 | }, 112 | { 113 | "label": "Update Image Size", 114 | "command": "emmet:update-image-size" 115 | }, 116 | { 117 | "label": "Wrap With Abbreviation", 118 | "command": "emmet:wrap-with-abbreviation" 119 | }, 120 | { 121 | "label": "Interactive Expand Abbreviation", 122 | "command": "emmet:interactive-expand-abbreviation" 123 | } 124 | ] 125 | } 126 | ] 127 | } 128 | ] 129 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "emmet", 3 | "description": "Emmet – the essential tool for web developers", 4 | "main": "./lib/emmet", 5 | "version": "2.4.3", 6 | "dependencies": { 7 | "emmet": "^1.3.2", 8 | "atom-space-pen-views": "^2.0.3" 9 | }, 10 | "license": "MIT", 11 | "repository": "https://github.com/emmetio/emmet-atom", 12 | "engines": { 13 | "atom": "*" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /spec/emmet-spec.coffee: -------------------------------------------------------------------------------- 1 | Path = require "path" 2 | Fs = require "fs" 3 | 4 | readFile = (path) -> 5 | Fs.readFileSync(Path.join(__dirname, "./fixtures/", path), "utf8") 6 | 7 | describe "Emmet", -> 8 | [editor, editorElement] = [] 9 | 10 | console.log atom.keymaps.onDidMatchBinding (event) -> 11 | console.log 'Matched keybinding', event 12 | 13 | 14 | simulateTabKeyEvent = () -> 15 | event = keydownEvent("tab", {target: editorElement}) 16 | atom.keymaps.handleKeyboardEvent(event.originalEvent) 17 | 18 | beforeEach -> 19 | waitsForPromise -> 20 | atom.workspace.open("tabbing.html") 21 | 22 | waitsForPromise -> 23 | atom.packages.activatePackage("emmet") 24 | 25 | waitsForPromise -> 26 | atom.packages.activatePackage("snippets") # to intentionally disrupt tab expansion 27 | 28 | waitsForPromise -> 29 | atom.packages.activatePackage("language-css", sync: true) 30 | 31 | waitsForPromise -> 32 | atom.packages.activatePackage("language-sass", sync: true) 33 | 34 | waitsForPromise -> 35 | atom.packages.activatePackage("language-php", sync: true) 36 | 37 | waitsForPromise -> 38 | atom.packages.activatePackage("language-html", sync: true) 39 | 40 | runs -> 41 | # make sure emitter is initiated to properly deactivate package 42 | atom.packages.getLoadedPackage('snippets')?.mainModule?.getEmitter() 43 | editor = atom.workspace.getActiveTextEditor() 44 | editorElement = atom.views.getView(editor) 45 | 46 | describe "tabbing", -> 47 | beforeEach -> 48 | atom.workspace.open('tabbing.html') 49 | editor.setCursorScreenPosition([1, 4]) 50 | 51 | it "moves the cursor along", -> 52 | simulateTabKeyEvent() 53 | cursorPos = editor.getCursorScreenPosition() 54 | expect(cursorPos.column).toBe 6 55 | 56 | describe "emmet:expand-abbreviation", -> 57 | expansion = null 58 | 59 | describe "for normal HTML", -> 60 | beforeEach -> 61 | editor.setText readFile "abbreviation/before/html-abbrv.html" 62 | editor.moveToEndOfLine() 63 | 64 | expansion = readFile "abbreviation/after/html-abbrv.html" 65 | 66 | it "expands HTML abbreviations via commands", -> 67 | atom.commands.dispatch editorElement, "emmet:expand-abbreviation" 68 | expect(editor.getText()).toBe expansion 69 | 70 | it "expands HTML abbreviations via keybindings", -> 71 | event = keydownEvent('e', shiftKey: true, metaKey: true, target: editorElement) 72 | atom.keymaps.handleKeyboardEvent(event.originalEvent) 73 | expect(editor.getText()).toBe expansion 74 | 75 | it "expands HTML abbreviations via Tab", -> 76 | console.log atom.keymaps.findKeyBindings keystrokes: 'tab' 77 | simulateTabKeyEvent() 78 | expect(editor.getText()).toBe expansion 79 | 80 | # describe "for HTML with attributes", -> 81 | # beforeEach -> 82 | # workspaceView.openSync(Path.join(__dirname, './fixtures/abbreviation/before/anchor-class-expand.html')) 83 | # editorView = workspaceView.getActiveView() 84 | # editor = editorView.getEditor() 85 | # editSession = workspaceView.getActivePaneItem() 86 | # editSession.moveCursorToEndOfLine() 87 | 88 | # expansion = Fs.readFileSync(Path.join(__dirname, './fixtures/abbreviation/after/anchor-class-expand.html'), "utf8") 89 | 90 | # it "expands HTML abbreviations via commands", -> 91 | # editorView.trigger "emmet:expand-abbreviation" 92 | # expect(editorView.getText()).toBe expansion 93 | # cursorPos = editor.getCursorScreenPosition() 94 | # expect(cursorPos.column).toBe 9 95 | 96 | # it "expands HTML abbreviations via keybindings", -> 97 | # editorView.trigger keydownEvent('e', shiftKey: true, metaKey: true, target: editor[0]) 98 | # expect(editor.getText()).toBe expansion 99 | # cursorPos = editor.getCursorScreenPosition() 100 | # expect(cursorPos.column).toBe 9 101 | 102 | # it "expands HTML abbreviations via Tab", -> 103 | # editorView.trigger keydownEvent('tab', target: editor[0]) 104 | # expect(editor.getText()).toBe expansion 105 | # cursorPos = editor.getCursorScreenPosition() 106 | # expect(cursorPos.column).toBe 9 107 | 108 | # # headers seem to be a special case: http://git.io/7XeBKQ 109 | # describe "for headers in HTML", -> 110 | # beforeEach -> 111 | # workspaceView.openSync(Path.join(__dirname, './fixtures/abbreviation/before/header-expand.html')) 112 | # editorView = workspaceView.getActiveView() 113 | # editor = editorView.getEditor() 114 | # editSession = workspaceView.getActivePaneItem() 115 | # editSession.moveCursorToEndOfLine() 116 | 117 | # expansion = Fs.readFileSync(Path.join(__dirname, './fixtures/abbreviation/after/header-expand.html'), "utf8") 118 | 119 | # it "expands HTML abbreviations via commands", -> 120 | # editorView.trigger "emmet:expand-abbreviation" 121 | # expect(editorView.getText()).toBe expansion 122 | 123 | # it "expands HTML abbreviations via keybindings", -> 124 | # editorView.trigger keydownEvent('e', shiftKey: true, metaKey: true, target: editor[0]) 125 | # expect(editorView.getText()).toBe expansion 126 | 127 | # it "expands HTML abbreviations via Tab", -> 128 | # editorView.trigger keydownEvent('tab', target: editor[0]) 129 | # expect(editorView.getText()).toBe expansion 130 | 131 | # describe "for CSS", -> 132 | # beforeEach -> 133 | # workspaceView.openSync(Path.join(__dirname, './fixtures/abbreviation/before/css-abbrv.css')) 134 | # editorView = workspaceView.getActiveView() 135 | # editor = editorView.getEditor() 136 | # editSession = workspaceView.getActivePaneItem() 137 | # editSession.moveCursorToEndOfLine() 138 | 139 | # expansion = Fs.readFileSync(Path.join(__dirname, './fixtures/abbreviation/after/css-abbrv.css'), "utf8") 140 | 141 | # it "expands CSS abbreviations via commands", -> 142 | # editorView.trigger "emmet:expand-abbreviation" 143 | # expect(editor.getText()).toBe expansion 144 | 145 | # it "expands CSS abbreviations via keybindings", -> 146 | # editorView.trigger keydownEvent('e', shiftKey: true, metaKey: true, target: editor[0]) 147 | # expect(editor.getText()).toBe expansion 148 | 149 | # it "expands CSS abbreviations via tab", -> 150 | # editorView.trigger keydownEvent('tab', target: editor[0]) 151 | # expect(editor.getText()).toBe expansion 152 | 153 | # describe "for PHP", -> 154 | # describe "for PHP with HTML", -> 155 | # beforeEach -> 156 | # workspaceView.openSync(Path.join(__dirname, './fixtures/abbreviation/before/php-in-html.php')) 157 | # editorView = workspaceView.getActiveView() 158 | # editor = editorView.getEditor() 159 | # editSession = workspaceView.getActivePaneItem() 160 | # editSession.setCursorBufferPosition([6, 5]) 161 | 162 | # expansion = Fs.readFileSync(Path.join(__dirname, './fixtures/abbreviation/after/php-in-html.php'), "utf8") 163 | 164 | # it "expands abbreviations via commands", -> 165 | # editorView.trigger "emmet:expand-abbreviation" 166 | # expect(editor.getText()).toBe expansion 167 | 168 | # it "expands abbreviations via keybindings", -> 169 | # editorView.trigger keydownEvent('e', shiftKey: true, metaKey: true, target: editor[0]) 170 | # expect(editor.getText()).toBe expansion 171 | 172 | # it "expands abbreviations via tab", -> 173 | # editorView.trigger keydownEvent('tab', target: editor[0]) 174 | # expect(editor.getText()).toBe expansion 175 | 176 | # # fdescribe "for vanilla PHP", -> 177 | # # beforeEach -> 178 | # # workspaceView.openSync(Path.join(__dirname, './fixtures/abbreviation/before/vanilla-php.php')) 179 | # # editorView = workspaceView.getActiveView() 180 | # # editor = editorView.getEditor() 181 | # # editSession = workspaceView.getActivePaneItem() 182 | # # editSession.setCursorBufferPosition([1, 3]) 183 | # # 184 | # # expansion = Fs.readFileSync(Path.join(__dirname, './fixtures/abbreviation/after/vanilla-php.php'), "utf8") 185 | # # 186 | # # it "expands abbreviations via commands", -> 187 | # # editorView.trigger "emmet:expand-abbreviation" 188 | # # expect(editor.getText()).toBe expansion 189 | # # 190 | # # it "expands abbreviations via keybindings", -> 191 | # # editorView.trigger keydownEvent('e', shiftKey: true, metaKey: true, target: editor[0]) 192 | # # expect(editor.getText()).toBe expansion 193 | # # 194 | # # it "expands abbreviations via tab", -> 195 | # # editorView.trigger keydownEvent('tab', target: editor[0]) 196 | # # expect(editor.getText()).toBe expansion 197 | 198 | # describe "for SASS", -> 199 | # beforeEach -> 200 | # workspaceView.openSync(Path.join(__dirname, './fixtures/abbreviation/before/sass-test.sass')) 201 | # editorView = workspaceView.getActiveView() 202 | # editor = editorView.getEditor() 203 | # editSession = workspaceView.getActivePaneItem() 204 | # editSession.moveCursorToEndOfLine() 205 | 206 | # expansion = Fs.readFileSync(Path.join(__dirname, './fixtures/abbreviation/after/sass-test.sass'), "utf8") 207 | 208 | # it "expands abbreviations via commands", -> 209 | # editorView.trigger "emmet:expand-abbreviation" 210 | # expect(editor.getText()).toBe expansion 211 | 212 | # it "expands abbreviations via keybindings", -> 213 | # editorView.trigger keydownEvent('e', shiftKey: true, metaKey: true, target: editor[0]) 214 | # expect(editor.getText()).toBe expansion 215 | 216 | # it "expands abbreviations via tab", -> 217 | # editorView.trigger keydownEvent('tab', target: editor[0]) 218 | # expect(editor.getText()).toBe expansion 219 | 220 | # describe "for multiple cursors", -> 221 | # beforeEach -> 222 | # workspaceView.openSync(Path.join(__dirname, './fixtures/abbreviation/before/multi-line.html')) 223 | # editorView = workspaceView.getActiveView() 224 | # editor = editorView.getEditor() 225 | # editSession = workspaceView.getActivePaneItem() 226 | 227 | # editor.addCursorAtBufferPosition([0, 9]) 228 | # editor.addCursorAtBufferPosition([1, 9]) 229 | # editor.addCursorAtBufferPosition([2, 9]) 230 | 231 | # expansion = Fs.readFileSync(Path.join(__dirname, './fixtures/abbreviation/after/multi-line.html'), "utf8") 232 | 233 | # it "expands HTML abbreviations via commands", -> 234 | # editorView.trigger "emmet:expand-abbreviation" 235 | # expect(editorView.getText()).toBe expansion 236 | 237 | # # it "expands HTML abbreviations via keybindings", -> 238 | # # editorView.trigger keydownEvent('e', shiftKey: true, metaKey: true, target: editor[0]) 239 | # # expect(editor.getText()).toBe expansion 240 | # # 241 | # # it "expands HTML abbreviations via Tab", -> 242 | # # editorView.trigger keydownEvent('tab', target: editor[0]) 243 | # # expect(editor.getText()).toBe expansion 244 | 245 | # describe "emmet:balance", -> 246 | # beforeEach -> 247 | # workspaceView.openSync(Path.join(__dirname, './fixtures/balance/sample.html')) 248 | # editorView = workspaceView.getActiveView() 249 | # editor = editorView.getEditor() 250 | # editSession = workspaceView.getActivePaneItem() 251 | 252 | # describe "for balance-outward", -> 253 | # beforeEach -> 254 | # editSession.setCursorBufferPosition([3, 23]) 255 | 256 | # it "matches pairs outwards via commands", -> 257 | # expect(editor.getSelection().getBufferRange()).toEqual [[3, 23], [3, 23]] 258 | # editorView.trigger "emmet:balance-outward" 259 | # expect(editor.getSelection().getBufferRange()).toEqual [[3, 11], [3, 38]] 260 | # editorView.trigger "emmet:balance-outward" 261 | # expect(editor.getSelection().getBufferRange()).toEqual [[3, 8], [3, 42]] 262 | # editorView.trigger "emmet:balance-outward" 263 | # expect(editor.getSelection().getBufferRange()).toEqual [[1, 29], [4, 4]] 264 | 265 | # it "matches pairs outwards via keybindings", -> 266 | # expect(editor.getSelection().getBufferRange()).toEqual [[3, 23], [3, 23]] 267 | # editorView.trigger keydownEvent('d', ctrlKey: true, target: editor[0]) 268 | # expect(editor.getSelection().getBufferRange()).toEqual [[3, 11], [3, 38]] 269 | # editorView.trigger keydownEvent('d', ctrlKey: true, target: editor[0]) 270 | # expect(editor.getSelection().getBufferRange()).toEqual [[3, 8], [3, 42]] 271 | # editorView.trigger keydownEvent('d', ctrlKey: true, target: editor[0]) 272 | # expect(editor.getSelection().getBufferRange()).toEqual [[1, 29], [4, 4]] 273 | 274 | # describe "for balance-inward", -> 275 | # beforeEach -> 276 | # editSession.setCursorBufferPosition([1, 4]) 277 | 278 | # it "matches pairs inwards via commands", -> 279 | # editorView.trigger "emmet:balance-inward" 280 | # expect(editor.getSelection().getBufferRange()).toEqual [[0, 15], [5, 0]] 281 | # editorView.trigger "emmet:balance-inward" 282 | # expect(editor.getSelection().getBufferRange()).toEqual [[1, 4], [4, 14]] 283 | # editorView.trigger "emmet:balance-inward" 284 | # expect(editor.getSelection().getBufferRange()).toEqual [[1, 29], [4, 4]] 285 | # editorView.trigger "emmet:balance-inward" 286 | # expect(editor.getSelection().getBufferRange()).toEqual [[2, 8], [2, 33]] 287 | 288 | # it "matches pairs inwards via keybindings", -> 289 | # editorView.trigger keydownEvent('d', altKey: true, target: editor[0]) 290 | # expect(editor.getSelection().getBufferRange()).toEqual [[0, 15], [5, 0]] 291 | # editorView.trigger keydownEvent('d', altKey: true, target: editor[0]) 292 | # expect(editor.getSelection().getBufferRange()).toEqual [[1, 4], [4, 14]] 293 | # editorView.trigger keydownEvent('d', altKey: true, target: editor[0]) 294 | # expect(editor.getSelection().getBufferRange()).toEqual [[1, 29], [4, 4]] 295 | # editorView.trigger keydownEvent('d', altKey: true, target: editor[0]) 296 | # expect(editor.getSelection().getBufferRange()).toEqual [[2, 8], [2, 33]] 297 | 298 | # describe "for go-to match-pair", -> 299 | # it "goes to the match-pair via commands", -> 300 | # editSession.setCursorBufferPosition([4, 10]) 301 | # editorView.trigger "emmet:matching-pair" 302 | # expect(editor.getCursor().getBufferPosition()).toEqual [1, 4] 303 | 304 | # editSession.setCursorBufferPosition([5, 5]) 305 | # editorView.trigger "emmet:matching-pair" 306 | # expect(editor.getCursor().getBufferPosition()).toEqual [0, 0] 307 | 308 | # it "goes to the match-pair via keybindings", -> 309 | # editSession.setCursorBufferPosition([4, 10]) 310 | # editorView.trigger keydownEvent('j', ctrlKey: true, altKey: true, target: editor[0]) 311 | # expect(editor.getCursor().getBufferPosition()).toEqual [1, 4] 312 | 313 | # editSession.setCursorBufferPosition([5, 5]) 314 | # editorView.trigger keydownEvent('j', ctrlKey: true, altKey: true, target: editor[0]) 315 | # expect(editor.getCursor().getBufferPosition()).toEqual [0, 0] 316 | 317 | # describe "emmet:edit-point", -> 318 | # beforeEach -> 319 | # workspaceView.openSync(Path.join(__dirname, './fixtures/edit-points/edit-points.html')) 320 | # editorView = workspaceView.getActiveView() 321 | # editor = editorView.getEditor() 322 | # editSession = workspaceView.getActivePaneItem() 323 | 324 | # describe "for next-edit-point", -> 325 | # beforeEach -> 326 | # editSession.setCursorBufferPosition([0, 0]) 327 | 328 | # it "finds the next-edit-point via commands", -> 329 | # editorView.trigger "emmet:next-edit-point" 330 | # expect(editor.getCursor().getBufferPosition()).toEqual [1, 8] 331 | # editorView.trigger "emmet:next-edit-point" 332 | # expect(editor.getCursor().getBufferPosition()).toEqual [1, 17] 333 | # editorView.trigger "emmet:next-edit-point" 334 | # expect(editor.getCursor().getBufferPosition()).toEqual [1, 19] 335 | 336 | # it "finds the next-edit-point via keybindings", -> 337 | # editorView.trigger keydownEvent('.', ctrlKey: true, altKey:true, target: editor[0]) 338 | # expect(editor.getCursor().getBufferPosition()).toEqual [1, 8] 339 | # editorView.trigger keydownEvent('.', ctrlKey: true, altKey:true, target: editor[0]) 340 | # expect(editor.getCursor().getBufferPosition()).toEqual [1, 17] 341 | # editorView.trigger keydownEvent('.', ctrlKey: true, altKey:true, target: editor[0]) 342 | # expect(editor.getCursor().getBufferPosition()).toEqual [1, 19] 343 | 344 | # describe "for prev-edit-point", -> 345 | # beforeEach -> 346 | # editSession.setCursorBufferPosition([9, 15]) 347 | 348 | # it "finds the prev-edit-point via commands", -> 349 | # editorView.trigger "emmet:prev-edit-point" 350 | # expect(editor.getCursor().getBufferPosition()).toEqual [2, 23] 351 | # editorView.trigger "emmet:prev-edit-point" 352 | # expect(editor.getCursor().getBufferPosition()).toEqual [2, 19] 353 | # editorView.trigger "emmet:prev-edit-point" 354 | # expect(editor.getCursor().getBufferPosition()).toEqual [2, 17] 355 | 356 | # it "finds the prev-edit-point via keybindings", -> 357 | # editorView.trigger keydownEvent(',', ctrlKey: true, altKey:true, target: editor[0]) 358 | # expect(editor.getCursor().getBufferPosition()).toEqual [2, 23] 359 | # editorView.trigger keydownEvent(',', ctrlKey: true, altKey:true, target: editor[0]) 360 | # expect(editor.getCursor().getBufferPosition()).toEqual [2, 19] 361 | # editorView.trigger keydownEvent(',', ctrlKey: true, altKey:true, target: editor[0]) 362 | # expect(editor.getCursor().getBufferPosition()).toEqual [2, 17] 363 | 364 | # describe "emmet:split-join-tag", -> 365 | # beforeEach -> 366 | # workspaceView.openSync(Path.join(__dirname, './fixtures/split-join-tag/split-join-tag.html')) 367 | # editorView = workspaceView.getActiveView() 368 | # editor = editorView.getEditor() 369 | # editSession = workspaceView.getActivePaneItem() 370 | 371 | # describe "for split-join-tag", -> 372 | # beforeEach -> 373 | # editSession.setCursorBufferPosition([1, 10]) 374 | 375 | # it "calls split-join-tag via commands", -> 376 | # editorView.trigger "emmet:split-join-tag" 377 | # expect(editor.lineForBufferRow(0)).toBe "" 378 | # editorView.trigger "emmet:split-join-tag" 379 | # expect(editor.lineForBufferRow(0)).toBe "" 380 | # editorView.trigger "emmet:split-join-tag" 381 | # expect(editor.lineForBufferRow(0)).toBe "" 382 | 383 | # it "calls split-join-tag via keybindings", -> 384 | # editorView.trigger keydownEvent('j', shiftKey: true, metaKey: true, target: editor[0]) 385 | # expect(editor.lineForBufferRow(0)).toBe "" 386 | # editorView.trigger keydownEvent('j', shiftKey: true, metaKey: true, target: editor[0]) 387 | # expect(editor.lineForBufferRow(0)).toBe "" 388 | # editorView.trigger keydownEvent('j', shiftKey: true, metaKey: true, target: editor[0]) 389 | # expect(editor.lineForBufferRow(0)).toBe "" 390 | 391 | # describe "emmet:remove-tag", -> 392 | # onceRemoved = twiceRemoved = null 393 | 394 | # beforeEach -> 395 | # workspaceView.openSync(Path.join(__dirname, './fixtures/remove-tag/before/remove-tag.html')) 396 | # editorView = workspaceView.getActiveView() 397 | # editor = editorView.getEditor() 398 | # editSession = workspaceView.getActivePaneItem() 399 | 400 | # onceRemoved = Fs.readFileSync(Path.join(__dirname, './fixtures/remove-tag/after/remove-tag-once.html'), "utf8") 401 | # twiceRemoved = Fs.readFileSync(Path.join(__dirname, './fixtures/remove-tag/after/remove-tag-twice.html'), "utf8") 402 | 403 | # editSession.setCursorBufferPosition([1, 10]) 404 | 405 | # it "calls remove-tag via commands", -> 406 | # editorView.trigger "emmet:remove-tag" 407 | # expect(editor.getText()).toBe onceRemoved 408 | # editorView.trigger "emmet:remove-tag" 409 | # expect(editor.getText()).toBe twiceRemoved 410 | 411 | # it "calls remove-tag via keybindings", -> 412 | # editorView.trigger keydownEvent('\'', metaKey: true, target: editor[0]) 413 | # expect(editor.getText()).toBe onceRemoved 414 | # editorView.trigger keydownEvent('\'', metaKey: true, target: editor[0]) 415 | # expect(editor.getText()).toBe twiceRemoved 416 | 417 | # describe "emmet:evaluate-math-expression", -> 418 | # beforeEach -> 419 | # workspaceView.openSync(Path.join(__dirname, './fixtures/evaluate-math-expression/evaluate-math-expression.html')) 420 | # editorView = workspaceView.getActiveView() 421 | # editor = editorView.getEditor() 422 | # editSession = workspaceView.getActivePaneItem() 423 | 424 | # describe "for evaluate-math-expression", -> 425 | # it "calls evaluate-math-expression via commands", -> 426 | # editSession.setCursorBufferPosition([0, 3]) 427 | # editorView.trigger "emmet:evaluate-math-expression" 428 | # editSession.setCursorBufferPosition([0, 7]) 429 | # editorView.trigger "emmet:evaluate-math-expression" 430 | # editSession.setCursorBufferPosition([0, 12]) 431 | # editorView.trigger "emmet:evaluate-math-expression" 432 | # expect(editor.getText()).toBe "12 3 90\n" 433 | 434 | # it "calls evaluate-math-expression via keybindings", -> 435 | # editSession.setCursorBufferPosition([0, 3]) 436 | # editorView.trigger keydownEvent('y', shiftKey: true, metaKey: true, target: editor[0]) 437 | # editSession.setCursorBufferPosition([0, 7]) 438 | # editorView.trigger keydownEvent('y', shiftKey: true, metaKey: true, target: editor[0]) 439 | # editSession.setCursorBufferPosition([0, 12]) 440 | # editorView.trigger keydownEvent('y', shiftKey: true, metaKey: true, target: editor[0]) 441 | # expect(editor.getText()).toBe "12 3 90\n" 442 | 443 | # describe "emmet increment/decrement numbers", -> 444 | # beforeEach -> 445 | # workspaceView.openSync(Path.join(__dirname, './fixtures/increment-decrement-numbers/increment-decrement-numbers.css')) 446 | # editorView = workspaceView.getActiveView() 447 | # editor = editorView.getEditor() 448 | # editSession = workspaceView.getActivePaneItem() 449 | 450 | # describe "for incrementing", -> 451 | # describe "increment by 01", -> 452 | # beforeEach -> 453 | # editSession.setCursorBufferPosition([1, 18]) 454 | 455 | # it "increments via commands", -> 456 | # editorView.trigger "emmet:increment-number-by-01" 457 | # editorView.trigger "emmet:increment-number-by-01" 458 | # expect(editor.lineForBufferRow(1)).toMatch(/1\.9/) 459 | # editorView.trigger "emmet:increment-number-by-01" 460 | # editorView.trigger "emmet:increment-number-by-01" 461 | # expect(editor.lineForBufferRow(1)).toMatch(/2\.1/) 462 | 463 | # it "increments via keybindings", -> 464 | # editorView.trigger keydownEvent('up', ctrlKey: true, altKey: true, target: editor[0]) 465 | # editorView.trigger keydownEvent('up', ctrlKey: true, altKey: true, target: editor[0]) 466 | # expect(editor.lineForBufferRow(1)).toMatch(/1\.9/) 467 | # editorView.trigger keydownEvent('up', ctrlKey: true, altKey: true, target: editor[0]) 468 | # editorView.trigger keydownEvent('up', ctrlKey: true, altKey: true, target: editor[0]) 469 | # expect(editor.lineForBufferRow(1)).toMatch(/2\.1/) 470 | 471 | # describe "increment by 1", -> 472 | # beforeEach -> 473 | # editSession.setCursorBufferPosition([2, 13]) 474 | 475 | # it "increments via commands", -> 476 | # editorView.trigger "emmet:increment-number-by-1" 477 | # editorView.trigger "emmet:increment-number-by-1" 478 | # expect(editor.lineForBufferRow(2)).toMatch(/12/) 479 | # for i in [0..12] by 1 480 | # editorView.trigger "emmet:increment-number-by-1" 481 | # expect(editor.lineForBufferRow(2)).toMatch(/25/) 482 | 483 | # it "increments via keybindings", -> 484 | # editorView.trigger keydownEvent('up', ctrlKey: true, altKey: true, metaKey:true, target: editor[0]) 485 | # editorView.trigger keydownEvent('up', ctrlKey: true, altKey: true, metaKey:true, target: editor[0]) 486 | # expect(editor.lineForBufferRow(2)).toMatch(/12/) 487 | # for i in [0..12] by 1 488 | # editorView.trigger keydownEvent('up', ctrlKey: true, altKey: true, metaKey:true, target: editor[0]) 489 | # expect(editor.lineForBufferRow(2)).toMatch(/25/) 490 | 491 | # describe "increment by 10", -> 492 | # beforeEach -> 493 | # editSession.setCursorBufferPosition([3, 12]) 494 | 495 | # it "increments via commands", -> 496 | # editorView.trigger "emmet:increment-number-by-10" 497 | # editorView.trigger "emmet:increment-number-by-10" 498 | # expect(editor.lineForBufferRow(3)).toMatch(/120/) 499 | 500 | # it "increments via keybindings", -> 501 | # editorView.trigger keydownEvent('up', ctrlKey: true, altKey: true, metaKey: true, shiftKey: true, target: editor[0]) 502 | # editorView.trigger keydownEvent('up', ctrlKey: true, altKey: true, metaKey: true, shiftKey: true, target: editor[0]) 503 | # expect(editor.lineForBufferRow(3)).toMatch(/120/) 504 | 505 | # describe "for decrementing", -> 506 | # describe "decrement by 01", -> 507 | # beforeEach -> 508 | # editSession.setCursorBufferPosition([1, 18]) 509 | 510 | # it "decrements via commands", -> 511 | # editorView.trigger "emmet:decrement-number-by-01" 512 | # editorView.trigger "emmet:decrement-number-by-01" 513 | # expect(editor.lineForBufferRow(1)).toMatch(/1\.5/) 514 | # for i in [0..20] by 1 515 | # editorView.trigger "emmet:decrement-number-by-01" 516 | # expect(editor.lineForBufferRow(1)).toMatch(/\-0\.6/) 517 | 518 | # it "decrements via keybindings", -> 519 | # editorView.trigger keydownEvent('down', ctrlKey: true, altKey: true, target: editor[0]) 520 | # editorView.trigger keydownEvent('down', ctrlKey: true, altKey: true, target: editor[0]) 521 | # expect(editor.lineForBufferRow(1)).toMatch(/1\.5/) 522 | # for i in [0..20] by 1 523 | # editorView.trigger keydownEvent('down', ctrlKey: true, altKey: true, target: editor[0]) 524 | # expect(editor.lineForBufferRow(1)).toMatch(/\-0\.6/) 525 | 526 | # describe "decrement by 1", -> 527 | # beforeEach -> 528 | # editSession.setCursorBufferPosition([2, 13]) 529 | 530 | # it "decrements via commands", -> 531 | # editorView.trigger "emmet:decrement-number-by-1" 532 | # editorView.trigger "emmet:decrement-number-by-1" 533 | # expect(editor.lineForBufferRow(2)).toMatch(/8/) 534 | # for i in [0..12] by 1 535 | # editorView.trigger "emmet:decrement-number-by-1" 536 | # expect(editor.lineForBufferRow(2)).toMatch(/\-5/) 537 | 538 | # it "decrements via keybindings", -> 539 | # editorView.trigger keydownEvent('down', ctrlKey: true, altKey: true, metaKey:true, target: editor[0]) 540 | # editorView.trigger keydownEvent('down', ctrlKey: true, altKey: true, metaKey:true, target: editor[0]) 541 | # expect(editor.lineForBufferRow(2)).toMatch(/8/) 542 | # for i in [0..12] by 1 543 | # editorView.trigger keydownEvent('down', ctrlKey: true, altKey: true, metaKey:true, target: editor[0]) 544 | # expect(editor.lineForBufferRow(2)).toMatch(/\-5/) 545 | 546 | # describe "decrement by 10", -> 547 | # beforeEach -> 548 | # editSession.setCursorBufferPosition([3, 12]) 549 | 550 | # it "decrements via commands", -> 551 | # editorView.trigger "emmet:decrement-number-by-10" 552 | # editorView.trigger "emmet:decrement-number-by-10" 553 | # expect(editor.lineForBufferRow(3)).toMatch(/80/) 554 | 555 | # it "decrements via keybindings", -> 556 | # editorView.trigger keydownEvent('down', ctrlKey: true, altKey: true, metaKey: true, shiftKey: true, target: editor[0]) 557 | # editorView.trigger keydownEvent('down', ctrlKey: true, altKey: true, metaKey: true, shiftKey: true, target: editor[0]) 558 | # expect(editor.lineForBufferRow(3)).toMatch(/80/) 559 | 560 | # describe "emmet select items", -> 561 | # describe "for HTML", -> 562 | # beforeEach -> 563 | # workspaceView.openSync(Path.join(__dirname, './fixtures/select-item/select-item.html')) 564 | # editorView = workspaceView.getActiveView() 565 | # editor = editorView.getEditor() 566 | # editSession = workspaceView.getActivePaneItem() 567 | 568 | # describe "selecting next item", -> 569 | # beforeEach -> 570 | # editSession.setCursorBufferPosition([0, 0]) 571 | 572 | # it "selects next items via commands", -> 573 | # editorView.trigger "emmet:select-next-item" 574 | # expect(editor.getSelection().getBufferRange()).toEqual [[0, 1], [0, 8]] 575 | # editorView.trigger "emmet:select-next-item" 576 | # expect(editor.getSelection().getBufferRange()).toEqual [[1, 5], [1, 6]] 577 | # editorView.trigger "emmet:select-next-item" 578 | # expect(editor.getSelection().getBufferRange()).toEqual [[2, 5], [2, 8]] 579 | # editorView.trigger "emmet:select-next-item" 580 | # expect(editor.getSelection().getBufferRange()).toEqual [[2, 9], [2, 28]] 581 | # editorView.trigger "emmet:select-next-item" 582 | # expect(editor.getSelection().getBufferRange()).toEqual [[2, 16], [2, 27]] 583 | # editorView.trigger "emmet:select-next-item" 584 | # expect(editor.getSelection().getBufferRange()).toEqual [[2, 16], [2, 20]] 585 | # editorView.trigger "emmet:select-next-item" 586 | # expect(editor.getSelection().getBufferRange()).toEqual [[2, 21], [2, 27]] 587 | 588 | # it "selects next items via keybindings", -> 589 | # editorView.trigger keydownEvent('.', altKey: true, metaKey: true, target: editor[0]) 590 | # expect(editor.getSelection().getBufferRange()).toEqual [[0, 1], [0, 8]] 591 | # editorView.trigger keydownEvent('.', altKey: true, metaKey: true, target: editor[0]) 592 | # expect(editor.getSelection().getBufferRange()).toEqual [[1, 5], [1, 6]] 593 | # editorView.trigger keydownEvent('.', altKey: true, metaKey: true, target: editor[0]) 594 | # expect(editor.getSelection().getBufferRange()).toEqual [[2, 5], [2, 8]] 595 | # editorView.trigger keydownEvent('.', altKey: true, metaKey: true, target: editor[0]) 596 | # expect(editor.getSelection().getBufferRange()).toEqual [[2, 9], [2, 28]] 597 | # editorView.trigger keydownEvent('.', altKey: true, metaKey: true, target: editor[0]) 598 | # expect(editor.getSelection().getBufferRange()).toEqual [[2, 16], [2, 27]] 599 | # editorView.trigger keydownEvent('.', altKey: true, metaKey: true, target: editor[0]) 600 | # expect(editor.getSelection().getBufferRange()).toEqual [[2, 16], [2, 20]] 601 | # editorView.trigger keydownEvent('.', altKey: true, metaKey: true, target: editor[0]) 602 | # expect(editor.getSelection().getBufferRange()).toEqual [[2, 21], [2, 27]] 603 | 604 | # describe "selecting previous item", -> 605 | # beforeEach -> 606 | # editSession.setCursorBufferPosition([2, 21]) 607 | 608 | # it "selects previous items via commands", -> 609 | # editorView.trigger "emmet:select-previous-item" 610 | # expect(editor.getSelection().getBufferRange()).toEqual [[2, 16], [2, 20]] 611 | # editorView.trigger "emmet:select-previous-item" 612 | # expect(editor.getSelection().getBufferRange()).toEqual [[2, 16], [2, 27]] 613 | # editorView.trigger "emmet:select-previous-item" 614 | # expect(editor.getSelection().getBufferRange()).toEqual [[2, 9], [2, 28]] 615 | # editorView.trigger "emmet:select-previous-item" 616 | # expect(editor.getSelection().getBufferRange()).toEqual [[2, 5], [2, 8]] 617 | # editorView.trigger "emmet:select-previous-item" 618 | # expect(editor.getSelection().getBufferRange()).toEqual [[1, 5], [1, 6]] 619 | # editorView.trigger "emmet:select-previous-item" 620 | # expect(editor.getSelection().getBufferRange()).toEqual [[0, 1], [0, 8]] 621 | 622 | # it "selects previous items via keybindings", -> 623 | # editorView.trigger keydownEvent(',', altKey: true, metaKey: true, target: editor[0]) 624 | # expect(editor.getSelection().getBufferRange()).toEqual [[2, 16], [2, 20]] 625 | # editorView.trigger keydownEvent(',', altKey: true, metaKey: true, target: editor[0]) 626 | # expect(editor.getSelection().getBufferRange()).toEqual [[2, 16], [2, 27]] 627 | # editorView.trigger keydownEvent(',', altKey: true, metaKey: true, target: editor[0]) 628 | # expect(editor.getSelection().getBufferRange()).toEqual [[2, 9], [2, 28]] 629 | # editorView.trigger keydownEvent(',', altKey: true, metaKey: true, target: editor[0]) 630 | # expect(editor.getSelection().getBufferRange()).toEqual [[2, 5], [2, 8]] 631 | # editorView.trigger keydownEvent(',', altKey: true, metaKey: true, target: editor[0]) 632 | # expect(editor.getSelection().getBufferRange()).toEqual [[1, 5], [1, 6]] 633 | # editorView.trigger keydownEvent(',', altKey: true, metaKey: true, target: editor[0]) 634 | # expect(editor.getSelection().getBufferRange()).toEqual [[0, 1], [0, 8]] 635 | 636 | # describe "for CSS", -> 637 | # beforeEach -> 638 | # workspaceView.openSync(Path.join(__dirname, './fixtures/select-item/select-item.css')) 639 | # editorView = workspaceView.getActiveView() 640 | # editor = editorView.getEditor() 641 | # editSession = workspaceView.getActivePaneItem() 642 | 643 | # describe "selecting next item", -> 644 | # beforeEach -> 645 | # editSession.setCursorBufferPosition([0, 0]) 646 | 647 | # it "selects next items via commands", -> 648 | # editorView.trigger "emmet:select-next-item" 649 | # expect(editor.getSelection().getBufferRange()).toEqual [[0, 0], [0, 4]] 650 | # editorView.trigger "emmet:select-next-item" 651 | # expect(editor.getSelection().getBufferRange()).toEqual [[1, 4], [1, 28]] 652 | # editorView.trigger "emmet:select-next-item" 653 | # expect(editor.getSelection().getBufferRange()).toEqual [[1, 12], [1, 27]] 654 | # editorView.trigger "emmet:select-next-item" 655 | # expect(editor.getSelection().getBufferRange()).toEqual [[1, 12], [1, 15]] 656 | # editorView.trigger "emmet:select-next-item" 657 | # expect(editor.getSelection().getBufferRange()).toEqual [[1, 16], [1, 21]] 658 | # editorView.trigger "emmet:select-next-item" 659 | # expect(editor.getSelection().getBufferRange()).toEqual [[1, 22], [1, 27]] 660 | # editorView.trigger "emmet:select-next-item" 661 | # expect(editor.getSelection().getBufferRange()).toEqual [[2, 4], [2, 46]] 662 | 663 | # it "selects next items via keybindings", -> 664 | # editorView.trigger keydownEvent('.', altKey: true, metaKey: true, target: editor[0]) 665 | # expect(editor.getSelection().getBufferRange()).toEqual [[0, 0], [0, 4]] 666 | # editorView.trigger keydownEvent('.', altKey: true, metaKey: true, target: editor[0]) 667 | # expect(editor.getSelection().getBufferRange()).toEqual [[1, 4], [1, 28]] 668 | # editorView.trigger keydownEvent('.', altKey: true, metaKey: true, target: editor[0]) 669 | # expect(editor.getSelection().getBufferRange()).toEqual [[1, 12], [1, 27]] 670 | # editorView.trigger keydownEvent('.', altKey: true, metaKey: true, target: editor[0]) 671 | # expect(editor.getSelection().getBufferRange()).toEqual [[1, 12], [1, 15]] 672 | # editorView.trigger keydownEvent('.', altKey: true, metaKey: true, target: editor[0]) 673 | # expect(editor.getSelection().getBufferRange()).toEqual [[1, 16], [1, 21]] 674 | # editorView.trigger keydownEvent('.', altKey: true, metaKey: true, target: editor[0]) 675 | # expect(editor.getSelection().getBufferRange()).toEqual [[1, 22], [1, 27]] 676 | # editorView.trigger keydownEvent('.', altKey: true, metaKey: true, target: editor[0]) 677 | # expect(editor.getSelection().getBufferRange()).toEqual [[2, 4], [2, 46]] 678 | 679 | # describe "selecting previous item", -> 680 | # beforeEach -> 681 | # editSession.setCursorBufferPosition([2, 4]) 682 | 683 | # it "selects previous items via commands", -> 684 | # editorView.trigger "emmet:select-previous-item" 685 | # expect(editor.getSelection().getBufferRange()).toEqual [[2, 4], [2, 46]] 686 | # editorView.trigger "emmet:select-previous-item" 687 | # expect(editor.getSelection().getBufferRange()).toEqual [[1, 22], [1, 27]] 688 | # editorView.trigger "emmet:select-previous-item" 689 | # expect(editor.getSelection().getBufferRange()).toEqual [[1, 16], [1, 21]] 690 | # editorView.trigger "emmet:select-previous-item" 691 | # expect(editor.getSelection().getBufferRange()).toEqual [[1, 12], [1, 15]] 692 | # editorView.trigger "emmet:select-previous-item" 693 | # expect(editor.getSelection().getBufferRange()).toEqual [[1, 12], [1, 27]] 694 | # editorView.trigger "emmet:select-previous-item" 695 | # expect(editor.getSelection().getBufferRange()).toEqual [[1, 4], [1, 28]] 696 | 697 | # it "selects previous items via keybindings", -> 698 | # editorView.trigger keydownEvent(',', altKey: true, metaKey: true, target: editor[0]) 699 | # expect(editor.getSelection().getBufferRange()).toEqual [[2, 4], [2, 46]] 700 | # editorView.trigger keydownEvent(',', altKey: true, metaKey: true, target: editor[0]) 701 | # expect(editor.getSelection().getBufferRange()).toEqual [[1, 22], [1, 27]] 702 | # editorView.trigger keydownEvent(',', altKey: true, metaKey: true, target: editor[0]) 703 | # expect(editor.getSelection().getBufferRange()).toEqual [[1, 16], [1, 21]] 704 | # editorView.trigger keydownEvent(',', altKey: true, metaKey: true, target: editor[0]) 705 | # expect(editor.getSelection().getBufferRange()).toEqual [[1, 12], [1, 15]] 706 | # editorView.trigger keydownEvent(',', altKey: true, metaKey: true, target: editor[0]) 707 | # expect(editor.getSelection().getBufferRange()).toEqual [[1, 12], [1, 27]] 708 | # editorView.trigger keydownEvent(',', altKey: true, metaKey: true, target: editor[0]) 709 | # expect(editor.getSelection().getBufferRange()).toEqual [[1, 4], [1, 28]] 710 | 711 | # describe "emmet:reflect-css-value", -> 712 | # reflection = null 713 | 714 | # beforeEach -> 715 | # workspaceView.openSync(Path.join(__dirname, './fixtures/reflect-css-value/before/reflect-css-value.css')) 716 | # editorView = workspaceView.getActiveView() 717 | # editor = editorView.getEditor() 718 | # editSession = workspaceView.getActivePaneItem() 719 | 720 | # reflection = Fs.readFileSync(Path.join(__dirname, './fixtures/reflect-css-value/after/reflect-css-value.css'), "utf8") 721 | 722 | # it "reflects CSS via commands", -> 723 | # editor.setCursorBufferPosition([3, 32]) 724 | # editorView.trigger "emmet:reflect-css-value" 725 | # # editor.setCursorBufferPosition([9, 16]) 726 | # # editorView.trigger "emmet:reflect-css-value" 727 | # expect(editor.getText()).toBe reflection 728 | 729 | # it "reflects CSS via keybindings", -> 730 | # editor.setCursorBufferPosition([3, 32]) 731 | # editorView.trigger keydownEvent('r', shiftKey: true, metaKey: true, target: editor[0]) 732 | # # editor.setCursorBufferPosition([9, 16]) 733 | # # editorView.trigger keydownEvent('r', shiftKey: true, metaKey: true, target: editor[0]) 734 | # expect(editor.getText()).toBe reflection 735 | 736 | # # describe "emmet:encode-decode-data-url", -> 737 | # # encoded = null 738 | # # beforeEach -> 739 | # # workspaceView.openSync(Path.join(__dirname, './fixtures/encode-decode-data-url/before/encode-decode-data-url.css')) 740 | # # editorView = workspaceView.getActiveView() 741 | # # editor = editorView.getEditor() 742 | # # editSession = workspaceView.getActivePaneItem() 743 | # # 744 | # # editSession.setCursorBufferPosition([1, 22]) 745 | # # 746 | # # encoded = Fs.readFileSync(Path.join(__dirname, './fixtures/encode-decode-data-url/after/encode-decode-data-url.css'), "utf8") 747 | # # 748 | # # it "encodes and decodes URL via commands", -> 749 | # # editorView.trigger "emmet:encode-decode-data-url" 750 | # # expect(editor.getText()).toBe encoded 751 | # # 752 | # # it "encodes and decodes CSS via keybindings", -> 753 | # # editorView.trigger keydownEvent('d', shiftKey: true, ctrlKey: true, target: editor[0]) 754 | # # expect(editor.getText()).toBe encoded 755 | 756 | # # describe "emmet:update-image-size", -> 757 | # # updated = null 758 | # # 759 | # # describe "for HTML", -> 760 | # # beforeEach -> 761 | # # workspaceView.openSync(Path.join(__dirname, './fixtures/update-image-size/before/update-image-size.html')) 762 | # # editorView = workspaceView.getActiveView() 763 | # # editor = editorView.getEditor() 764 | # # editSession = workspaceView.getActivePaneItem() 765 | # # editSession.setCursorBufferPosition([0, 15]) 766 | # # 767 | # # updated = Fs.readFileSync(Path.join(__dirname, './fixtures/update-image-size/after/update-image-size.html'), "utf8") 768 | # # 769 | # # it "updates the image via commands", -> 770 | # # editorView.trigger "emmet:update-image-size" 771 | # # expect(editor.getText()).toBe updated 772 | # # 773 | # # it "updates the image via keybindings", -> 774 | # # editorView.trigger keydownEvent('i', shiftKey: true, ctrlKey: true, target: editor[0]) 775 | # # expect(editor.getText()).toBe updated 776 | # # 777 | # # describe "for CSS", -> 778 | # # beforeEach -> 779 | # # workspaceView.openSync(Path.join(__dirname, './fixtures/update-image-size/before/update-image-size.css')) 780 | # # editorView = workspaceView.getActiveView() 781 | # # editor = editorView.getEditor() 782 | # # editSession = workspaceView.getActivePaneItem() 783 | # # editSession.setCursorBufferPosition([0, 15]) 784 | # # 785 | # # updated = Fs.readFileSync(Path.join(__dirname, './fixtures/update-image-size/after/update-image-size.css'), "utf8") 786 | # # 787 | # # it "updates the image via commands", -> 788 | # # editorView.trigger "emmet:update-image-size" 789 | # # expect(editor.getText()).toBe updated 790 | # # 791 | # # it "updates the image via keybindings", -> 792 | # # editorView.trigger keydownEvent('i', shiftKey: true, ctrlKey: true, target: editor[0]) 793 | # # expect(editor.getText()).toBe updated 794 | 795 | # describe "emmet:update-tag", -> 796 | # updated = null 797 | # prompt = null 798 | 799 | # describe "for HTML", -> 800 | # beforeEach -> 801 | # workspaceView.openSync(Path.join(__dirname, './fixtures/update-tag/before/update-tag.html')) 802 | # editorView = workspaceView.getActiveView() 803 | # editor = editorView.getEditor() 804 | # editSession = workspaceView.getActivePaneItem() 805 | # editSession.setCursorBufferPosition([0, 11]) 806 | 807 | # updated = Fs.readFileSync(Path.join(__dirname, './fixtures/update-tag/after/update-tag.html'), "utf8") 808 | 809 | # it "updates the tag via commands", -> 810 | # editorView.trigger "emmet:update-tag" 811 | # prompt = atom.workspaceView.find(".emmet-prompt").view() 812 | 813 | # prompt.panelInput.insertText(".+c2[title=Hello]") 814 | # prompt.trigger 'core:confirm' 815 | 816 | # expect(editor.getText()).toBe updated 817 | 818 | # it "updates the tag via keybindings", -> 819 | # editorView.trigger keydownEvent('u', shiftKey: true, ctrlKey: true, target: editor[0]) 820 | 821 | # prompt.panelInput.insertText(".+c2[title=Hello]") 822 | # prompt.trigger 'core:confirm' 823 | 824 | # expect(editor.getText()).toBe updated 825 | 826 | # describe "emmet:wrap-with-abbreviation", -> 827 | # updated = null 828 | # prompt = null 829 | 830 | # describe "for HTML", -> 831 | # beforeEach -> 832 | # workspaceView.openSync(Path.join(__dirname, './fixtures/wrap-with-abbreviation/before/wrap-with-abbreviation.html')) 833 | # editorView = workspaceView.getActiveView() 834 | # editor = editorView.getEditor() 835 | # editSession = workspaceView.getActivePaneItem() 836 | # editSession.setCursorBufferPosition([1, 4]) 837 | 838 | # updated = Fs.readFileSync(Path.join(__dirname, './fixtures/wrap-with-abbreviation/after/wrap-with-abbreviation.html'), "utf8") 839 | 840 | # it "wraps an abbreviation via commands", -> 841 | # editorView.trigger "emmet:wrap-with-abbreviation" 842 | # prompt = atom.workspaceView.find(".emmet-prompt").view() 843 | 844 | # prompt.panelInput.setText(".wrapper>h1{Title}+.content") 845 | # prompt.trigger 'core:confirm' 846 | 847 | # expect(editor.getText()).toBe updated 848 | 849 | # it "wraps an abbreviation via keybindings", -> 850 | # editorView.trigger keydownEvent('a', shiftKey: true, metaKey: true, target: editor[0]) 851 | # prompt = atom.workspaceView.find(".emmet-prompt").view() 852 | 853 | # prompt.panelInput.setText(".wrapper>h1{Title}+.content") 854 | # prompt.trigger 'core:confirm' 855 | 856 | # expect(editor.getText()).toBe updated 857 | 858 | # describe "emmet:merge-lines", -> 859 | # updated = null 860 | 861 | # describe "for HTML", -> 862 | # beforeEach -> 863 | # workspaceView.openSync(Path.join(__dirname, './fixtures/merge-lines/before/merge-lines.html')) 864 | # editorView = workspaceView.getActiveView() 865 | # editor = editorView.getEditor() 866 | # editSession = workspaceView.getActivePaneItem() 867 | # editSession.setCursorBufferPosition([3, 5]) 868 | 869 | # updated = Fs.readFileSync(Path.join(__dirname, './fixtures/merge-lines/after/merge-lines.html'), "utf8") 870 | 871 | # it "performs merge lines via commands", -> 872 | # editorView.trigger "emmet:merge-lines" 873 | # expect(editor.getText()).toBe updated 874 | 875 | # it "performs merge lines via keybindings", -> 876 | # editorView.trigger keydownEvent('M', shiftKey: true, metaKey: true, target: editor[0]) 877 | # expect(editor.getText()).toBe updated 878 | -------------------------------------------------------------------------------- /spec/fixtures/abbreviation/after/anchor-class-expand.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /spec/fixtures/abbreviation/after/css-abbrv.css: -------------------------------------------------------------------------------- 1 | margin: 10px; 2 | -------------------------------------------------------------------------------- /spec/fixtures/abbreviation/after/header-expand.html: -------------------------------------------------------------------------------- 1 |

2 | -------------------------------------------------------------------------------- /spec/fixtures/abbreviation/after/html-abbrv.html: -------------------------------------------------------------------------------- 1 | 9 | -------------------------------------------------------------------------------- /spec/fixtures/abbreviation/after/multi-line.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | -------------------------------------------------------------------------------- /spec/fixtures/abbreviation/after/php-in-html.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | PHP Test 4 | 5 | 6 | Hello World

'; ?> 7 |
8 | 9 | 10 | -------------------------------------------------------------------------------- /spec/fixtures/abbreviation/after/sass-test.sass: -------------------------------------------------------------------------------- 1 | margin: 10px 2 | -------------------------------------------------------------------------------- /spec/fixtures/abbreviation/after/vanilla-php.php: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /spec/fixtures/abbreviation/before/anchor-class-expand.html: -------------------------------------------------------------------------------- 1 | a.selected -------------------------------------------------------------------------------- /spec/fixtures/abbreviation/before/css-abbrv.css: -------------------------------------------------------------------------------- 1 | m10 2 | -------------------------------------------------------------------------------- /spec/fixtures/abbreviation/before/header-expand.html: -------------------------------------------------------------------------------- 1 | h1 2 | -------------------------------------------------------------------------------- /spec/fixtures/abbreviation/before/html-abbrv.html: -------------------------------------------------------------------------------- 1 | #header>ul#nav>li*4>a[href] 2 | -------------------------------------------------------------------------------- /spec/fixtures/abbreviation/before/multi-line.html: -------------------------------------------------------------------------------- 1 | .selector 2 | .selector 3 | .selector 4 | -------------------------------------------------------------------------------- /spec/fixtures/abbreviation/before/php-in-html.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | PHP Test 4 | 5 | 6 | Hello World

'; ?> 7 | .wow 8 | 9 | 10 | -------------------------------------------------------------------------------- /spec/fixtures/abbreviation/before/sass-test.sass: -------------------------------------------------------------------------------- 1 | m10 2 | -------------------------------------------------------------------------------- /spec/fixtures/abbreviation/before/vanilla-php.php: -------------------------------------------------------------------------------- 1 | 5 | -------------------------------------------------------------------------------- /spec/fixtures/balance/sample.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

Document example

4 |

Lorem ipsum dolor sit amet.

5 |
6 |
7 | -------------------------------------------------------------------------------- /spec/fixtures/edit-points/edit-points.html: -------------------------------------------------------------------------------- 1 |
    2 |
  • 3 |
  • 4 |
5 |
6 | 7 |
8 | 9 | 12 | -------------------------------------------------------------------------------- /spec/fixtures/encode-decode-data-url/after/encode-decode-data-url.css: -------------------------------------------------------------------------------- 1 | body { 2 | background: url(data:application/octet-stream;base64,/VBORw0KGgoAAAANSUhEUgAAADAAAAAwCAMAAABg/Qn9AAAC/VBMVEUAAABEREBEREBEREBEREBEREBEREBEREBEREBEREBEREBEREBEREBEREBEREBEREA2cv04dP05c/05c/06dP06dP07bf07bP08bf04dP05dP06dP05df03df07Zf05dP06c/07bf0+Zf1AU2Q6bf06dP05df05dP06dP1AcP07bP05dP0udP05df04df06cv05dP02ef0AAP05cv05c/06dP05dP06dP05df05c/05dP06c/39WTtA/f04c/05dP06bv06bv06b/05c/05c/04dP0A/f39Wzn9Vzv9WDz9SUk6bP03c/06dP05c/05df04cf08Y/0+XX4+V3L9Tjv9WDr9WTz9WDv9WDv9VTz9UTz9TTz9WD79WTv9WDr9WDv9VTz9WDv9WDv9WDr9WTv9WDz9WDr9VDv9Uzz9VTv9Vzv9WDv9Vzv9VDz9WDv9VTz9WDv9VTz9WDv9Vzv9WTr9YED9Vzv9WDv9WDv9WDt0TEr9Vjn9VD39Vjz9Vjz9WTv9WDv9WTz9VUD9VTz9Wj79WDv9WDz9Vzv9WDv9Uz39VD39Vjv9Wjv9VT79AAD9Tj39WTv9VDxMRUJhRUL9Uj39VTv9Vjz9WTz9Vzv9Wjz9VVX9VTv9WDv9VT39VTz9WDv9WTv9Vjz9VTz9WDr9WDv9Vzv9WTv9WDv9WDv9VDz9WVD9VTz9VjxlUE07av1ATVD9Ujz9Vzr9WTv9WDv9WDv9WDv9VDz9Tj1BU2M6cv07bP06bv05cv1A/f39Vzv9Vjz9VD39VD39Vzz9WTr9WTv9Vzz9VzpCUl88aP06c/07bf05dP04dP04c/05cv1AW3U/UF07dv03dv05cf04cv06bP07bf06b/05c/05c/05dP05dP05df06df08eP04df06df05c/05c/07cv1AWXA9Zv05cv05dP04dP04dP06df05dP04c/07a/07av08av01df05dP05c/06b/06bv39WDv9WDv9Vjz9Vjz9/XX9AAAA/XRSTlMAAQUGAQsMAhASFRgDGgMfJk1vfv39/f39/X1uTCVY/f39WC79Wf39EP39C/39df0TAf1ZZf39/f39VCsESf39/f39/UACLf13Bx4qOUdVR0xCLw39/f39/WQvHVb9/f39s/39/f39/f39+P39/f39dgj9/f39BiP9/f39/XMYHiVOXWx6/XldSiEBOv1wISH9/f39UiIDJ1j9/fz9/f39/f39/f0c/f0reSRD/f39yD0mZ/39XAhJV3b9eW1kVUYqdv39/f1SLDIoDRwtWP39/f39/f39/RE7/f39ODVZcf39/f39/f39fRj9/f07AAAACXBIWXMAAABIAAAASABG/Ws+AAAC/UlEQVRI/WNgIA8wMjEzMRJC/WdhZWNlIf39DP39OTg5CWL9/W1g/f39/QH9/RBgcf39XP39/f39Bxb9/f39/RMQFBIWERUT/f39/f39/f1BZf05QC5jZP2r/RP9/QgE/T5//f0J/f39/f39MP0L/TImNg4e/f39/SdVNXVk/SD9/Sb9dv06ZlZ2/Qla/f11GBh0Uf1//f0Hcy0kSP1Y/f39/Whg/WBk/f39/Qn9egZG/X8ZTP39LSz9/VtZI/1n/Yj9MP39/Ts4Iv07Of39/TH9IzMwIf1n/f39Av39fXz9/f0DAv39Qf1CQv39/WEx/QMVCf0aERkV/RQnDDH9cf39EmD9ef0xDRUJ/f39/f1v/Un9Kf1p/Rn9Wf05X/1+/f09FxYTGDH9B1L9/StYFRIrAWdM/WNV/f0AZ0wXYlX9/QhnTP1jVf39CGdM/WFVD4Aj/fH9B2r9Ff39WP1/Lf0Z5WX9/f0rKv1w/TQDQ3VNbR39/f39/Sb9/Rgx/Qz9/WppbWv9SEv9/f39/f0D/Y8z/SdM/f39/SH9/VP9/f39af1n/f1D/f01e/39eQRj/X79/f39/S5e/XT9/RVDL/3x/XQRmA7q/WsB/Tz9TT39PF39Vf39/Thjev1qLP39LFr9M/3t8HH9ZmT9W/1u/mMnmLV7/V4G/f19/Q9MOXj9/f39wCn9/Qn9/Thj/Sf9/f1I/T13/QINFy9d/XL9/f1PH0/9/f0b/TL9/f1b/f39/R39MW14/SN6bQJkff0z/RkY/T94/f39/f1jZP39Yhr9ev39/f0XL1/9fv39/f39D/39/Xn9Dy/9/f16/f12ACc0/f1tZ0BZRP1jICwA/f39/ToJ/f0AAAAldEVYdGRhdGU6Y3JlYXRlADIwMTMtMDYtMTJUMTg6Mjg6MTQtMDU6MDD9Dv0wAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDEzLTA2LTEyVDE4OjI4OjE0LTA1OjAw/VNT/QAAAABJRU5E/UJg/Q==); 3 | } 4 | -------------------------------------------------------------------------------- /spec/fixtures/encode-decode-data-url/barrel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emmetio/emmet-atom/8d5fdacfef954ec5b33866f5fac32532742f72e3/spec/fixtures/encode-decode-data-url/barrel.png -------------------------------------------------------------------------------- /spec/fixtures/encode-decode-data-url/before/encode-decode-data-url.css: -------------------------------------------------------------------------------- 1 | body { 2 | background: url(../barrel.png); 3 | } 4 | -------------------------------------------------------------------------------- /spec/fixtures/evaluate-math-expression/evaluate-math-expression.html: -------------------------------------------------------------------------------- 1 | 2*6 10\3 20*4+10 2 | -------------------------------------------------------------------------------- /spec/fixtures/increment-decrement-numbers/increment-decrement-numbers.css: -------------------------------------------------------------------------------- 1 | body { 2 | line-height: 1.7; 3 | padding: 10px; 4 | width: 100%; 5 | } 6 | -------------------------------------------------------------------------------- /spec/fixtures/merge-lines/after/merge-lines.html: -------------------------------------------------------------------------------- 1 |

Lorem ipsum dolor sit amet.Officiis animi consequuntur iure.Ea asperiores aperiam non necessitatibus?Expedita iusto cupiditate eum esse

2 | -------------------------------------------------------------------------------- /spec/fixtures/merge-lines/before/merge-lines.html: -------------------------------------------------------------------------------- 1 |

2 | Lorem ipsum dolor sit amet. 3 | Officiis animi consequuntur iure. 4 | Ea asperiores aperiam non necessitatibus? 5 | Expedita iusto cupiditate eum esse 6 |

7 | -------------------------------------------------------------------------------- /spec/fixtures/reflect-css-value/after/reflect-css-value.css: -------------------------------------------------------------------------------- 1 | div { 2 | padding: 10px; 3 | 4 | -webkit-transform: rotate(50deg); 5 | -moz-transform: rotate(50deg); 6 | -ms-transform: rotate(50deg); 7 | -o-transform: rotate(50deg); 8 | transform: rotate(50deg); 9 | 10 | opacity: 0.7; 11 | filter: alpha(opacity=60); 12 | } 13 | -------------------------------------------------------------------------------- /spec/fixtures/reflect-css-value/before/reflect-css-value.css: -------------------------------------------------------------------------------- 1 | div { 2 | padding: 10px; 3 | 4 | -webkit-transform: rotate(50deg); 5 | -moz-transform: rotate(45deg); 6 | -ms-transform: rotate(45deg); 7 | -o-transform: rotate(45deg); 8 | transform: rotate(45deg); 9 | 10 | opacity: 0.7; 11 | filter: alpha(opacity=60); 12 | } 13 | -------------------------------------------------------------------------------- /spec/fixtures/remove-tag/after/remove-tag-once.html: -------------------------------------------------------------------------------- 1 | 2 |

Title

3 |

Lorem ipsum dolor sit amet.

4 |

Officiis animi consequuntur iure.

5 |

Ea asperiores aperiam non necessitatibus?

6 |

Expedita iusto cupiditate eum esse.

7 | 8 | -------------------------------------------------------------------------------- /spec/fixtures/remove-tag/after/remove-tag-twice.html: -------------------------------------------------------------------------------- 1 |

Title

2 |

Lorem ipsum dolor sit amet.

3 |

Officiis animi consequuntur iure.

4 |

Ea asperiores aperiam non necessitatibus?

5 |

Expedita iusto cupiditate eum esse.

6 | -------------------------------------------------------------------------------- /spec/fixtures/remove-tag/before/remove-tag.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |

Title

4 |

Lorem ipsum dolor sit amet.

5 |

Officiis animi consequuntur iure.

6 |

Ea asperiores aperiam non necessitatibus?

7 |

Expedita iusto cupiditate eum esse.

8 |
9 | 10 | -------------------------------------------------------------------------------- /spec/fixtures/select-item/select-item.css: -------------------------------------------------------------------------------- 1 | body { 2 | border: 1px solid black; 3 | background: url(image.jpg) #ccc no-repeat; 4 | } 5 | -------------------------------------------------------------------------------- /spec/fixtures/select-item/select-item.html: -------------------------------------------------------------------------------- 1 |
2 |

3 | 4 | 5 | 6 |
7 | -------------------------------------------------------------------------------- /spec/fixtures/split-join-tag/split-join-tag.html: -------------------------------------------------------------------------------- 1 | 2 | Lorem ipsum dolor sit amet 3 | 4 | -------------------------------------------------------------------------------- /spec/fixtures/tabbing.html: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /spec/fixtures/update-image-size/after/update-image-size.css: -------------------------------------------------------------------------------- 1 | .block { 2 | background: url(../raptor_dunk.jpg); 3 | width: 640px; 4 | height: 427px; 5 | } 6 | -------------------------------------------------------------------------------- /spec/fixtures/update-image-size/after/update-image-size.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /spec/fixtures/update-image-size/before/update-image-size.css: -------------------------------------------------------------------------------- 1 | .block { 2 | background: url(../raptor_dunk.jpg); 3 | } 4 | -------------------------------------------------------------------------------- /spec/fixtures/update-image-size/before/update-image-size.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /spec/fixtures/update-image-size/raptor_dunk.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emmetio/emmet-atom/8d5fdacfef954ec5b33866f5fac32532742f72e3/spec/fixtures/update-image-size/raptor_dunk.jpg -------------------------------------------------------------------------------- /spec/fixtures/update-tag/after/update-tag.html: -------------------------------------------------------------------------------- 1 |
2 | -------------------------------------------------------------------------------- /spec/fixtures/update-tag/before/update-tag.html: -------------------------------------------------------------------------------- 1 |
2 | -------------------------------------------------------------------------------- /spec/fixtures/wrap-with-abbreviation/after/wrap-with-abbreviation.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

Title

4 |
5 |

Hello world

6 |
7 |
8 |
9 | -------------------------------------------------------------------------------- /spec/fixtures/wrap-with-abbreviation/before/wrap-with-abbreviation.html: -------------------------------------------------------------------------------- 1 |
2 |

Hello world

3 |
4 | -------------------------------------------------------------------------------- /styles/emmet.less: -------------------------------------------------------------------------------- 1 | @import 'ui-variables'; 2 | 3 | .emmet-panel { 4 | position: absolute; 5 | z-index: 10; 6 | background: @pane-item-background-color; 7 | color: @text-color; 8 | padding: 5px; 9 | min-width: 200px; 10 | font-size: 12px; 11 | -webkit-box-shadow: 0 0 20px rgba(0, 0, 0, .5); 12 | box-shadow: 0 0 20px rgba(0, 0, 0, .5); 13 | 14 | &-tail { 15 | position: absolute; 16 | left: 8px; 17 | margin-top: -6px; 18 | width: 15px; 19 | height: 15px; 20 | content: ''; 21 | display: inline-block; 22 | background: inherit; 23 | z-index: -1; 24 | -webkit-transform: rotate(45deg); 25 | transform: rotate(45deg); 26 | } 27 | 28 | atom-text-editor[mini] { 29 | z-index: 1; 30 | line-height: 16px; 31 | } 32 | } 33 | 34 | .emmet-prompt { 35 | min-width: -webkit-min-content; 36 | padding: 10px; 37 | 38 | /* &__label { 39 | display: inline-block; 40 | white-space: nowrap; 41 | min-width: -webkit-min-content; 42 | min-width: min-content; 43 | padding-right: 10px; 44 | margin: 0; 45 | } */ 46 | 47 | &__input { 48 | flex: 1 100%; 49 | margin: 0; 50 | } 51 | } 52 | --------------------------------------------------------------------------------