@@ -38,6 +38,12 @@ define(function (require, exports, module) {
3838 CSSProperties = require ( "text!CSSProperties.json" ) ,
3939 properties = JSON . parse ( CSSProperties ) ;
4040
41+ /**
42+ * Emmet API:
43+ * This provides a function to expand abbreviations into full CSS properties.
44+ */
45+ const EXPAND_ABBR = Phoenix . libs . Emmet . expand ;
46+
4147 require ( "./css-lint" ) ;
4248
4349 const BOOSTED_PROPERTIES = [
@@ -248,7 +254,7 @@ define(function (require, exports, module) {
248254 }
249255
250256 /**
251- * Returns a list of availble CSS propertyname or -value hints if possible for the current
257+ * Returns a list of available CSS property name or -value hints if possible for the current
252258 * editor context.
253259 *
254260 * @param {Editor } implicitChar
@@ -377,8 +383,48 @@ define(function (require, exports, module) {
377383 }
378384 }
379385
386+ // pushedHints stores all the hints that will be displayed to the user
387+ // up until this much is the normal working of css code hints
388+ let pushedHints = formatHints ( result ) ;
389+
390+ // needle gives the current word before cursor, make sure that it exists
391+ // also needle shouldn't contain `-`, because for example if user typed:
392+ // `box-siz` then in that case it is very obvious that user wants to type `box-sizing`
393+ // but emmet expands it `box: siz;`. So we prevent calling emmet when needle has `-`.
394+ if ( needle && ! needle . includes ( '-' ) ) {
395+ let expandedAbbr = EXPAND_ABBR ( needle , { syntax : "css" , type : "stylesheet" } ) ;
396+ if ( expandedAbbr && isEmmetExpandable ( needle , expandedAbbr ) ) {
397+
398+ // if the expandedAbbr doesn't have any numbers, we should split the expandedAbbr to,
399+ // get its first word before `:`.
400+ // For instance, `m` expands to `margin: ;`. Here the `: ;` is unnecessary.
401+ // Also, `bgc` expands to `background-color: #fff;`. Here we don't need the `: #fff;`
402+ // as we have cssIntelligence to display hints based on the property
403+ if ( ! isEmmetAbbrNumeric ( expandedAbbr ) ) {
404+ expandedAbbr = expandedAbbr . split ( ':' ) [ 0 ] ;
405+ }
406+
407+ if ( pushedHints ) {
408+
409+ // to remove duplicate hints. one comes from emmet and other from default css hints.
410+ // we remove the default css hints and push emmet hint at the beginning.
411+ for ( let i = 0 ; i < pushedHints . length ; i ++ ) {
412+ if ( pushedHints [ i ] [ 0 ] . getAttribute ( 'data-val' ) === expandedAbbr ) {
413+ pushedHints . splice ( i , 1 ) ;
414+ break ;
415+ }
416+ }
417+ pushedHints . unshift ( expandedAbbr ) ;
418+ } else {
419+ pushedHints = expandedAbbr ;
420+ }
421+ }
422+ }
423+
424+
425+
380426 return {
381- hints : formatHints ( result ) ,
427+ hints : pushedHints ,
382428 match : null , // the CodeHintManager should not format the results
383429 selectInitial : selectInitial ,
384430 handleWideResults : false
@@ -387,6 +433,34 @@ define(function (require, exports, module) {
387433 return null ;
388434 } ;
389435
436+ /**
437+ * Checks whether the emmet abbr should be expanded or not.
438+ * For instance: EXPAND_ABBR function always expands a value passed to it.
439+ * if we pass 'xyz', then there's no CSS property matching to it, but it still expands this to `xyz: ;`.
440+ * So, make sure that `needle + ': ;'` doesn't add to expandedAbbr
441+ *
442+ * @param {String } needle the word before the cursor
443+ * @param {String } expandedAbbr the expanded abbr returned by EXPAND_ABBR emmet api
444+ * @returns {boolean } true if emmet should be expanded, otherwise false
445+ */
446+ function isEmmetExpandable ( needle , expandedAbbr ) {
447+ return needle + ': ;' !== expandedAbbr ;
448+ }
449+
450+ /**
451+ * Checks whether the expandedAbbr has any number.
452+ * For instance: `m0` expands to `margin: 0;`, so we need to display the whole thing in the code hint
453+ * Here, we also make sure that abbreviations which has `#`, `,` should not be included, because
454+ * * `color` expands to `color: #000;` or `color: rgb(0, 0, 0)`. So this actually has numbers, but we don't want to display this.
455+ *
456+ * @param {String } expandedAbbr the expanded abbr returned by EXPAND_ABBR emmet api
457+ * @returns {boolean } true if expandedAbbr has numbers (and doesn't include '#') otherwise false.
458+ */
459+ function isEmmetAbbrNumeric ( expandedAbbr ) {
460+ return expandedAbbr . match ( / \d / ) !== null && ! expandedAbbr . includes ( '#' ) && ! expandedAbbr . includes ( ',' ) ;
461+ }
462+
463+
390464 const HISTORY_PREFIX = "Live_hint_" ;
391465 let hintSessionId = 0 , isInLiveHighlightSession = false ;
392466
0 commit comments