Skip to content

Commit

Permalink
main: add nulltag/0, a new extra
Browse files Browse the repository at this point in the history
Close #4151.

Consider a parser attempting to emit a null tag, a tag whose
name is the empty string '\0'.

Original Behavior:

    It warns "ignoring null tag..." if both parserDefinition::allowNullTag and
    tagEntryInfo::allowNullTag are unset.

    It does not warn if either parserDefinition::allowNullTag or
    tagEntryInfo::allowNullTag is set.

    It does not emit the null tag, even if allowNullTag is set.

With This Change: The code now emits the null tag if:

    Either parserDefinition::allowNullTag or tagEntryInfo::allowNullTag
    is set, and

    The --extras=+0 (or --extras=+{nulltag}) option is specified.

TODO:
- versioning
- updating ctags(1),
- updating the hacking guide
- make readtags warn "unsupported" if it finds "!_TAG_FIELD_DESCRIPTION"

Signed-off-by: Masatake YAMATO <[email protected]>
  • Loading branch information
masatake committed Dec 8, 2024
1 parent bae63b3 commit a9b0a15
Show file tree
Hide file tree
Showing 16 changed files with 115 additions and 2 deletions.
5 changes: 5 additions & 0 deletions Tmain/extras-long.d/stdout-expected.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# resetting
- anonymous no NONE no Include tags for non-named objects like lambda
0 nulltag no NONE no Include tags with empty strings as their names
F fileScope no NONE no Include tags of file scope
f inputFile no NONE no Include an entry for the base file name of every input file
g guest no NONE no Include tags generated by guest parsers
Expand All @@ -18,6 +19,7 @@ s subparser yes NONE no Include tags generated by
- whitespaceSwapped yes Robot no Include tags swapping whitespace and underscore chars
# enabling 1
- anonymous yes NONE no Include tags for non-named objects like lambda
0 nulltag no NONE no Include tags with empty strings as their names
F fileScope yes NONE no Include tags of file scope
f inputFile no NONE no Include an entry for the base file name of every input file
g guest no NONE no Include tags generated by guest parsers
Expand All @@ -36,6 +38,7 @@ s subparser yes NONE no Include tags generated by
- whitespaceSwapped yes Robot no Include tags swapping whitespace and underscore chars
# disabling 1
- anonymous yes NONE no Include tags for non-named objects like lambda
0 nulltag no NONE no Include tags with empty strings as their names
F fileScope no NONE no Include tags of file scope
f inputFile no NONE no Include an entry for the base file name of every input file
g guest no NONE no Include tags generated by guest parsers
Expand All @@ -54,6 +57,7 @@ s subparser yes NONE no Include tags generated by
- whitespaceSwapped yes Robot no Include tags swapping whitespace and underscore chars
# combination
- anonymous yes NONE no Include tags for non-named objects like lambda
0 nulltag no NONE no Include tags with empty strings as their names
F fileScope no NONE no Include tags of file scope
f inputFile yes NONE no Include an entry for the base file name of every input file
g guest no NONE no Include tags generated by guest parsers
Expand All @@ -72,6 +76,7 @@ s subparser yes NONE no Include tags generated by
- whitespaceSwapped yes Robot no Include tags swapping whitespace and underscore chars
# combination with letters
- anonymous yes NONE no Include tags for non-named objects like lambda
0 nulltag no NONE no Include tags with empty strings as their names
F fileScope no NONE no Include tags of file scope
f inputFile no NONE no Include an entry for the base file name of every input file
g guest no NONE no Include tags generated by guest parsers
Expand Down
1 change: 1 addition & 0 deletions Tmain/json-output-format.d/stdout-expected.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
{"_type": "ptag", "name": "TAG_EXTRA_DESCRIPTION", "path": "fileScope", "pattern": "Include tags of file scope"}
{"_type": "ptag", "name": "TAG_EXTRA_DESCRIPTION", "path": "guest", "pattern": "Include tags generated by guest parsers"}
{"_type": "ptag", "name": "TAG_EXTRA_DESCRIPTION", "path": "inputFile", "pattern": "Include an entry for the base file name of every input file"}
{"_type": "ptag", "name": "TAG_EXTRA_DESCRIPTION", "path": "nulltag", "pattern": "Include tags with empty strings as their names"}
{"_type": "ptag", "name": "TAG_EXTRA_DESCRIPTION", "path": "pseudo", "pattern": "Include pseudo tags"}
{"_type": "ptag", "name": "TAG_EXTRA_DESCRIPTION", "path": "qualified", "pattern": "Include an extra class-qualified tag entry for each tag"}
{"_type": "ptag", "name": "TAG_EXTRA_DESCRIPTION", "path": "reference", "pattern": "Include reference tags"}
Expand Down
4 changes: 4 additions & 0 deletions Tmain/kind-abnormal-spec.d/stdout-expected.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ r emit a tag with multi roles
R emit a tag with multi roles(disabled by default) [off]
f tag for testing field:
n trigger notice output
z emit a tag having an empty string
Z don't emit a tag having an empty string

# list kinds-full
#LETTER NAME ENABLED REFONLY NROLES MASTER DESCRIPTION
Expand All @@ -22,12 +24,14 @@ L ThisShouldNotBePrintedKindNameMustBeGiven yes no 0 NONE
N nothingSpecial yes no 0 NONE emit a normal tag
Q quit yes no 0 NONE stop the parsing
R rolesDisabled no yes 2 NONE emit a tag with multi roles(disabled by default)
Z dontEmitNullTag yes no 0 NONE don't emit a tag having an empty string
b broken tag yes no 1 NONE name with unwanted characters
d disabled no no 2 NONE a kind disabled by default
e enabled yes no 2 NONE a kind enabled by default
f fieldMaker yes no 0 NONE tag for testing field:
n triggerNotice yes no 0 NONE trigger notice output
r roles yes yes 4 NONE emit a tag with multi roles
z emitNullTag yes no 0 NONE emit a tag having an empty string

# +K
abnormal kindDefinition testing (no letter) input.x /^@$/;" no letter
Expand Down
3 changes: 3 additions & 0 deletions Tmain/list-extras.d/stdout-expected.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#LETTER NAME ENABLED LANGUAGE FIXED DESCRIPTION
- anonymous yes NONE no Include tags for non-named objects like lambda
0 nulltag yes NONE no Include tags with empty strings as their names
F fileScope yes NONE no Include tags of file scope
f inputFile yes NONE no Include an entry for the base file name of every input file
g guest yes NONE no Include tags generated by guest parsers
Expand All @@ -18,6 +19,7 @@ s subparser yes NONE no Include tags generated by
- whitespaceSwapped yes Robot no Include tags swapping whitespace and underscore chars
#LETTER NAME ENABLED LANGUAGE FIXED DESCRIPTION
- anonymous yes NONE no Include tags for non-named objects like lambda
0 nulltag yes NONE no Include tags with empty strings as their names
F fileScope yes NONE no Include tags of file scope
f inputFile yes NONE no Include an entry for the base file name of every input file
g guest yes NONE no Include tags generated by guest parsers
Expand All @@ -36,6 +38,7 @@ s subparser yes NONE no Include tags generated by subparsers
- whitespaceSwapped yes Robot no Include tags swapping whitespace and underscore chars
#LETTER NAME ENABLED LANGUAGE FIXED DESCRIPTION
- anonymous no NONE no Include tags for non-named objects like lambda
0 nulltag no NONE no Include tags with empty strings as their names
F fileScope no NONE no Include tags of file scope
f inputFile no NONE no Include an entry for the base file name of every input file
g guest no NONE no Include tags generated by guest parsers
Expand Down
3 changes: 3 additions & 0 deletions Tmain/nulltag-extra.d/input.cst
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Z
z

39 changes: 39 additions & 0 deletions Tmain/nulltag-extra.d/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Copyright: 2022 Masatake YAMATO
# License: GPL-2

CTAGS=$1

. ../utils.sh

# is_feature_available $CTAGS json

O="--options=NONE --language-force=CTagsSelfTest"

for fmt in u-ctags; do

{
echo "# no extra ($fmt)"
${CTAGS} $O -o - --output-format="$fmt" input.cst
} 2>&1

{
echo "# drop '0' extra ($fmt)"
${CTAGS} $O -o - --output-format="$fmt" --extras=-0 input.cst
} 2>&1

{
echo "# drop '{nulltag}' extra ($fmt)"
${CTAGS} $O -o - --output-format="$fmt" --extras=-'{nulltag}' input.cst
} 2>&1

{
echo '# with --extras=+0 ($fmt)'
${CTAGS} $O -o - --output-format="$fmt" --extras=+0 input.cst
} 2>&1

{
echo "# with --extras=+{nulltag}' ($fmt)"
${CTAGS} $O -o - --output-format="$fmt" --extras=+'{nulltag}' input.cst
} 2>&1

done
Empty file.
17 changes: 17 additions & 0 deletions Tmain/nulltag-extra.d/stdout-expected.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# no extra (u-ctags)
ctags: Notice: No options will be read from files or environment
ctags: Notice: ignoring null tag in input.cst(line: 1, language: CTagsSelfTest)
# drop '0' extra (u-ctags)
ctags: Notice: No options will be read from files or environment
ctags: Notice: ignoring null tag in input.cst(line: 1, language: CTagsSelfTest)
# drop '{nulltag}' extra (u-ctags)
ctags: Notice: No options will be read from files or environment
ctags: Notice: ignoring null tag in input.cst(line: 1, language: CTagsSelfTest)
# with --extras=+0 ($fmt)
ctags: Notice: No options will be read from files or environment
ctags: Notice: ignoring null tag in input.cst(line: 1, language: CTagsSelfTest)
input.cst /^z$/;" z
# with --extras=+{nulltag}' (u-ctags)
ctags: Notice: No options will be read from files or environment
ctags: Notice: ignoring null tag in input.cst(line: 1, language: CTagsSelfTest)
input.cst /^z$/;" z
17 changes: 16 additions & 1 deletion main/entry.c
Original file line number Diff line number Diff line change
Expand Up @@ -1770,6 +1770,15 @@ static void writeTagEntry (tagEntryInfo *const tag)

DebugStatement ( debugEntry (tag); )

if (isTagExtraBitMarked(tag, XTAG_NULLTAG))
{
if (!writerCanPrintNullTag())
return;

if (!isXtagEnabled(XTAG_NULLTAG))
return;
}

#ifdef _WIN32
if (getFilenameSeparator(Option.useSlashAsFilenameSeparator) == FILENAME_SEP_USE_SLASH)
{
Expand Down Expand Up @@ -1939,10 +1948,16 @@ extern int makeTagEntry (tagEntryInfo *const tag)
if (tag->name [0] == '\0' && (!tag->placeholder))
{
if (! tag->allowNullTag)
{
error (NOTICE, "ignoring null tag in %s(line: %lu, language: %s)",
getInputFileName (), tag->lineNumber,
getLanguageName (tag->langType));
goto out;
goto out;
}

/* writeTagEntry decides whether ctags emits this tag or not.
* At this point, we just mark the tag as a null tag. */
markTagExtraBit(tag, XTAG_NULLTAG);
}

if (TagFile.cork)
Expand Down
14 changes: 14 additions & 0 deletions main/parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -5550,6 +5550,8 @@ typedef enum {
K_ROLES_DISABLED,
K_FIELD_TESTING,
K_TRIGGER_NOTICE,
K_EMIT_NULL_TAG,
K_DONT_EMIT_NULL_TAG,
KIND_COUNT
} CTST_Kind;

Expand Down Expand Up @@ -5631,6 +5633,8 @@ static kindDefinition CTST_Kinds[KIND_COUNT] = {
.referenceOnly = true, ATTACH_ROLES (CTST_RolesDisabledKindRoles)},
{true, 'f', "fieldMaker", "tag for testing field:" },
{true, 'n', "triggerNotice", "trigger notice output"},
{true, 'z', "emitNullTag", "emit a tag having an empty string"},
{true, 'Z', "dontEmitNullTag", "don't emit a tag having an empty string"},
};

typedef enum {
Expand Down Expand Up @@ -5820,6 +5824,16 @@ static void createCTSTTags (void)
case K_TRIGGER_NOTICE:
notice ("notice output for testing: %s", CTST_Kinds [i].name);
break;
case K_EMIT_NULL_TAG:
initTagEntry (&e, "", i);
e.allowNullTag = 1;
makeTagEntry (&e);
break;
case K_DONT_EMIT_NULL_TAG:
initTagEntry (&e, "", i);
e.allowNullTag = 0;
makeTagEntry (&e);
break;
}

if (quit)
Expand Down
1 change: 1 addition & 0 deletions main/writer-ctags.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ tagWriter uCtagsWriter = {
.rescanFailedEntry = NULL,
.treatFieldAsFixed = treatFieldAsFixed,
.checkOptions = checkCtagsOptions,
.canPrintNullTag = true,
#ifdef _WIN32
.overrideFilenameSeparator = overrideFilenameSeparator,
#endif
Expand Down
1 change: 1 addition & 0 deletions main/writer-json.c
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,7 @@ tagWriter jsonWriter = {
.preWriteEntry = NULL,
.postWriteEntry = NULL,
.defaultFileName = "-",
.canPrintNullTag = false,
};

extern bool ptagMakeJsonOutputVersion (ptagDesc *desc, langType language CTAGS_ATTR_UNUSED,
Expand Down
4 changes: 4 additions & 0 deletions main/writer.c
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,10 @@ extern bool writerCanPrintPtag (void)
return (writer->writePtagEntry)? true: false;
}

extern bool writerCanPrintNullTag (void)
{
return writer->canPrintNullTag;
}
extern bool writerDoesTreatFieldAsFixed (int fieldType)
{
if (writer->treatFieldAsFixed)
Expand Down
3 changes: 3 additions & 0 deletions main/writer_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ struct sTagWriter {

void (* checkOptions) (tagWriter *writer, bool fieldsWereReset);

bool canPrintNullTag;

#ifdef _WIN32
enum filenameSepOp (* overrideFilenameSeparator) (enum filenameSepOp currentSetting);
#endif /* _WIN32 */
Expand Down Expand Up @@ -95,6 +97,7 @@ extern bool ptagMakeCtagsOutputFilesep (ptagDesc *desc, langType language CTAGS_
extern bool ptagMakeCtagsOutputExcmd (ptagDesc *desc, langType language CTAGS_ATTR_UNUSED, const void *data);

extern bool writerCanPrintPtag (void);
extern bool writerCanPrintNullTag (void);
extern bool writerDoesTreatFieldAsFixed (int fieldType);

extern void writerCheckOptions (bool fieldsWereReset);
Expand Down
2 changes: 2 additions & 0 deletions main/xtag.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ static xtagDefinition xtagDefinitions [] = {
"Include tags generated by subparsers"},
{ true, '\0', "anonymous",
"Include tags for non-named objects like lambda"},
{ false, '0', "nulltag",
"Include tags with empty strings as their names"},
};

static unsigned int xtagObjectUsed;
Expand Down
3 changes: 2 additions & 1 deletion main/xtag.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ typedef enum eXtagType { /* extra tag content control */
XTAG_TAGS_GENERATED_BY_GUEST_PARSERS = XTAG_GUEST, /* Geany uses the old name */
XTAG_SUBPARSER,
XTAG_ANONYMOUS,
XTAG_NULLTAG,

XTAG_COUNT
} xtagType;
Expand All @@ -42,7 +43,7 @@ struct sXtagDefinition {
bool enabled;
/* letter, and ftype are initialized in the main part,
not in a parser. */
#define NUL_XTAG_LETTER '\0'
#define NUL_XTAG_LETTER '\0' /* Nothing todo with NULLTAG. */
unsigned char letter;
const char* name; /* used in extra: field */
const char* description; /* displayed in --list-extra output */
Expand Down

0 comments on commit a9b0a15

Please sign in to comment.