@@ -504,6 +504,8 @@ define(function (require, exports, module) {
504504 starts that this selector (e.g. .baz) is part of. Particularly relevant for
505505 groups that are on multiple lines.
506506 selectorGroupStartChar: column in line where the selector group starts.
507+ selectorGroup: the entire selector group containing this selector, or undefined if there
508+ is only one selector in the rule.
507509 declListStartLine: line where the declaration list for the rule starts
508510 declListStartChar: column in line where the declaration list for the rule starts
509511 declListEndLine: line where the declaration list for the rule ends
@@ -690,6 +692,25 @@ define(function (require, exports, module) {
690692 var j ;
691693 declListStartLine = line ;
692694 declListStartChar = stream . start ;
695+
696+ // Extract the entire selector group we just saw.
697+ var selectorGroup , sgLine ;
698+ if ( selectorGroupStartLine !== - 1 ) {
699+ selectorGroup = "" ;
700+ for ( sgLine = selectorGroupStartLine ; sgLine <= declListStartLine ; sgLine ++ ) {
701+ var startChar = 0 , endChar = lines [ sgLine ] . length ;
702+ if ( sgLine === selectorGroupStartLine ) {
703+ startChar = selectorGroupStartChar ;
704+ } else {
705+ selectorGroup += " " ; // replace the newline with a single space
706+ }
707+ if ( sgLine === declListStartLine ) {
708+ endChar = declListStartChar ;
709+ }
710+ selectorGroup += lines [ sgLine ] . substring ( startChar , endChar ) ;
711+ }
712+ selectorGroup = selectorGroup . trim ( ) ;
713+ }
693714
694715 // Since we're now in a declaration list, that means we also finished
695716 // parsing the whole selector group. Therefore, reset selectorGroupStartLine
@@ -706,7 +727,7 @@ define(function (require, exports, module) {
706727 }
707728 }
708729
709- // assign this declaration list position to every selector on the stack
730+ // assign this declaration list position and selector group to every selector on the stack
710731 // that doesn't have a declaration list start and end line
711732 for ( j = selectors . length - 1 ; j >= 0 ; j -- ) {
712733 if ( selectors [ j ] . declListEndLine !== - 1 ) {
@@ -716,6 +737,9 @@ define(function (require, exports, module) {
716737 selectors [ j ] . declListStartChar = declListStartChar ;
717738 selectors [ j ] . declListEndLine = line ;
718739 selectors [ j ] . declListEndChar = stream . pos - 1 ; // stream.pos actually points to the char after the }
740+ if ( selectorGroup ) {
741+ selectors [ j ] . selectorGroup = selectorGroup ;
742+ }
719743 }
720744 }
721745 }
@@ -915,7 +939,8 @@ define(function (require, exports, module) {
915939 name : selectorInfo . selector ,
916940 document : sourceDoc ,
917941 lineStart : selectorInfo . ruleStartLine + lineOffset ,
918- lineEnd : selectorInfo . declListEndLine + lineOffset
942+ lineEnd : selectorInfo . declListEndLine + lineOffset ,
943+ selectorGroup : selectorInfo . selectorGroup
919944 } ) ;
920945 } ) ;
921946 }
@@ -1220,13 +1245,66 @@ define(function (require, exports, module) {
12201245 } ;
12211246 }
12221247
1248+ /**
1249+ *
1250+ * In the given rule array (as returned by `findMatchingRules()`), if multiple rules in a row
1251+ * refer to the same rule (because there were multiple matching selectors), eliminate the redundant
1252+ * rules and use the selectorGroup as the name instead of the original selector.
1253+ */
1254+ function consolidateRules ( rules ) {
1255+ var newRules = [ ] , lastRule ;
1256+ rules . forEach ( function ( rule ) {
1257+ if ( lastRule &&
1258+ rule . document === lastRule . document &&
1259+ rule . lineStart === lastRule . lineStart &&
1260+ rule . lineEnd === lastRule . lineEnd &&
1261+ rule . selectorGroup === lastRule . selectorGroup ) {
1262+ lastRule . name = lastRule . selectorGroup ;
1263+ } else {
1264+ newRules . push ( rule ) ;
1265+ }
1266+ lastRule = rule ;
1267+ } ) ;
1268+ return newRules ;
1269+ }
1270+
1271+ /**
1272+ * Given a TextRange, extracts the selector(s) for the rule in the range and returns it.
1273+ * Assumes the range only contains one rule; if there's more than one, it will return the
1274+ * selector(s) for the first rule.
1275+ * @param {TextRange } range The range to extract the selector(s) from.
1276+ * @return {string } The selector(s) for the rule in the range.
1277+ */
1278+ function getRangeSelectors ( range ) {
1279+ // There's currently no immediate way to access a given line in a Document, because it's just
1280+ // stored as a string. Eventually, we should have Documents cache the lines in the document
1281+ // as well, or make them use CodeMirror documents which do the same thing.
1282+ var i , startIndex = 0 , endIndex , text = range . document . getText ( ) ;
1283+ for ( i = 0 ; i < range . startLine ; i ++ ) {
1284+ startIndex = text . indexOf ( "\n" , startIndex ) + 1 ;
1285+ }
1286+ endIndex = startIndex ;
1287+ // Go one line past the end line. We'll extract text up to but not including the last newline.
1288+ for ( i = range . startLine + 1 ; i <= range . endLine + 1 ; i ++ ) {
1289+ endIndex = text . indexOf ( "\n" , endIndex ) + 1 ;
1290+ }
1291+ var allSelectors = extractAllSelectors ( text . substring ( startIndex , endIndex ) ) ;
1292+
1293+ // There should only be one rule in the range, and if there are multiple selectors for
1294+ // the first rule, they'll all be recorded in the "selectorGroup" for the first selector,
1295+ // so we only need to look at the first one.
1296+ return ( allSelectors . length ? allSelectors [ 0 ] . selectorGroup || allSelectors [ 0 ] . selector : "" ) ;
1297+ }
1298+
12231299 exports . _findAllMatchingSelectorsInText = _findAllMatchingSelectorsInText ; // For testing only
12241300 exports . findMatchingRules = findMatchingRules ;
12251301 exports . extractAllSelectors = extractAllSelectors ;
12261302 exports . extractAllNamedFlows = extractAllNamedFlows ;
12271303 exports . findSelectorAtDocumentPos = findSelectorAtDocumentPos ;
12281304 exports . reduceStyleSheetForRegExParsing = reduceStyleSheetForRegExParsing ;
12291305 exports . addRuleToDocument = addRuleToDocument ;
1306+ exports . consolidateRules = consolidateRules ;
1307+ exports . getRangeSelectors = getRangeSelectors ;
12301308
12311309 exports . SELECTOR = SELECTOR ;
12321310 exports . PROP_NAME = PROP_NAME ;
0 commit comments