Skip to content

Commit f998e51

Browse files
committed
lregex: implement new scope action "replace"
Suggested by @Fmajor in #1577. Signed-off-by: Masatake YAMATO <[email protected]>
1 parent dcac970 commit f998e51

File tree

6 files changed

+121
-16
lines changed

6 files changed

+121
-16
lines changed

Tmain/list-mtable-regex-flags.d/stdout-expected.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ p pcre2 use pcre2 regex engine
66
- fatal="MESSAGE" print the given MESSAGE and exit
77
- mgroup=N a group in pattern determining the line number of tag
88
- placeholder don't put this tag to tags file.
9-
- scope=ACTION use scope stack: ACTION = ref|push|pop|clear|set
9+
- scope=ACTION use scope stack: ACTION = ref|push|pop|clear|set|replace
1010
- tenter=TABLE[,CONT] enter to given regext table (with specifying continuation)
1111
- tjump=TABLE jump to another regext table(don't push the current table to state stack)
1212
- tleave leave from the current regext table

Tmain/list-regex-flags.d/stdout-expected.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ p pcre2 use pcre2 regex engine
66
x exclusive skip testing the other patterns if a line is matched to this pattern
77
- fatal="MESSAGE" print the given MESSAGE and exit
88
- placeholder don't put this tag to tags file.
9-
- scope=ACTION use scope stack: ACTION = ref|push|pop|clear|set
9+
- scope=ACTION use scope stack: ACTION = ref|push|pop|clear|set|replace
1010
- warning="MESSAGE" print the given MESSAGE at WARNING level
1111
- _anonymous=PREFIX make an anonymous tag with PREFIX
1212
- _extra=EXTRA record the tag only when the extra is enabled

docs/man/ctags-optlib.7.rst

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,7 @@ representation. ``--list-regex-flags`` lists all the flags.
329329
can be an empty string. See the following description of
330330
``scope=...`` flag about how this is useful.
331331

332-
``scope=(ref|push|pop|clear|set)``
332+
``scope=(ref|push|pop|clear|set|replace)``
333333

334334
Specify what to do with the internal scope stack.
335335

@@ -342,7 +342,7 @@ representation. ``--list-regex-flags`` lists all the flags.
342342
``--regex-<LANG>`` is pushed to the stack. ``{scope=push}``
343343
implies ``{scope=ref}``.
344344

345-
You can fill the scope field of captured tag with
345+
You can fill the scope field (``scope:``) of captured tag with
346346
``{scope=ref}``. If ``{scope=ref}`` flag is given,
347347
ctags attaches the tag at the top to the tag
348348
captured with ``--regex-<LANG>`` as the value for the ``scope:``
@@ -356,6 +356,21 @@ representation. ``--list-regex-flags`` lists all the flags.
356356
Specifying ``{scope=set}`` removes all the tags in the scope, and
357357
then pushes the captured tag as ``{scope=push}`` does.
358358

359+
``{scope=replace}`` does the three things sequentially. First it
360+
does the same as ``{scope=pop}``, then fills the ``scope:`` field
361+
of the tag captured with ``--regex-<LANG>``, and pushes the tag to
362+
the scope stack as if ``{scope=push}`` was given finally.
363+
You cannot specify another scope action together with
364+
``{scope=replace}``.
365+
366+
You don't want to specify ``{scope=pop}{scope=push}`` as an
367+
alternative to ``{scope=replace}``; ``{scope=pop}{scope=push}``
368+
fills the ``scope:`` field of the tag captured with ``--regex-<LANG>``
369+
first, then pops the tag at the top of the stack, and pushes
370+
the captured tag to the scope stack finally. The timing when
371+
filling the end field is different between ``{scope=replace}`` and
372+
``{scope=pop}{scope=push}``.
373+
359374
In some cases, you may want to use ``--regex-<LANG>`` only for its
360375
side effects: using it only to manipulate the stack but not for
361376
capturing a tag. In such a case, make *<name_pattern>* component of

docs/optlib.rst

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -570,6 +570,56 @@ Example 2:
570570
foo /tmp/input.pp /^class foo {$/;" c
571571
572572
573+
Example 3:
574+
575+
.. code-block::
576+
577+
# in /tmp/input.docdoc
578+
title T
579+
...
580+
section S0
581+
...
582+
section S1
583+
...
584+
585+
.. code-block:: ctags
586+
:emphasize-lines: 15,21
587+
588+
# in /tmp/doc.ctags:
589+
--langdef=doc
590+
--map-doc=+.docdoc
591+
--kinddef-doc=s,section,sections
592+
--kinddef-doc=S,subsection,subsections
593+
594+
--_tabledef-doc=main
595+
--_tabledef-doc=section
596+
--_tabledef-doc=subsection
597+
598+
--_mtable-regex-doc=main/section +([^\n]+)\n/\1/s/{scope=push}{tenter=section}
599+
--_mtable-regex-doc=main/[^\n]+\n|[^\n]+|\n//
600+
--_mtable-regex-doc=main///{scope=clear}{tquit}
601+
602+
--_mtable-regex-doc=section/section +([^\n]+)\n/\1/s/{scope=replace}
603+
--_mtable-regex-doc=section/subsection +([^\n]+)\n/\1/S/{scope=push}{tenter=subsection}
604+
--_mtable-regex-doc=section/[^\n]+\n|[^\n]+|\n//
605+
--_mtable-regex-doc=section///{scope=clear}{tquit}
606+
607+
--_mtable-regex-doc=subsection/(section )//{_advanceTo=0start}{tleave}{scope=pop}
608+
--_mtable-regex-doc=subsection/subsection +([^\n]+)\n/\1/S/{scope=replace}
609+
--_mtable-regex-doc=subsection/[^\n]+\n|[^\n]+|\n//
610+
--_mtable-regex-doc=subsection///{scope=clear}{tquit}
611+
612+
.. code-block:: console
613+
614+
% ctags --sort=no --fields=+nl --options=/tmp/doc.ctags -o - /tmp/input.docdoc
615+
SEC0 /tmp/input.docdoc /^section SEC0$/;" s line:1 language:doc
616+
SUB0-1 /tmp/input.docdoc /^subsection SUB0-1$/;" S line:3 language:doc section:SEC0
617+
SUB0-2 /tmp/input.docdoc /^subsection SUB0-2$/;" S line:5 language:doc section:SEC0
618+
SEC1 /tmp/input.docdoc /^section SEC1$/;" s line:7 language:doc
619+
SUB1-1 /tmp/input.docdoc /^subsection SUB1-1$/;" S line:9 language:doc section:SEC1
620+
SUB1-2 /tmp/input.docdoc /^subsection SUB1-2$/;" S line:11 language:doc section:SEC1
621+
622+
573623
NOTE: This flag doesn't work well with ``--mline-regex-<LANG>=``.
574624

575625
Overriding the letter for file kind

main/lregex.c

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -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

8283
enum 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

590593
static 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+
15671585
static 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
{

man/ctags-optlib.7.rst.in

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,7 @@ representation. ``--list-regex-flags`` lists all the flags.
329329
can be an empty string. See the following description of
330330
``scope=...`` flag about how this is useful.
331331

332-
``scope=(ref|push|pop|clear|set)``
332+
``scope=(ref|push|pop|clear|set|replace)``
333333

334334
Specify what to do with the internal scope stack.
335335

@@ -342,7 +342,7 @@ representation. ``--list-regex-flags`` lists all the flags.
342342
``--regex-<LANG>`` is pushed to the stack. ``{scope=push}``
343343
implies ``{scope=ref}``.
344344

345-
You can fill the scope field of captured tag with
345+
You can fill the scope field (``scope:``) of captured tag with
346346
``{scope=ref}``. If ``{scope=ref}`` flag is given,
347347
@CTAGS_NAME_EXECUTABLE@ attaches the tag at the top to the tag
348348
captured with ``--regex-<LANG>`` as the value for the ``scope:``
@@ -356,6 +356,21 @@ representation. ``--list-regex-flags`` lists all the flags.
356356
Specifying ``{scope=set}`` removes all the tags in the scope, and
357357
then pushes the captured tag as ``{scope=push}`` does.
358358

359+
``{scope=replace}`` does the three things sequentially. First it
360+
does the same as ``{scope=pop}``, then fills the ``scope:`` field
361+
of the tag captured with ``--regex-<LANG>``, and pushes the tag to
362+
the scope stack as if ``{scope=push}`` was given finally.
363+
You cannot specify another scope action together with
364+
``{scope=replace}``.
365+
366+
You don't want to specify ``{scope=pop}{scope=push}`` as an
367+
alternative to ``{scope=replace}``; ``{scope=pop}{scope=push}``
368+
fills the ``scope:`` field of the tag captured with ``--regex-<LANG>``
369+
first, then pops the tag at the top of the stack, and pushes
370+
the captured tag to the scope stack finally. The timing when
371+
filling the end field is different between ``{scope=replace}`` and
372+
``{scope=pop}{scope=push}``.
373+
359374
In some cases, you may want to use ``--regex-<LANG>`` only for its
360375
side effects: using it only to manipulate the stack but not for
361376
capturing a tag. In such a case, make *<name_pattern>* component of

0 commit comments

Comments
 (0)