@@ -76,7 +76,8 @@ enum scopeAction {
7676 SCOPE_POP = 1UL << 1 ,
7777 SCOPE_PUSH = 1UL << 2 ,
7878 SCOPE_CLEAR = 1UL << 3 ,
79- SCOPE_PLACEHOLDER = 1UL << 4 ,
79+ SCOPE_REF_AFTER_POP = 1UL << 4 ,
80+ SCOPE_PLACEHOLDER = 1UL << 5 ,
8081};
8182
8283enum tableAction {
@@ -576,6 +577,8 @@ static void scope_ptrn_flag_eval (const char* const f CTAGS_ATTR_UNUSED,
576577 * bfields |= SCOPE_CLEAR ;
577578 else if (strcmp (v , "set" ) == 0 )
578579 * bfields |= (SCOPE_CLEAR | SCOPE_PUSH );
580+ else if (strcmp (v , "replace" ) == 0 )
581+ * bfields |= (SCOPE_POP |SCOPE_REF_AFTER_POP |SCOPE_PUSH );
579582 else
580583 error (FATAL , "Unexpected value for scope flag in regex definition: scope=%s" , v );
581584}
@@ -589,7 +592,7 @@ static void placeholder_ptrn_flag_eval (const char* const f CTAGS_ATTR_UNUSED,
589592
590593static flagDefinition scopePtrnFlagDef [] = {
591594 { '\0' , "scope" , NULL , scope_ptrn_flag_eval ,
592- "ACTION" , "use scope stack: ACTION = ref|push|pop|clear|set" },
595+ "ACTION" , "use scope stack: ACTION = ref|push|pop|clear|set|replace " },
593596 { '\0' , "placeholder" , NULL , placeholder_ptrn_flag_eval ,
594597 NULL , "don't put this tag to tags file." },
595598};
@@ -1300,7 +1303,12 @@ static void patternEvalFlags (struct lregexControlBlock *lcb,
13001303 }
13011304
13021305 if (regptype == REG_PARSER_SINGLE_LINE || regptype == REG_PARSER_MULTI_TABLE )
1306+ {
13031307 flagsEval (flags , scopePtrnFlagDef , ARRAY_SIZE (scopePtrnFlagDef ), & ptrn -> scopeActions );
1308+ if ((ptrn -> scopeActions & (SCOPE_REF |SCOPE_REF_AFTER_POP )) == (SCOPE_REF |SCOPE_REF_AFTER_POP ))
1309+ error (WARNING , "%s: don't combine \"replace\" with the other scope action." ,
1310+ getLanguageName (lcb -> owner ));
1311+ }
13041312
13051313 if (regptype == REG_PARSER_MULTI_LINE || regptype == REG_PARSER_MULTI_TABLE )
13061314 {
@@ -1564,6 +1572,16 @@ static bool hasNameSlot (const regexPattern* const patbuf)
15641572 || patbuf -> anonymous_tag_prefix );
15651573}
15661574
1575+ static int scopeActionRef (int currentScope )
1576+ {
1577+ int scope = currentScope ;
1578+ tagEntryInfo * entry ;
1579+ while ((entry = getEntryInCorkQueue (scope )) && entry -> placeholder )
1580+ /* Look at parent */
1581+ scope = entry -> extensionFields .scopeIndex ;
1582+ return scope ;
1583+ }
1584+
15671585static void matchTagPattern (struct lregexControlBlock * lcb ,
15681586 const char * line ,
15691587 const regexPattern * const patbuf ,
@@ -1585,14 +1603,7 @@ static void matchTagPattern (struct lregexControlBlock *lcb,
15851603 vStringStripTrailing (name );
15861604
15871605 if (patbuf -> scopeActions & SCOPE_REF )
1588- {
1589- tagEntryInfo * entry ;
1590-
1591- scope = lcb -> currentScope ;
1592- while ((entry = getEntryInCorkQueue (scope )) && entry -> placeholder )
1593- /* Look at parent */
1594- scope = entry -> extensionFields .scopeIndex ;
1595- }
1606+ scope = scopeActionRef (lcb -> currentScope );
15961607 if (patbuf -> scopeActions & SCOPE_CLEAR )
15971608 {
15981609 unsigned long endline = getInputLineNumberInRegPType (patbuf -> regptype , offset );
@@ -1614,10 +1625,24 @@ static void matchTagPattern (struct lregexControlBlock *lcb,
16141625 tagEntryInfo * entry = getEntryInCorkQueue (lcb -> currentScope );
16151626
16161627 if (entry && (entry -> extensionFields .endLine == 0 ))
1628+ {
16171629 entry -> extensionFields .endLine = getInputLineNumberInRegPType (patbuf -> regptype , offset );
16181630
1631+ /*
1632+ * SCOPE_POP|SCOPE_REF_AFTER_POP implies that "replace" was specified as the
1633+ * scope action. If the specified action is "replace", getInputLineNumberInRegPType()
1634+ * returns the start line of the NEW scope. The popped scope is ended BEFORE
1635+ * the new scope. There is a gap. We must adjust the "end:" field here.
1636+ */
1637+ if ((patbuf -> scopeActions & SCOPE_REF_AFTER_POP ) &&
1638+ entry -> extensionFields .endLine > 1 )
1639+ entry -> extensionFields .endLine -- ;
1640+ }
1641+
16191642 lcb -> currentScope = entry ? entry -> extensionFields .scopeIndex : CORK_NIL ;
16201643 }
1644+ if (patbuf -> scopeActions & SCOPE_REF_AFTER_POP )
1645+ scope = scopeActionRef (lcb -> currentScope );
16211646
16221647 if (vStringLength (name ) == 0 && (placeholder == false))
16231648 {
0 commit comments