css_completions.py (32774B)
1 import re 2 import sublime 3 import sublime_plugin 4 import timeit 5 6 from functools import cached_property, wraps 7 8 __all__ = ['CSSCompletions'] 9 10 KIND_CSS_PROPERTY = (sublime.KIND_ID_KEYWORD, "p", "property") 11 KIND_CSS_FUNCTION = (sublime.KIND_ID_FUNCTION, "f", "function") 12 KIND_CSS_CONSTANT = (sublime.KIND_ID_VARIABLE, "c", "constant") 13 14 ENABLE_TIMING = False 15 16 17 def timing(func): 18 @wraps(func) 19 def wrap(*args, **kw): 20 if ENABLE_TIMING: 21 ts = timeit.default_timer() 22 result = func(*args, **kw) 23 if ENABLE_TIMING: 24 te = timeit.default_timer() 25 print(f"{func.__name__}({args}, {kw}) took: {1000.0 * (te - ts):2.3f} ms") 26 return result 27 return wrap 28 29 30 def get_properties(): 31 """ 32 Gets the properties. 33 34 Prepare some common property values for when there is more than one way to 35 specify a certain value type. The color value for example can be specified 36 by `rgb()` or `hsl()` and so on. Example where `|` denotes the caret: 37 38 color: rg| --> color: rgb(|); 39 40 This is also helpful when multiple properties share the same value types. 41 """ 42 common_values = { 43 'animation_direction': [ 44 'alternate', 'alternate-reverse', 'normal', 'reverse' 45 ], 46 'absolute_size': [ 47 'xx-small', 'x-small', 'small', 'medium', 'large', 'x-large', 'xx-large' 48 ], 49 'absolute_weight': [ 50 '100', '200', '300', '400', '500', '600', '700', '800', '900', 51 'normal', 'bold' 52 ], 53 'basic_shape': [ 54 ['circle()', 'circle($1)'], 55 ['ellipse()', 'ellipse($1)'], 56 ['inset()', 'inset($1)'], 57 ['polygon()', 'polygon($1)'] 58 ], 59 'blend_mode': [ 60 'normal', 'multiply', 'screen', 'overlay', 'darken', 'lighten', 61 'color-dodge', 'color-burn', 'hard-light', 'soft-light', 'difference', 62 'exclusion', 'hue', 'saturation', 'color', 'luminosity' 63 ], 64 'border_style': [ 65 'none', 'hidden', 'dotted', 'dashed', 'solid', 'double', 66 'groove', 'ridge', 'inset', 'outset' 67 ], 68 'border_width': ['thin', 'medium', 'thick'], 69 'break_before_after': [ 70 'always', 'left', 'right', 'recto', 'verso', 'page', 'column', 'region' 71 ], 72 'break_inside': [ 73 'auto', 'avoid', 'avoid-page', 'avoid-column', 'avoid-region' 74 ], 75 'color': [ 76 'currentColor', 77 'transparent', 78 ['rgb()', 'rgb(${1:0}, ${2:0}, ${3:0})'], 79 ['rgba()', 'rgba(${1:0}, ${2:0}, ${3:0}, ${4:1.0})'], 80 ['hsl()', 'hsl(${1:0}, ${2:100%}, ${3:50%})'], 81 ['hsla()', 'hsla(${1:0}, ${2:100%}, ${3:50%}, ${4:1.0})'], 82 # Named colors 83 'aliceblue', 'antiquewhite', 'aqua', 'aquamarine', 'azure', 'beige', 84 'bisque', 'black', 'blanchedalmond', 'blue', 'blueviolet', 'brown', 85 'burlywood', 'cadetblue', 'chartreuse', 'chocolate', 'coral', 86 'cornflowerblue', 'cornsilk', 'crimson', 'cyan', 'darkblue', 87 'darkcyan', 'darkgoldenrod', 'darkgray', 'darkgrey', 'darkgreen', 88 'darkkhaki', 'darkmagenta', 'darkolivegreen', 'darkorange', 89 'darkorchid', 'darkred', 'darksalmon', 'darkseagreen', 90 'darkslateblue', 'darkslategray', 'darkslategrey', 'darkturquoise', 91 'darkviolet', 'deeppink', 'deepskyblue', 'dimgray', 'dimgrey', 92 'dodgerblue', 'firebrick', 'floralwhite', 'forestgreen', 'fuchsia', 93 'gainsboro', 'ghostwhite', 'gold', 'goldenrod', 'gray', 'grey', 94 'green', 'greenyellow', 'honeydew', 'hotpink', 'indianred', 'indigo', 95 'ivory', 'khaki', 'lavender', 'lavenderblush', 'lawngreen', 96 'lemonchiffon', 'lightblue', 'lightcoral', 'lightcyan', 97 'lightgoldenrodyellow', 'lightgray', 'lightgrey', 'lightgreen', 98 'lightpink', 'lightsalmon', 'lightseagreen', 'lightskyblue', 99 'lightslategray', 'lightslategrey', 'lightsteelblue', 'lightyellow', 100 'lime', 'limegreen', 'linen', 'magenta', 'maroon', 'mediumaquamarine', 101 'mediumblue', 'mediumorchid', 'mediumpurple', 'mediumseagreen', 102 'mediumslateblue', 'mediumspringgreen', 'mediumturquoise', 103 'mediumvioletred', 'midnightblue', 'mintcream', 'mistyrose', 104 'moccasin', 'navajowhite', 'navy', 'oldlace', 'olive', 'olivedrab', 105 'orange', 'orangered', 'orchid', 'palegoldenrod', 'palegreen', 106 'paleturquoise', 'palevioletred', 'papayawhip', 'peachpuff', 'peru', 107 'pink', 'plum', 'powderblue', 'purple', 'rebeccapurple', 'red', 108 'rosybrown', 'royalblue', 'saddlebrown', 'salmon', 'sandybrown', 109 'seagreen', 'seashell', 'sienna', 'silver', 'skyblue', 'slateblue', 110 'slategray', 'slategrey', 'snow', 'springgreen', 'steelblue', 'tan', 111 'teal', 'thistle', 'tomato', 'turquoise', 'violet', 'wheat', 'white', 112 'whitesmoke', 'yellow', 'yellowgreen' 113 ], 114 'counter_symbols': [ 115 'cyclic', 'numeric', 'alphabetic', 'symbolic', 'additive', 'fixed' 116 ], 117 'font_variant_alternates': [ 118 'normal', 'historical-forms', 119 ['stylistic()', 'stylistic($1)'], 120 ['styleset()', 'styleset($1)'], 121 ['character-variant()', 'character-variant($1)'], 122 ['swash()', 'swash($1)'], 123 ['ornaments()', 'ornaments($1)'], 124 ['annotation()', 'annotation($1)'] 125 ], 126 'generic_name': [ 127 'serif', 'sans-serif', 'cursive', 'fantasy', 'monospace' 128 ], 129 'gradient': [ 130 ['conic-gradient()', 'conic-gradient($1)'], 131 ['linear-gradient()', 'linear-gradient($1)'], 132 ['radial-gradient()', 'radial-gradient($1)'], 133 ['repeating-conic-gradient()', 'repeating-conic-gradient($1)'], 134 ['repeating-linear-gradient()', 'repeating-linear-gradient($1)'], 135 ['repeating-radial-gradient()', 'repeating-radial-gradient($1)'] 136 ], 137 'grid': [ 138 ['repeat()', 'repeat(${1:2}, ${2:1fr})'], 139 ['minmax()', 'minmax(${1:100px}, ${2:1fr})'], 140 ], 141 'list_style_type': [ 142 'none', 'inline', 'disc', 'circle', 'square', 'decimal', 143 'decimal-leading-zero', 'arabic-indic', 'binary', 'bengali', 144 'cambodian', 'khmer', 'devanagari', 'gujarati', 'gurmukhi', 145 'kannada', 'lower-hexadecimal', 'lao', 'malayalam', 'mongolian', 146 'myanmar', 'octal', 'oriya', 'persian', 'urdu', 'telugu', 147 'tibetan', 'thai', 'upper-hexadecimal', 'lower-roman', 148 'upper-roman', 'lower-greek', 'lower-alpha', 'lower-latin', 149 'upper-alpha', 'upper-latin', 'afar', 'ethiopic-halehame-aa-et', 150 'ethiopic-halehame-aa-er', 'amharic', 'ethiopic-halehame-am-et', 151 'amharic-abegede', 'ethiopic-abegede-am-et', 'cjk-earthly-branch', 152 'cjk-heavenly-stem', 'ethiopic', 'ethiopic-halehame-gez', 153 'ethiopic-abegede', 'ethiopic-abegede-gez', 'hangul-consonant', 154 'hangul', 'lower-norwegian', 'oromo', 'ethiopic-halehame-om-et', 155 'sidama', 'ethiopic-halehame-sid-et', 'somali', 156 'ethiopic-halehame-so-et', 'tigre', 'ethiopic-halehame-tig', 157 'tigrinya-er', 'ethiopic-halehame-ti-er', 'tigrinya-er-abegede', 158 'ethiopic-abegede-ti-er', 'tigrinya-et', 'ethiopic-halehame-ti-et', 159 'tigrinya-et-abegede', 'ethiopic-abegede-ti-et', 'upper-greek', 160 'upper-norwegian', 'asterisks', 'footnotes', 'hebrew', 'armenian', 161 'lower-armenian', 'upper-armenian', 'georgian', 'cjk-ideographic', 162 'hiragana', 'katakana', 'hiragana-iroha', 'katakana-iroha' 163 ], 164 'position': ['top', 'right', 'bottom', 'left', 'center'], 165 'relative_size': ['larger', 'smaller'], 166 'relative_weight': ['bolder', 'lighter'], 167 'repeat_style': [ 168 'repeat', 'repeat-x', 'repeat-y', 'space', 'round', 'no-repeat' 169 ], 170 'string': ['\"$1\"'], 171 'timing_function': [ 172 'linear', 173 'ease', 'ease-in', 'ease-out', 'ease-in-out', 'step-start', 'step-end', 174 ['cubic-bezier()', 'cubic-bezier(${1:0.0}, ${2:0.0}, ${3:1.0}, ${4:1.0})'], 175 ['steps()', 'steps(${1:2}, ${2:start})'], 176 ], 177 'uri': [['url()', 'url($1)']], 178 } 179 180 properties_dict = { 181 'align-content': [ 182 'center', 'flex-end', 'flex-start', 'space-around', 'space-between', 183 'stretch' 184 ], 185 'align-items': [ 186 'baseline', 'center', 'flex-end', 'flex-start', 'stretch' 187 ], 188 'align-self': [ 189 'auto', 'baseline', 'center', 'flex-end', 'flex-start', 'stretch' 190 ], 191 'alignment-baseline': [ 192 'baseline', 'middle', 'auto', 'before-edge', 'after-edge', 'central', 193 'text-before-edge', 'text-after-edge', 'ideographic', 'alphabetic', 194 'hanging', 'mathematical' 195 ], 196 'animation': [ 197 'none', '<timing_function>', 'infinite', '<animation_direction>', 198 'forwards', 'backwards', 'both', 'running', 'paused' 199 ], 200 'animation-name': ['none', '<custom-ident>'], 201 'animation-duration': ['<time>'], 202 'animation-timing-function': ['<timing_function>'], 203 'animation-delay': ['<time>'], 204 'animation-iteration-count': ['infinite', '<number>'], 205 'animation-direction': ['<animation_direction>'], 206 'animation-fill-mode': ['none', 'forwards', 'backwards', 'both'], 207 'animation-play-state': ['running', 'paused'], 208 'backface-visibility': ['visible', 'hidden'], 209 'background': [ 210 '<color>', '<gradient>', '<position>', '<uri>', 211 'repeat', 'repeat-x', 'repeat-y', 'no-repeat', 'scroll', 'fixed' 212 ], 213 'background-attachment': ['fixed', 'local', 'scroll'], 214 'background-blend-mode': ['<blend_mode>'], 215 'background-clip': ['border-box', 'padding-box', 'content-box'], 216 'background-color': ['<color>'], 217 'background-image': ['<uri>', 'none'], 218 'background-origin': ['border-box', 'padding-box', 'content-box'], 219 'background-position': ['<position>'], 220 'background-repeat': ['<repeat_style>'], 221 'background-size': [ 222 'auto', 'cover', 'contain', '<length>', '<percentage>' 223 ], 224 'baseline-shift': ['baseline', 'sub', 'super'], 225 'border': ['<border_width>', '<border_style>', '<color>'], 226 'border-width': ['<border_width>'], 227 'border-style': ['<border_style>'], 228 'border-color': ['<color>'], 229 'border-collapse': ['collapse', 'separate'], 230 'border-radius': ['<length>', '<percentage>'], 231 'border-spacing': ['<length>'], 232 'border-image': [ 233 '<border-image-source>', '<border-image-slice>', 234 '<border-image-width>', '<border-image-outset>', 235 '<border-image-repeat>' 236 ], 237 'border-image-outset': ['<length>', '<number>'], 238 'border-image-repeat': ['stretch', 'repeat', 'round', 'space'], 239 'border-image-slice': ['fill', '<number>', '<percentage>'], 240 'border-image-source': ['none', '<image>'], 241 'border-image-width': ['<length>', '<percentage>', '<number>', 'auto'], 242 'border-top | border-right | border-bottom | border-left': [ 243 '<border_width>', '<border_style>', '<color>' 244 ], 245 'border-top-color | border-right-color | border-bottom-color | border-left-color': ['<color>'], 246 'border-top-left-radius | border-top-right-radius | border-bottom-right-radius | border-bottom-left-radius': [ 247 '<length>', '<percentage>' 248 ], 249 'border-top-style | border-right-style | border-bottom-style | border-left-style': ['<border_style>'], 250 'border-top-width | border-right-width | border-bottom-width | border-left-width': ['<border_width>'], 251 'bottom': ['<length>', '<percentage>', 'auto'], 252 'box-decoration-break': ['slice', 'clone'], 253 'box-shadow': ['none', 'inset', '<color>'], 254 'box-sizing': ['content-box', 'border-box'], 255 'break-after': ['<break_before_after>', '<break_inside>'], 256 'break-before': ['<break_before_after>', '<break_inside>'], 257 'break-inside': ['<break_inside>'], 258 'caption-side': ['top', 'bottom'], 259 'clear': ['none', 'left', 'right', 'both'], 260 'clip': [ 261 ['rect()', 'rect(${1:0}, ${2:0}, ${3:0}, ${4:0})'], 262 'auto' 263 ], 264 'clip-path': ['none', '<uri>', '<basic_shape>'], 265 'clip-rule': ['nonzero', 'evenodd'], 266 'color': ['<color>'], 267 'color-interpolation': ['auto', 'sRGB', 'linearRGB'], 268 'color-interpolation-filters': ['auto', 'sRGB', 'linearRGB'], 269 'color-profile': ['auto', 'sRGB', '<uri>'], 270 'color-rendering': ['auto', 'optimizeSpeed', 'optimizeQuality'], 271 'columns': ['auto'], 272 'column-count': ['auto', '<number>'], 273 'column-fill': ['auto', 'balance'], 274 'column-gap': ['normal', '<length>'], 275 'column-rule': ['<border_width>', '<border_style>', '<color>'], 276 'column-rule-color': ['<color>'], 277 'column-rule-style': ['<border_style>'], 278 'column-rule-width': ['<border_width>'], 279 'column-span': ['none'], 280 'column-width': ['auto', '<length>'], 281 'content': [ 282 'none', 'normal', '<string>', '<uri>', 283 'open-quote', 'close-quote', 'no-open-quote', 'no-close-quote', 284 ['attr()', 'attr($1)'], 285 ['counter()', 'counter($1)'] 286 ], 287 'counter-increment': ['none', '<custom_ident>', '<integer>'], 288 'counter-reset': ['none', '<custom_ident>', '<integer>'], 289 'cursor': [ 290 '<uri>', 'auto', 'default', 'none', 'context-menu', 'help', 291 'pointer', 'progress', 'wait', 'cell', 'crosshair', 'text', 292 'vertical-text', 'alias', 'copy', 'move', 'no-drop', 'not-allowed', 293 'e-resize', 'n-resize', 'ne-resize', 'nw-resize', 's-resize', 294 'se-resize', 'sw-resize', 'w-resize', 'ew-resize', 'ns-resize', 295 'nesw-resize', 'nwse-resize', 'col-resize', 'row-resize', 296 'all-scroll', 'zoom-in', 'zoom-out' 297 ], 298 'direction': ['ltr', 'rtl'], 299 'display': [ 300 'none', 'inline', 'block', 'contents', 'list-item', 'inline-block', 301 'inline-table', 'table', 'table-cell', 'table-column', 302 'table-column-group', 'table-footer-group', 'table-header-group', 303 'table-row', 'table-row-group', 'table-caption', 'flex', 304 'inline-flex', 'grid', 'inline-grid', 'ruby', 'ruby-base', 305 'ruby-text', 'ruby-base-container', 'ruby-text-container', 'run-in' 306 ], 307 'dominant-baseline': [ 308 'auto', 'middle', 'central', 'text-before-edge', 309 'text-after-edge', 'ideographic', 'alphabetic', 'hanging', 310 'mathematical', 'use-script', 'no-change', 'reset-size' 311 ], 312 'empty-cells': ['show', 'hide'], 313 'fill': ['<color>'], 314 'fill-rule': ['nonzero', 'evenodd'], 315 'filter': [ 316 '<uri>', 317 ['blur()', 'blur(${1:5px})'], 318 ['brightness()', 'brightness(${1:1.0})'], 319 ['contrast()', 'contrast(${1:100%})'], 320 ['drop-shadow()', 'drop-shadow(${1:1px} ${2:1px})'], 321 ['grayscale()', 'grayscale(${1:50%})'], 322 ['hue-rotate()', 'hue-rotate(${1:90deg})'], 323 ['invert()', 'invert(${1:50%})'], 324 ['opacity()', 'opacity(${1:100%})'], 325 ['saturate()', 'saturate(${1:50%})'], 326 ['sepia()', 'sepia(${1:50%})'] 327 ], 328 'flex': ['none'], 329 'flex-grow': ['<number>'], 330 'flex-shrink': ['<number>'], 331 'flex-basis': ['auto', '<width>'], 332 'flex-flow': [ 333 'row', 'row-reverse', 'column', 'column-reverse', 'nowrap', 'wrap', 334 'wrap-reverse' 335 ], 336 'flex-direction': ['row', 'row-reverse', 'column', 'column-reverse'], 337 'flex-wrap': ['nowrap', 'wrap', 'wrap-reverse'], 338 'float': ['left', 'right', 'none'], 339 'flood-color': ['<color>'], 340 'font': [ 341 '<absolute_weight>', '<generic_name>', '<relative_weight>', 342 'caption', 'icon', 'italic', 'menu', 'message-box', 'oblique', 343 'small-caps', 'small-caption', 'status-bar' 344 ], 345 'font-display': ['auto', 'block', 'swap', 'fallback', 'optional'], 346 'font-family': ['<generic_name>'], 347 'font-feature-settings': ['normal', '<string>'], 348 'font-kerning': ['auto', 'normal', 'none'], 349 'font-language-override': ['normal', '<string>'], 350 'font-size': [ 351 '<absolute_size>', '<relative_size>', '<length>', '<percentage>' 352 ], 353 'font-size-adjust': ['none', '<number>'], 354 'font-style': ['normal', 'italic', 'oblique'], 355 'font-stretch': [ 356 'normal', 'semi-condensed', 'condensed', 'extra-condensed', 357 'ultra-condensed', 'semi-expanded', 'expanded', 'extra-expanded', 358 'ultra-expanded' 359 ], 360 'font-synthesis': ['none', 'weight', 'style'], 361 'font-variant': ['normal', 'small-caps'], 362 'font-variant-alternates': ['<font_variant_alternates>'], 363 'font-variant-caps': [ 364 'normal', 'small-caps', 'all-small-caps', 'petite-caps', 365 'all-petite-caps', 'unicase', 'titling-case' 366 ], 367 'font-variant-east-asian': [ 368 'normal', 'ruby', 'jis78', 'jis83', 'jis90', 'jis04', 'simplified', 369 'traditional' 370 ], 371 'font-variant-ligatures': [ 372 'normal', 'none', 'common-ligatures', 'no-common-ligatures', 373 'discretionary-ligatures', 'no-discretionary-ligatures', 374 'historical-ligatures', 'no-historical-ligatures', 'contextual', 375 'no-contextual' 376 ], 377 'font-variant-numeric': [ 378 'normal', 'ordinal', 'slashed-zero', 'lining-nums', 'oldstyle-nums', 379 'proportional-nums', 'tabular-nums', 'diagonal-fractions', 380 'stacked-fractions' 381 ], 382 'font-variant-position': ['normal', 'sub', 'super'], 383 'font-weight': ['<absolute_weight>', '<relative_weight>'], 384 'grid': [], 385 'grid-area': [], 386 'grid-auto-columns': ['auto', '<percentage>', '<length>'], 387 'grid-auto-flow': ['row', 'column', 'dense'], 388 'grid-auto-rows': ['auto', '<percentage>', '<length>'], 389 'grid-column-gap': ['<length>', '<percentage>'], 390 'grid-gap': ['<length>', '<percentage>'], 391 'grid-row-gap': ['<length>', '<percentage>'], 392 'grid-template-areas': [], 393 'grid-template-columns': ['auto', '<grid>', '<percentage>', '<length>'], 394 'grid-template-rows': ['auto', '<grid>', '<percentage>', '<length>'], 395 'grid-column': ['<number>'], 396 'grid-column-end': ['<number>'], 397 'grid-column-start': ['<number>'], 398 'grid-row': ['<number>'], 399 'grid-row-end': ['<number>'], 400 'grid-row-start': ['<number>'], 401 'height': ['<length>', '<percentage>', 'auto', 'fit-content'], 402 'hyphens': ['none', 'manual', 'auto'], 403 'image-rendering': [ 404 'auto', 'optimizeSpeed', 'optimizeQuality', 'pixelated' 405 ], 406 'ime-mode': ['auto', 'normal', 'active', 'inactive', 'disabled'], 407 'isolation': ['auto', 'isolation'], 408 'justify-content | justify-items | justify-self': [ 409 'start', 'end', 'flex-start', 'flex-end', 'center', 'left', 'right', 410 'safe start', 'safe end', 'safe flex-start', 'safe flex-end', 411 'safe center', 'safe left', 'safe right', 'unsafe start', 412 'unsafe end', 'unsafe flex-start', 'unsafe flex-end', 'unsafe center', 413 'unsafe left', 'unsafe right', 'normal', 'baseline', 'first baseline', 414 'last baseline', 'space-between', 'space-around', 'space-evenly', 415 'stretch', 'legacy', 'lecacy center', 'legacy left', 'legacy right' 416 ], 417 'kerning': ['auto'], 418 'left': ['<length>', '<percentage>', 'auto'], 419 'letter-spacing': ['normal', '<length>'], 420 'lighting-color': ['<color>'], 421 'line-height': ['normal', '<number>', '<length>', '<percentage>'], 422 'list-style': ['<list_style_type>', 'inside', 'outside', '<uri>'], 423 'list-style-image': ['<uri>', 'none'], 424 'list-style-position': ['inside', 'outside'], 425 'list-style-type': ['<list_style_type>'], 426 'margin': ['auto', '<margin-width>'], 427 'margin-top | margin-right | margin-bottom | margin-left': [ 428 'auto', '<margin-width>' 429 ], 430 'marker-end | marker-start | marker-mid': ['<uri>', 'none'], 431 'marks': ['crop', 'cross', 'none'], 432 'mask': ['<uri>', 'none'], 433 'mask-type': ['luminance', 'alpha'], 434 'max-height': ['<length>', '<percentage>', 'fit-content', 'none'], 435 'max-width': ['<length>', '<percentage>', 'fit-content', 'none'], 436 'min-height': ['<length>', '<percentage>', 'fit-content'], 437 'min-width': ['<length>', '<percentage>', 'fit-content'], 438 'mix-blend-mode': ['<blend_mode>'], 439 'object-fit': ['fill', 'contain', 'cover', 'none', 'scale-down'], 440 'object-position': ['<position>'], 441 'opacity': ['<number>'], 442 'order': ['<integer>'], 443 'orphans': ['<integer>'], 444 'outline': [ 445 '<color>', '<border_style>', '<border_width>', '<length>' 446 ], 447 'outline-color': ['<color>', 'invert'], 448 'outline-offset': ['<length>'], 449 'outline-style': ['<border_style>'], 450 'outline-width': ['<border_width>', '<length>'], 451 'overflow | overflow-x | overflow-y': [ 452 'visible', 'hidden', 'scroll', 'auto' 453 ], 454 'overflow-wrap': ['normal', 'break-word'], 455 'padding': ['auto', '<padding-width>'], 456 'padding-top | padding-right | padding-bottom | padding-left': [ 457 'auto', '<padding-width>' 458 ], 459 'page-break-after': ['auto', 'always', 'avoid', 'left', 'right'], 460 'page-break-before': ['auto', 'always', 'avoid', 'left', 'right'], 461 'page-break-inside': ['avoid', 'auto'], 462 'paint-order': ['normal', 'fill', 'stroke', 'markers'], 463 'perspective': ['none'], 464 'perspective-origin': ['<position>'], 465 'pointer-events': [ 466 'auto', 'none', 'all', 'visiblePainted', 'visibleFill', 467 'visibleStroke', 'visible', 'painted', 'fill', 'stroke' 468 ], 469 'position': ['static', 'relative', 'absolute', 'fixed', 'sticky'], 470 'quotes': ['none', '<string>'], 471 'resize': ['none', 'both', 'horizontal', 'vertical'], 472 'right': ['<length>', '<percentage>', 'auto'], 473 'scroll-behavior': ['auto', 'smooth'], 474 'shape-image-threshold': ['<number>'], 475 'shape-margin': ['<length>', '<percentage>'], 476 'shape-outside': [ 477 'none', 'margin-box', 'content-box', 'border-box', 'padding-box', 478 '<basic_shape>', '<uri>' 479 ], 480 'shape-rendering': [ 481 'auto', 'optimizeSpeed', 'crispEdges', 'geometricPrecision' 482 ], 483 'size': [ 484 'a3', 'a4', 'a5', 'b4', 'b5', 'jis-b4', 'jis-b5', 'landscape', 485 'ledger', 'legal', 'letter', 'portrait' 486 ], 487 'stop-color': ['<color>'], 488 'stroke': ['<color>'], 489 'stroke-dasharray': ['none'], 490 'stroke-linecap': ['butt', 'round', 'square'], 491 'stroke-linejoin': ['round', 'miter', 'bevel'], 492 'system': ['<counter_symbols>'], 493 'table-layout': ['auto', 'fixed'], 494 'text-align': ['left', 'right', 'center', 'justify', 'justify-all'], 495 'text-align-last': ['start', 'end', 'left', 'right', 'center', 'justify'], 496 'text-anchor': ['start', 'middle', 'end'], 497 'text-decoration': [ 498 'none', 'underline', 'overline', 'line-through', 'blink' 499 ], 500 'text-decoration-color': ['<color>'], 501 'text-decoration-line': ['none', 'underline', 'overline', 'line-through'], 502 'text-decoration-style': ['solid', 'double', 'dotted', 'dashed', 'wavy'], 503 'text-indent': ['<length>', '<percentage>'], 504 'text-orientation': ['mixed', 'upright', 'sideways', 'use-glyph-orientation'], 505 'text-overflow': ['clip', 'ellipsis'], 506 'text-rendering': [ 507 'auto', 'optimizeSpeed', 'optimizeLegibility', 'geometricPrecision' 508 ], 509 'text-shadow': ['none', '<color>'], 510 'text-transform': ['capitalize', 'uppercase', 'lowercase', 'none'], 511 'text-underline-position': ['auto', 'under', 'left', 'right'], 512 'top': ['<length>', '<percentage>', 'auto'], 513 'transform': [ 514 'none', 515 ['matrix()', 'matrix(${1:1}, ${2:1}, ${3:1}, ${4:1}, ${5:2}, ${6:2})'], 516 [ 517 'matrix3d()', 518 'matrix3d(' 519 '${1:1}, ${2:1}, ${3:0}, ${4:0}, ' 520 '${5:1}, ${6:1}, ${7:0}, ${8:0}, ' 521 '${9:0}, ${10:0}, ${11:1}, ${12:0}, ' 522 '${13:2}, ${14:2}, ${15:0}, ${16:1}' 523 ')' 524 ], 525 ['perspective()', 'perspective(${1:0})'], 526 ['rotate()', 'rotate(${1:45deg})'], 527 ['rotate3d()', 'rotate3d(${1:0}, ${2:0}, ${3:1}, ${4:45deg})'], 528 ['rotateX()', 'rotateX(${1:45deg})'], 529 ['rotateY()', 'rotateY(${1:45deg})'], 530 ['rotateZ()', 'rotateZ(${1:45deg})'], 531 ['scale()', 'scale(${1:1.0})'], 532 ['scale3d()', 'scale3d(${1:1.0}, ${2:1.0}, ${3:1.0})'], 533 ['scaleX()', 'scaleX(${1:1.0})'], 534 ['scaleY()', 'scaleY(${1:1.0})'], 535 ['scaleZ()', 'scaleZ(${1:1.0})'], 536 ['skew()', 'skew(${1:10deg})'], 537 ['skewX()', 'skewX(${1:10deg})'], 538 ['skewY()', 'skewY(${1:10deg})'], 539 ['translate()', 'translate(${1:10px})'], 540 ['translate3d()', 'translate3d(${1:10px}, ${2:0px}, ${3:0px})'], 541 ['translateX()', 'translateX(${1:10px})'], 542 ['translateY()', 'translateY(${1:10px})'], 543 ['translateZ()', 'translateZ(${1:10px})'] 544 ], 545 'transform-origin': ['<position>'], 546 'transform-style': ['preserve-3d', 'flat'], 547 'transition': [], 548 'transition-delay': ['<time>'], 549 'transition-duration': ['<time>'], 550 'transition-property': ['none', '<custom-ident>'], 551 'transition-timing-function': ['<timing_function>'], 552 'unicode-bidi': ['normal', 'embed', 'bidi-override'], 553 'unicode-range': [], 554 'user-select': ['auto', 'text', 'none', 'contain'], 555 'vertical-align': [ 556 'baseline', 'sub', 'super', 'text-top', 'text-bottom', 'middle', 557 'top', 'bottom', '<percentage>', '<length>' 558 ], 559 'visibility': ['visible', 'hidden', 'collapse'], 560 'white-space': ['normal', 'pre', 'nowrap', 'pre-wrap', 'pre-line'], 561 'widows': ['<integer>'], 562 'width': ['<length>', '<percentage>', 'auto', 'fit-content'], 563 'will-change': ['auto', 'contents', 'scroll-position', '<custom-ident>'], 564 'word-break': ['normal', 'break-all', 'keep-all'], 565 'word-spacing': ['normal', '<length>'], 566 'word-wrap': ['normal', 'break-word'], 567 'writing-mode': [ 568 'horizontal-tb', 'vertical-rl', 'vertical-lr', 'sideways-rl', 569 'sideways-lr' 570 ], 571 'z-index': ['auto', '<integer>'], 572 } 573 574 props = {} 575 576 for names, values in properties_dict.items(): 577 # Values that are allowed for all properties 578 allowed_values = ['all', 'inherit', 'initial', 'unset', ['var()', 'var($1)']] 579 580 # Determine which values are available for the current property name 581 for value in values: 582 if value[0] == '<' and value[-1] == '>': 583 key = value[1:-1] 584 if key in common_values: 585 allowed_values += common_values[key] 586 else: 587 allowed_values.append(value) 588 589 for name in names.split(' | '): 590 props[name] = allowed_values 591 592 return props 593 594 595 def match_selector(view, pt, scope): 596 # This will catch scenarios like: 597 # - .foo {font-style: |} 598 # - <style type="text/css">.foo { font-weight: b|</style> 599 return any(view.match_selector(p, scope) for p in (pt, pt - 1)) 600 601 602 def next_none_whitespace(view, pt): 603 for pt in range(pt, view.size()): 604 ch = view.substr(pt) 605 if ch not in ' \t': 606 return ch 607 608 609 class CSSCompletions(sublime_plugin.EventListener): 610 @cached_property 611 def props(self): 612 return get_properties() 613 614 @cached_property 615 def re_name(self): 616 return re.compile(r"([a-zA-Z-]+)\s*:[^:;{}]*$") 617 618 @cached_property 619 def re_value(self): 620 return re.compile(r"^(?:\s*(:)|([ \t]*))([^:]*)([;}])") 621 622 @timing 623 def on_query_completions(self, view, prefix, locations): 624 625 settings = sublime.load_settings('CSS.sublime-settings') 626 if settings.get('disable_default_completions'): 627 return None 628 629 selector = settings.get('default_completions_selector', '') 630 if isinstance(selector, list): 631 selector = ''.join(selector) 632 633 pt = locations[0] 634 if not match_selector(view, pt, selector): 635 return None 636 637 if match_selector(view, pt, "meta.property-value.css meta.function-call"): 638 items = self.complete_function_argument(view, prefix, pt) 639 elif match_selector(view, pt, "meta.property-value.css"): 640 items = self.complete_property_value(view, prefix, pt) 641 elif match_selector(view, pt, "meta.property-list.css, meta.property-name.css"): 642 items = self.complete_property_name(view, prefix, pt) 643 else: 644 # TODO: provide selectors, at-rules 645 items = None 646 647 if items: 648 return sublime.CompletionList(items, sublime.INHIBIT_WORD_COMPLETIONS) 649 return None 650 651 def complete_property_name(self, view, prefix, pt): 652 if match_selector(view, pt, "meta.group"): 653 # don't append semicolon in groups e.g.: `@media screen (prop: |)` 654 suffix = ": $0" 655 else: 656 suffix = ": $0;" 657 text = view.substr(sublime.Region(pt, view.line(pt).end())) 658 matches = self.re_value.search(text) 659 if matches: 660 colon, space, value, term = matches.groups() 661 if colon: 662 # don't append anything if the next character is a colon 663 suffix = "" 664 elif value: 665 # only append colon if value already exists 666 suffix = ":" if space else ": " 667 elif term == ";": 668 # ommit semicolon if rule is already terminated 669 suffix = ": $0" 670 671 return ( 672 sublime.CompletionItem( 673 trigger=prop, 674 completion=prop + suffix, 675 completion_format=sublime.COMPLETION_FORMAT_SNIPPET, 676 kind=KIND_CSS_PROPERTY 677 ) for prop in self.props 678 ) 679 680 def complete_property_value(self, view, prefix, pt): 681 completions = [] 682 text = view.substr(sublime.Region(view.line(pt).begin(), pt - len(prefix))) 683 matches = self.re_name.search(text) 684 if matches: 685 prop = matches.group(1) 686 values = self.props.get(prop) 687 if values: 688 details = f"<code>{prop}</code> property-value" 689 690 if match_selector(view, pt, "meta.group"): 691 # don't append semicolon in groups e.g.: `@media screen (prop: val)` 692 suffix = "" 693 elif next_none_whitespace(view, pt) == ";": 694 suffix = "" 695 else: 696 suffix = "$0;" 697 698 for value in values: 699 if isinstance(value, list): 700 desc, snippet = value 701 kind = KIND_CSS_FUNCTION 702 else: 703 desc = value 704 snippet = value 705 kind = KIND_CSS_CONSTANT 706 707 completions.append(sublime.CompletionItem( 708 trigger=desc, 709 completion=snippet + suffix, 710 completion_format=sublime.COMPLETION_FORMAT_SNIPPET, 711 kind=kind, 712 details=details 713 )) 714 715 return completions 716 717 def complete_function_argument(self, view, prefix, pt): 718 return None