From f5c4671bfbad96bf346bd7e9a21fc4317b4959df Mon Sep 17 00:00:00 2001 From: Indrajith K L Date: Sat, 3 Dec 2022 17:00:20 +0530 Subject: Adds most of the tools --- ctags/docs/.buildinfo | 4 + ctags/docs/_images/area-and-parsers.svg | 456 + ctags/docs/_images/input-text-stream.svg | 498 ++ ctags/docs/_images/output-tag-stream.svg | 693 ++ ctags/docs/_images/promise.svg | 546 ++ ctags/docs/_images/stack-and-parsers.svg | 618 ++ ctags/docs/_static/basic.css | 904 ++ ctags/docs/_static/classic.css | 266 + ctags/docs/_static/default.css | 1 + ctags/docs/_static/doctools.js | 321 + ctags/docs/_static/documentation_options.js | 12 + ctags/docs/_static/file.png | Bin 0 -> 286 bytes ctags/docs/_static/jquery-3.5.1.js | 10872 ++++++++++++++++++++++++ ctags/docs/_static/jquery.js | 2 + ctags/docs/_static/language_data.js | 297 + ctags/docs/_static/minus.png | Bin 0 -> 90 bytes ctags/docs/_static/plus.png | Bin 0 -> 90 bytes ctags/docs/_static/pygments.css | 74 + ctags/docs/_static/searchtools.js | 522 ++ ctags/docs/_static/sidebar.js | 159 + ctags/docs/_static/underscore-1.13.1.js | 2042 +++++ ctags/docs/_static/underscore.js | 6 + ctags/docs/autotools.html | 210 + ctags/docs/building.html | 121 + ctags/docs/contributions.html | 636 ++ ctags/docs/developers.html | 167 + ctags/docs/extending.html | 157 + ctags/docs/genindex.html | 80 + ctags/docs/index.html | 285 + ctags/docs/interactive-mode.html | 185 + ctags/docs/internal.html | 854 ++ ctags/docs/man-pages.html | 336 + ctags/docs/man/ctags-client-tools.7.html | 615 ++ ctags/docs/man/ctags-faq.7.html | 510 ++ ctags/docs/man/ctags-incompatibilities.7.html | 337 + ctags/docs/man/ctags-lang-iPythonCell.7.html | 186 + ctags/docs/man/ctags-lang-inko.7.html | 141 + ctags/docs/man/ctags-lang-julia.7.html | 332 + ctags/docs/man/ctags-lang-python.7.html | 476 ++ ctags/docs/man/ctags-lang-r.7.html | 210 + ctags/docs/man/ctags-lang-sql.7.html | 237 + ctags/docs/man/ctags-lang-verilog.7.html | 318 + ctags/docs/man/ctags-optlib.7.html | 520 ++ ctags/docs/man/ctags.1.html | 1989 +++++ ctags/docs/man/readtags.1.html | 449 + ctags/docs/man/tags.5.html | 619 ++ ctags/docs/news.html | 673 ++ ctags/docs/objects.inv | Bin 0 -> 2475 bytes ctags/docs/option-file.html | 284 + ctags/docs/optlib.html | 1610 ++++ ctags/docs/optscript.html | 425 + ctags/docs/osx.html | 165 + ctags/docs/other-projects.html | 811 ++ ctags/docs/output-format.html | 144 + ctags/docs/output-json.html | 101 + ctags/docs/output-tags.html | 551 ++ ctags/docs/output-xref.html | 236 + ctags/docs/parser-asm.html | 119 + ctags/docs/parser-cmake.html | 128 + ctags/docs/parser-cxx.html | 396 + ctags/docs/parser-html.html | 135 + ctags/docs/parser-in-c.html | 199 + ctags/docs/parser-puppetManifest.html | 116 + ctags/docs/parser-python.html | 142 + ctags/docs/parser-tcl.html | 153 + ctags/docs/parser-vim.html | 122 + ctags/docs/parser-xslt.html | 117 + ctags/docs/parsers.html | 129 + ctags/docs/reporting.html | 302 + ctags/docs/running-multi-parsers.html | 548 ++ ctags/docs/search.html | 98 + ctags/docs/searchindex.js | 1 + ctags/docs/testing.html | 754 ++ ctags/docs/tips.html | 247 + ctags/docs/tracking.html | 605 ++ ctags/docs/windows.html | 257 + 76 files changed, 37831 insertions(+) create mode 100644 ctags/docs/.buildinfo create mode 100644 ctags/docs/_images/area-and-parsers.svg create mode 100644 ctags/docs/_images/input-text-stream.svg create mode 100644 ctags/docs/_images/output-tag-stream.svg create mode 100644 ctags/docs/_images/promise.svg create mode 100644 ctags/docs/_images/stack-and-parsers.svg create mode 100644 ctags/docs/_static/basic.css create mode 100644 ctags/docs/_static/classic.css create mode 100644 ctags/docs/_static/default.css create mode 100644 ctags/docs/_static/doctools.js create mode 100644 ctags/docs/_static/documentation_options.js create mode 100644 ctags/docs/_static/file.png create mode 100644 ctags/docs/_static/jquery-3.5.1.js create mode 100644 ctags/docs/_static/jquery.js create mode 100644 ctags/docs/_static/language_data.js create mode 100644 ctags/docs/_static/minus.png create mode 100644 ctags/docs/_static/plus.png create mode 100644 ctags/docs/_static/pygments.css create mode 100644 ctags/docs/_static/searchtools.js create mode 100644 ctags/docs/_static/sidebar.js create mode 100644 ctags/docs/_static/underscore-1.13.1.js create mode 100644 ctags/docs/_static/underscore.js create mode 100644 ctags/docs/autotools.html create mode 100644 ctags/docs/building.html create mode 100644 ctags/docs/contributions.html create mode 100644 ctags/docs/developers.html create mode 100644 ctags/docs/extending.html create mode 100644 ctags/docs/genindex.html create mode 100644 ctags/docs/index.html create mode 100644 ctags/docs/interactive-mode.html create mode 100644 ctags/docs/internal.html create mode 100644 ctags/docs/man-pages.html create mode 100644 ctags/docs/man/ctags-client-tools.7.html create mode 100644 ctags/docs/man/ctags-faq.7.html create mode 100644 ctags/docs/man/ctags-incompatibilities.7.html create mode 100644 ctags/docs/man/ctags-lang-iPythonCell.7.html create mode 100644 ctags/docs/man/ctags-lang-inko.7.html create mode 100644 ctags/docs/man/ctags-lang-julia.7.html create mode 100644 ctags/docs/man/ctags-lang-python.7.html create mode 100644 ctags/docs/man/ctags-lang-r.7.html create mode 100644 ctags/docs/man/ctags-lang-sql.7.html create mode 100644 ctags/docs/man/ctags-lang-verilog.7.html create mode 100644 ctags/docs/man/ctags-optlib.7.html create mode 100644 ctags/docs/man/ctags.1.html create mode 100644 ctags/docs/man/readtags.1.html create mode 100644 ctags/docs/man/tags.5.html create mode 100644 ctags/docs/news.html create mode 100644 ctags/docs/objects.inv create mode 100644 ctags/docs/option-file.html create mode 100644 ctags/docs/optlib.html create mode 100644 ctags/docs/optscript.html create mode 100644 ctags/docs/osx.html create mode 100644 ctags/docs/other-projects.html create mode 100644 ctags/docs/output-format.html create mode 100644 ctags/docs/output-json.html create mode 100644 ctags/docs/output-tags.html create mode 100644 ctags/docs/output-xref.html create mode 100644 ctags/docs/parser-asm.html create mode 100644 ctags/docs/parser-cmake.html create mode 100644 ctags/docs/parser-cxx.html create mode 100644 ctags/docs/parser-html.html create mode 100644 ctags/docs/parser-in-c.html create mode 100644 ctags/docs/parser-puppetManifest.html create mode 100644 ctags/docs/parser-python.html create mode 100644 ctags/docs/parser-tcl.html create mode 100644 ctags/docs/parser-vim.html create mode 100644 ctags/docs/parser-xslt.html create mode 100644 ctags/docs/parsers.html create mode 100644 ctags/docs/reporting.html create mode 100644 ctags/docs/running-multi-parsers.html create mode 100644 ctags/docs/search.html create mode 100644 ctags/docs/searchindex.js create mode 100644 ctags/docs/testing.html create mode 100644 ctags/docs/tips.html create mode 100644 ctags/docs/tracking.html create mode 100644 ctags/docs/windows.html (limited to 'ctags/docs') diff --git a/ctags/docs/.buildinfo b/ctags/docs/.buildinfo new file mode 100644 index 0000000..c689e10 --- /dev/null +++ b/ctags/docs/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. +config: dc0bed28d76d27b3f327399c8812a8fd +tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/ctags/docs/_images/area-and-parsers.svg b/ctags/docs/_images/area-and-parsers.svg new file mode 100644 index 0000000..55688e5 --- /dev/null +++ b/ctags/docs/_images/area-and-parsers.svg @@ -0,0 +1,456 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input file + + + + + + + + + + + + + + + + + + + + + + host parser + guest parser + + diff --git a/ctags/docs/_images/input-text-stream.svg b/ctags/docs/_images/input-text-stream.svg new file mode 100644 index 0000000..1842f6c --- /dev/null +++ b/ctags/docs/_images/input-text-stream.svg @@ -0,0 +1,498 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + File + + + inputFileInfo + + MIO + .input + + .mio + .source + + inputFile + inputFileInfo + .name + .lineNumber + + .name + .lineNumber + + readLineFromInputFile() + getcFromInputFile() + + lang->parser() + native parser written in C + + + readLineFromBypass() + + MIO + + readLineRaw() + + + + regex parser pattern matching + + diff --git a/ctags/docs/_images/output-tag-stream.svg b/ctags/docs/_images/output-tag-stream.svg new file mode 100644 index 0000000..adccd79 --- /dev/null +++ b/ctags/docs/_images/output-tag-stream.svg @@ -0,0 +1,693 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + jsonWriter + xrefWriter + ctagsWriter + etagsWriter + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + TagFile + + + + + + .mio + .corkQueue + tagFile + sCorkQueue + .queue + MIO + endEtagsFile() + MIO + if (!use_cork) + writeTagEntry() + flushing + if (use_cork) + makeTagEntry() + queueTagEntry() + lang->parser() + native parser written in C + tagEntryInfo + tagEntryInfo + writer-etags.c private + writeWriteTag() + + + + + + + writerTable[] + + diff --git a/ctags/docs/_images/promise.svg b/ctags/docs/_images/promise.svg new file mode 100644 index 0000000..346dc5f --- /dev/null +++ b/ctags/docs/_images/promise.svg @@ -0,0 +1,546 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + t + A host parser runs + + + + + + + + guest parser X is scheduled + guest parser Y is scheduled + X runs + + + Y runs + promise for X is forced + promise for Y is forced + + opens an input file + + closes the input file + + diff --git a/ctags/docs/_images/stack-and-parsers.svg b/ctags/docs/_images/stack-and-parsers.svg new file mode 100644 index 0000000..a8429dd --- /dev/null +++ b/ctags/docs/_images/stack-and-parsers.svg @@ -0,0 +1,618 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + base parser + subparser + + + + + + callback + lower view + higher view + + diff --git a/ctags/docs/_static/basic.css b/ctags/docs/_static/basic.css new file mode 100644 index 0000000..aa9df31 --- /dev/null +++ b/ctags/docs/_static/basic.css @@ -0,0 +1,904 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +div.section::after { + display: block; + content: ''; + clear: left; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox form.search { + overflow: hidden; +} + +div.sphinxsidebar #searchbox input[type="text"] { + float: left; + width: 80%; + padding: 0.25em; + box-sizing: border-box; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + float: left; + width: 20%; + border-left: none; + padding: 0.25em; + box-sizing: border-box; +} + + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li p.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body { + min-width: 450px; + max-width: 800px; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +a.brackets:before, +span.brackets > a:before{ + content: "["; +} + +a.brackets:after, +span.brackets > a:after { + content: "]"; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, figure.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, figure.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, figure.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +img.align-default, figure.align-default, .figure.align-default { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-default { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar, +aside.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px; + background-color: #ffe; + width: 40%; + float: right; + clear: right; + overflow-x: auto; +} + +p.sidebar-title { + font-weight: bold; +} + +div.admonition, div.topic, blockquote { + clear: left; +} + +/* -- topics ---------------------------------------------------------------- */ + +div.topic { + border: 1px solid #ccc; + padding: 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- content of sidebars/topics/admonitions -------------------------------- */ + +div.sidebar > :last-child, +aside.sidebar > :last-child, +div.topic > :last-child, +div.admonition > :last-child { + margin-bottom: 0; +} + +div.sidebar::after, +aside.sidebar::after, +div.topic::after, +div.admonition::after, +blockquote::after { + display: block; + content: ''; + clear: both; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + margin-top: 10px; + margin-bottom: 10px; + border: 0; + border-collapse: collapse; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +table.align-default { + margin-left: auto; + margin-right: auto; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +table.footnote td, table.footnote th { + border: 0 !important; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +th > :first-child, +td > :first-child { + margin-top: 0px; +} + +th > :last-child, +td > :last-child { + margin-bottom: 0px; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure, figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption, figcaption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number, +figcaption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text, +figcaption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- hlist styles ---------------------------------------------------------- */ + +table.hlist { + margin: 1em 0; +} + +table.hlist td { + vertical-align: top; +} + +/* -- object description styles --------------------------------------------- */ + +.sig { + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; +} + +.sig-name, code.descname { + background-color: transparent; + font-weight: bold; +} + +.sig-name { + font-size: 1.1em; +} + +code.descname { + font-size: 1.2em; +} + +.sig-prename, code.descclassname { + background-color: transparent; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.sig-param.n { + font-style: italic; +} + +/* C++ specific styling */ + +.sig-inline.c-texpr, +.sig-inline.cpp-texpr { + font-family: unset; +} + +.sig.c .k, .sig.c .kt, +.sig.cpp .k, .sig.cpp .kt { + color: #0033B3; +} + +.sig.c .m, +.sig.cpp .m { + color: #1750EB; +} + +.sig.c .s, .sig.c .sc, +.sig.cpp .s, .sig.cpp .sc { + color: #067D17; +} + + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +:not(li) > ol > li:first-child > :first-child, +:not(li) > ul > li:first-child > :first-child { + margin-top: 0px; +} + +:not(li) > ol > li:last-child > :last-child, +:not(li) > ul > li:last-child > :last-child { + margin-bottom: 0px; +} + +ol.simple ol p, +ol.simple ul p, +ul.simple ol p, +ul.simple ul p { + margin-top: 0; +} + +ol.simple > li:not(:first-child) > p, +ul.simple > li:not(:first-child) > p { + margin-top: 0; +} + +ol.simple p, +ul.simple p { + margin-bottom: 0; +} + +dl.footnote > dt, +dl.citation > dt { + float: left; + margin-right: 0.5em; +} + +dl.footnote > dd, +dl.citation > dd { + margin-bottom: 0em; +} + +dl.footnote > dd:after, +dl.citation > dd:after { + content: ""; + clear: both; +} + +dl.field-list { + display: grid; + grid-template-columns: fit-content(30%) auto; +} + +dl.field-list > dt { + font-weight: bold; + word-break: break-word; + padding-left: 0.5em; + padding-right: 5px; +} + +dl.field-list > dt:after { + content: ":"; +} + +dl.field-list > dd { + padding-left: 0.5em; + margin-top: 0em; + margin-left: 0em; + margin-bottom: 0em; +} + +dl { + margin-bottom: 15px; +} + +dd > :first-child { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +dl > dd:last-child, +dl > dd:last-child > :last-child { + margin-bottom: 0; +} + +dt:target, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +.classifier:before { + font-style: normal; + margin: 0.5em; + content: ":"; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +pre, div[class*="highlight-"] { + clear: both; +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; +} + +div[class*="highlight-"] { + margin: 1em 0; +} + +td.linenos pre { + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + display: block; +} + +table.highlighttable tbody { + display: block; +} + +table.highlighttable tr { + display: flex; +} + +table.highlighttable td { + margin: 0; + padding: 0; +} + +table.highlighttable td.linenos { + padding-right: 0.5em; +} + +table.highlighttable td.code { + flex: 1; + overflow: hidden; +} + +.highlight .hll { + display: block; +} + +div.highlight pre, +table.highlighttable pre { + margin: 0; +} + +div.code-block-caption + div { + margin-top: 0; +} + +div.code-block-caption { + margin-top: 1em; + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +table.highlighttable td.linenos, +span.linenos, +div.doctest > div.highlight span.gp { /* gp: Generic.Prompt */ + user-select: none; + -webkit-user-select: text; /* Safari fallback only */ + -webkit-user-select: none; /* Chrome/Safari */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* IE10+ */ +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + margin: 1em 0; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: absolute; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/ctags/docs/_static/classic.css b/ctags/docs/_static/classic.css new file mode 100644 index 0000000..dcae946 --- /dev/null +++ b/ctags/docs/_static/classic.css @@ -0,0 +1,266 @@ +/* + * classic.css_t + * ~~~~~~~~~~~~~ + * + * Sphinx stylesheet -- classic theme. + * + * :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +@import url("basic.css"); + +/* -- page layout ----------------------------------------------------------- */ + +html { + /* CSS hack for macOS's scrollbar (see #1125) */ + background-color: #FFFFFF; +} + +body { + font-family: sans-serif; + font-size: 100%; + background-color: #11303d; + color: #000; + margin: 0; + padding: 0; +} + +div.document { + background-color: #1c4e63; +} + +div.documentwrapper { + float: left; + width: 100%; +} + +div.bodywrapper { + margin: 0 0 0 230px; +} + +div.body { + background-color: #ffffff; + color: #000000; + padding: 0 20px 30px 20px; +} + +div.footer { + color: #ffffff; + width: 100%; + padding: 9px 0 9px 0; + text-align: center; + font-size: 75%; +} + +div.footer a { + color: #ffffff; + text-decoration: underline; +} + +div.related { + background-color: #133f52; + line-height: 30px; + color: #ffffff; +} + +div.related a { + color: #ffffff; +} + +div.sphinxsidebar { +} + +div.sphinxsidebar h3 { + font-family: 'Trebuchet MS', sans-serif; + color: #ffffff; + font-size: 1.4em; + font-weight: normal; + margin: 0; + padding: 0; +} + +div.sphinxsidebar h3 a { + color: #ffffff; +} + +div.sphinxsidebar h4 { + font-family: 'Trebuchet MS', sans-serif; + color: #ffffff; + font-size: 1.3em; + font-weight: normal; + margin: 5px 0 0 0; + padding: 0; +} + +div.sphinxsidebar p { + color: #ffffff; +} + +div.sphinxsidebar p.topless { + margin: 5px 10px 10px 10px; +} + +div.sphinxsidebar ul { + margin: 10px; + padding: 0; + color: #ffffff; +} + +div.sphinxsidebar a { + color: #98dbcc; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + + + +/* -- hyperlink styles ------------------------------------------------------ */ + +a { + color: #355f7c; + text-decoration: none; +} + +a:visited { + color: #355f7c; + text-decoration: none; +} + +a:hover { + text-decoration: underline; +} + + + +/* -- body styles ----------------------------------------------------------- */ + +div.body h1, +div.body h2, +div.body h3, +div.body h4, +div.body h5, +div.body h6 { + font-family: 'Trebuchet MS', sans-serif; + background-color: #f2f2f2; + font-weight: normal; + color: #20435c; + border-bottom: 1px solid #ccc; + margin: 20px -20px 10px -20px; + padding: 3px 0 3px 10px; +} + +div.body h1 { margin-top: 0; font-size: 200%; } +div.body h2 { font-size: 160%; } +div.body h3 { font-size: 140%; } +div.body h4 { font-size: 120%; } +div.body h5 { font-size: 110%; } +div.body h6 { font-size: 100%; } + +a.headerlink { + color: #c60f0f; + font-size: 0.8em; + padding: 0 4px 0 4px; + text-decoration: none; +} + +a.headerlink:hover { + background-color: #c60f0f; + color: white; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + text-align: justify; + line-height: 130%; +} + +div.admonition p.admonition-title + p { + display: inline; +} + +div.admonition p { + margin-bottom: 5px; +} + +div.admonition pre { + margin-bottom: 5px; +} + +div.admonition ul, div.admonition ol { + margin-bottom: 5px; +} + +div.note { + background-color: #eee; + border: 1px solid #ccc; +} + +div.seealso { + background-color: #ffc; + border: 1px solid #ff6; +} + +div.topic { + background-color: #eee; +} + +div.warning { + background-color: #ffe4e4; + border: 1px solid #f66; +} + +p.admonition-title { + display: inline; +} + +p.admonition-title:after { + content: ":"; +} + +pre { + padding: 5px; + background-color: unset; + color: unset; + line-height: 120%; + border: 1px solid #ac9; + border-left: none; + border-right: none; +} + +code { + background-color: #ecf0f3; + padding: 0 1px 0 1px; + font-size: 0.95em; +} + +th, dl.field-list > dt { + background-color: #ede; +} + +.warning code { + background: #efc2c2; +} + +.note code { + background: #d6d6d6; +} + +.viewcode-back { + font-family: sans-serif; +} + +div.viewcode-block:target { + background-color: #f4debf; + border-top: 1px solid #ac9; + border-bottom: 1px solid #ac9; +} + +div.code-block-caption { + color: #efefef; + background-color: #1c4e63; +} \ No newline at end of file diff --git a/ctags/docs/_static/default.css b/ctags/docs/_static/default.css new file mode 100644 index 0000000..81b9363 --- /dev/null +++ b/ctags/docs/_static/default.css @@ -0,0 +1 @@ +@import url("classic.css"); diff --git a/ctags/docs/_static/doctools.js b/ctags/docs/_static/doctools.js new file mode 100644 index 0000000..61ac9d2 --- /dev/null +++ b/ctags/docs/_static/doctools.js @@ -0,0 +1,321 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Sphinx JavaScript utilities for all documentation. + * + * :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/** + * select a different prefix for underscore + */ +$u = _.noConflict(); + +/** + * make the code below compatible with browsers without + * an installed firebug like debugger +if (!window.console || !console.firebug) { + var names = ["log", "debug", "info", "warn", "error", "assert", "dir", + "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace", + "profile", "profileEnd"]; + window.console = {}; + for (var i = 0; i < names.length; ++i) + window.console[names[i]] = function() {}; +} + */ + +/** + * small helper function to urldecode strings + * + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent#Decoding_query_parameters_from_a_URL + */ +jQuery.urldecode = function(x) { + if (!x) { + return x + } + return decodeURIComponent(x.replace(/\+/g, ' ')); +}; + +/** + * small helper function to urlencode strings + */ +jQuery.urlencode = encodeURIComponent; + +/** + * This function returns the parsed url parameters of the + * current request. Multiple values per key are supported, + * it will always return arrays of strings for the value parts. + */ +jQuery.getQueryParameters = function(s) { + if (typeof s === 'undefined') + s = document.location.search; + var parts = s.substr(s.indexOf('?') + 1).split('&'); + var result = {}; + for (var i = 0; i < parts.length; i++) { + var tmp = parts[i].split('=', 2); + var key = jQuery.urldecode(tmp[0]); + var value = jQuery.urldecode(tmp[1]); + if (key in result) + result[key].push(value); + else + result[key] = [value]; + } + return result; +}; + +/** + * highlight a given string on a jquery object by wrapping it in + * span elements with the given class name. + */ +jQuery.fn.highlightText = function(text, className) { + function highlight(node, addItems) { + if (node.nodeType === 3) { + var val = node.nodeValue; + var pos = val.toLowerCase().indexOf(text); + if (pos >= 0 && + !jQuery(node.parentNode).hasClass(className) && + !jQuery(node.parentNode).hasClass("nohighlight")) { + var span; + var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.className = className; + } + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + node.parentNode.insertBefore(span, node.parentNode.insertBefore( + document.createTextNode(val.substr(pos + text.length)), + node.nextSibling)); + node.nodeValue = val.substr(0, pos); + if (isInSVG) { + var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); + var bbox = node.parentElement.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute('class', className); + addItems.push({ + "parent": node.parentNode, + "target": rect}); + } + } + } + else if (!jQuery(node).is("button, select, textarea")) { + jQuery.each(node.childNodes, function() { + highlight(this, addItems); + }); + } + } + var addItems = []; + var result = this.each(function() { + highlight(this, addItems); + }); + for (var i = 0; i < addItems.length; ++i) { + jQuery(addItems[i].parent).before(addItems[i].target); + } + return result; +}; + +/* + * backward compatibility for jQuery.browser + * This will be supported until firefox bug is fixed. + */ +if (!jQuery.browser) { + jQuery.uaMatch = function(ua) { + ua = ua.toLowerCase(); + + var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || + /(webkit)[ \/]([\w.]+)/.exec(ua) || + /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || + /(msie) ([\w.]+)/.exec(ua) || + ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || + []; + + return { + browser: match[ 1 ] || "", + version: match[ 2 ] || "0" + }; + }; + jQuery.browser = {}; + jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; +} + +/** + * Small JavaScript module for the documentation. + */ +var Documentation = { + + init : function() { + this.fixFirefoxAnchorBug(); + this.highlightSearchWords(); + this.initIndexTable(); + if (DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) { + this.initOnKeyListeners(); + } + }, + + /** + * i18n support + */ + TRANSLATIONS : {}, + PLURAL_EXPR : function(n) { return n === 1 ? 0 : 1; }, + LOCALE : 'unknown', + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext : function(string) { + var translated = Documentation.TRANSLATIONS[string]; + if (typeof translated === 'undefined') + return string; + return (typeof translated === 'string') ? translated : translated[0]; + }, + + ngettext : function(singular, plural, n) { + var translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated === 'undefined') + return (n == 1) ? singular : plural; + return translated[Documentation.PLURALEXPR(n)]; + }, + + addTranslations : function(catalog) { + for (var key in catalog.messages) + this.TRANSLATIONS[key] = catalog.messages[key]; + this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')'); + this.LOCALE = catalog.locale; + }, + + /** + * add context elements like header anchor links + */ + addContextElements : function() { + $('div[id] > :header:first').each(function() { + $('\u00B6'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this headline')). + appendTo(this); + }); + $('dt[id]').each(function() { + $('\u00B6'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this definition')). + appendTo(this); + }); + }, + + /** + * workaround a firefox stupidity + * see: https://bugzilla.mozilla.org/show_bug.cgi?id=645075 + */ + fixFirefoxAnchorBug : function() { + if (document.location.hash && $.browser.mozilla) + window.setTimeout(function() { + document.location.href += ''; + }, 10); + }, + + /** + * highlight the search words provided in the url in the text + */ + highlightSearchWords : function() { + var params = $.getQueryParameters(); + var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : []; + if (terms.length) { + var body = $('div.body'); + if (!body.length) { + body = $('body'); + } + window.setTimeout(function() { + $.each(terms, function() { + body.highlightText(this.toLowerCase(), 'highlighted'); + }); + }, 10); + $('') + .appendTo($('#searchbox')); + } + }, + + /** + * init the domain index toggle buttons + */ + initIndexTable : function() { + var togglers = $('img.toggler').click(function() { + var src = $(this).attr('src'); + var idnum = $(this).attr('id').substr(7); + $('tr.cg-' + idnum).toggle(); + if (src.substr(-9) === 'minus.png') + $(this).attr('src', src.substr(0, src.length-9) + 'plus.png'); + else + $(this).attr('src', src.substr(0, src.length-8) + 'minus.png'); + }).css('display', ''); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) { + togglers.click(); + } + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords : function() { + $('#searchbox .highlight-link').fadeOut(300); + $('span.highlighted').removeClass('highlighted'); + }, + + /** + * make the url absolute + */ + makeURL : function(relativeURL) { + return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL; + }, + + /** + * get the current relative url + */ + getCurrentURL : function() { + var path = document.location.pathname; + var parts = path.split(/\//); + $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() { + if (this === '..') + parts.pop(); + }); + var url = parts.join('/'); + return path.substring(url.lastIndexOf('/') + 1, path.length - 1); + }, + + initOnKeyListeners: function() { + $(document).keydown(function(event) { + var activeElementType = document.activeElement.tagName; + // don't navigate when in search box, textarea, dropdown or button + if (activeElementType !== 'TEXTAREA' && activeElementType !== 'INPUT' && activeElementType !== 'SELECT' + && activeElementType !== 'BUTTON' && !event.altKey && !event.ctrlKey && !event.metaKey + && !event.shiftKey) { + switch (event.keyCode) { + case 37: // left + var prevHref = $('link[rel="prev"]').prop('href'); + if (prevHref) { + window.location.href = prevHref; + return false; + } + case 39: // right + var nextHref = $('link[rel="next"]').prop('href'); + if (nextHref) { + window.location.href = nextHref; + return false; + } + } + } + }); + } +}; + +// quick alias for translations +_ = Documentation.gettext; + +$(document).ready(function() { + Documentation.init(); +}); diff --git a/ctags/docs/_static/documentation_options.js b/ctags/docs/_static/documentation_options.js new file mode 100644 index 0000000..dd5b32f --- /dev/null +++ b/ctags/docs/_static/documentation_options.js @@ -0,0 +1,12 @@ +var DOCUMENTATION_OPTIONS = { + URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'), + VERSION: '0.3.0', + LANGUAGE: 'None', + COLLAPSE_INDEX: false, + BUILDER: 'html', + FILE_SUFFIX: '.html', + LINK_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt', + NAVIGATION_WITH_KEYS: false +}; \ No newline at end of file diff --git a/ctags/docs/_static/file.png b/ctags/docs/_static/file.png new file mode 100644 index 0000000..a858a41 Binary files /dev/null and b/ctags/docs/_static/file.png differ diff --git a/ctags/docs/_static/jquery-3.5.1.js b/ctags/docs/_static/jquery-3.5.1.js new file mode 100644 index 0000000..5093733 --- /dev/null +++ b/ctags/docs/_static/jquery-3.5.1.js @@ -0,0 +1,10872 @@ +/*! + * jQuery JavaScript Library v3.5.1 + * https://jquery.com/ + * + * Includes Sizzle.js + * https://sizzlejs.com/ + * + * Copyright JS Foundation and other contributors + * Released under the MIT license + * https://jquery.org/license + * + * Date: 2020-05-04T22:49Z + */ +( function( global, factory ) { + + "use strict"; + + if ( typeof module === "object" && typeof module.exports === "object" ) { + + // For CommonJS and CommonJS-like environments where a proper `window` + // is present, execute the factory and get jQuery. + // For environments that do not have a `window` with a `document` + // (such as Node.js), expose a factory as module.exports. + // This accentuates the need for the creation of a real `window`. + // e.g. var jQuery = require("jquery")(window); + // See ticket #14549 for more info. + module.exports = global.document ? + factory( global, true ) : + function( w ) { + if ( !w.document ) { + throw new Error( "jQuery requires a window with a document" ); + } + return factory( w ); + }; + } else { + factory( global ); + } + +// Pass this if window is not defined yet +} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) { + +// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1 +// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode +// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common +// enough that all such attempts are guarded in a try block. +"use strict"; + +var arr = []; + +var getProto = Object.getPrototypeOf; + +var slice = arr.slice; + +var flat = arr.flat ? function( array ) { + return arr.flat.call( array ); +} : function( array ) { + return arr.concat.apply( [], array ); +}; + + +var push = arr.push; + +var indexOf = arr.indexOf; + +var class2type = {}; + +var toString = class2type.toString; + +var hasOwn = class2type.hasOwnProperty; + +var fnToString = hasOwn.toString; + +var ObjectFunctionString = fnToString.call( Object ); + +var support = {}; + +var isFunction = function isFunction( obj ) { + + // Support: Chrome <=57, Firefox <=52 + // In some browsers, typeof returns "function" for HTML elements + // (i.e., `typeof document.createElement( "object" ) === "function"`). + // We don't want to classify *any* DOM node as a function. + return typeof obj === "function" && typeof obj.nodeType !== "number"; + }; + + +var isWindow = function isWindow( obj ) { + return obj != null && obj === obj.window; + }; + + +var document = window.document; + + + + var preservedScriptAttributes = { + type: true, + src: true, + nonce: true, + noModule: true + }; + + function DOMEval( code, node, doc ) { + doc = doc || document; + + var i, val, + script = doc.createElement( "script" ); + + script.text = code; + if ( node ) { + for ( i in preservedScriptAttributes ) { + + // Support: Firefox 64+, Edge 18+ + // Some browsers don't support the "nonce" property on scripts. + // On the other hand, just using `getAttribute` is not enough as + // the `nonce` attribute is reset to an empty string whenever it + // becomes browsing-context connected. + // See https://github.com/whatwg/html/issues/2369 + // See https://html.spec.whatwg.org/#nonce-attributes + // The `node.getAttribute` check was added for the sake of + // `jQuery.globalEval` so that it can fake a nonce-containing node + // via an object. + val = node[ i ] || node.getAttribute && node.getAttribute( i ); + if ( val ) { + script.setAttribute( i, val ); + } + } + } + doc.head.appendChild( script ).parentNode.removeChild( script ); + } + + +function toType( obj ) { + if ( obj == null ) { + return obj + ""; + } + + // Support: Android <=2.3 only (functionish RegExp) + return typeof obj === "object" || typeof obj === "function" ? + class2type[ toString.call( obj ) ] || "object" : + typeof obj; +} +/* global Symbol */ +// Defining this global in .eslintrc.json would create a danger of using the global +// unguarded in another place, it seems safer to define global only for this module + + + +var + version = "3.5.1", + + // Define a local copy of jQuery + jQuery = function( selector, context ) { + + // The jQuery object is actually just the init constructor 'enhanced' + // Need init if jQuery is called (just allow error to be thrown if not included) + return new jQuery.fn.init( selector, context ); + }; + +jQuery.fn = jQuery.prototype = { + + // The current version of jQuery being used + jquery: version, + + constructor: jQuery, + + // The default length of a jQuery object is 0 + length: 0, + + toArray: function() { + return slice.call( this ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + + // Return all the elements in a clean array + if ( num == null ) { + return slice.call( this ); + } + + // Return just the one element from the set + return num < 0 ? this[ num + this.length ] : this[ num ]; + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems ) { + + // Build a new jQuery matched element set + var ret = jQuery.merge( this.constructor(), elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + each: function( callback ) { + return jQuery.each( this, callback ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map( this, function( elem, i ) { + return callback.call( elem, i, elem ); + } ) ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ) ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + even: function() { + return this.pushStack( jQuery.grep( this, function( _elem, i ) { + return ( i + 1 ) % 2; + } ) ); + }, + + odd: function() { + return this.pushStack( jQuery.grep( this, function( _elem, i ) { + return i % 2; + } ) ); + }, + + eq: function( i ) { + var len = this.length, + j = +i + ( i < 0 ? len : 0 ); + return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); + }, + + end: function() { + return this.prevObject || this.constructor(); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: arr.sort, + splice: arr.splice +}; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[ 0 ] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + + // Skip the boolean and the target + target = arguments[ i ] || {}; + i++; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !isFunction( target ) ) { + target = {}; + } + + // Extend jQuery itself if only one argument is passed + if ( i === length ) { + target = this; + i--; + } + + for ( ; i < length; i++ ) { + + // Only deal with non-null/undefined values + if ( ( options = arguments[ i ] ) != null ) { + + // Extend the base object + for ( name in options ) { + copy = options[ name ]; + + // Prevent Object.prototype pollution + // Prevent never-ending loop + if ( name === "__proto__" || target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject( copy ) || + ( copyIsArray = Array.isArray( copy ) ) ) ) { + src = target[ name ]; + + // Ensure proper type for the source value + if ( copyIsArray && !Array.isArray( src ) ) { + clone = []; + } else if ( !copyIsArray && !jQuery.isPlainObject( src ) ) { + clone = {}; + } else { + clone = src; + } + copyIsArray = false; + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend( { + + // Unique for each copy of jQuery on the page + expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), + + // Assume jQuery is ready without the ready module + isReady: true, + + error: function( msg ) { + throw new Error( msg ); + }, + + noop: function() {}, + + isPlainObject: function( obj ) { + var proto, Ctor; + + // Detect obvious negatives + // Use toString instead of jQuery.type to catch host objects + if ( !obj || toString.call( obj ) !== "[object Object]" ) { + return false; + } + + proto = getProto( obj ); + + // Objects with no prototype (e.g., `Object.create( null )`) are plain + if ( !proto ) { + return true; + } + + // Objects with prototype are plain iff they were constructed by a global Object function + Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor; + return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString; + }, + + isEmptyObject: function( obj ) { + var name; + + for ( name in obj ) { + return false; + } + return true; + }, + + // Evaluates a script in a provided context; falls back to the global one + // if not specified. + globalEval: function( code, options, doc ) { + DOMEval( code, { nonce: options && options.nonce }, doc ); + }, + + each: function( obj, callback ) { + var length, i = 0; + + if ( isArrayLike( obj ) ) { + length = obj.length; + for ( ; i < length; i++ ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } else { + for ( i in obj ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } + + return obj; + }, + + // results is for internal usage only + makeArray: function( arr, results ) { + var ret = results || []; + + if ( arr != null ) { + if ( isArrayLike( Object( arr ) ) ) { + jQuery.merge( ret, + typeof arr === "string" ? + [ arr ] : arr + ); + } else { + push.call( ret, arr ); + } + } + + return ret; + }, + + inArray: function( elem, arr, i ) { + return arr == null ? -1 : indexOf.call( arr, elem, i ); + }, + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + merge: function( first, second ) { + var len = +second.length, + j = 0, + i = first.length; + + for ( ; j < len; j++ ) { + first[ i++ ] = second[ j ]; + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, invert ) { + var callbackInverse, + matches = [], + i = 0, + length = elems.length, + callbackExpect = !invert; + + // Go through the array, only saving the items + // that pass the validator function + for ( ; i < length; i++ ) { + callbackInverse = !callback( elems[ i ], i ); + if ( callbackInverse !== callbackExpect ) { + matches.push( elems[ i ] ); + } + } + + return matches; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var length, value, + i = 0, + ret = []; + + // Go through the array, translating each of the items to their new values + if ( isArrayLike( elems ) ) { + length = elems.length; + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + + // Go through every key on the object, + } else { + for ( i in elems ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + } + + // Flatten any nested arrays + return flat( ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // jQuery.support is not used in Core but other projects attach their + // properties to it so it needs to exist. + support: support +} ); + +if ( typeof Symbol === "function" ) { + jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; +} + +// Populate the class2type map +jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), +function( _i, name ) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); +} ); + +function isArrayLike( obj ) { + + // Support: real iOS 8.2 only (not reproducible in simulator) + // `in` check used to prevent JIT error (gh-2145) + // hasOwn isn't used here due to false negatives + // regarding Nodelist length in IE + var length = !!obj && "length" in obj && obj.length, + type = toType( obj ); + + if ( isFunction( obj ) || isWindow( obj ) ) { + return false; + } + + return type === "array" || length === 0 || + typeof length === "number" && length > 0 && ( length - 1 ) in obj; +} +var Sizzle = +/*! + * Sizzle CSS Selector Engine v2.3.5 + * https://sizzlejs.com/ + * + * Copyright JS Foundation and other contributors + * Released under the MIT license + * https://js.foundation/ + * + * Date: 2020-03-14 + */ +( function( window ) { +var i, + support, + Expr, + getText, + isXML, + tokenize, + compile, + select, + outermostContext, + sortInput, + hasDuplicate, + + // Local document vars + setDocument, + document, + docElem, + documentIsHTML, + rbuggyQSA, + rbuggyMatches, + matches, + contains, + + // Instance-specific data + expando = "sizzle" + 1 * new Date(), + preferredDoc = window.document, + dirruns = 0, + done = 0, + classCache = createCache(), + tokenCache = createCache(), + compilerCache = createCache(), + nonnativeSelectorCache = createCache(), + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + } + return 0; + }, + + // Instance methods + hasOwn = ( {} ).hasOwnProperty, + arr = [], + pop = arr.pop, + pushNative = arr.push, + push = arr.push, + slice = arr.slice, + + // Use a stripped-down indexOf as it's faster than native + // https://jsperf.com/thor-indexof-vs-for/5 + indexOf = function( list, elem ) { + var i = 0, + len = list.length; + for ( ; i < len; i++ ) { + if ( list[ i ] === elem ) { + return i; + } + } + return -1; + }, + + booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|" + + "ismap|loop|multiple|open|readonly|required|scoped", + + // Regular expressions + + // http://www.w3.org/TR/css3-selectors/#whitespace + whitespace = "[\\x20\\t\\r\\n\\f]", + + // https://www.w3.org/TR/css-syntax-3/#ident-token-diagram + identifier = "(?:\\\\[\\da-fA-F]{1,6}" + whitespace + + "?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+", + + // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors + attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + + + // Operator (capture 2) + "*([*^$|!~]?=)" + whitespace + + + // "Attribute values must be CSS identifiers [capture 5] + // or strings [capture 3 or capture 4]" + "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + + whitespace + "*\\]", + + pseudos = ":(" + identifier + ")(?:\\((" + + + // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: + // 1. quoted (capture 3; capture 4 or capture 5) + "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + + + // 2. simple (capture 6) + "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + + + // 3. anything else (capture 2) + ".*" + + ")\\)|)", + + // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter + rwhitespace = new RegExp( whitespace + "+", "g" ), + rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + + whitespace + "+$", "g" ), + + rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), + rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + + "*" ), + rdescend = new RegExp( whitespace + "|>" ), + + rpseudo = new RegExp( pseudos ), + ridentifier = new RegExp( "^" + identifier + "$" ), + + matchExpr = { + "ID": new RegExp( "^#(" + identifier + ")" ), + "CLASS": new RegExp( "^\\.(" + identifier + ")" ), + "TAG": new RegExp( "^(" + identifier + "|[*])" ), + "ATTR": new RegExp( "^" + attributes ), + "PSEUDO": new RegExp( "^" + pseudos ), + "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + + whitespace + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + + whitespace + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), + "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), + + // For use in libraries implementing .is() + // We use this for POS matching in `select` + "needsContext": new RegExp( "^" + whitespace + + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace + + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) + }, + + rhtml = /HTML$/i, + rinputs = /^(?:input|select|textarea|button)$/i, + rheader = /^h\d$/i, + + rnative = /^[^{]+\{\s*\[native \w/, + + // Easily-parseable/retrievable ID or TAG or CLASS selectors + rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, + + rsibling = /[+~]/, + + // CSS escapes + // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters + runescape = new RegExp( "\\\\[\\da-fA-F]{1,6}" + whitespace + "?|\\\\([^\\r\\n\\f])", "g" ), + funescape = function( escape, nonHex ) { + var high = "0x" + escape.slice( 1 ) - 0x10000; + + return nonHex ? + + // Strip the backslash prefix from a non-hex escape sequence + nonHex : + + // Replace a hexadecimal escape sequence with the encoded Unicode code point + // Support: IE <=11+ + // For values outside the Basic Multilingual Plane (BMP), manually construct a + // surrogate pair + high < 0 ? + String.fromCharCode( high + 0x10000 ) : + String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); + }, + + // CSS string/identifier serialization + // https://drafts.csswg.org/cssom/#common-serializing-idioms + rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g, + fcssescape = function( ch, asCodePoint ) { + if ( asCodePoint ) { + + // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER + if ( ch === "\0" ) { + return "\uFFFD"; + } + + // Control characters and (dependent upon position) numbers get escaped as code points + return ch.slice( 0, -1 ) + "\\" + + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; + } + + // Other potentially-special ASCII characters get backslash-escaped + return "\\" + ch; + }, + + // Used for iframes + // See setDocument() + // Removing the function wrapper causes a "Permission Denied" + // error in IE + unloadHandler = function() { + setDocument(); + }, + + inDisabledFieldset = addCombinator( + function( elem ) { + return elem.disabled === true && elem.nodeName.toLowerCase() === "fieldset"; + }, + { dir: "parentNode", next: "legend" } + ); + +// Optimize for push.apply( _, NodeList ) +try { + push.apply( + ( arr = slice.call( preferredDoc.childNodes ) ), + preferredDoc.childNodes + ); + + // Support: Android<4.0 + // Detect silently failing push.apply + // eslint-disable-next-line no-unused-expressions + arr[ preferredDoc.childNodes.length ].nodeType; +} catch ( e ) { + push = { apply: arr.length ? + + // Leverage slice if possible + function( target, els ) { + pushNative.apply( target, slice.call( els ) ); + } : + + // Support: IE<9 + // Otherwise append directly + function( target, els ) { + var j = target.length, + i = 0; + + // Can't trust NodeList.length + while ( ( target[ j++ ] = els[ i++ ] ) ) {} + target.length = j - 1; + } + }; +} + +function Sizzle( selector, context, results, seed ) { + var m, i, elem, nid, match, groups, newSelector, + newContext = context && context.ownerDocument, + + // nodeType defaults to 9, since context defaults to document + nodeType = context ? context.nodeType : 9; + + results = results || []; + + // Return early from calls with invalid selector or context + if ( typeof selector !== "string" || !selector || + nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { + + return results; + } + + // Try to shortcut find operations (as opposed to filters) in HTML documents + if ( !seed ) { + setDocument( context ); + context = context || document; + + if ( documentIsHTML ) { + + // If the selector is sufficiently simple, try using a "get*By*" DOM method + // (excepting DocumentFragment context, where the methods don't exist) + if ( nodeType !== 11 && ( match = rquickExpr.exec( selector ) ) ) { + + // ID selector + if ( ( m = match[ 1 ] ) ) { + + // Document context + if ( nodeType === 9 ) { + if ( ( elem = context.getElementById( m ) ) ) { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( elem.id === m ) { + results.push( elem ); + return results; + } + } else { + return results; + } + + // Element context + } else { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( newContext && ( elem = newContext.getElementById( m ) ) && + contains( context, elem ) && + elem.id === m ) { + + results.push( elem ); + return results; + } + } + + // Type selector + } else if ( match[ 2 ] ) { + push.apply( results, context.getElementsByTagName( selector ) ); + return results; + + // Class selector + } else if ( ( m = match[ 3 ] ) && support.getElementsByClassName && + context.getElementsByClassName ) { + + push.apply( results, context.getElementsByClassName( m ) ); + return results; + } + } + + // Take advantage of querySelectorAll + if ( support.qsa && + !nonnativeSelectorCache[ selector + " " ] && + ( !rbuggyQSA || !rbuggyQSA.test( selector ) ) && + + // Support: IE 8 only + // Exclude object elements + ( nodeType !== 1 || context.nodeName.toLowerCase() !== "object" ) ) { + + newSelector = selector; + newContext = context; + + // qSA considers elements outside a scoping root when evaluating child or + // descendant combinators, which is not what we want. + // In such cases, we work around the behavior by prefixing every selector in the + // list with an ID selector referencing the scope context. + // The technique has to be used as well when a leading combinator is used + // as such selectors are not recognized by querySelectorAll. + // Thanks to Andrew Dupont for this technique. + if ( nodeType === 1 && + ( rdescend.test( selector ) || rcombinators.test( selector ) ) ) { + + // Expand context for sibling selectors + newContext = rsibling.test( selector ) && testContext( context.parentNode ) || + context; + + // We can use :scope instead of the ID hack if the browser + // supports it & if we're not changing the context. + if ( newContext !== context || !support.scope ) { + + // Capture the context ID, setting it first if necessary + if ( ( nid = context.getAttribute( "id" ) ) ) { + nid = nid.replace( rcssescape, fcssescape ); + } else { + context.setAttribute( "id", ( nid = expando ) ); + } + } + + // Prefix every selector in the list + groups = tokenize( selector ); + i = groups.length; + while ( i-- ) { + groups[ i ] = ( nid ? "#" + nid : ":scope" ) + " " + + toSelector( groups[ i ] ); + } + newSelector = groups.join( "," ); + } + + try { + push.apply( results, + newContext.querySelectorAll( newSelector ) + ); + return results; + } catch ( qsaError ) { + nonnativeSelectorCache( selector, true ); + } finally { + if ( nid === expando ) { + context.removeAttribute( "id" ); + } + } + } + } + } + + // All others + return select( selector.replace( rtrim, "$1" ), context, results, seed ); +} + +/** + * Create key-value caches of limited size + * @returns {function(string, object)} Returns the Object data after storing it on itself with + * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) + * deleting the oldest entry + */ +function createCache() { + var keys = []; + + function cache( key, value ) { + + // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) + if ( keys.push( key + " " ) > Expr.cacheLength ) { + + // Only keep the most recent entries + delete cache[ keys.shift() ]; + } + return ( cache[ key + " " ] = value ); + } + return cache; +} + +/** + * Mark a function for special use by Sizzle + * @param {Function} fn The function to mark + */ +function markFunction( fn ) { + fn[ expando ] = true; + return fn; +} + +/** + * Support testing using an element + * @param {Function} fn Passed the created element and returns a boolean result + */ +function assert( fn ) { + var el = document.createElement( "fieldset" ); + + try { + return !!fn( el ); + } catch ( e ) { + return false; + } finally { + + // Remove from its parent by default + if ( el.parentNode ) { + el.parentNode.removeChild( el ); + } + + // release memory in IE + el = null; + } +} + +/** + * Adds the same handler for all of the specified attrs + * @param {String} attrs Pipe-separated list of attributes + * @param {Function} handler The method that will be applied + */ +function addHandle( attrs, handler ) { + var arr = attrs.split( "|" ), + i = arr.length; + + while ( i-- ) { + Expr.attrHandle[ arr[ i ] ] = handler; + } +} + +/** + * Checks document order of two siblings + * @param {Element} a + * @param {Element} b + * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b + */ +function siblingCheck( a, b ) { + var cur = b && a, + diff = cur && a.nodeType === 1 && b.nodeType === 1 && + a.sourceIndex - b.sourceIndex; + + // Use IE sourceIndex if available on both nodes + if ( diff ) { + return diff; + } + + // Check if b follows a + if ( cur ) { + while ( ( cur = cur.nextSibling ) ) { + if ( cur === b ) { + return -1; + } + } + } + + return a ? 1 : -1; +} + +/** + * Returns a function to use in pseudos for input types + * @param {String} type + */ +function createInputPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for buttons + * @param {String} type + */ +function createButtonPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return ( name === "input" || name === "button" ) && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for :enabled/:disabled + * @param {Boolean} disabled true for :disabled; false for :enabled + */ +function createDisabledPseudo( disabled ) { + + // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable + return function( elem ) { + + // Only certain elements can match :enabled or :disabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled + if ( "form" in elem ) { + + // Check for inherited disabledness on relevant non-disabled elements: + // * listed form-associated elements in a disabled fieldset + // https://html.spec.whatwg.org/multipage/forms.html#category-listed + // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled + // * option elements in a disabled optgroup + // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled + // All such elements have a "form" property. + if ( elem.parentNode && elem.disabled === false ) { + + // Option elements defer to a parent optgroup if present + if ( "label" in elem ) { + if ( "label" in elem.parentNode ) { + return elem.parentNode.disabled === disabled; + } else { + return elem.disabled === disabled; + } + } + + // Support: IE 6 - 11 + // Use the isDisabled shortcut property to check for disabled fieldset ancestors + return elem.isDisabled === disabled || + + // Where there is no isDisabled, check manually + /* jshint -W018 */ + elem.isDisabled !== !disabled && + inDisabledFieldset( elem ) === disabled; + } + + return elem.disabled === disabled; + + // Try to winnow out elements that can't be disabled before trusting the disabled property. + // Some victims get caught in our net (label, legend, menu, track), but it shouldn't + // even exist on them, let alone have a boolean value. + } else if ( "label" in elem ) { + return elem.disabled === disabled; + } + + // Remaining elements are neither :enabled nor :disabled + return false; + }; +} + +/** + * Returns a function to use in pseudos for positionals + * @param {Function} fn + */ +function createPositionalPseudo( fn ) { + return markFunction( function( argument ) { + argument = +argument; + return markFunction( function( seed, matches ) { + var j, + matchIndexes = fn( [], seed.length, argument ), + i = matchIndexes.length; + + // Match elements found at the specified indexes + while ( i-- ) { + if ( seed[ ( j = matchIndexes[ i ] ) ] ) { + seed[ j ] = !( matches[ j ] = seed[ j ] ); + } + } + } ); + } ); +} + +/** + * Checks a node for validity as a Sizzle context + * @param {Element|Object=} context + * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value + */ +function testContext( context ) { + return context && typeof context.getElementsByTagName !== "undefined" && context; +} + +// Expose support vars for convenience +support = Sizzle.support = {}; + +/** + * Detects XML nodes + * @param {Element|Object} elem An element or a document + * @returns {Boolean} True iff elem is a non-HTML XML node + */ +isXML = Sizzle.isXML = function( elem ) { + var namespace = elem.namespaceURI, + docElem = ( elem.ownerDocument || elem ).documentElement; + + // Support: IE <=8 + // Assume HTML when documentElement doesn't yet exist, such as inside loading iframes + // https://bugs.jquery.com/ticket/4833 + return !rhtml.test( namespace || docElem && docElem.nodeName || "HTML" ); +}; + +/** + * Sets document-related variables once based on the current document + * @param {Element|Object} [doc] An element or document object to use to set the document + * @returns {Object} Returns the current document + */ +setDocument = Sizzle.setDocument = function( node ) { + var hasCompare, subWindow, + doc = node ? node.ownerDocument || node : preferredDoc; + + // Return early if doc is invalid or already selected + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( doc == document || doc.nodeType !== 9 || !doc.documentElement ) { + return document; + } + + // Update global variables + document = doc; + docElem = document.documentElement; + documentIsHTML = !isXML( document ); + + // Support: IE 9 - 11+, Edge 12 - 18+ + // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( preferredDoc != document && + ( subWindow = document.defaultView ) && subWindow.top !== subWindow ) { + + // Support: IE 11, Edge + if ( subWindow.addEventListener ) { + subWindow.addEventListener( "unload", unloadHandler, false ); + + // Support: IE 9 - 10 only + } else if ( subWindow.attachEvent ) { + subWindow.attachEvent( "onunload", unloadHandler ); + } + } + + // Support: IE 8 - 11+, Edge 12 - 18+, Chrome <=16 - 25 only, Firefox <=3.6 - 31 only, + // Safari 4 - 5 only, Opera <=11.6 - 12.x only + // IE/Edge & older browsers don't support the :scope pseudo-class. + // Support: Safari 6.0 only + // Safari 6.0 supports :scope but it's an alias of :root there. + support.scope = assert( function( el ) { + docElem.appendChild( el ).appendChild( document.createElement( "div" ) ); + return typeof el.querySelectorAll !== "undefined" && + !el.querySelectorAll( ":scope fieldset div" ).length; + } ); + + /* Attributes + ---------------------------------------------------------------------- */ + + // Support: IE<8 + // Verify that getAttribute really returns attributes and not properties + // (excepting IE8 booleans) + support.attributes = assert( function( el ) { + el.className = "i"; + return !el.getAttribute( "className" ); + } ); + + /* getElement(s)By* + ---------------------------------------------------------------------- */ + + // Check if getElementsByTagName("*") returns only elements + support.getElementsByTagName = assert( function( el ) { + el.appendChild( document.createComment( "" ) ); + return !el.getElementsByTagName( "*" ).length; + } ); + + // Support: IE<9 + support.getElementsByClassName = rnative.test( document.getElementsByClassName ); + + // Support: IE<10 + // Check if getElementById returns elements by name + // The broken getElementById methods don't pick up programmatically-set names, + // so use a roundabout getElementsByName test + support.getById = assert( function( el ) { + docElem.appendChild( el ).id = expando; + return !document.getElementsByName || !document.getElementsByName( expando ).length; + } ); + + // ID filter and find + if ( support.getById ) { + Expr.filter[ "ID" ] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + return elem.getAttribute( "id" ) === attrId; + }; + }; + Expr.find[ "ID" ] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var elem = context.getElementById( id ); + return elem ? [ elem ] : []; + } + }; + } else { + Expr.filter[ "ID" ] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + var node = typeof elem.getAttributeNode !== "undefined" && + elem.getAttributeNode( "id" ); + return node && node.value === attrId; + }; + }; + + // Support: IE 6 - 7 only + // getElementById is not reliable as a find shortcut + Expr.find[ "ID" ] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var node, i, elems, + elem = context.getElementById( id ); + + if ( elem ) { + + // Verify the id attribute + node = elem.getAttributeNode( "id" ); + if ( node && node.value === id ) { + return [ elem ]; + } + + // Fall back on getElementsByName + elems = context.getElementsByName( id ); + i = 0; + while ( ( elem = elems[ i++ ] ) ) { + node = elem.getAttributeNode( "id" ); + if ( node && node.value === id ) { + return [ elem ]; + } + } + } + + return []; + } + }; + } + + // Tag + Expr.find[ "TAG" ] = support.getElementsByTagName ? + function( tag, context ) { + if ( typeof context.getElementsByTagName !== "undefined" ) { + return context.getElementsByTagName( tag ); + + // DocumentFragment nodes don't have gEBTN + } else if ( support.qsa ) { + return context.querySelectorAll( tag ); + } + } : + + function( tag, context ) { + var elem, + tmp = [], + i = 0, + + // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too + results = context.getElementsByTagName( tag ); + + // Filter out possible comments + if ( tag === "*" ) { + while ( ( elem = results[ i++ ] ) ) { + if ( elem.nodeType === 1 ) { + tmp.push( elem ); + } + } + + return tmp; + } + return results; + }; + + // Class + Expr.find[ "CLASS" ] = support.getElementsByClassName && function( className, context ) { + if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { + return context.getElementsByClassName( className ); + } + }; + + /* QSA/matchesSelector + ---------------------------------------------------------------------- */ + + // QSA and matchesSelector support + + // matchesSelector(:active) reports false when true (IE9/Opera 11.5) + rbuggyMatches = []; + + // qSa(:focus) reports false when true (Chrome 21) + // We allow this because of a bug in IE8/9 that throws an error + // whenever `document.activeElement` is accessed on an iframe + // So, we allow :focus to pass through QSA all the time to avoid the IE error + // See https://bugs.jquery.com/ticket/13378 + rbuggyQSA = []; + + if ( ( support.qsa = rnative.test( document.querySelectorAll ) ) ) { + + // Build QSA regex + // Regex strategy adopted from Diego Perini + assert( function( el ) { + + var input; + + // Select is set to empty string on purpose + // This is to test IE's treatment of not explicitly + // setting a boolean content attribute, + // since its presence should be enough + // https://bugs.jquery.com/ticket/12359 + docElem.appendChild( el ).innerHTML = "" + + ""; + + // Support: IE8, Opera 11-12.16 + // Nothing should be selected when empty strings follow ^= or $= or *= + // The test attribute must be unknown in Opera but "safe" for WinRT + // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section + if ( el.querySelectorAll( "[msallowcapture^='']" ).length ) { + rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); + } + + // Support: IE8 + // Boolean attributes and "value" are not treated correctly + if ( !el.querySelectorAll( "[selected]" ).length ) { + rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); + } + + // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+ + if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) { + rbuggyQSA.push( "~=" ); + } + + // Support: IE 11+, Edge 15 - 18+ + // IE 11/Edge don't find elements on a `[name='']` query in some cases. + // Adding a temporary attribute to the document before the selection works + // around the issue. + // Interestingly, IE 10 & older don't seem to have the issue. + input = document.createElement( "input" ); + input.setAttribute( "name", "" ); + el.appendChild( input ); + if ( !el.querySelectorAll( "[name='']" ).length ) { + rbuggyQSA.push( "\\[" + whitespace + "*name" + whitespace + "*=" + + whitespace + "*(?:''|\"\")" ); + } + + // Webkit/Opera - :checked should return selected option elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + // IE8 throws error here and will not see later tests + if ( !el.querySelectorAll( ":checked" ).length ) { + rbuggyQSA.push( ":checked" ); + } + + // Support: Safari 8+, iOS 8+ + // https://bugs.webkit.org/show_bug.cgi?id=136851 + // In-page `selector#id sibling-combinator selector` fails + if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) { + rbuggyQSA.push( ".#.+[+~]" ); + } + + // Support: Firefox <=3.6 - 5 only + // Old Firefox doesn't throw on a badly-escaped identifier. + el.querySelectorAll( "\\\f" ); + rbuggyQSA.push( "[\\r\\n\\f]" ); + } ); + + assert( function( el ) { + el.innerHTML = "" + + ""; + + // Support: Windows 8 Native Apps + // The type and name attributes are restricted during .innerHTML assignment + var input = document.createElement( "input" ); + input.setAttribute( "type", "hidden" ); + el.appendChild( input ).setAttribute( "name", "D" ); + + // Support: IE8 + // Enforce case-sensitivity of name attribute + if ( el.querySelectorAll( "[name=d]" ).length ) { + rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); + } + + // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) + // IE8 throws error here and will not see later tests + if ( el.querySelectorAll( ":enabled" ).length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Support: IE9-11+ + // IE's :disabled selector does not pick up the children of disabled fieldsets + docElem.appendChild( el ).disabled = true; + if ( el.querySelectorAll( ":disabled" ).length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Support: Opera 10 - 11 only + // Opera 10-11 does not throw on post-comma invalid pseudos + el.querySelectorAll( "*,:x" ); + rbuggyQSA.push( ",.*:" ); + } ); + } + + if ( ( support.matchesSelector = rnative.test( ( matches = docElem.matches || + docElem.webkitMatchesSelector || + docElem.mozMatchesSelector || + docElem.oMatchesSelector || + docElem.msMatchesSelector ) ) ) ) { + + assert( function( el ) { + + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9) + support.disconnectedMatch = matches.call( el, "*" ); + + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( el, "[s!='']:x" ); + rbuggyMatches.push( "!=", pseudos ); + } ); + } + + rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join( "|" ) ); + rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join( "|" ) ); + + /* Contains + ---------------------------------------------------------------------- */ + hasCompare = rnative.test( docElem.compareDocumentPosition ); + + // Element contains another + // Purposefully self-exclusive + // As in, an element does not contain itself + contains = hasCompare || rnative.test( docElem.contains ) ? + function( a, b ) { + var adown = a.nodeType === 9 ? a.documentElement : a, + bup = b && b.parentNode; + return a === bup || !!( bup && bup.nodeType === 1 && ( + adown.contains ? + adown.contains( bup ) : + a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 + ) ); + } : + function( a, b ) { + if ( b ) { + while ( ( b = b.parentNode ) ) { + if ( b === a ) { + return true; + } + } + } + return false; + }; + + /* Sorting + ---------------------------------------------------------------------- */ + + // Document order sorting + sortOrder = hasCompare ? + function( a, b ) { + + // Flag for duplicate removal + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + // Sort on method existence if only one input has compareDocumentPosition + var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; + if ( compare ) { + return compare; + } + + // Calculate position if both inputs belong to the same document + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + compare = ( a.ownerDocument || a ) == ( b.ownerDocument || b ) ? + a.compareDocumentPosition( b ) : + + // Otherwise we know they are disconnected + 1; + + // Disconnected nodes + if ( compare & 1 || + ( !support.sortDetached && b.compareDocumentPosition( a ) === compare ) ) { + + // Choose the first element that is related to our preferred document + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( a == document || a.ownerDocument == preferredDoc && + contains( preferredDoc, a ) ) { + return -1; + } + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( b == document || b.ownerDocument == preferredDoc && + contains( preferredDoc, b ) ) { + return 1; + } + + // Maintain original order + return sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + } + + return compare & 4 ? -1 : 1; + } : + function( a, b ) { + + // Exit early if the nodes are identical + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + var cur, + i = 0, + aup = a.parentNode, + bup = b.parentNode, + ap = [ a ], + bp = [ b ]; + + // Parentless nodes are either documents or disconnected + if ( !aup || !bup ) { + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + /* eslint-disable eqeqeq */ + return a == document ? -1 : + b == document ? 1 : + /* eslint-enable eqeqeq */ + aup ? -1 : + bup ? 1 : + sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + + // If the nodes are siblings, we can do a quick check + } else if ( aup === bup ) { + return siblingCheck( a, b ); + } + + // Otherwise we need full lists of their ancestors for comparison + cur = a; + while ( ( cur = cur.parentNode ) ) { + ap.unshift( cur ); + } + cur = b; + while ( ( cur = cur.parentNode ) ) { + bp.unshift( cur ); + } + + // Walk down the tree looking for a discrepancy + while ( ap[ i ] === bp[ i ] ) { + i++; + } + + return i ? + + // Do a sibling check if the nodes have a common ancestor + siblingCheck( ap[ i ], bp[ i ] ) : + + // Otherwise nodes in our document sort first + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + /* eslint-disable eqeqeq */ + ap[ i ] == preferredDoc ? -1 : + bp[ i ] == preferredDoc ? 1 : + /* eslint-enable eqeqeq */ + 0; + }; + + return document; +}; + +Sizzle.matches = function( expr, elements ) { + return Sizzle( expr, null, null, elements ); +}; + +Sizzle.matchesSelector = function( elem, expr ) { + setDocument( elem ); + + if ( support.matchesSelector && documentIsHTML && + !nonnativeSelectorCache[ expr + " " ] && + ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && + ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { + + try { + var ret = matches.call( elem, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || support.disconnectedMatch || + + // As well, disconnected nodes are said to be in a document + // fragment in IE 9 + elem.document && elem.document.nodeType !== 11 ) { + return ret; + } + } catch ( e ) { + nonnativeSelectorCache( expr, true ); + } + } + + return Sizzle( expr, document, null, [ elem ] ).length > 0; +}; + +Sizzle.contains = function( context, elem ) { + + // Set document vars if needed + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( ( context.ownerDocument || context ) != document ) { + setDocument( context ); + } + return contains( context, elem ); +}; + +Sizzle.attr = function( elem, name ) { + + // Set document vars if needed + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( ( elem.ownerDocument || elem ) != document ) { + setDocument( elem ); + } + + var fn = Expr.attrHandle[ name.toLowerCase() ], + + // Don't get fooled by Object.prototype properties (jQuery #13807) + val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? + fn( elem, name, !documentIsHTML ) : + undefined; + + return val !== undefined ? + val : + support.attributes || !documentIsHTML ? + elem.getAttribute( name ) : + ( val = elem.getAttributeNode( name ) ) && val.specified ? + val.value : + null; +}; + +Sizzle.escape = function( sel ) { + return ( sel + "" ).replace( rcssescape, fcssescape ); +}; + +Sizzle.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +/** + * Document sorting and removing duplicates + * @param {ArrayLike} results + */ +Sizzle.uniqueSort = function( results ) { + var elem, + duplicates = [], + j = 0, + i = 0; + + // Unless we *know* we can detect duplicates, assume their presence + hasDuplicate = !support.detectDuplicates; + sortInput = !support.sortStable && results.slice( 0 ); + results.sort( sortOrder ); + + if ( hasDuplicate ) { + while ( ( elem = results[ i++ ] ) ) { + if ( elem === results[ i ] ) { + j = duplicates.push( i ); + } + } + while ( j-- ) { + results.splice( duplicates[ j ], 1 ); + } + } + + // Clear input after sorting to release objects + // See https://github.com/jquery/sizzle/pull/225 + sortInput = null; + + return results; +}; + +/** + * Utility function for retrieving the text value of an array of DOM nodes + * @param {Array|Element} elem + */ +getText = Sizzle.getText = function( elem ) { + var node, + ret = "", + i = 0, + nodeType = elem.nodeType; + + if ( !nodeType ) { + + // If no nodeType, this is expected to be an array + while ( ( node = elem[ i++ ] ) ) { + + // Do not traverse comment nodes + ret += getText( node ); + } + } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + + // Use textContent for elements + // innerText usage removed for consistency of new lines (jQuery #11153) + if ( typeof elem.textContent === "string" ) { + return elem.textContent; + } else { + + // Traverse its children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + ret += getText( elem ); + } + } + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + + // Do not include comment or processing instruction nodes + + return ret; +}; + +Expr = Sizzle.selectors = { + + // Can be adjusted by the user + cacheLength: 50, + + createPseudo: markFunction, + + match: matchExpr, + + attrHandle: {}, + + find: {}, + + relative: { + ">": { dir: "parentNode", first: true }, + " ": { dir: "parentNode" }, + "+": { dir: "previousSibling", first: true }, + "~": { dir: "previousSibling" } + }, + + preFilter: { + "ATTR": function( match ) { + match[ 1 ] = match[ 1 ].replace( runescape, funescape ); + + // Move the given value to match[3] whether quoted or unquoted + match[ 3 ] = ( match[ 3 ] || match[ 4 ] || + match[ 5 ] || "" ).replace( runescape, funescape ); + + if ( match[ 2 ] === "~=" ) { + match[ 3 ] = " " + match[ 3 ] + " "; + } + + return match.slice( 0, 4 ); + }, + + "CHILD": function( match ) { + + /* matches from matchExpr["CHILD"] + 1 type (only|nth|...) + 2 what (child|of-type) + 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) + 4 xn-component of xn+y argument ([+-]?\d*n|) + 5 sign of xn-component + 6 x of xn-component + 7 sign of y-component + 8 y of y-component + */ + match[ 1 ] = match[ 1 ].toLowerCase(); + + if ( match[ 1 ].slice( 0, 3 ) === "nth" ) { + + // nth-* requires argument + if ( !match[ 3 ] ) { + Sizzle.error( match[ 0 ] ); + } + + // numeric x and y parameters for Expr.filter.CHILD + // remember that false/true cast respectively to 0/1 + match[ 4 ] = +( match[ 4 ] ? + match[ 5 ] + ( match[ 6 ] || 1 ) : + 2 * ( match[ 3 ] === "even" || match[ 3 ] === "odd" ) ); + match[ 5 ] = +( ( match[ 7 ] + match[ 8 ] ) || match[ 3 ] === "odd" ); + + // other types prohibit arguments + } else if ( match[ 3 ] ) { + Sizzle.error( match[ 0 ] ); + } + + return match; + }, + + "PSEUDO": function( match ) { + var excess, + unquoted = !match[ 6 ] && match[ 2 ]; + + if ( matchExpr[ "CHILD" ].test( match[ 0 ] ) ) { + return null; + } + + // Accept quoted arguments as-is + if ( match[ 3 ] ) { + match[ 2 ] = match[ 4 ] || match[ 5 ] || ""; + + // Strip excess characters from unquoted arguments + } else if ( unquoted && rpseudo.test( unquoted ) && + + // Get excess from tokenize (recursively) + ( excess = tokenize( unquoted, true ) ) && + + // advance to the next closing parenthesis + ( excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length ) ) { + + // excess is a negative index + match[ 0 ] = match[ 0 ].slice( 0, excess ); + match[ 2 ] = unquoted.slice( 0, excess ); + } + + // Return only captures needed by the pseudo filter method (type and argument) + return match.slice( 0, 3 ); + } + }, + + filter: { + + "TAG": function( nodeNameSelector ) { + var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); + return nodeNameSelector === "*" ? + function() { + return true; + } : + function( elem ) { + return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; + }; + }, + + "CLASS": function( className ) { + var pattern = classCache[ className + " " ]; + + return pattern || + ( pattern = new RegExp( "(^|" + whitespace + + ")" + className + "(" + whitespace + "|$)" ) ) && classCache( + className, function( elem ) { + return pattern.test( + typeof elem.className === "string" && elem.className || + typeof elem.getAttribute !== "undefined" && + elem.getAttribute( "class" ) || + "" + ); + } ); + }, + + "ATTR": function( name, operator, check ) { + return function( elem ) { + var result = Sizzle.attr( elem, name ); + + if ( result == null ) { + return operator === "!="; + } + if ( !operator ) { + return true; + } + + result += ""; + + /* eslint-disable max-len */ + + return operator === "=" ? result === check : + operator === "!=" ? result !== check : + operator === "^=" ? check && result.indexOf( check ) === 0 : + operator === "*=" ? check && result.indexOf( check ) > -1 : + operator === "$=" ? check && result.slice( -check.length ) === check : + operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 : + operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : + false; + /* eslint-enable max-len */ + + }; + }, + + "CHILD": function( type, what, _argument, first, last ) { + var simple = type.slice( 0, 3 ) !== "nth", + forward = type.slice( -4 ) !== "last", + ofType = what === "of-type"; + + return first === 1 && last === 0 ? + + // Shortcut for :nth-*(n) + function( elem ) { + return !!elem.parentNode; + } : + + function( elem, _context, xml ) { + var cache, uniqueCache, outerCache, node, nodeIndex, start, + dir = simple !== forward ? "nextSibling" : "previousSibling", + parent = elem.parentNode, + name = ofType && elem.nodeName.toLowerCase(), + useCache = !xml && !ofType, + diff = false; + + if ( parent ) { + + // :(first|last|only)-(child|of-type) + if ( simple ) { + while ( dir ) { + node = elem; + while ( ( node = node[ dir ] ) ) { + if ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) { + + return false; + } + } + + // Reverse direction for :only-* (if we haven't yet done so) + start = dir = type === "only" && !start && "nextSibling"; + } + return true; + } + + start = [ forward ? parent.firstChild : parent.lastChild ]; + + // non-xml :nth-child(...) stores cache data on `parent` + if ( forward && useCache ) { + + // Seek `elem` from a previously-cached index + + // ...in a gzip-friendly way + node = parent; + outerCache = node[ expando ] || ( node[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + ( outerCache[ node.uniqueID ] = {} ); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex && cache[ 2 ]; + node = nodeIndex && parent.childNodes[ nodeIndex ]; + + while ( ( node = ++nodeIndex && node && node[ dir ] || + + // Fallback to seeking `elem` from the start + ( diff = nodeIndex = 0 ) || start.pop() ) ) { + + // When found, cache indexes on `parent` and break + if ( node.nodeType === 1 && ++diff && node === elem ) { + uniqueCache[ type ] = [ dirruns, nodeIndex, diff ]; + break; + } + } + + } else { + + // Use previously-cached element index if available + if ( useCache ) { + + // ...in a gzip-friendly way + node = elem; + outerCache = node[ expando ] || ( node[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + ( outerCache[ node.uniqueID ] = {} ); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex; + } + + // xml :nth-child(...) + // or :nth-last-child(...) or :nth(-last)?-of-type(...) + if ( diff === false ) { + + // Use the same loop as above to seek `elem` from the start + while ( ( node = ++nodeIndex && node && node[ dir ] || + ( diff = nodeIndex = 0 ) || start.pop() ) ) { + + if ( ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) && + ++diff ) { + + // Cache the index of each encountered element + if ( useCache ) { + outerCache = node[ expando ] || + ( node[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + ( outerCache[ node.uniqueID ] = {} ); + + uniqueCache[ type ] = [ dirruns, diff ]; + } + + if ( node === elem ) { + break; + } + } + } + } + } + + // Incorporate the offset, then check against cycle size + diff -= last; + return diff === first || ( diff % first === 0 && diff / first >= 0 ); + } + }; + }, + + "PSEUDO": function( pseudo, argument ) { + + // pseudo-class names are case-insensitive + // http://www.w3.org/TR/selectors/#pseudo-classes + // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters + // Remember that setFilters inherits from pseudos + var args, + fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || + Sizzle.error( "unsupported pseudo: " + pseudo ); + + // The user may use createPseudo to indicate that + // arguments are needed to create the filter function + // just as Sizzle does + if ( fn[ expando ] ) { + return fn( argument ); + } + + // But maintain support for old signatures + if ( fn.length > 1 ) { + args = [ pseudo, pseudo, "", argument ]; + return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? + markFunction( function( seed, matches ) { + var idx, + matched = fn( seed, argument ), + i = matched.length; + while ( i-- ) { + idx = indexOf( seed, matched[ i ] ); + seed[ idx ] = !( matches[ idx ] = matched[ i ] ); + } + } ) : + function( elem ) { + return fn( elem, 0, args ); + }; + } + + return fn; + } + }, + + pseudos: { + + // Potentially complex pseudos + "not": markFunction( function( selector ) { + + // Trim the selector passed to compile + // to avoid treating leading and trailing + // spaces as combinators + var input = [], + results = [], + matcher = compile( selector.replace( rtrim, "$1" ) ); + + return matcher[ expando ] ? + markFunction( function( seed, matches, _context, xml ) { + var elem, + unmatched = matcher( seed, null, xml, [] ), + i = seed.length; + + // Match elements unmatched by `matcher` + while ( i-- ) { + if ( ( elem = unmatched[ i ] ) ) { + seed[ i ] = !( matches[ i ] = elem ); + } + } + } ) : + function( elem, _context, xml ) { + input[ 0 ] = elem; + matcher( input, null, xml, results ); + + // Don't keep the element (issue #299) + input[ 0 ] = null; + return !results.pop(); + }; + } ), + + "has": markFunction( function( selector ) { + return function( elem ) { + return Sizzle( selector, elem ).length > 0; + }; + } ), + + "contains": markFunction( function( text ) { + text = text.replace( runescape, funescape ); + return function( elem ) { + return ( elem.textContent || getText( elem ) ).indexOf( text ) > -1; + }; + } ), + + // "Whether an element is represented by a :lang() selector + // is based solely on the element's language value + // being equal to the identifier C, + // or beginning with the identifier C immediately followed by "-". + // The matching of C against the element's language value is performed case-insensitively. + // The identifier C does not have to be a valid language name." + // http://www.w3.org/TR/selectors/#lang-pseudo + "lang": markFunction( function( lang ) { + + // lang value must be a valid identifier + if ( !ridentifier.test( lang || "" ) ) { + Sizzle.error( "unsupported lang: " + lang ); + } + lang = lang.replace( runescape, funescape ).toLowerCase(); + return function( elem ) { + var elemLang; + do { + if ( ( elemLang = documentIsHTML ? + elem.lang : + elem.getAttribute( "xml:lang" ) || elem.getAttribute( "lang" ) ) ) { + + elemLang = elemLang.toLowerCase(); + return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; + } + } while ( ( elem = elem.parentNode ) && elem.nodeType === 1 ); + return false; + }; + } ), + + // Miscellaneous + "target": function( elem ) { + var hash = window.location && window.location.hash; + return hash && hash.slice( 1 ) === elem.id; + }, + + "root": function( elem ) { + return elem === docElem; + }, + + "focus": function( elem ) { + return elem === document.activeElement && + ( !document.hasFocus || document.hasFocus() ) && + !!( elem.type || elem.href || ~elem.tabIndex ); + }, + + // Boolean properties + "enabled": createDisabledPseudo( false ), + "disabled": createDisabledPseudo( true ), + + "checked": function( elem ) { + + // In CSS3, :checked should return both checked and selected elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + var nodeName = elem.nodeName.toLowerCase(); + return ( nodeName === "input" && !!elem.checked ) || + ( nodeName === "option" && !!elem.selected ); + }, + + "selected": function( elem ) { + + // Accessing this property makes selected-by-default + // options in Safari work properly + if ( elem.parentNode ) { + // eslint-disable-next-line no-unused-expressions + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + // Contents + "empty": function( elem ) { + + // http://www.w3.org/TR/selectors/#empty-pseudo + // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), + // but not by others (comment: 8; processing instruction: 7; etc.) + // nodeType < 6 works because attributes (2) do not appear as children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + if ( elem.nodeType < 6 ) { + return false; + } + } + return true; + }, + + "parent": function( elem ) { + return !Expr.pseudos[ "empty" ]( elem ); + }, + + // Element/input types + "header": function( elem ) { + return rheader.test( elem.nodeName ); + }, + + "input": function( elem ) { + return rinputs.test( elem.nodeName ); + }, + + "button": function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === "button" || name === "button"; + }, + + "text": function( elem ) { + var attr; + return elem.nodeName.toLowerCase() === "input" && + elem.type === "text" && + + // Support: IE<8 + // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" + ( ( attr = elem.getAttribute( "type" ) ) == null || + attr.toLowerCase() === "text" ); + }, + + // Position-in-collection + "first": createPositionalPseudo( function() { + return [ 0 ]; + } ), + + "last": createPositionalPseudo( function( _matchIndexes, length ) { + return [ length - 1 ]; + } ), + + "eq": createPositionalPseudo( function( _matchIndexes, length, argument ) { + return [ argument < 0 ? argument + length : argument ]; + } ), + + "even": createPositionalPseudo( function( matchIndexes, length ) { + var i = 0; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ), + + "odd": createPositionalPseudo( function( matchIndexes, length ) { + var i = 1; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ), + + "lt": createPositionalPseudo( function( matchIndexes, length, argument ) { + var i = argument < 0 ? + argument + length : + argument > length ? + length : + argument; + for ( ; --i >= 0; ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ), + + "gt": createPositionalPseudo( function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; ++i < length; ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ) + } +}; + +Expr.pseudos[ "nth" ] = Expr.pseudos[ "eq" ]; + +// Add button/input type pseudos +for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { + Expr.pseudos[ i ] = createInputPseudo( i ); +} +for ( i in { submit: true, reset: true } ) { + Expr.pseudos[ i ] = createButtonPseudo( i ); +} + +// Easy API for creating new setFilters +function setFilters() {} +setFilters.prototype = Expr.filters = Expr.pseudos; +Expr.setFilters = new setFilters(); + +tokenize = Sizzle.tokenize = function( selector, parseOnly ) { + var matched, match, tokens, type, + soFar, groups, preFilters, + cached = tokenCache[ selector + " " ]; + + if ( cached ) { + return parseOnly ? 0 : cached.slice( 0 ); + } + + soFar = selector; + groups = []; + preFilters = Expr.preFilter; + + while ( soFar ) { + + // Comma and first run + if ( !matched || ( match = rcomma.exec( soFar ) ) ) { + if ( match ) { + + // Don't consume trailing commas as valid + soFar = soFar.slice( match[ 0 ].length ) || soFar; + } + groups.push( ( tokens = [] ) ); + } + + matched = false; + + // Combinators + if ( ( match = rcombinators.exec( soFar ) ) ) { + matched = match.shift(); + tokens.push( { + value: matched, + + // Cast descendant combinators to space + type: match[ 0 ].replace( rtrim, " " ) + } ); + soFar = soFar.slice( matched.length ); + } + + // Filters + for ( type in Expr.filter ) { + if ( ( match = matchExpr[ type ].exec( soFar ) ) && ( !preFilters[ type ] || + ( match = preFilters[ type ]( match ) ) ) ) { + matched = match.shift(); + tokens.push( { + value: matched, + type: type, + matches: match + } ); + soFar = soFar.slice( matched.length ); + } + } + + if ( !matched ) { + break; + } + } + + // Return the length of the invalid excess + // if we're just parsing + // Otherwise, throw an error or return tokens + return parseOnly ? + soFar.length : + soFar ? + Sizzle.error( selector ) : + + // Cache the tokens + tokenCache( selector, groups ).slice( 0 ); +}; + +function toSelector( tokens ) { + var i = 0, + len = tokens.length, + selector = ""; + for ( ; i < len; i++ ) { + selector += tokens[ i ].value; + } + return selector; +} + +function addCombinator( matcher, combinator, base ) { + var dir = combinator.dir, + skip = combinator.next, + key = skip || dir, + checkNonElements = base && key === "parentNode", + doneName = done++; + + return combinator.first ? + + // Check against closest ancestor/preceding element + function( elem, context, xml ) { + while ( ( elem = elem[ dir ] ) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + return matcher( elem, context, xml ); + } + } + return false; + } : + + // Check against all ancestor/preceding elements + function( elem, context, xml ) { + var oldCache, uniqueCache, outerCache, + newCache = [ dirruns, doneName ]; + + // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching + if ( xml ) { + while ( ( elem = elem[ dir ] ) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + if ( matcher( elem, context, xml ) ) { + return true; + } + } + } + } else { + while ( ( elem = elem[ dir ] ) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + outerCache = elem[ expando ] || ( elem[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ elem.uniqueID ] || + ( outerCache[ elem.uniqueID ] = {} ); + + if ( skip && skip === elem.nodeName.toLowerCase() ) { + elem = elem[ dir ] || elem; + } else if ( ( oldCache = uniqueCache[ key ] ) && + oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { + + // Assign to newCache so results back-propagate to previous elements + return ( newCache[ 2 ] = oldCache[ 2 ] ); + } else { + + // Reuse newcache so results back-propagate to previous elements + uniqueCache[ key ] = newCache; + + // A match means we're done; a fail means we have to keep checking + if ( ( newCache[ 2 ] = matcher( elem, context, xml ) ) ) { + return true; + } + } + } + } + } + return false; + }; +} + +function elementMatcher( matchers ) { + return matchers.length > 1 ? + function( elem, context, xml ) { + var i = matchers.length; + while ( i-- ) { + if ( !matchers[ i ]( elem, context, xml ) ) { + return false; + } + } + return true; + } : + matchers[ 0 ]; +} + +function multipleContexts( selector, contexts, results ) { + var i = 0, + len = contexts.length; + for ( ; i < len; i++ ) { + Sizzle( selector, contexts[ i ], results ); + } + return results; +} + +function condense( unmatched, map, filter, context, xml ) { + var elem, + newUnmatched = [], + i = 0, + len = unmatched.length, + mapped = map != null; + + for ( ; i < len; i++ ) { + if ( ( elem = unmatched[ i ] ) ) { + if ( !filter || filter( elem, context, xml ) ) { + newUnmatched.push( elem ); + if ( mapped ) { + map.push( i ); + } + } + } + } + + return newUnmatched; +} + +function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { + if ( postFilter && !postFilter[ expando ] ) { + postFilter = setMatcher( postFilter ); + } + if ( postFinder && !postFinder[ expando ] ) { + postFinder = setMatcher( postFinder, postSelector ); + } + return markFunction( function( seed, results, context, xml ) { + var temp, i, elem, + preMap = [], + postMap = [], + preexisting = results.length, + + // Get initial elements from seed or context + elems = seed || multipleContexts( + selector || "*", + context.nodeType ? [ context ] : context, + [] + ), + + // Prefilter to get matcher input, preserving a map for seed-results synchronization + matcherIn = preFilter && ( seed || !selector ) ? + condense( elems, preMap, preFilter, context, xml ) : + elems, + + matcherOut = matcher ? + + // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, + postFinder || ( seed ? preFilter : preexisting || postFilter ) ? + + // ...intermediate processing is necessary + [] : + + // ...otherwise use results directly + results : + matcherIn; + + // Find primary matches + if ( matcher ) { + matcher( matcherIn, matcherOut, context, xml ); + } + + // Apply postFilter + if ( postFilter ) { + temp = condense( matcherOut, postMap ); + postFilter( temp, [], context, xml ); + + // Un-match failing elements by moving them back to matcherIn + i = temp.length; + while ( i-- ) { + if ( ( elem = temp[ i ] ) ) { + matcherOut[ postMap[ i ] ] = !( matcherIn[ postMap[ i ] ] = elem ); + } + } + } + + if ( seed ) { + if ( postFinder || preFilter ) { + if ( postFinder ) { + + // Get the final matcherOut by condensing this intermediate into postFinder contexts + temp = []; + i = matcherOut.length; + while ( i-- ) { + if ( ( elem = matcherOut[ i ] ) ) { + + // Restore matcherIn since elem is not yet a final match + temp.push( ( matcherIn[ i ] = elem ) ); + } + } + postFinder( null, ( matcherOut = [] ), temp, xml ); + } + + // Move matched elements from seed to results to keep them synchronized + i = matcherOut.length; + while ( i-- ) { + if ( ( elem = matcherOut[ i ] ) && + ( temp = postFinder ? indexOf( seed, elem ) : preMap[ i ] ) > -1 ) { + + seed[ temp ] = !( results[ temp ] = elem ); + } + } + } + + // Add elements to results, through postFinder if defined + } else { + matcherOut = condense( + matcherOut === results ? + matcherOut.splice( preexisting, matcherOut.length ) : + matcherOut + ); + if ( postFinder ) { + postFinder( null, results, matcherOut, xml ); + } else { + push.apply( results, matcherOut ); + } + } + } ); +} + +function matcherFromTokens( tokens ) { + var checkContext, matcher, j, + len = tokens.length, + leadingRelative = Expr.relative[ tokens[ 0 ].type ], + implicitRelative = leadingRelative || Expr.relative[ " " ], + i = leadingRelative ? 1 : 0, + + // The foundational matcher ensures that elements are reachable from top-level context(s) + matchContext = addCombinator( function( elem ) { + return elem === checkContext; + }, implicitRelative, true ), + matchAnyContext = addCombinator( function( elem ) { + return indexOf( checkContext, elem ) > -1; + }, implicitRelative, true ), + matchers = [ function( elem, context, xml ) { + var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( + ( checkContext = context ).nodeType ? + matchContext( elem, context, xml ) : + matchAnyContext( elem, context, xml ) ); + + // Avoid hanging onto element (issue #299) + checkContext = null; + return ret; + } ]; + + for ( ; i < len; i++ ) { + if ( ( matcher = Expr.relative[ tokens[ i ].type ] ) ) { + matchers = [ addCombinator( elementMatcher( matchers ), matcher ) ]; + } else { + matcher = Expr.filter[ tokens[ i ].type ].apply( null, tokens[ i ].matches ); + + // Return special upon seeing a positional matcher + if ( matcher[ expando ] ) { + + // Find the next relative operator (if any) for proper handling + j = ++i; + for ( ; j < len; j++ ) { + if ( Expr.relative[ tokens[ j ].type ] ) { + break; + } + } + return setMatcher( + i > 1 && elementMatcher( matchers ), + i > 1 && toSelector( + + // If the preceding token was a descendant combinator, insert an implicit any-element `*` + tokens + .slice( 0, i - 1 ) + .concat( { value: tokens[ i - 2 ].type === " " ? "*" : "" } ) + ).replace( rtrim, "$1" ), + matcher, + i < j && matcherFromTokens( tokens.slice( i, j ) ), + j < len && matcherFromTokens( ( tokens = tokens.slice( j ) ) ), + j < len && toSelector( tokens ) + ); + } + matchers.push( matcher ); + } + } + + return elementMatcher( matchers ); +} + +function matcherFromGroupMatchers( elementMatchers, setMatchers ) { + var bySet = setMatchers.length > 0, + byElement = elementMatchers.length > 0, + superMatcher = function( seed, context, xml, results, outermost ) { + var elem, j, matcher, + matchedCount = 0, + i = "0", + unmatched = seed && [], + setMatched = [], + contextBackup = outermostContext, + + // We must always have either seed elements or outermost context + elems = seed || byElement && Expr.find[ "TAG" ]( "*", outermost ), + + // Use integer dirruns iff this is the outermost matcher + dirrunsUnique = ( dirruns += contextBackup == null ? 1 : Math.random() || 0.1 ), + len = elems.length; + + if ( outermost ) { + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + outermostContext = context == document || context || outermost; + } + + // Add elements passing elementMatchers directly to results + // Support: IE<9, Safari + // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id + for ( ; i !== len && ( elem = elems[ i ] ) != null; i++ ) { + if ( byElement && elem ) { + j = 0; + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( !context && elem.ownerDocument != document ) { + setDocument( elem ); + xml = !documentIsHTML; + } + while ( ( matcher = elementMatchers[ j++ ] ) ) { + if ( matcher( elem, context || document, xml ) ) { + results.push( elem ); + break; + } + } + if ( outermost ) { + dirruns = dirrunsUnique; + } + } + + // Track unmatched elements for set filters + if ( bySet ) { + + // They will have gone through all possible matchers + if ( ( elem = !matcher && elem ) ) { + matchedCount--; + } + + // Lengthen the array for every element, matched or not + if ( seed ) { + unmatched.push( elem ); + } + } + } + + // `i` is now the count of elements visited above, and adding it to `matchedCount` + // makes the latter nonnegative. + matchedCount += i; + + // Apply set filters to unmatched elements + // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount` + // equals `i`), unless we didn't visit _any_ elements in the above loop because we have + // no element matchers and no seed. + // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that + // case, which will result in a "00" `matchedCount` that differs from `i` but is also + // numerically zero. + if ( bySet && i !== matchedCount ) { + j = 0; + while ( ( matcher = setMatchers[ j++ ] ) ) { + matcher( unmatched, setMatched, context, xml ); + } + + if ( seed ) { + + // Reintegrate element matches to eliminate the need for sorting + if ( matchedCount > 0 ) { + while ( i-- ) { + if ( !( unmatched[ i ] || setMatched[ i ] ) ) { + setMatched[ i ] = pop.call( results ); + } + } + } + + // Discard index placeholder values to get only actual matches + setMatched = condense( setMatched ); + } + + // Add matches to results + push.apply( results, setMatched ); + + // Seedless set matches succeeding multiple successful matchers stipulate sorting + if ( outermost && !seed && setMatched.length > 0 && + ( matchedCount + setMatchers.length ) > 1 ) { + + Sizzle.uniqueSort( results ); + } + } + + // Override manipulation of globals by nested matchers + if ( outermost ) { + dirruns = dirrunsUnique; + outermostContext = contextBackup; + } + + return unmatched; + }; + + return bySet ? + markFunction( superMatcher ) : + superMatcher; +} + +compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { + var i, + setMatchers = [], + elementMatchers = [], + cached = compilerCache[ selector + " " ]; + + if ( !cached ) { + + // Generate a function of recursive functions that can be used to check each element + if ( !match ) { + match = tokenize( selector ); + } + i = match.length; + while ( i-- ) { + cached = matcherFromTokens( match[ i ] ); + if ( cached[ expando ] ) { + setMatchers.push( cached ); + } else { + elementMatchers.push( cached ); + } + } + + // Cache the compiled function + cached = compilerCache( + selector, + matcherFromGroupMatchers( elementMatchers, setMatchers ) + ); + + // Save selector and tokenization + cached.selector = selector; + } + return cached; +}; + +/** + * A low-level selection function that works with Sizzle's compiled + * selector functions + * @param {String|Function} selector A selector or a pre-compiled + * selector function built with Sizzle.compile + * @param {Element} context + * @param {Array} [results] + * @param {Array} [seed] A set of elements to match against + */ +select = Sizzle.select = function( selector, context, results, seed ) { + var i, tokens, token, type, find, + compiled = typeof selector === "function" && selector, + match = !seed && tokenize( ( selector = compiled.selector || selector ) ); + + results = results || []; + + // Try to minimize operations if there is only one selector in the list and no seed + // (the latter of which guarantees us context) + if ( match.length === 1 ) { + + // Reduce context if the leading compound selector is an ID + tokens = match[ 0 ] = match[ 0 ].slice( 0 ); + if ( tokens.length > 2 && ( token = tokens[ 0 ] ).type === "ID" && + context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[ 1 ].type ] ) { + + context = ( Expr.find[ "ID" ]( token.matches[ 0 ] + .replace( runescape, funescape ), context ) || [] )[ 0 ]; + if ( !context ) { + return results; + + // Precompiled matchers will still verify ancestry, so step up a level + } else if ( compiled ) { + context = context.parentNode; + } + + selector = selector.slice( tokens.shift().value.length ); + } + + // Fetch a seed set for right-to-left matching + i = matchExpr[ "needsContext" ].test( selector ) ? 0 : tokens.length; + while ( i-- ) { + token = tokens[ i ]; + + // Abort if we hit a combinator + if ( Expr.relative[ ( type = token.type ) ] ) { + break; + } + if ( ( find = Expr.find[ type ] ) ) { + + // Search, expanding context for leading sibling combinators + if ( ( seed = find( + token.matches[ 0 ].replace( runescape, funescape ), + rsibling.test( tokens[ 0 ].type ) && testContext( context.parentNode ) || + context + ) ) ) { + + // If seed is empty or no tokens remain, we can return early + tokens.splice( i, 1 ); + selector = seed.length && toSelector( tokens ); + if ( !selector ) { + push.apply( results, seed ); + return results; + } + + break; + } + } + } + } + + // Compile and execute a filtering function if one is not provided + // Provide `match` to avoid retokenization if we modified the selector above + ( compiled || compile( selector, match ) )( + seed, + context, + !documentIsHTML, + results, + !context || rsibling.test( selector ) && testContext( context.parentNode ) || context + ); + return results; +}; + +// One-time assignments + +// Sort stability +support.sortStable = expando.split( "" ).sort( sortOrder ).join( "" ) === expando; + +// Support: Chrome 14-35+ +// Always assume duplicates if they aren't passed to the comparison function +support.detectDuplicates = !!hasDuplicate; + +// Initialize against the default document +setDocument(); + +// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) +// Detached nodes confoundingly follow *each other* +support.sortDetached = assert( function( el ) { + + // Should return 1, but returns 4 (following) + return el.compareDocumentPosition( document.createElement( "fieldset" ) ) & 1; +} ); + +// Support: IE<8 +// Prevent attribute/property "interpolation" +// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx +if ( !assert( function( el ) { + el.innerHTML = ""; + return el.firstChild.getAttribute( "href" ) === "#"; +} ) ) { + addHandle( "type|href|height|width", function( elem, name, isXML ) { + if ( !isXML ) { + return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); + } + } ); +} + +// Support: IE<9 +// Use defaultValue in place of getAttribute("value") +if ( !support.attributes || !assert( function( el ) { + el.innerHTML = ""; + el.firstChild.setAttribute( "value", "" ); + return el.firstChild.getAttribute( "value" ) === ""; +} ) ) { + addHandle( "value", function( elem, _name, isXML ) { + if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { + return elem.defaultValue; + } + } ); +} + +// Support: IE<9 +// Use getAttributeNode to fetch booleans when getAttribute lies +if ( !assert( function( el ) { + return el.getAttribute( "disabled" ) == null; +} ) ) { + addHandle( booleans, function( elem, name, isXML ) { + var val; + if ( !isXML ) { + return elem[ name ] === true ? name.toLowerCase() : + ( val = elem.getAttributeNode( name ) ) && val.specified ? + val.value : + null; + } + } ); +} + +return Sizzle; + +} )( window ); + + + +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; + +// Deprecated +jQuery.expr[ ":" ] = jQuery.expr.pseudos; +jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; +jQuery.escapeSelector = Sizzle.escape; + + + + +var dir = function( elem, dir, until ) { + var matched = [], + truncate = until !== undefined; + + while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) { + if ( elem.nodeType === 1 ) { + if ( truncate && jQuery( elem ).is( until ) ) { + break; + } + matched.push( elem ); + } + } + return matched; +}; + + +var siblings = function( n, elem ) { + var matched = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + matched.push( n ); + } + } + + return matched; +}; + + +var rneedsContext = jQuery.expr.match.needsContext; + + + +function nodeName( elem, name ) { + + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + +}; +var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i ); + + + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, not ) { + if ( isFunction( qualifier ) ) { + return jQuery.grep( elements, function( elem, i ) { + return !!qualifier.call( elem, i, elem ) !== not; + } ); + } + + // Single element + if ( qualifier.nodeType ) { + return jQuery.grep( elements, function( elem ) { + return ( elem === qualifier ) !== not; + } ); + } + + // Arraylike of elements (jQuery, arguments, Array) + if ( typeof qualifier !== "string" ) { + return jQuery.grep( elements, function( elem ) { + return ( indexOf.call( qualifier, elem ) > -1 ) !== not; + } ); + } + + // Filtered directly for both simple and complex selectors + return jQuery.filter( qualifier, elements, not ); +} + +jQuery.filter = function( expr, elems, not ) { + var elem = elems[ 0 ]; + + if ( not ) { + expr = ":not(" + expr + ")"; + } + + if ( elems.length === 1 && elem.nodeType === 1 ) { + return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : []; + } + + return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { + return elem.nodeType === 1; + } ) ); +}; + +jQuery.fn.extend( { + find: function( selector ) { + var i, ret, + len = this.length, + self = this; + + if ( typeof selector !== "string" ) { + return this.pushStack( jQuery( selector ).filter( function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + } ) ); + } + + ret = this.pushStack( [] ); + + for ( i = 0; i < len; i++ ) { + jQuery.find( selector, self[ i ], ret ); + } + + return len > 1 ? jQuery.uniqueSort( ret ) : ret; + }, + filter: function( selector ) { + return this.pushStack( winnow( this, selector || [], false ) ); + }, + not: function( selector ) { + return this.pushStack( winnow( this, selector || [], true ) ); + }, + is: function( selector ) { + return !!winnow( + this, + + // If this is a positional/relative selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + typeof selector === "string" && rneedsContext.test( selector ) ? + jQuery( selector ) : + selector || [], + false + ).length; + } +} ); + + +// Initialize a jQuery object + + +// A central reference to the root jQuery(document) +var rootjQuery, + + // A simple way to check for HTML strings + // Prioritize #id over to avoid XSS via location.hash (#9521) + // Strict HTML recognition (#11290: must start with <) + // Shortcut simple #id case for speed + rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/, + + init = jQuery.fn.init = function( selector, context, root ) { + var match, elem; + + // HANDLE: $(""), $(null), $(undefined), $(false) + if ( !selector ) { + return this; + } + + // Method init() accepts an alternate rootjQuery + // so migrate can support jQuery.sub (gh-2101) + root = root || rootjQuery; + + // Handle HTML strings + if ( typeof selector === "string" ) { + if ( selector[ 0 ] === "<" && + selector[ selector.length - 1 ] === ">" && + selector.length >= 3 ) { + + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = rquickExpr.exec( selector ); + } + + // Match html or make sure no context is specified for #id + if ( match && ( match[ 1 ] || !context ) ) { + + // HANDLE: $(html) -> $(array) + if ( match[ 1 ] ) { + context = context instanceof jQuery ? context[ 0 ] : context; + + // Option to run scripts is true for back-compat + // Intentionally let the error be thrown if parseHTML is not present + jQuery.merge( this, jQuery.parseHTML( + match[ 1 ], + context && context.nodeType ? context.ownerDocument || context : document, + true + ) ); + + // HANDLE: $(html, props) + if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) { + for ( match in context ) { + + // Properties of context are called as methods if possible + if ( isFunction( this[ match ] ) ) { + this[ match ]( context[ match ] ); + + // ...and otherwise set as attributes + } else { + this.attr( match, context[ match ] ); + } + } + } + + return this; + + // HANDLE: $(#id) + } else { + elem = document.getElementById( match[ 2 ] ); + + if ( elem ) { + + // Inject the element directly into the jQuery object + this[ 0 ] = elem; + this.length = 1; + } + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return ( context || root ).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(DOMElement) + } else if ( selector.nodeType ) { + this[ 0 ] = selector; + this.length = 1; + return this; + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( isFunction( selector ) ) { + return root.ready !== undefined ? + root.ready( selector ) : + + // Execute immediately if ready is not present + selector( jQuery ); + } + + return jQuery.makeArray( selector, this ); + }; + +// Give the init function the jQuery prototype for later instantiation +init.prototype = jQuery.fn; + +// Initialize central reference +rootjQuery = jQuery( document ); + + +var rparentsprev = /^(?:parents|prev(?:Until|All))/, + + // Methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.fn.extend( { + has: function( target ) { + var targets = jQuery( target, this ), + l = targets.length; + + return this.filter( function() { + var i = 0; + for ( ; i < l; i++ ) { + if ( jQuery.contains( this, targets[ i ] ) ) { + return true; + } + } + } ); + }, + + closest: function( selectors, context ) { + var cur, + i = 0, + l = this.length, + matched = [], + targets = typeof selectors !== "string" && jQuery( selectors ); + + // Positional selectors never match, since there's no _selection_ context + if ( !rneedsContext.test( selectors ) ) { + for ( ; i < l; i++ ) { + for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) { + + // Always skip document fragments + if ( cur.nodeType < 11 && ( targets ? + targets.index( cur ) > -1 : + + // Don't pass non-elements to Sizzle + cur.nodeType === 1 && + jQuery.find.matchesSelector( cur, selectors ) ) ) { + + matched.push( cur ); + break; + } + } + } + } + + return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched ); + }, + + // Determine the position of an element within the set + index: function( elem ) { + + // No argument, return index in parent + if ( !elem ) { + return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1; + } + + // Index in selector + if ( typeof elem === "string" ) { + return indexOf.call( jQuery( elem ), this[ 0 ] ); + } + + // Locate the position of the desired element + return indexOf.call( this, + + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[ 0 ] : elem + ); + }, + + add: function( selector, context ) { + return this.pushStack( + jQuery.uniqueSort( + jQuery.merge( this.get(), jQuery( selector, context ) ) + ) + ); + }, + + addBack: function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter( selector ) + ); + } +} ); + +function sibling( cur, dir ) { + while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {} + return cur; +} + +jQuery.each( { + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, _i, until ) { + return dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return sibling( elem, "nextSibling" ); + }, + prev: function( elem ) { + return sibling( elem, "previousSibling" ); + }, + nextAll: function( elem ) { + return dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, _i, until ) { + return dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, _i, until ) { + return dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return siblings( ( elem.parentNode || {} ).firstChild, elem ); + }, + children: function( elem ) { + return siblings( elem.firstChild ); + }, + contents: function( elem ) { + if ( elem.contentDocument != null && + + // Support: IE 11+ + // elements with no `data` attribute has an object + // `contentDocument` with a `null` prototype. + getProto( elem.contentDocument ) ) { + + return elem.contentDocument; + } + + // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only + // Treat the template element as a regular one in browsers that + // don't support it. + if ( nodeName( elem, "template" ) ) { + elem = elem.content || elem; + } + + return jQuery.merge( [], elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var matched = jQuery.map( this, fn, until ); + + if ( name.slice( -5 ) !== "Until" ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + matched = jQuery.filter( selector, matched ); + } + + if ( this.length > 1 ) { + + // Remove duplicates + if ( !guaranteedUnique[ name ] ) { + jQuery.uniqueSort( matched ); + } + + // Reverse order for parents* and prev-derivatives + if ( rparentsprev.test( name ) ) { + matched.reverse(); + } + } + + return this.pushStack( matched ); + }; +} ); +var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g ); + + + +// Convert String-formatted options into Object-formatted ones +function createOptions( options ) { + var object = {}; + jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) { + object[ flag ] = true; + } ); + return object; +} + +/* + * Create a callback list using the following parameters: + * + * options: an optional list of space-separated options that will change how + * the callback list behaves or a more traditional option object + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible options: + * + * once: will ensure the callback list can only be fired once (like a Deferred) + * + * memory: will keep track of previous values and will call any callback added + * after the list has been fired right away with the latest "memorized" + * values (like a Deferred) + * + * unique: will ensure a callback can only be added once (no duplicate in the list) + * + * stopOnFalse: interrupt callings when a callback returns false + * + */ +jQuery.Callbacks = function( options ) { + + // Convert options from String-formatted to Object-formatted if needed + // (we check in cache first) + options = typeof options === "string" ? + createOptions( options ) : + jQuery.extend( {}, options ); + + var // Flag to know if list is currently firing + firing, + + // Last fire value for non-forgettable lists + memory, + + // Flag to know if list was already fired + fired, + + // Flag to prevent firing + locked, + + // Actual callback list + list = [], + + // Queue of execution data for repeatable lists + queue = [], + + // Index of currently firing callback (modified by add/remove as needed) + firingIndex = -1, + + // Fire callbacks + fire = function() { + + // Enforce single-firing + locked = locked || options.once; + + // Execute callbacks for all pending executions, + // respecting firingIndex overrides and runtime changes + fired = firing = true; + for ( ; queue.length; firingIndex = -1 ) { + memory = queue.shift(); + while ( ++firingIndex < list.length ) { + + // Run callback and check for early termination + if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false && + options.stopOnFalse ) { + + // Jump to end and forget the data so .add doesn't re-fire + firingIndex = list.length; + memory = false; + } + } + } + + // Forget the data if we're done with it + if ( !options.memory ) { + memory = false; + } + + firing = false; + + // Clean up if we're done firing for good + if ( locked ) { + + // Keep an empty list if we have data for future add calls + if ( memory ) { + list = []; + + // Otherwise, this object is spent + } else { + list = ""; + } + } + }, + + // Actual Callbacks object + self = { + + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + + // If we have memory from a past run, we should fire after adding + if ( memory && !firing ) { + firingIndex = list.length - 1; + queue.push( memory ); + } + + ( function add( args ) { + jQuery.each( args, function( _, arg ) { + if ( isFunction( arg ) ) { + if ( !options.unique || !self.has( arg ) ) { + list.push( arg ); + } + } else if ( arg && arg.length && toType( arg ) !== "string" ) { + + // Inspect recursively + add( arg ); + } + } ); + } )( arguments ); + + if ( memory && !firing ) { + fire(); + } + } + return this; + }, + + // Remove a callback from the list + remove: function() { + jQuery.each( arguments, function( _, arg ) { + var index; + while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { + list.splice( index, 1 ); + + // Handle firing indexes + if ( index <= firingIndex ) { + firingIndex--; + } + } + } ); + return this; + }, + + // Check if a given callback is in the list. + // If no argument is given, return whether or not list has callbacks attached. + has: function( fn ) { + return fn ? + jQuery.inArray( fn, list ) > -1 : + list.length > 0; + }, + + // Remove all callbacks from the list + empty: function() { + if ( list ) { + list = []; + } + return this; + }, + + // Disable .fire and .add + // Abort any current/pending executions + // Clear all callbacks and values + disable: function() { + locked = queue = []; + list = memory = ""; + return this; + }, + disabled: function() { + return !list; + }, + + // Disable .fire + // Also disable .add unless we have memory (since it would have no effect) + // Abort any pending executions + lock: function() { + locked = queue = []; + if ( !memory && !firing ) { + list = memory = ""; + } + return this; + }, + locked: function() { + return !!locked; + }, + + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + if ( !locked ) { + args = args || []; + args = [ context, args.slice ? args.slice() : args ]; + queue.push( args ); + if ( !firing ) { + fire(); + } + } + return this; + }, + + // Call all the callbacks with the given arguments + fire: function() { + self.fireWith( this, arguments ); + return this; + }, + + // To know if the callbacks have already been called at least once + fired: function() { + return !!fired; + } + }; + + return self; +}; + + +function Identity( v ) { + return v; +} +function Thrower( ex ) { + throw ex; +} + +function adoptValue( value, resolve, reject, noValue ) { + var method; + + try { + + // Check for promise aspect first to privilege synchronous behavior + if ( value && isFunction( ( method = value.promise ) ) ) { + method.call( value ).done( resolve ).fail( reject ); + + // Other thenables + } else if ( value && isFunction( ( method = value.then ) ) ) { + method.call( value, resolve, reject ); + + // Other non-thenables + } else { + + // Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer: + // * false: [ value ].slice( 0 ) => resolve( value ) + // * true: [ value ].slice( 1 ) => resolve() + resolve.apply( undefined, [ value ].slice( noValue ) ); + } + + // For Promises/A+, convert exceptions into rejections + // Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in + // Deferred#then to conditionally suppress rejection. + } catch ( value ) { + + // Support: Android 4.0 only + // Strict mode functions invoked without .call/.apply get global-object context + reject.apply( undefined, [ value ] ); + } +} + +jQuery.extend( { + + Deferred: function( func ) { + var tuples = [ + + // action, add listener, callbacks, + // ... .then handlers, argument index, [final state] + [ "notify", "progress", jQuery.Callbacks( "memory" ), + jQuery.Callbacks( "memory" ), 2 ], + [ "resolve", "done", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 0, "resolved" ], + [ "reject", "fail", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 1, "rejected" ] + ], + state = "pending", + promise = { + state: function() { + return state; + }, + always: function() { + deferred.done( arguments ).fail( arguments ); + return this; + }, + "catch": function( fn ) { + return promise.then( null, fn ); + }, + + // Keep pipe for back-compat + pipe: function( /* fnDone, fnFail, fnProgress */ ) { + var fns = arguments; + + return jQuery.Deferred( function( newDefer ) { + jQuery.each( tuples, function( _i, tuple ) { + + // Map tuples (progress, done, fail) to arguments (done, fail, progress) + var fn = isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ]; + + // deferred.progress(function() { bind to newDefer or newDefer.notify }) + // deferred.done(function() { bind to newDefer or newDefer.resolve }) + // deferred.fail(function() { bind to newDefer or newDefer.reject }) + deferred[ tuple[ 1 ] ]( function() { + var returned = fn && fn.apply( this, arguments ); + if ( returned && isFunction( returned.promise ) ) { + returned.promise() + .progress( newDefer.notify ) + .done( newDefer.resolve ) + .fail( newDefer.reject ); + } else { + newDefer[ tuple[ 0 ] + "With" ]( + this, + fn ? [ returned ] : arguments + ); + } + } ); + } ); + fns = null; + } ).promise(); + }, + then: function( onFulfilled, onRejected, onProgress ) { + var maxDepth = 0; + function resolve( depth, deferred, handler, special ) { + return function() { + var that = this, + args = arguments, + mightThrow = function() { + var returned, then; + + // Support: Promises/A+ section 2.3.3.3.3 + // https://promisesaplus.com/#point-59 + // Ignore double-resolution attempts + if ( depth < maxDepth ) { + return; + } + + returned = handler.apply( that, args ); + + // Support: Promises/A+ section 2.3.1 + // https://promisesaplus.com/#point-48 + if ( returned === deferred.promise() ) { + throw new TypeError( "Thenable self-resolution" ); + } + + // Support: Promises/A+ sections 2.3.3.1, 3.5 + // https://promisesaplus.com/#point-54 + // https://promisesaplus.com/#point-75 + // Retrieve `then` only once + then = returned && + + // Support: Promises/A+ section 2.3.4 + // https://promisesaplus.com/#point-64 + // Only check objects and functions for thenability + ( typeof returned === "object" || + typeof returned === "function" ) && + returned.then; + + // Handle a returned thenable + if ( isFunction( then ) ) { + + // Special processors (notify) just wait for resolution + if ( special ) { + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ) + ); + + // Normal processors (resolve) also hook into progress + } else { + + // ...and disregard older resolution values + maxDepth++; + + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ), + resolve( maxDepth, deferred, Identity, + deferred.notifyWith ) + ); + } + + // Handle all other returned values + } else { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Identity ) { + that = undefined; + args = [ returned ]; + } + + // Process the value(s) + // Default process is resolve + ( special || deferred.resolveWith )( that, args ); + } + }, + + // Only normal processors (resolve) catch and reject exceptions + process = special ? + mightThrow : + function() { + try { + mightThrow(); + } catch ( e ) { + + if ( jQuery.Deferred.exceptionHook ) { + jQuery.Deferred.exceptionHook( e, + process.stackTrace ); + } + + // Support: Promises/A+ section 2.3.3.3.4.1 + // https://promisesaplus.com/#point-61 + // Ignore post-resolution exceptions + if ( depth + 1 >= maxDepth ) { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Thrower ) { + that = undefined; + args = [ e ]; + } + + deferred.rejectWith( that, args ); + } + } + }; + + // Support: Promises/A+ section 2.3.3.3.1 + // https://promisesaplus.com/#point-57 + // Re-resolve promises immediately to dodge false rejection from + // subsequent errors + if ( depth ) { + process(); + } else { + + // Call an optional hook to record the stack, in case of exception + // since it's otherwise lost when execution goes async + if ( jQuery.Deferred.getStackHook ) { + process.stackTrace = jQuery.Deferred.getStackHook(); + } + window.setTimeout( process ); + } + }; + } + + return jQuery.Deferred( function( newDefer ) { + + // progress_handlers.add( ... ) + tuples[ 0 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onProgress ) ? + onProgress : + Identity, + newDefer.notifyWith + ) + ); + + // fulfilled_handlers.add( ... ) + tuples[ 1 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onFulfilled ) ? + onFulfilled : + Identity + ) + ); + + // rejected_handlers.add( ... ) + tuples[ 2 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onRejected ) ? + onRejected : + Thrower + ) + ); + } ).promise(); + }, + + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + return obj != null ? jQuery.extend( obj, promise ) : promise; + } + }, + deferred = {}; + + // Add list-specific methods + jQuery.each( tuples, function( i, tuple ) { + var list = tuple[ 2 ], + stateString = tuple[ 5 ]; + + // promise.progress = list.add + // promise.done = list.add + // promise.fail = list.add + promise[ tuple[ 1 ] ] = list.add; + + // Handle state + if ( stateString ) { + list.add( + function() { + + // state = "resolved" (i.e., fulfilled) + // state = "rejected" + state = stateString; + }, + + // rejected_callbacks.disable + // fulfilled_callbacks.disable + tuples[ 3 - i ][ 2 ].disable, + + // rejected_handlers.disable + // fulfilled_handlers.disable + tuples[ 3 - i ][ 3 ].disable, + + // progress_callbacks.lock + tuples[ 0 ][ 2 ].lock, + + // progress_handlers.lock + tuples[ 0 ][ 3 ].lock + ); + } + + // progress_handlers.fire + // fulfilled_handlers.fire + // rejected_handlers.fire + list.add( tuple[ 3 ].fire ); + + // deferred.notify = function() { deferred.notifyWith(...) } + // deferred.resolve = function() { deferred.resolveWith(...) } + // deferred.reject = function() { deferred.rejectWith(...) } + deferred[ tuple[ 0 ] ] = function() { + deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments ); + return this; + }; + + // deferred.notifyWith = list.fireWith + // deferred.resolveWith = list.fireWith + // deferred.rejectWith = list.fireWith + deferred[ tuple[ 0 ] + "With" ] = list.fireWith; + } ); + + // Make the deferred a promise + promise.promise( deferred ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( singleValue ) { + var + + // count of uncompleted subordinates + remaining = arguments.length, + + // count of unprocessed arguments + i = remaining, + + // subordinate fulfillment data + resolveContexts = Array( i ), + resolveValues = slice.call( arguments ), + + // the master Deferred + master = jQuery.Deferred(), + + // subordinate callback factory + updateFunc = function( i ) { + return function( value ) { + resolveContexts[ i ] = this; + resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; + if ( !( --remaining ) ) { + master.resolveWith( resolveContexts, resolveValues ); + } + }; + }; + + // Single- and empty arguments are adopted like Promise.resolve + if ( remaining <= 1 ) { + adoptValue( singleValue, master.done( updateFunc( i ) ).resolve, master.reject, + !remaining ); + + // Use .then() to unwrap secondary thenables (cf. gh-3000) + if ( master.state() === "pending" || + isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) { + + return master.then(); + } + } + + // Multiple arguments are aggregated like Promise.all array elements + while ( i-- ) { + adoptValue( resolveValues[ i ], updateFunc( i ), master.reject ); + } + + return master.promise(); + } +} ); + + +// These usually indicate a programmer mistake during development, +// warn about them ASAP rather than swallowing them by default. +var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/; + +jQuery.Deferred.exceptionHook = function( error, stack ) { + + // Support: IE 8 - 9 only + // Console exists when dev tools are open, which can happen at any time + if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) { + window.console.warn( "jQuery.Deferred exception: " + error.message, error.stack, stack ); + } +}; + + + + +jQuery.readyException = function( error ) { + window.setTimeout( function() { + throw error; + } ); +}; + + + + +// The deferred used on DOM ready +var readyList = jQuery.Deferred(); + +jQuery.fn.ready = function( fn ) { + + readyList + .then( fn ) + + // Wrap jQuery.readyException in a function so that the lookup + // happens at the time of error handling instead of callback + // registration. + .catch( function( error ) { + jQuery.readyException( error ); + } ); + + return this; +}; + +jQuery.extend( { + + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See #6781 + readyWait: 1, + + // Handle when the DOM is ready + ready: function( wait ) { + + // Abort if there are pending holds or we're already ready + if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { + return; + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.resolveWith( document, [ jQuery ] ); + } +} ); + +jQuery.ready.then = readyList.then; + +// The ready event handler and self cleanup method +function completed() { + document.removeEventListener( "DOMContentLoaded", completed ); + window.removeEventListener( "load", completed ); + jQuery.ready(); +} + +// Catch cases where $(document).ready() is called +// after the browser event has already occurred. +// Support: IE <=9 - 10 only +// Older IE sometimes signals "interactive" too soon +if ( document.readyState === "complete" || + ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) { + + // Handle it asynchronously to allow scripts the opportunity to delay ready + window.setTimeout( jQuery.ready ); + +} else { + + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", completed ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", completed ); +} + + + + +// Multifunctional method to get and set values of a collection +// The value/s can optionally be executed if it's a function +var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { + var i = 0, + len = elems.length, + bulk = key == null; + + // Sets many values + if ( toType( key ) === "object" ) { + chainable = true; + for ( i in key ) { + access( elems, fn, i, key[ i ], true, emptyGet, raw ); + } + + // Sets one value + } else if ( value !== undefined ) { + chainable = true; + + if ( !isFunction( value ) ) { + raw = true; + } + + if ( bulk ) { + + // Bulk operations run against the entire set + if ( raw ) { + fn.call( elems, value ); + fn = null; + + // ...except when executing function values + } else { + bulk = fn; + fn = function( elem, _key, value ) { + return bulk.call( jQuery( elem ), value ); + }; + } + } + + if ( fn ) { + for ( ; i < len; i++ ) { + fn( + elems[ i ], key, raw ? + value : + value.call( elems[ i ], i, fn( elems[ i ], key ) ) + ); + } + } + } + + if ( chainable ) { + return elems; + } + + // Gets + if ( bulk ) { + return fn.call( elems ); + } + + return len ? fn( elems[ 0 ], key ) : emptyGet; +}; + + +// Matches dashed string for camelizing +var rmsPrefix = /^-ms-/, + rdashAlpha = /-([a-z])/g; + +// Used by camelCase as callback to replace() +function fcamelCase( _all, letter ) { + return letter.toUpperCase(); +} + +// Convert dashed to camelCase; used by the css and data modules +// Support: IE <=9 - 11, Edge 12 - 15 +// Microsoft forgot to hump their vendor prefix (#9572) +function camelCase( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); +} +var acceptData = function( owner ) { + + // Accepts only: + // - Node + // - Node.ELEMENT_NODE + // - Node.DOCUMENT_NODE + // - Object + // - Any + return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType ); +}; + + + + +function Data() { + this.expando = jQuery.expando + Data.uid++; +} + +Data.uid = 1; + +Data.prototype = { + + cache: function( owner ) { + + // Check if the owner object already has a cache + var value = owner[ this.expando ]; + + // If not, create one + if ( !value ) { + value = {}; + + // We can accept data for non-element nodes in modern browsers, + // but we should not, see #8335. + // Always return an empty object. + if ( acceptData( owner ) ) { + + // If it is a node unlikely to be stringify-ed or looped over + // use plain assignment + if ( owner.nodeType ) { + owner[ this.expando ] = value; + + // Otherwise secure it in a non-enumerable property + // configurable must be true to allow the property to be + // deleted when data is removed + } else { + Object.defineProperty( owner, this.expando, { + value: value, + configurable: true + } ); + } + } + } + + return value; + }, + set: function( owner, data, value ) { + var prop, + cache = this.cache( owner ); + + // Handle: [ owner, key, value ] args + // Always use camelCase key (gh-2257) + if ( typeof data === "string" ) { + cache[ camelCase( data ) ] = value; + + // Handle: [ owner, { properties } ] args + } else { + + // Copy the properties one-by-one to the cache object + for ( prop in data ) { + cache[ camelCase( prop ) ] = data[ prop ]; + } + } + return cache; + }, + get: function( owner, key ) { + return key === undefined ? + this.cache( owner ) : + + // Always use camelCase key (gh-2257) + owner[ this.expando ] && owner[ this.expando ][ camelCase( key ) ]; + }, + access: function( owner, key, value ) { + + // In cases where either: + // + // 1. No key was specified + // 2. A string key was specified, but no value provided + // + // Take the "read" path and allow the get method to determine + // which value to return, respectively either: + // + // 1. The entire cache object + // 2. The data stored at the key + // + if ( key === undefined || + ( ( key && typeof key === "string" ) && value === undefined ) ) { + + return this.get( owner, key ); + } + + // When the key is not a string, or both a key and value + // are specified, set or extend (existing objects) with either: + // + // 1. An object of properties + // 2. A key and value + // + this.set( owner, key, value ); + + // Since the "set" path can have two possible entry points + // return the expected data based on which path was taken[*] + return value !== undefined ? value : key; + }, + remove: function( owner, key ) { + var i, + cache = owner[ this.expando ]; + + if ( cache === undefined ) { + return; + } + + if ( key !== undefined ) { + + // Support array or space separated string of keys + if ( Array.isArray( key ) ) { + + // If key is an array of keys... + // We always set camelCase keys, so remove that. + key = key.map( camelCase ); + } else { + key = camelCase( key ); + + // If a key with the spaces exists, use it. + // Otherwise, create an array by matching non-whitespace + key = key in cache ? + [ key ] : + ( key.match( rnothtmlwhite ) || [] ); + } + + i = key.length; + + while ( i-- ) { + delete cache[ key[ i ] ]; + } + } + + // Remove the expando if there's no more data + if ( key === undefined || jQuery.isEmptyObject( cache ) ) { + + // Support: Chrome <=35 - 45 + // Webkit & Blink performance suffers when deleting properties + // from DOM nodes, so set to undefined instead + // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted) + if ( owner.nodeType ) { + owner[ this.expando ] = undefined; + } else { + delete owner[ this.expando ]; + } + } + }, + hasData: function( owner ) { + var cache = owner[ this.expando ]; + return cache !== undefined && !jQuery.isEmptyObject( cache ); + } +}; +var dataPriv = new Data(); + +var dataUser = new Data(); + + + +// Implementation Summary +// +// 1. Enforce API surface and semantic compatibility with 1.9.x branch +// 2. Improve the module's maintainability by reducing the storage +// paths to a single mechanism. +// 3. Use the same single mechanism to support "private" and "user" data. +// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData) +// 5. Avoid exposing implementation details on user objects (eg. expando properties) +// 6. Provide a clear path for implementation upgrade to WeakMap in 2014 + +var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, + rmultiDash = /[A-Z]/g; + +function getData( data ) { + if ( data === "true" ) { + return true; + } + + if ( data === "false" ) { + return false; + } + + if ( data === "null" ) { + return null; + } + + // Only convert to a number if it doesn't change the string + if ( data === +data + "" ) { + return +data; + } + + if ( rbrace.test( data ) ) { + return JSON.parse( data ); + } + + return data; +} + +function dataAttr( elem, key, data ) { + var name; + + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase(); + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = getData( data ); + } catch ( e ) {} + + // Make sure we set the data so it isn't changed later + dataUser.set( elem, key, data ); + } else { + data = undefined; + } + } + return data; +} + +jQuery.extend( { + hasData: function( elem ) { + return dataUser.hasData( elem ) || dataPriv.hasData( elem ); + }, + + data: function( elem, name, data ) { + return dataUser.access( elem, name, data ); + }, + + removeData: function( elem, name ) { + dataUser.remove( elem, name ); + }, + + // TODO: Now that all calls to _data and _removeData have been replaced + // with direct calls to dataPriv methods, these can be deprecated. + _data: function( elem, name, data ) { + return dataPriv.access( elem, name, data ); + }, + + _removeData: function( elem, name ) { + dataPriv.remove( elem, name ); + } +} ); + +jQuery.fn.extend( { + data: function( key, value ) { + var i, name, data, + elem = this[ 0 ], + attrs = elem && elem.attributes; + + // Gets all values + if ( key === undefined ) { + if ( this.length ) { + data = dataUser.get( elem ); + + if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) { + i = attrs.length; + while ( i-- ) { + + // Support: IE 11 only + // The attrs elements can be null (#14894) + if ( attrs[ i ] ) { + name = attrs[ i ].name; + if ( name.indexOf( "data-" ) === 0 ) { + name = camelCase( name.slice( 5 ) ); + dataAttr( elem, name, data[ name ] ); + } + } + } + dataPriv.set( elem, "hasDataAttrs", true ); + } + } + + return data; + } + + // Sets multiple values + if ( typeof key === "object" ) { + return this.each( function() { + dataUser.set( this, key ); + } ); + } + + return access( this, function( value ) { + var data; + + // The calling jQuery object (element matches) is not empty + // (and therefore has an element appears at this[ 0 ]) and the + // `value` parameter was not undefined. An empty jQuery object + // will result in `undefined` for elem = this[ 0 ] which will + // throw an exception if an attempt to read a data cache is made. + if ( elem && value === undefined ) { + + // Attempt to get data from the cache + // The key will always be camelCased in Data + data = dataUser.get( elem, key ); + if ( data !== undefined ) { + return data; + } + + // Attempt to "discover" the data in + // HTML5 custom data-* attrs + data = dataAttr( elem, key ); + if ( data !== undefined ) { + return data; + } + + // We tried really hard, but the data doesn't exist. + return; + } + + // Set the data... + this.each( function() { + + // We always store the camelCased key + dataUser.set( this, key, value ); + } ); + }, null, value, arguments.length > 1, null, true ); + }, + + removeData: function( key ) { + return this.each( function() { + dataUser.remove( this, key ); + } ); + } +} ); + + +jQuery.extend( { + queue: function( elem, type, data ) { + var queue; + + if ( elem ) { + type = ( type || "fx" ) + "queue"; + queue = dataPriv.get( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !queue || Array.isArray( data ) ) { + queue = dataPriv.access( elem, type, jQuery.makeArray( data ) ); + } else { + queue.push( data ); + } + } + return queue || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + startLength = queue.length, + fn = queue.shift(), + hooks = jQuery._queueHooks( elem, type ), + next = function() { + jQuery.dequeue( elem, type ); + }; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + startLength--; + } + + if ( fn ) { + + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift( "inprogress" ); + } + + // Clear up the last queue stop function + delete hooks.stop; + fn.call( elem, next, hooks ); + } + + if ( !startLength && hooks ) { + hooks.empty.fire(); + } + }, + + // Not public - generate a queueHooks object, or return the current one + _queueHooks: function( elem, type ) { + var key = type + "queueHooks"; + return dataPriv.get( elem, key ) || dataPriv.access( elem, key, { + empty: jQuery.Callbacks( "once memory" ).add( function() { + dataPriv.remove( elem, [ type + "queue", key ] ); + } ) + } ); + } +} ); + +jQuery.fn.extend( { + queue: function( type, data ) { + var setter = 2; + + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + setter--; + } + + if ( arguments.length < setter ) { + return jQuery.queue( this[ 0 ], type ); + } + + return data === undefined ? + this : + this.each( function() { + var queue = jQuery.queue( this, type, data ); + + // Ensure a hooks for this queue + jQuery._queueHooks( this, type ); + + if ( type === "fx" && queue[ 0 ] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + } ); + }, + dequeue: function( type ) { + return this.each( function() { + jQuery.dequeue( this, type ); + } ); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, obj ) { + var tmp, + count = 1, + defer = jQuery.Deferred(), + elements = this, + i = this.length, + resolve = function() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + }; + + if ( typeof type !== "string" ) { + obj = type; + type = undefined; + } + type = type || "fx"; + + while ( i-- ) { + tmp = dataPriv.get( elements[ i ], type + "queueHooks" ); + if ( tmp && tmp.empty ) { + count++; + tmp.empty.add( resolve ); + } + } + resolve(); + return defer.promise( obj ); + } +} ); +var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source; + +var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ); + + +var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; + +var documentElement = document.documentElement; + + + + var isAttached = function( elem ) { + return jQuery.contains( elem.ownerDocument, elem ); + }, + composed = { composed: true }; + + // Support: IE 9 - 11+, Edge 12 - 18+, iOS 10.0 - 10.2 only + // Check attachment across shadow DOM boundaries when possible (gh-3504) + // Support: iOS 10.0-10.2 only + // Early iOS 10 versions support `attachShadow` but not `getRootNode`, + // leading to errors. We need to check for `getRootNode`. + if ( documentElement.getRootNode ) { + isAttached = function( elem ) { + return jQuery.contains( elem.ownerDocument, elem ) || + elem.getRootNode( composed ) === elem.ownerDocument; + }; + } +var isHiddenWithinTree = function( elem, el ) { + + // isHiddenWithinTree might be called from jQuery#filter function; + // in that case, element will be second argument + elem = el || elem; + + // Inline style trumps all + return elem.style.display === "none" || + elem.style.display === "" && + + // Otherwise, check computed style + // Support: Firefox <=43 - 45 + // Disconnected elements can have computed display: none, so first confirm that elem is + // in the document. + isAttached( elem ) && + + jQuery.css( elem, "display" ) === "none"; + }; + + + +function adjustCSS( elem, prop, valueParts, tween ) { + var adjusted, scale, + maxIterations = 20, + currentValue = tween ? + function() { + return tween.cur(); + } : + function() { + return jQuery.css( elem, prop, "" ); + }, + initial = currentValue(), + unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ), + + // Starting value computation is required for potential unit mismatches + initialInUnit = elem.nodeType && + ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && + rcssNum.exec( jQuery.css( elem, prop ) ); + + if ( initialInUnit && initialInUnit[ 3 ] !== unit ) { + + // Support: Firefox <=54 + // Halve the iteration target value to prevent interference from CSS upper bounds (gh-2144) + initial = initial / 2; + + // Trust units reported by jQuery.css + unit = unit || initialInUnit[ 3 ]; + + // Iteratively approximate from a nonzero starting point + initialInUnit = +initial || 1; + + while ( maxIterations-- ) { + + // Evaluate and update our best guess (doubling guesses that zero out). + // Finish if the scale equals or crosses 1 (making the old*new product non-positive). + jQuery.style( elem, prop, initialInUnit + unit ); + if ( ( 1 - scale ) * ( 1 - ( scale = currentValue() / initial || 0.5 ) ) <= 0 ) { + maxIterations = 0; + } + initialInUnit = initialInUnit / scale; + + } + + initialInUnit = initialInUnit * 2; + jQuery.style( elem, prop, initialInUnit + unit ); + + // Make sure we update the tween properties later on + valueParts = valueParts || []; + } + + if ( valueParts ) { + initialInUnit = +initialInUnit || +initial || 0; + + // Apply relative offset (+=/-=) if specified + adjusted = valueParts[ 1 ] ? + initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] : + +valueParts[ 2 ]; + if ( tween ) { + tween.unit = unit; + tween.start = initialInUnit; + tween.end = adjusted; + } + } + return adjusted; +} + + +var defaultDisplayMap = {}; + +function getDefaultDisplay( elem ) { + var temp, + doc = elem.ownerDocument, + nodeName = elem.nodeName, + display = defaultDisplayMap[ nodeName ]; + + if ( display ) { + return display; + } + + temp = doc.body.appendChild( doc.createElement( nodeName ) ); + display = jQuery.css( temp, "display" ); + + temp.parentNode.removeChild( temp ); + + if ( display === "none" ) { + display = "block"; + } + defaultDisplayMap[ nodeName ] = display; + + return display; +} + +function showHide( elements, show ) { + var display, elem, + values = [], + index = 0, + length = elements.length; + + // Determine new display value for elements that need to change + for ( ; index < length; index++ ) { + elem = elements[ index ]; + if ( !elem.style ) { + continue; + } + + display = elem.style.display; + if ( show ) { + + // Since we force visibility upon cascade-hidden elements, an immediate (and slow) + // check is required in this first loop unless we have a nonempty display value (either + // inline or about-to-be-restored) + if ( display === "none" ) { + values[ index ] = dataPriv.get( elem, "display" ) || null; + if ( !values[ index ] ) { + elem.style.display = ""; + } + } + if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) { + values[ index ] = getDefaultDisplay( elem ); + } + } else { + if ( display !== "none" ) { + values[ index ] = "none"; + + // Remember what we're overwriting + dataPriv.set( elem, "display", display ); + } + } + } + + // Set the display of the elements in a second loop to avoid constant reflow + for ( index = 0; index < length; index++ ) { + if ( values[ index ] != null ) { + elements[ index ].style.display = values[ index ]; + } + } + + return elements; +} + +jQuery.fn.extend( { + show: function() { + return showHide( this, true ); + }, + hide: function() { + return showHide( this ); + }, + toggle: function( state ) { + if ( typeof state === "boolean" ) { + return state ? this.show() : this.hide(); + } + + return this.each( function() { + if ( isHiddenWithinTree( this ) ) { + jQuery( this ).show(); + } else { + jQuery( this ).hide(); + } + } ); + } +} ); +var rcheckableType = ( /^(?:checkbox|radio)$/i ); + +var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]*)/i ); + +var rscriptType = ( /^$|^module$|\/(?:java|ecma)script/i ); + + + +( function() { + var fragment = document.createDocumentFragment(), + div = fragment.appendChild( document.createElement( "div" ) ), + input = document.createElement( "input" ); + + // Support: Android 4.0 - 4.3 only + // Check state lost if the name is set (#11217) + // Support: Windows Web Apps (WWA) + // `name` and `type` must use .setAttribute for WWA (#14901) + input.setAttribute( "type", "radio" ); + input.setAttribute( "checked", "checked" ); + input.setAttribute( "name", "t" ); + + div.appendChild( input ); + + // Support: Android <=4.1 only + // Older WebKit doesn't clone checked state correctly in fragments + support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Support: IE <=11 only + // Make sure textarea (and checkbox) defaultValue is properly cloned + div.innerHTML = ""; + support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; + + // Support: IE <=9 only + // IE <=9 replaces "; + support.option = !!div.lastChild; +} )(); + + +// We have to close these tags to support XHTML (#13200) +var wrapMap = { + + // XHTML parsers do not magically insert elements in the + // same way that tag soup parsers do. So we cannot shorten + // this by omitting or other required elements. + thead: [ 1, "", "
" ], + col: [ 2, "", "
" ], + tr: [ 2, "", "
" ], + td: [ 3, "", "
" ], + + _default: [ 0, "", "" ] +}; + +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + +// Support: IE <=9 only +if ( !support.option ) { + wrapMap.optgroup = wrapMap.option = [ 1, "" ]; +} + + +function getAll( context, tag ) { + + // Support: IE <=9 - 11 only + // Use typeof to avoid zero-argument method invocation on host objects (#15151) + var ret; + + if ( typeof context.getElementsByTagName !== "undefined" ) { + ret = context.getElementsByTagName( tag || "*" ); + + } else if ( typeof context.querySelectorAll !== "undefined" ) { + ret = context.querySelectorAll( tag || "*" ); + + } else { + ret = []; + } + + if ( tag === undefined || tag && nodeName( context, tag ) ) { + return jQuery.merge( [ context ], ret ); + } + + return ret; +} + + +// Mark scripts as having already been evaluated +function setGlobalEval( elems, refElements ) { + var i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + dataPriv.set( + elems[ i ], + "globalEval", + !refElements || dataPriv.get( refElements[ i ], "globalEval" ) + ); + } +} + + +var rhtml = /<|&#?\w+;/; + +function buildFragment( elems, context, scripts, selection, ignored ) { + var elem, tmp, tag, wrap, attached, j, + fragment = context.createDocumentFragment(), + nodes = [], + i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + elem = elems[ i ]; + + if ( elem || elem === 0 ) { + + // Add nodes directly + if ( toType( elem ) === "object" ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); + + // Convert non-html into a text node + } else if ( !rhtml.test( elem ) ) { + nodes.push( context.createTextNode( elem ) ); + + // Convert html into DOM nodes + } else { + tmp = tmp || fragment.appendChild( context.createElement( "div" ) ); + + // Deserialize a standard representation + tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase(); + wrap = wrapMap[ tag ] || wrapMap._default; + tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ]; + + // Descend through wrappers to the right content + j = wrap[ 0 ]; + while ( j-- ) { + tmp = tmp.lastChild; + } + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, tmp.childNodes ); + + // Remember the top-level container + tmp = fragment.firstChild; + + // Ensure the created nodes are orphaned (#12392) + tmp.textContent = ""; + } + } + } + + // Remove wrapper from fragment + fragment.textContent = ""; + + i = 0; + while ( ( elem = nodes[ i++ ] ) ) { + + // Skip elements already in the context collection (trac-4087) + if ( selection && jQuery.inArray( elem, selection ) > -1 ) { + if ( ignored ) { + ignored.push( elem ); + } + continue; + } + + attached = isAttached( elem ); + + // Append to fragment + tmp = getAll( fragment.appendChild( elem ), "script" ); + + // Preserve script evaluation history + if ( attached ) { + setGlobalEval( tmp ); + } + + // Capture executables + if ( scripts ) { + j = 0; + while ( ( elem = tmp[ j++ ] ) ) { + if ( rscriptType.test( elem.type || "" ) ) { + scripts.push( elem ); + } + } + } + } + + return fragment; +} + + +var + rkeyEvent = /^key/, + rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/, + rtypenamespace = /^([^.]*)(?:\.(.+)|)/; + +function returnTrue() { + return true; +} + +function returnFalse() { + return false; +} + +// Support: IE <=9 - 11+ +// focus() and blur() are asynchronous, except when they are no-op. +// So expect focus to be synchronous when the element is already active, +// and blur to be synchronous when the element is not already active. +// (focus and blur are always synchronous in other supported browsers, +// this just defines when we can count on it). +function expectSync( elem, type ) { + return ( elem === safeActiveElement() ) === ( type === "focus" ); +} + +// Support: IE <=9 only +// Accessing document.activeElement can throw unexpectedly +// https://bugs.jquery.com/ticket/13393 +function safeActiveElement() { + try { + return document.activeElement; + } catch ( err ) { } +} + +function on( elem, types, selector, data, fn, one ) { + var origFn, type; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { + + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + on( elem, type, selector, data, types[ type ], one ); + } + return elem; + } + + if ( data == null && fn == null ) { + + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return elem; + } + + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return elem.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + } ); +} + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + global: {}, + + add: function( elem, types, handler, data, selector ) { + + var handleObjIn, eventHandle, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.get( elem ); + + // Only attach events to objects that accept data + if ( !acceptData( elem ) ) { + return; + } + + // Caller can pass in an object of custom data in lieu of the handler + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + selector = handleObjIn.selector; + } + + // Ensure that invalid selectors throw exceptions at attach time + // Evaluate against documentElement in case elem is a non-element node (e.g., document) + if ( selector ) { + jQuery.find.matchesSelector( documentElement, selector ); + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure and main handler, if this is the first + if ( !( events = elemData.events ) ) { + events = elemData.events = Object.create( null ); + } + if ( !( eventHandle = elemData.handle ) ) { + eventHandle = elemData.handle = function( e ) { + + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ? + jQuery.event.dispatch.apply( elem, arguments ) : undefined; + }; + } + + // Handle multiple events separated by a space + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // There *must* be a type, no attaching namespace-only handlers + if ( !type ) { + continue; + } + + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[ type ] || {}; + + // If selector defined, determine special event api type, otherwise given type + type = ( selector ? special.delegateType : special.bindType ) || type; + + // Update special based on newly reset type + special = jQuery.event.special[ type ] || {}; + + // handleObj is passed to all event handlers + handleObj = jQuery.extend( { + type: type, + origType: origType, + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + needsContext: selector && jQuery.expr.match.needsContext.test( selector ), + namespace: namespaces.join( "." ) + }, handleObjIn ); + + // Init the event handler queue if we're the first + if ( !( handlers = events[ type ] ) ) { + handlers = events[ type ] = []; + handlers.delegateCount = 0; + + // Only use addEventListener if the special events handler returns false + if ( !special.setup || + special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } + + // Keep track of which events have ever been used, for event optimization + jQuery.event.global[ type ] = true; + } + + }, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + + var j, origCount, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.hasData( elem ) && dataPriv.get( elem ); + + if ( !elemData || !( events = elemData.events ) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + for ( type in events ) { + jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); + } + continue; + } + + special = jQuery.event.special[ type ] || {}; + type = ( selector ? special.delegateType : special.bindType ) || type; + handlers = events[ type ] || []; + tmp = tmp[ 2 ] && + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ); + + // Remove matching events + origCount = j = handlers.length; + while ( j-- ) { + handleObj = handlers[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !tmp || tmp.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || + selector === "**" && handleObj.selector ) ) { + handlers.splice( j, 1 ); + + if ( handleObj.selector ) { + handlers.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + } + + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( origCount && !handlers.length ) { + if ( !special.teardown || + special.teardown.call( elem, namespaces, elemData.handle ) === false ) { + + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove data and the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + dataPriv.remove( elem, "handle events" ); + } + }, + + dispatch: function( nativeEvent ) { + + var i, j, ret, matched, handleObj, handlerQueue, + args = new Array( arguments.length ), + + // Make a writable jQuery.Event from the native event object + event = jQuery.event.fix( nativeEvent ), + + handlers = ( + dataPriv.get( this, "events" ) || Object.create( null ) + )[ event.type ] || [], + special = jQuery.event.special[ event.type ] || {}; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[ 0 ] = event; + + for ( i = 1; i < arguments.length; i++ ) { + args[ i ] = arguments[ i ]; + } + + event.delegateTarget = this; + + // Call the preDispatch hook for the mapped type, and let it bail if desired + if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { + return; + } + + // Determine handlers + handlerQueue = jQuery.event.handlers.call( this, event, handlers ); + + // Run delegates first; they may want to stop propagation beneath us + i = 0; + while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) { + event.currentTarget = matched.elem; + + j = 0; + while ( ( handleObj = matched.handlers[ j++ ] ) && + !event.isImmediatePropagationStopped() ) { + + // If the event is namespaced, then each handler is only invoked if it is + // specially universal or its namespaces are a superset of the event's. + if ( !event.rnamespace || handleObj.namespace === false || + event.rnamespace.test( handleObj.namespace ) ) { + + event.handleObj = handleObj; + event.data = handleObj.data; + + ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle || + handleObj.handler ).apply( matched.elem, args ); + + if ( ret !== undefined ) { + if ( ( event.result = ret ) === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } + + // Call the postDispatch hook for the mapped type + if ( special.postDispatch ) { + special.postDispatch.call( this, event ); + } + + return event.result; + }, + + handlers: function( event, handlers ) { + var i, handleObj, sel, matchedHandlers, matchedSelectors, + handlerQueue = [], + delegateCount = handlers.delegateCount, + cur = event.target; + + // Find delegate handlers + if ( delegateCount && + + // Support: IE <=9 + // Black-hole SVG instance trees (trac-13180) + cur.nodeType && + + // Support: Firefox <=42 + // Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861) + // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click + // Support: IE 11 only + // ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343) + !( event.type === "click" && event.button >= 1 ) ) { + + for ( ; cur !== this; cur = cur.parentNode || this ) { + + // Don't check non-elements (#13208) + // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) + if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) { + matchedHandlers = []; + matchedSelectors = {}; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + + // Don't conflict with Object.prototype properties (#13203) + sel = handleObj.selector + " "; + + if ( matchedSelectors[ sel ] === undefined ) { + matchedSelectors[ sel ] = handleObj.needsContext ? + jQuery( sel, this ).index( cur ) > -1 : + jQuery.find( sel, this, null, [ cur ] ).length; + } + if ( matchedSelectors[ sel ] ) { + matchedHandlers.push( handleObj ); + } + } + if ( matchedHandlers.length ) { + handlerQueue.push( { elem: cur, handlers: matchedHandlers } ); + } + } + } + } + + // Add the remaining (directly-bound) handlers + cur = this; + if ( delegateCount < handlers.length ) { + handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } ); + } + + return handlerQueue; + }, + + addProp: function( name, hook ) { + Object.defineProperty( jQuery.Event.prototype, name, { + enumerable: true, + configurable: true, + + get: isFunction( hook ) ? + function() { + if ( this.originalEvent ) { + return hook( this.originalEvent ); + } + } : + function() { + if ( this.originalEvent ) { + return this.originalEvent[ name ]; + } + }, + + set: function( value ) { + Object.defineProperty( this, name, { + enumerable: true, + configurable: true, + writable: true, + value: value + } ); + } + } ); + }, + + fix: function( originalEvent ) { + return originalEvent[ jQuery.expando ] ? + originalEvent : + new jQuery.Event( originalEvent ); + }, + + special: { + load: { + + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + click: { + + // Utilize native event to ensure correct state for checkable inputs + setup: function( data ) { + + // For mutual compressibility with _default, replace `this` access with a local var. + // `|| data` is dead code meant only to preserve the variable through minification. + var el = this || data; + + // Claim the first handler + if ( rcheckableType.test( el.type ) && + el.click && nodeName( el, "input" ) ) { + + // dataPriv.set( el, "click", ... ) + leverageNative( el, "click", returnTrue ); + } + + // Return false to allow normal processing in the caller + return false; + }, + trigger: function( data ) { + + // For mutual compressibility with _default, replace `this` access with a local var. + // `|| data` is dead code meant only to preserve the variable through minification. + var el = this || data; + + // Force setup before triggering a click + if ( rcheckableType.test( el.type ) && + el.click && nodeName( el, "input" ) ) { + + leverageNative( el, "click" ); + } + + // Return non-false to allow normal event-path propagation + return true; + }, + + // For cross-browser consistency, suppress native .click() on links + // Also prevent it if we're currently inside a leveraged native-event stack + _default: function( event ) { + var target = event.target; + return rcheckableType.test( target.type ) && + target.click && nodeName( target, "input" ) && + dataPriv.get( target, "click" ) || + nodeName( target, "a" ); + } + }, + + beforeunload: { + postDispatch: function( event ) { + + // Support: Firefox 20+ + // Firefox doesn't alert if the returnValue field is not set. + if ( event.result !== undefined && event.originalEvent ) { + event.originalEvent.returnValue = event.result; + } + } + } + } +}; + +// Ensure the presence of an event listener that handles manually-triggered +// synthetic events by interrupting progress until reinvoked in response to +// *native* events that it fires directly, ensuring that state changes have +// already occurred before other listeners are invoked. +function leverageNative( el, type, expectSync ) { + + // Missing expectSync indicates a trigger call, which must force setup through jQuery.event.add + if ( !expectSync ) { + if ( dataPriv.get( el, type ) === undefined ) { + jQuery.event.add( el, type, returnTrue ); + } + return; + } + + // Register the controller as a special universal handler for all event namespaces + dataPriv.set( el, type, false ); + jQuery.event.add( el, type, { + namespace: false, + handler: function( event ) { + var notAsync, result, + saved = dataPriv.get( this, type ); + + if ( ( event.isTrigger & 1 ) && this[ type ] ) { + + // Interrupt processing of the outer synthetic .trigger()ed event + // Saved data should be false in such cases, but might be a leftover capture object + // from an async native handler (gh-4350) + if ( !saved.length ) { + + // Store arguments for use when handling the inner native event + // There will always be at least one argument (an event object), so this array + // will not be confused with a leftover capture object. + saved = slice.call( arguments ); + dataPriv.set( this, type, saved ); + + // Trigger the native event and capture its result + // Support: IE <=9 - 11+ + // focus() and blur() are asynchronous + notAsync = expectSync( this, type ); + this[ type ](); + result = dataPriv.get( this, type ); + if ( saved !== result || notAsync ) { + dataPriv.set( this, type, false ); + } else { + result = {}; + } + if ( saved !== result ) { + + // Cancel the outer synthetic event + event.stopImmediatePropagation(); + event.preventDefault(); + return result.value; + } + + // If this is an inner synthetic event for an event with a bubbling surrogate + // (focus or blur), assume that the surrogate already propagated from triggering the + // native event and prevent that from happening again here. + // This technically gets the ordering wrong w.r.t. to `.trigger()` (in which the + // bubbling surrogate propagates *after* the non-bubbling base), but that seems + // less bad than duplication. + } else if ( ( jQuery.event.special[ type ] || {} ).delegateType ) { + event.stopPropagation(); + } + + // If this is a native event triggered above, everything is now in order + // Fire an inner synthetic event with the original arguments + } else if ( saved.length ) { + + // ...and capture the result + dataPriv.set( this, type, { + value: jQuery.event.trigger( + + // Support: IE <=9 - 11+ + // Extend with the prototype to reset the above stopImmediatePropagation() + jQuery.extend( saved[ 0 ], jQuery.Event.prototype ), + saved.slice( 1 ), + this + ) + } ); + + // Abort handling of the native event + event.stopImmediatePropagation(); + } + } + } ); +} + +jQuery.removeEvent = function( elem, type, handle ) { + + // This "if" is needed for plain objects + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle ); + } +}; + +jQuery.Event = function( src, props ) { + + // Allow instantiation without the 'new' keyword + if ( !( this instanceof jQuery.Event ) ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = src.defaultPrevented || + src.defaultPrevented === undefined && + + // Support: Android <=2.3 only + src.returnValue === false ? + returnTrue : + returnFalse; + + // Create target properties + // Support: Safari <=6 - 7 only + // Target should not be a text node (#504, #13143) + this.target = ( src.target && src.target.nodeType === 3 ) ? + src.target.parentNode : + src.target; + + this.currentTarget = src.currentTarget; + this.relatedTarget = src.relatedTarget; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || Date.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + constructor: jQuery.Event, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse, + isSimulated: false, + + preventDefault: function() { + var e = this.originalEvent; + + this.isDefaultPrevented = returnTrue; + + if ( e && !this.isSimulated ) { + e.preventDefault(); + } + }, + stopPropagation: function() { + var e = this.originalEvent; + + this.isPropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopPropagation(); + } + }, + stopImmediatePropagation: function() { + var e = this.originalEvent; + + this.isImmediatePropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopImmediatePropagation(); + } + + this.stopPropagation(); + } +}; + +// Includes all common event props including KeyEvent and MouseEvent specific props +jQuery.each( { + altKey: true, + bubbles: true, + cancelable: true, + changedTouches: true, + ctrlKey: true, + detail: true, + eventPhase: true, + metaKey: true, + pageX: true, + pageY: true, + shiftKey: true, + view: true, + "char": true, + code: true, + charCode: true, + key: true, + keyCode: true, + button: true, + buttons: true, + clientX: true, + clientY: true, + offsetX: true, + offsetY: true, + pointerId: true, + pointerType: true, + screenX: true, + screenY: true, + targetTouches: true, + toElement: true, + touches: true, + + which: function( event ) { + var button = event.button; + + // Add which for key events + if ( event.which == null && rkeyEvent.test( event.type ) ) { + return event.charCode != null ? event.charCode : event.keyCode; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + if ( !event.which && button !== undefined && rmouseEvent.test( event.type ) ) { + if ( button & 1 ) { + return 1; + } + + if ( button & 2 ) { + return 3; + } + + if ( button & 4 ) { + return 2; + } + + return 0; + } + + return event.which; + } +}, jQuery.event.addProp ); + +jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateType ) { + jQuery.event.special[ type ] = { + + // Utilize native event if possible so blur/focus sequence is correct + setup: function() { + + // Claim the first handler + // dataPriv.set( this, "focus", ... ) + // dataPriv.set( this, "blur", ... ) + leverageNative( this, type, expectSync ); + + // Return false to allow normal processing in the caller + return false; + }, + trigger: function() { + + // Force setup before trigger + leverageNative( this, type ); + + // Return non-false to allow normal event-path propagation + return true; + }, + + delegateType: delegateType + }; +} ); + +// Create mouseenter/leave events using mouseover/out and event-time checks +// so that event delegation works in jQuery. +// Do the same for pointerenter/pointerleave and pointerover/pointerout +// +// Support: Safari 7 only +// Safari sends mouseenter too often; see: +// https://bugs.chromium.org/p/chromium/issues/detail?id=470258 +// for the description of the bug (it existed in older Chrome versions as well). +jQuery.each( { + mouseenter: "mouseover", + mouseleave: "mouseout", + pointerenter: "pointerover", + pointerleave: "pointerout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var ret, + target = this, + related = event.relatedTarget, + handleObj = event.handleObj; + + // For mouseenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) { + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = fix; + } + return ret; + } + }; +} ); + +jQuery.fn.extend( { + + on: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn ); + }, + one: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + var handleObj, type; + if ( types && types.preventDefault && types.handleObj ) { + + // ( event ) dispatched jQuery.Event + handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace ? + handleObj.origType + "." + handleObj.namespace : + handleObj.origType, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + + // ( types-object [, selector] ) + for ( type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each( function() { + jQuery.event.remove( this, types, fn, selector ); + } ); + } +} ); + + +var + + // Support: IE <=10 - 11, Edge 12 - 13 only + // In IE/Edge using regex groups here causes severe slowdowns. + // See https://connect.microsoft.com/IE/feedback/details/1736512/ + rnoInnerhtml = /\s*$/g; + +// Prefer a tbody over its parent table for containing new rows +function manipulationTarget( elem, content ) { + if ( nodeName( elem, "table" ) && + nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) { + + return jQuery( elem ).children( "tbody" )[ 0 ] || elem; + } + + return elem; +} + +// Replace/restore the type attribute of script elements for safe DOM manipulation +function disableScript( elem ) { + elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type; + return elem; +} +function restoreScript( elem ) { + if ( ( elem.type || "" ).slice( 0, 5 ) === "true/" ) { + elem.type = elem.type.slice( 5 ); + } else { + elem.removeAttribute( "type" ); + } + + return elem; +} + +function cloneCopyEvent( src, dest ) { + var i, l, type, pdataOld, udataOld, udataCur, events; + + if ( dest.nodeType !== 1 ) { + return; + } + + // 1. Copy private data: events, handlers, etc. + if ( dataPriv.hasData( src ) ) { + pdataOld = dataPriv.get( src ); + events = pdataOld.events; + + if ( events ) { + dataPriv.remove( dest, "handle events" ); + + for ( type in events ) { + for ( i = 0, l = events[ type ].length; i < l; i++ ) { + jQuery.event.add( dest, type, events[ type ][ i ] ); + } + } + } + } + + // 2. Copy user data + if ( dataUser.hasData( src ) ) { + udataOld = dataUser.access( src ); + udataCur = jQuery.extend( {}, udataOld ); + + dataUser.set( dest, udataCur ); + } +} + +// Fix IE bugs, see support tests +function fixInput( src, dest ) { + var nodeName = dest.nodeName.toLowerCase(); + + // Fails to persist the checked state of a cloned checkbox or radio button. + if ( nodeName === "input" && rcheckableType.test( src.type ) ) { + dest.checked = src.checked; + + // Fails to return the selected option to the default selected state when cloning options + } else if ( nodeName === "input" || nodeName === "textarea" ) { + dest.defaultValue = src.defaultValue; + } +} + +function domManip( collection, args, callback, ignored ) { + + // Flatten any nested arrays + args = flat( args ); + + var fragment, first, scripts, hasScripts, node, doc, + i = 0, + l = collection.length, + iNoClone = l - 1, + value = args[ 0 ], + valueIsFunction = isFunction( value ); + + // We can't cloneNode fragments that contain checked, in WebKit + if ( valueIsFunction || + ( l > 1 && typeof value === "string" && + !support.checkClone && rchecked.test( value ) ) ) { + return collection.each( function( index ) { + var self = collection.eq( index ); + if ( valueIsFunction ) { + args[ 0 ] = value.call( this, index, self.html() ); + } + domManip( self, args, callback, ignored ); + } ); + } + + if ( l ) { + fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored ); + first = fragment.firstChild; + + if ( fragment.childNodes.length === 1 ) { + fragment = first; + } + + // Require either new content or an interest in ignored elements to invoke the callback + if ( first || ignored ) { + scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); + hasScripts = scripts.length; + + // Use the original fragment for the last item + // instead of the first because it can end up + // being emptied incorrectly in certain situations (#8070). + for ( ; i < l; i++ ) { + node = fragment; + + if ( i !== iNoClone ) { + node = jQuery.clone( node, true, true ); + + // Keep references to cloned scripts for later restoration + if ( hasScripts ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( scripts, getAll( node, "script" ) ); + } + } + + callback.call( collection[ i ], node, i ); + } + + if ( hasScripts ) { + doc = scripts[ scripts.length - 1 ].ownerDocument; + + // Reenable scripts + jQuery.map( scripts, restoreScript ); + + // Evaluate executable scripts on first document insertion + for ( i = 0; i < hasScripts; i++ ) { + node = scripts[ i ]; + if ( rscriptType.test( node.type || "" ) && + !dataPriv.access( node, "globalEval" ) && + jQuery.contains( doc, node ) ) { + + if ( node.src && ( node.type || "" ).toLowerCase() !== "module" ) { + + // Optional AJAX dependency, but won't run scripts if not present + if ( jQuery._evalUrl && !node.noModule ) { + jQuery._evalUrl( node.src, { + nonce: node.nonce || node.getAttribute( "nonce" ) + }, doc ); + } + } else { + DOMEval( node.textContent.replace( rcleanScript, "" ), node, doc ); + } + } + } + } + } + } + + return collection; +} + +function remove( elem, selector, keepData ) { + var node, + nodes = selector ? jQuery.filter( selector, elem ) : elem, + i = 0; + + for ( ; ( node = nodes[ i ] ) != null; i++ ) { + if ( !keepData && node.nodeType === 1 ) { + jQuery.cleanData( getAll( node ) ); + } + + if ( node.parentNode ) { + if ( keepData && isAttached( node ) ) { + setGlobalEval( getAll( node, "script" ) ); + } + node.parentNode.removeChild( node ); + } + } + + return elem; +} + +jQuery.extend( { + htmlPrefilter: function( html ) { + return html; + }, + + clone: function( elem, dataAndEvents, deepDataAndEvents ) { + var i, l, srcElements, destElements, + clone = elem.cloneNode( true ), + inPage = isAttached( elem ); + + // Fix IE cloning issues + if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && + !jQuery.isXMLDoc( elem ) ) { + + // We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2 + destElements = getAll( clone ); + srcElements = getAll( elem ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + fixInput( srcElements[ i ], destElements[ i ] ); + } + } + + // Copy the events from the original to the clone + if ( dataAndEvents ) { + if ( deepDataAndEvents ) { + srcElements = srcElements || getAll( elem ); + destElements = destElements || getAll( clone ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + cloneCopyEvent( srcElements[ i ], destElements[ i ] ); + } + } else { + cloneCopyEvent( elem, clone ); + } + } + + // Preserve script evaluation history + destElements = getAll( clone, "script" ); + if ( destElements.length > 0 ) { + setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); + } + + // Return the cloned set + return clone; + }, + + cleanData: function( elems ) { + var data, elem, type, + special = jQuery.event.special, + i = 0; + + for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) { + if ( acceptData( elem ) ) { + if ( ( data = elem[ dataPriv.expando ] ) ) { + if ( data.events ) { + for ( type in data.events ) { + if ( special[ type ] ) { + jQuery.event.remove( elem, type ); + + // This is a shortcut to avoid jQuery.event.remove's overhead + } else { + jQuery.removeEvent( elem, type, data.handle ); + } + } + } + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataPriv.expando ] = undefined; + } + if ( elem[ dataUser.expando ] ) { + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataUser.expando ] = undefined; + } + } + } + } +} ); + +jQuery.fn.extend( { + detach: function( selector ) { + return remove( this, selector, true ); + }, + + remove: function( selector ) { + return remove( this, selector ); + }, + + text: function( value ) { + return access( this, function( value ) { + return value === undefined ? + jQuery.text( this ) : + this.empty().each( function() { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + this.textContent = value; + } + } ); + }, null, value, arguments.length ); + }, + + append: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.appendChild( elem ); + } + } ); + }, + + prepend: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.insertBefore( elem, target.firstChild ); + } + } ); + }, + + before: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this ); + } + } ); + }, + + after: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this.nextSibling ); + } + } ); + }, + + empty: function() { + var elem, + i = 0; + + for ( ; ( elem = this[ i ] ) != null; i++ ) { + if ( elem.nodeType === 1 ) { + + // Prevent memory leaks + jQuery.cleanData( getAll( elem, false ) ); + + // Remove any remaining nodes + elem.textContent = ""; + } + } + + return this; + }, + + clone: function( dataAndEvents, deepDataAndEvents ) { + dataAndEvents = dataAndEvents == null ? false : dataAndEvents; + deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; + + return this.map( function() { + return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); + } ); + }, + + html: function( value ) { + return access( this, function( value ) { + var elem = this[ 0 ] || {}, + i = 0, + l = this.length; + + if ( value === undefined && elem.nodeType === 1 ) { + return elem.innerHTML; + } + + // See if we can take a shortcut and just use innerHTML + if ( typeof value === "string" && !rnoInnerhtml.test( value ) && + !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { + + value = jQuery.htmlPrefilter( value ); + + try { + for ( ; i < l; i++ ) { + elem = this[ i ] || {}; + + // Remove element nodes and prevent memory leaks + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + elem.innerHTML = value; + } + } + + elem = 0; + + // If using innerHTML throws an exception, use the fallback method + } catch ( e ) {} + } + + if ( elem ) { + this.empty().append( value ); + } + }, null, value, arguments.length ); + }, + + replaceWith: function() { + var ignored = []; + + // Make the changes, replacing each non-ignored context element with the new content + return domManip( this, arguments, function( elem ) { + var parent = this.parentNode; + + if ( jQuery.inArray( this, ignored ) < 0 ) { + jQuery.cleanData( getAll( this ) ); + if ( parent ) { + parent.replaceChild( elem, this ); + } + } + + // Force callback invocation + }, ignored ); + } +} ); + +jQuery.each( { + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" +}, function( name, original ) { + jQuery.fn[ name ] = function( selector ) { + var elems, + ret = [], + insert = jQuery( selector ), + last = insert.length - 1, + i = 0; + + for ( ; i <= last; i++ ) { + elems = i === last ? this : this.clone( true ); + jQuery( insert[ i ] )[ original ]( elems ); + + // Support: Android <=4.0 only, PhantomJS 1 only + // .get() because push.apply(_, arraylike) throws on ancient WebKit + push.apply( ret, elems.get() ); + } + + return this.pushStack( ret ); + }; +} ); +var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" ); + +var getStyles = function( elem ) { + + // Support: IE <=11 only, Firefox <=30 (#15098, #14150) + // IE throws on elements created in popups + // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" + var view = elem.ownerDocument.defaultView; + + if ( !view || !view.opener ) { + view = window; + } + + return view.getComputedStyle( elem ); + }; + +var swap = function( elem, options, callback ) { + var ret, name, + old = {}; + + // Remember the old values, and insert the new ones + for ( name in options ) { + old[ name ] = elem.style[ name ]; + elem.style[ name ] = options[ name ]; + } + + ret = callback.call( elem ); + + // Revert the old values + for ( name in options ) { + elem.style[ name ] = old[ name ]; + } + + return ret; +}; + + +var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" ); + + + +( function() { + + // Executing both pixelPosition & boxSizingReliable tests require only one layout + // so they're executed at the same time to save the second computation. + function computeStyleTests() { + + // This is a singleton, we need to execute it only once + if ( !div ) { + return; + } + + container.style.cssText = "position:absolute;left:-11111px;width:60px;" + + "margin-top:1px;padding:0;border:0"; + div.style.cssText = + "position:relative;display:block;box-sizing:border-box;overflow:scroll;" + + "margin:auto;border:1px;padding:1px;" + + "width:60%;top:1%"; + documentElement.appendChild( container ).appendChild( div ); + + var divStyle = window.getComputedStyle( div ); + pixelPositionVal = divStyle.top !== "1%"; + + // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44 + reliableMarginLeftVal = roundPixelMeasures( divStyle.marginLeft ) === 12; + + // Support: Android 4.0 - 4.3 only, Safari <=9.1 - 10.1, iOS <=7.0 - 9.3 + // Some styles come back with percentage values, even though they shouldn't + div.style.right = "60%"; + pixelBoxStylesVal = roundPixelMeasures( divStyle.right ) === 36; + + // Support: IE 9 - 11 only + // Detect misreporting of content dimensions for box-sizing:border-box elements + boxSizingReliableVal = roundPixelMeasures( divStyle.width ) === 36; + + // Support: IE 9 only + // Detect overflow:scroll screwiness (gh-3699) + // Support: Chrome <=64 + // Don't get tricked when zoom affects offsetWidth (gh-4029) + div.style.position = "absolute"; + scrollboxSizeVal = roundPixelMeasures( div.offsetWidth / 3 ) === 12; + + documentElement.removeChild( container ); + + // Nullify the div so it wouldn't be stored in the memory and + // it will also be a sign that checks already performed + div = null; + } + + function roundPixelMeasures( measure ) { + return Math.round( parseFloat( measure ) ); + } + + var pixelPositionVal, boxSizingReliableVal, scrollboxSizeVal, pixelBoxStylesVal, + reliableTrDimensionsVal, reliableMarginLeftVal, + container = document.createElement( "div" ), + div = document.createElement( "div" ); + + // Finish early in limited (non-browser) environments + if ( !div.style ) { + return; + } + + // Support: IE <=9 - 11 only + // Style of cloned element affects source element cloned (#8908) + div.style.backgroundClip = "content-box"; + div.cloneNode( true ).style.backgroundClip = ""; + support.clearCloneStyle = div.style.backgroundClip === "content-box"; + + jQuery.extend( support, { + boxSizingReliable: function() { + computeStyleTests(); + return boxSizingReliableVal; + }, + pixelBoxStyles: function() { + computeStyleTests(); + return pixelBoxStylesVal; + }, + pixelPosition: function() { + computeStyleTests(); + return pixelPositionVal; + }, + reliableMarginLeft: function() { + computeStyleTests(); + return reliableMarginLeftVal; + }, + scrollboxSize: function() { + computeStyleTests(); + return scrollboxSizeVal; + }, + + // Support: IE 9 - 11+, Edge 15 - 18+ + // IE/Edge misreport `getComputedStyle` of table rows with width/height + // set in CSS while `offset*` properties report correct values. + // Behavior in IE 9 is more subtle than in newer versions & it passes + // some versions of this test; make sure not to make it pass there! + reliableTrDimensions: function() { + var table, tr, trChild, trStyle; + if ( reliableTrDimensionsVal == null ) { + table = document.createElement( "table" ); + tr = document.createElement( "tr" ); + trChild = document.createElement( "div" ); + + table.style.cssText = "position:absolute;left:-11111px"; + tr.style.height = "1px"; + trChild.style.height = "9px"; + + documentElement + .appendChild( table ) + .appendChild( tr ) + .appendChild( trChild ); + + trStyle = window.getComputedStyle( tr ); + reliableTrDimensionsVal = parseInt( trStyle.height ) > 3; + + documentElement.removeChild( table ); + } + return reliableTrDimensionsVal; + } + } ); +} )(); + + +function curCSS( elem, name, computed ) { + var width, minWidth, maxWidth, ret, + + // Support: Firefox 51+ + // Retrieving style before computed somehow + // fixes an issue with getting wrong values + // on detached elements + style = elem.style; + + computed = computed || getStyles( elem ); + + // getPropertyValue is needed for: + // .css('filter') (IE 9 only, #12537) + // .css('--customProperty) (#3144) + if ( computed ) { + ret = computed.getPropertyValue( name ) || computed[ name ]; + + if ( ret === "" && !isAttached( elem ) ) { + ret = jQuery.style( elem, name ); + } + + // A tribute to the "awesome hack by Dean Edwards" + // Android Browser returns percentage for some values, + // but width seems to be reliably pixels. + // This is against the CSSOM draft spec: + // https://drafts.csswg.org/cssom/#resolved-values + if ( !support.pixelBoxStyles() && rnumnonpx.test( ret ) && rboxStyle.test( name ) ) { + + // Remember the original values + width = style.width; + minWidth = style.minWidth; + maxWidth = style.maxWidth; + + // Put in the new values to get a computed value out + style.minWidth = style.maxWidth = style.width = ret; + ret = computed.width; + + // Revert the changed values + style.width = width; + style.minWidth = minWidth; + style.maxWidth = maxWidth; + } + } + + return ret !== undefined ? + + // Support: IE <=9 - 11 only + // IE returns zIndex value as an integer. + ret + "" : + ret; +} + + +function addGetHookIf( conditionFn, hookFn ) { + + // Define the hook, we'll check on the first run if it's really needed. + return { + get: function() { + if ( conditionFn() ) { + + // Hook not needed (or it's not possible to use it due + // to missing dependency), remove it. + delete this.get; + return; + } + + // Hook needed; redefine it so that the support test is not executed again. + return ( this.get = hookFn ).apply( this, arguments ); + } + }; +} + + +var cssPrefixes = [ "Webkit", "Moz", "ms" ], + emptyStyle = document.createElement( "div" ).style, + vendorProps = {}; + +// Return a vendor-prefixed property or undefined +function vendorPropName( name ) { + + // Check for vendor prefixed names + var capName = name[ 0 ].toUpperCase() + name.slice( 1 ), + i = cssPrefixes.length; + + while ( i-- ) { + name = cssPrefixes[ i ] + capName; + if ( name in emptyStyle ) { + return name; + } + } +} + +// Return a potentially-mapped jQuery.cssProps or vendor prefixed property +function finalPropName( name ) { + var final = jQuery.cssProps[ name ] || vendorProps[ name ]; + + if ( final ) { + return final; + } + if ( name in emptyStyle ) { + return name; + } + return vendorProps[ name ] = vendorPropName( name ) || name; +} + + +var + + // Swappable if display is none or starts with table + // except "table", "table-cell", or "table-caption" + // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display + rdisplayswap = /^(none|table(?!-c[ea]).+)/, + rcustomProp = /^--/, + cssShow = { position: "absolute", visibility: "hidden", display: "block" }, + cssNormalTransform = { + letterSpacing: "0", + fontWeight: "400" + }; + +function setPositiveNumber( _elem, value, subtract ) { + + // Any relative (+/-) values have already been + // normalized at this point + var matches = rcssNum.exec( value ); + return matches ? + + // Guard against undefined "subtract", e.g., when used as in cssHooks + Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) : + value; +} + +function boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computedVal ) { + var i = dimension === "width" ? 1 : 0, + extra = 0, + delta = 0; + + // Adjustment may not be necessary + if ( box === ( isBorderBox ? "border" : "content" ) ) { + return 0; + } + + for ( ; i < 4; i += 2 ) { + + // Both box models exclude margin + if ( box === "margin" ) { + delta += jQuery.css( elem, box + cssExpand[ i ], true, styles ); + } + + // If we get here with a content-box, we're seeking "padding" or "border" or "margin" + if ( !isBorderBox ) { + + // Add padding + delta += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + + // For "border" or "margin", add border + if ( box !== "padding" ) { + delta += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + + // But still keep track of it otherwise + } else { + extra += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + + // If we get here with a border-box (content + padding + border), we're seeking "content" or + // "padding" or "margin" + } else { + + // For "content", subtract padding + if ( box === "content" ) { + delta -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + } + + // For "content" or "padding", subtract border + if ( box !== "margin" ) { + delta -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } + } + + // Account for positive content-box scroll gutter when requested by providing computedVal + if ( !isBorderBox && computedVal >= 0 ) { + + // offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border + // Assuming integer scroll gutter, subtract the rest and round down + delta += Math.max( 0, Math.ceil( + elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - + computedVal - + delta - + extra - + 0.5 + + // If offsetWidth/offsetHeight is unknown, then we can't determine content-box scroll gutter + // Use an explicit zero to avoid NaN (gh-3964) + ) ) || 0; + } + + return delta; +} + +function getWidthOrHeight( elem, dimension, extra ) { + + // Start with computed style + var styles = getStyles( elem ), + + // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-4322). + // Fake content-box until we know it's needed to know the true value. + boxSizingNeeded = !support.boxSizingReliable() || extra, + isBorderBox = boxSizingNeeded && + jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + valueIsBorderBox = isBorderBox, + + val = curCSS( elem, dimension, styles ), + offsetProp = "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ); + + // Support: Firefox <=54 + // Return a confounding non-pixel value or feign ignorance, as appropriate. + if ( rnumnonpx.test( val ) ) { + if ( !extra ) { + return val; + } + val = "auto"; + } + + + // Support: IE 9 - 11 only + // Use offsetWidth/offsetHeight for when box sizing is unreliable. + // In those cases, the computed value can be trusted to be border-box. + if ( ( !support.boxSizingReliable() && isBorderBox || + + // Support: IE 10 - 11+, Edge 15 - 18+ + // IE/Edge misreport `getComputedStyle` of table rows with width/height + // set in CSS while `offset*` properties report correct values. + // Interestingly, in some cases IE 9 doesn't suffer from this issue. + !support.reliableTrDimensions() && nodeName( elem, "tr" ) || + + // Fall back to offsetWidth/offsetHeight when value is "auto" + // This happens for inline elements with no explicit setting (gh-3571) + val === "auto" || + + // Support: Android <=4.1 - 4.3 only + // Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602) + !parseFloat( val ) && jQuery.css( elem, "display", false, styles ) === "inline" ) && + + // Make sure the element is visible & connected + elem.getClientRects().length ) { + + isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; + + // Where available, offsetWidth/offsetHeight approximate border box dimensions. + // Where not available (e.g., SVG), assume unreliable box-sizing and interpret the + // retrieved value as a content box dimension. + valueIsBorderBox = offsetProp in elem; + if ( valueIsBorderBox ) { + val = elem[ offsetProp ]; + } + } + + // Normalize "" and auto + val = parseFloat( val ) || 0; + + // Adjust for the element's box model + return ( val + + boxModelAdjustment( + elem, + dimension, + extra || ( isBorderBox ? "border" : "content" ), + valueIsBorderBox, + styles, + + // Provide the current computed size to request scroll gutter calculation (gh-3589) + val + ) + ) + "px"; +} + +jQuery.extend( { + + // Add in style property hooks for overriding the default + // behavior of getting and setting a style property + cssHooks: { + opacity: { + get: function( elem, computed ) { + if ( computed ) { + + // We should always get a number back from opacity + var ret = curCSS( elem, "opacity" ); + return ret === "" ? "1" : ret; + } + } + } + }, + + // Don't automatically add "px" to these possibly-unitless properties + cssNumber: { + "animationIterationCount": true, + "columnCount": true, + "fillOpacity": true, + "flexGrow": true, + "flexShrink": true, + "fontWeight": true, + "gridArea": true, + "gridColumn": true, + "gridColumnEnd": true, + "gridColumnStart": true, + "gridRow": true, + "gridRowEnd": true, + "gridRowStart": true, + "lineHeight": true, + "opacity": true, + "order": true, + "orphans": true, + "widows": true, + "zIndex": true, + "zoom": true + }, + + // Add in properties whose names you wish to fix before + // setting or getting the value + cssProps: {}, + + // Get and set the style property on a DOM Node + style: function( elem, name, value, extra ) { + + // Don't set styles on text and comment nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { + return; + } + + // Make sure that we're working with the right name + var ret, type, hooks, + origName = camelCase( name ), + isCustomProp = rcustomProp.test( name ), + style = elem.style; + + // Make sure that we're working with the right name. We don't + // want to query the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Gets hook for the prefixed version, then unprefixed version + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // Check if we're setting a value + if ( value !== undefined ) { + type = typeof value; + + // Convert "+=" or "-=" to relative numbers (#7345) + if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) { + value = adjustCSS( elem, name, ret ); + + // Fixes bug #9237 + type = "number"; + } + + // Make sure that null and NaN values aren't set (#7116) + if ( value == null || value !== value ) { + return; + } + + // If a number was passed in, add the unit (except for certain CSS properties) + // The isCustomProp check can be removed in jQuery 4.0 when we only auto-append + // "px" to a few hardcoded values. + if ( type === "number" && !isCustomProp ) { + value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" ); + } + + // background-* props affect original clone's values + if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) { + style[ name ] = "inherit"; + } + + // If a hook was provided, use that value, otherwise just set the specified value + if ( !hooks || !( "set" in hooks ) || + ( value = hooks.set( elem, value, extra ) ) !== undefined ) { + + if ( isCustomProp ) { + style.setProperty( name, value ); + } else { + style[ name ] = value; + } + } + + } else { + + // If a hook was provided get the non-computed value from there + if ( hooks && "get" in hooks && + ( ret = hooks.get( elem, false, extra ) ) !== undefined ) { + + return ret; + } + + // Otherwise just get the value from the style object + return style[ name ]; + } + }, + + css: function( elem, name, extra, styles ) { + var val, num, hooks, + origName = camelCase( name ), + isCustomProp = rcustomProp.test( name ); + + // Make sure that we're working with the right name. We don't + // want to modify the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Try prefixed name followed by the unprefixed name + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // If a hook was provided get the computed value from there + if ( hooks && "get" in hooks ) { + val = hooks.get( elem, true, extra ); + } + + // Otherwise, if a way to get the computed value exists, use that + if ( val === undefined ) { + val = curCSS( elem, name, styles ); + } + + // Convert "normal" to computed value + if ( val === "normal" && name in cssNormalTransform ) { + val = cssNormalTransform[ name ]; + } + + // Make numeric if forced or a qualifier was provided and val looks numeric + if ( extra === "" || extra ) { + num = parseFloat( val ); + return extra === true || isFinite( num ) ? num || 0 : val; + } + + return val; + } +} ); + +jQuery.each( [ "height", "width" ], function( _i, dimension ) { + jQuery.cssHooks[ dimension ] = { + get: function( elem, computed, extra ) { + if ( computed ) { + + // Certain elements can have dimension info if we invisibly show them + // but it must have a current display style that would benefit + return rdisplayswap.test( jQuery.css( elem, "display" ) ) && + + // Support: Safari 8+ + // Table columns in Safari have non-zero offsetWidth & zero + // getBoundingClientRect().width unless display is changed. + // Support: IE <=11 only + // Running getBoundingClientRect on a disconnected node + // in IE throws an error. + ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ? + swap( elem, cssShow, function() { + return getWidthOrHeight( elem, dimension, extra ); + } ) : + getWidthOrHeight( elem, dimension, extra ); + } + }, + + set: function( elem, value, extra ) { + var matches, + styles = getStyles( elem ), + + // Only read styles.position if the test has a chance to fail + // to avoid forcing a reflow. + scrollboxSizeBuggy = !support.scrollboxSize() && + styles.position === "absolute", + + // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-3991) + boxSizingNeeded = scrollboxSizeBuggy || extra, + isBorderBox = boxSizingNeeded && + jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + subtract = extra ? + boxModelAdjustment( + elem, + dimension, + extra, + isBorderBox, + styles + ) : + 0; + + // Account for unreliable border-box dimensions by comparing offset* to computed and + // faking a content-box to get border and padding (gh-3699) + if ( isBorderBox && scrollboxSizeBuggy ) { + subtract -= Math.ceil( + elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - + parseFloat( styles[ dimension ] ) - + boxModelAdjustment( elem, dimension, "border", false, styles ) - + 0.5 + ); + } + + // Convert to pixels if value adjustment is needed + if ( subtract && ( matches = rcssNum.exec( value ) ) && + ( matches[ 3 ] || "px" ) !== "px" ) { + + elem.style[ dimension ] = value; + value = jQuery.css( elem, dimension ); + } + + return setPositiveNumber( elem, value, subtract ); + } + }; +} ); + +jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft, + function( elem, computed ) { + if ( computed ) { + return ( parseFloat( curCSS( elem, "marginLeft" ) ) || + elem.getBoundingClientRect().left - + swap( elem, { marginLeft: 0 }, function() { + return elem.getBoundingClientRect().left; + } ) + ) + "px"; + } + } +); + +// These hooks are used by animate to expand properties +jQuery.each( { + margin: "", + padding: "", + border: "Width" +}, function( prefix, suffix ) { + jQuery.cssHooks[ prefix + suffix ] = { + expand: function( value ) { + var i = 0, + expanded = {}, + + // Assumes a single number if not a string + parts = typeof value === "string" ? value.split( " " ) : [ value ]; + + for ( ; i < 4; i++ ) { + expanded[ prefix + cssExpand[ i ] + suffix ] = + parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; + } + + return expanded; + } + }; + + if ( prefix !== "margin" ) { + jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; + } +} ); + +jQuery.fn.extend( { + css: function( name, value ) { + return access( this, function( elem, name, value ) { + var styles, len, + map = {}, + i = 0; + + if ( Array.isArray( name ) ) { + styles = getStyles( elem ); + len = name.length; + + for ( ; i < len; i++ ) { + map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); + } + + return map; + } + + return value !== undefined ? + jQuery.style( elem, name, value ) : + jQuery.css( elem, name ); + }, name, value, arguments.length > 1 ); + } +} ); + + +function Tween( elem, options, prop, end, easing ) { + return new Tween.prototype.init( elem, options, prop, end, easing ); +} +jQuery.Tween = Tween; + +Tween.prototype = { + constructor: Tween, + init: function( elem, options, prop, end, easing, unit ) { + this.elem = elem; + this.prop = prop; + this.easing = easing || jQuery.easing._default; + this.options = options; + this.start = this.now = this.cur(); + this.end = end; + this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); + }, + cur: function() { + var hooks = Tween.propHooks[ this.prop ]; + + return hooks && hooks.get ? + hooks.get( this ) : + Tween.propHooks._default.get( this ); + }, + run: function( percent ) { + var eased, + hooks = Tween.propHooks[ this.prop ]; + + if ( this.options.duration ) { + this.pos = eased = jQuery.easing[ this.easing ]( + percent, this.options.duration * percent, 0, 1, this.options.duration + ); + } else { + this.pos = eased = percent; + } + this.now = ( this.end - this.start ) * eased + this.start; + + if ( this.options.step ) { + this.options.step.call( this.elem, this.now, this ); + } + + if ( hooks && hooks.set ) { + hooks.set( this ); + } else { + Tween.propHooks._default.set( this ); + } + return this; + } +}; + +Tween.prototype.init.prototype = Tween.prototype; + +Tween.propHooks = { + _default: { + get: function( tween ) { + var result; + + // Use a property on the element directly when it is not a DOM element, + // or when there is no matching style property that exists. + if ( tween.elem.nodeType !== 1 || + tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) { + return tween.elem[ tween.prop ]; + } + + // Passing an empty string as a 3rd parameter to .css will automatically + // attempt a parseFloat and fallback to a string if the parse fails. + // Simple values such as "10px" are parsed to Float; + // complex values such as "rotate(1rad)" are returned as-is. + result = jQuery.css( tween.elem, tween.prop, "" ); + + // Empty strings, null, undefined and "auto" are converted to 0. + return !result || result === "auto" ? 0 : result; + }, + set: function( tween ) { + + // Use step hook for back compat. + // Use cssHook if its there. + // Use .style if available and use plain properties where available. + if ( jQuery.fx.step[ tween.prop ] ) { + jQuery.fx.step[ tween.prop ]( tween ); + } else if ( tween.elem.nodeType === 1 && ( + jQuery.cssHooks[ tween.prop ] || + tween.elem.style[ finalPropName( tween.prop ) ] != null ) ) { + jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); + } else { + tween.elem[ tween.prop ] = tween.now; + } + } + } +}; + +// Support: IE <=9 only +// Panic based approach to setting things on disconnected nodes +Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { + set: function( tween ) { + if ( tween.elem.nodeType && tween.elem.parentNode ) { + tween.elem[ tween.prop ] = tween.now; + } + } +}; + +jQuery.easing = { + linear: function( p ) { + return p; + }, + swing: function( p ) { + return 0.5 - Math.cos( p * Math.PI ) / 2; + }, + _default: "swing" +}; + +jQuery.fx = Tween.prototype.init; + +// Back compat <1.8 extension point +jQuery.fx.step = {}; + + + + +var + fxNow, inProgress, + rfxtypes = /^(?:toggle|show|hide)$/, + rrun = /queueHooks$/; + +function schedule() { + if ( inProgress ) { + if ( document.hidden === false && window.requestAnimationFrame ) { + window.requestAnimationFrame( schedule ); + } else { + window.setTimeout( schedule, jQuery.fx.interval ); + } + + jQuery.fx.tick(); + } +} + +// Animations created synchronously will run synchronously +function createFxNow() { + window.setTimeout( function() { + fxNow = undefined; + } ); + return ( fxNow = Date.now() ); +} + +// Generate parameters to create a standard animation +function genFx( type, includeWidth ) { + var which, + i = 0, + attrs = { height: type }; + + // If we include width, step value is 1 to do all cssExpand values, + // otherwise step value is 2 to skip over Left and Right + includeWidth = includeWidth ? 1 : 0; + for ( ; i < 4; i += 2 - includeWidth ) { + which = cssExpand[ i ]; + attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; + } + + if ( includeWidth ) { + attrs.opacity = attrs.width = type; + } + + return attrs; +} + +function createTween( value, prop, animation ) { + var tween, + collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ), + index = 0, + length = collection.length; + for ( ; index < length; index++ ) { + if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) { + + // We're done with this property + return tween; + } + } +} + +function defaultPrefilter( elem, props, opts ) { + var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display, + isBox = "width" in props || "height" in props, + anim = this, + orig = {}, + style = elem.style, + hidden = elem.nodeType && isHiddenWithinTree( elem ), + dataShow = dataPriv.get( elem, "fxshow" ); + + // Queue-skipping animations hijack the fx hooks + if ( !opts.queue ) { + hooks = jQuery._queueHooks( elem, "fx" ); + if ( hooks.unqueued == null ) { + hooks.unqueued = 0; + oldfire = hooks.empty.fire; + hooks.empty.fire = function() { + if ( !hooks.unqueued ) { + oldfire(); + } + }; + } + hooks.unqueued++; + + anim.always( function() { + + // Ensure the complete handler is called before this completes + anim.always( function() { + hooks.unqueued--; + if ( !jQuery.queue( elem, "fx" ).length ) { + hooks.empty.fire(); + } + } ); + } ); + } + + // Detect show/hide animations + for ( prop in props ) { + value = props[ prop ]; + if ( rfxtypes.test( value ) ) { + delete props[ prop ]; + toggle = toggle || value === "toggle"; + if ( value === ( hidden ? "hide" : "show" ) ) { + + // Pretend to be hidden if this is a "show" and + // there is still data from a stopped show/hide + if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) { + hidden = true; + + // Ignore all other no-op show/hide data + } else { + continue; + } + } + orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop ); + } + } + + // Bail out if this is a no-op like .hide().hide() + propTween = !jQuery.isEmptyObject( props ); + if ( !propTween && jQuery.isEmptyObject( orig ) ) { + return; + } + + // Restrict "overflow" and "display" styles during box animations + if ( isBox && elem.nodeType === 1 ) { + + // Support: IE <=9 - 11, Edge 12 - 15 + // Record all 3 overflow attributes because IE does not infer the shorthand + // from identically-valued overflowX and overflowY and Edge just mirrors + // the overflowX value there. + opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; + + // Identify a display type, preferring old show/hide data over the CSS cascade + restoreDisplay = dataShow && dataShow.display; + if ( restoreDisplay == null ) { + restoreDisplay = dataPriv.get( elem, "display" ); + } + display = jQuery.css( elem, "display" ); + if ( display === "none" ) { + if ( restoreDisplay ) { + display = restoreDisplay; + } else { + + // Get nonempty value(s) by temporarily forcing visibility + showHide( [ elem ], true ); + restoreDisplay = elem.style.display || restoreDisplay; + display = jQuery.css( elem, "display" ); + showHide( [ elem ] ); + } + } + + // Animate inline elements as inline-block + if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) { + if ( jQuery.css( elem, "float" ) === "none" ) { + + // Restore the original display value at the end of pure show/hide animations + if ( !propTween ) { + anim.done( function() { + style.display = restoreDisplay; + } ); + if ( restoreDisplay == null ) { + display = style.display; + restoreDisplay = display === "none" ? "" : display; + } + } + style.display = "inline-block"; + } + } + } + + if ( opts.overflow ) { + style.overflow = "hidden"; + anim.always( function() { + style.overflow = opts.overflow[ 0 ]; + style.overflowX = opts.overflow[ 1 ]; + style.overflowY = opts.overflow[ 2 ]; + } ); + } + + // Implement show/hide animations + propTween = false; + for ( prop in orig ) { + + // General show/hide setup for this element animation + if ( !propTween ) { + if ( dataShow ) { + if ( "hidden" in dataShow ) { + hidden = dataShow.hidden; + } + } else { + dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } ); + } + + // Store hidden/visible for toggle so `.stop().toggle()` "reverses" + if ( toggle ) { + dataShow.hidden = !hidden; + } + + // Show elements before animating them + if ( hidden ) { + showHide( [ elem ], true ); + } + + /* eslint-disable no-loop-func */ + + anim.done( function() { + + /* eslint-enable no-loop-func */ + + // The final step of a "hide" animation is actually hiding the element + if ( !hidden ) { + showHide( [ elem ] ); + } + dataPriv.remove( elem, "fxshow" ); + for ( prop in orig ) { + jQuery.style( elem, prop, orig[ prop ] ); + } + } ); + } + + // Per-property setup + propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim ); + if ( !( prop in dataShow ) ) { + dataShow[ prop ] = propTween.start; + if ( hidden ) { + propTween.end = propTween.start; + propTween.start = 0; + } + } + } +} + +function propFilter( props, specialEasing ) { + var index, name, easing, value, hooks; + + // camelCase, specialEasing and expand cssHook pass + for ( index in props ) { + name = camelCase( index ); + easing = specialEasing[ name ]; + value = props[ index ]; + if ( Array.isArray( value ) ) { + easing = value[ 1 ]; + value = props[ index ] = value[ 0 ]; + } + + if ( index !== name ) { + props[ name ] = value; + delete props[ index ]; + } + + hooks = jQuery.cssHooks[ name ]; + if ( hooks && "expand" in hooks ) { + value = hooks.expand( value ); + delete props[ name ]; + + // Not quite $.extend, this won't overwrite existing keys. + // Reusing 'index' because we have the correct "name" + for ( index in value ) { + if ( !( index in props ) ) { + props[ index ] = value[ index ]; + specialEasing[ index ] = easing; + } + } + } else { + specialEasing[ name ] = easing; + } + } +} + +function Animation( elem, properties, options ) { + var result, + stopped, + index = 0, + length = Animation.prefilters.length, + deferred = jQuery.Deferred().always( function() { + + // Don't match elem in the :animated selector + delete tick.elem; + } ), + tick = function() { + if ( stopped ) { + return false; + } + var currentTime = fxNow || createFxNow(), + remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), + + // Support: Android 2.3 only + // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497) + temp = remaining / animation.duration || 0, + percent = 1 - temp, + index = 0, + length = animation.tweens.length; + + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( percent ); + } + + deferred.notifyWith( elem, [ animation, percent, remaining ] ); + + // If there's more to do, yield + if ( percent < 1 && length ) { + return remaining; + } + + // If this was an empty animation, synthesize a final progress notification + if ( !length ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + } + + // Resolve the animation and report its conclusion + deferred.resolveWith( elem, [ animation ] ); + return false; + }, + animation = deferred.promise( { + elem: elem, + props: jQuery.extend( {}, properties ), + opts: jQuery.extend( true, { + specialEasing: {}, + easing: jQuery.easing._default + }, options ), + originalProperties: properties, + originalOptions: options, + startTime: fxNow || createFxNow(), + duration: options.duration, + tweens: [], + createTween: function( prop, end ) { + var tween = jQuery.Tween( elem, animation.opts, prop, end, + animation.opts.specialEasing[ prop ] || animation.opts.easing ); + animation.tweens.push( tween ); + return tween; + }, + stop: function( gotoEnd ) { + var index = 0, + + // If we are going to the end, we want to run all the tweens + // otherwise we skip this part + length = gotoEnd ? animation.tweens.length : 0; + if ( stopped ) { + return this; + } + stopped = true; + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( 1 ); + } + + // Resolve when we played the last frame; otherwise, reject + if ( gotoEnd ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + deferred.resolveWith( elem, [ animation, gotoEnd ] ); + } else { + deferred.rejectWith( elem, [ animation, gotoEnd ] ); + } + return this; + } + } ), + props = animation.props; + + propFilter( props, animation.opts.specialEasing ); + + for ( ; index < length; index++ ) { + result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts ); + if ( result ) { + if ( isFunction( result.stop ) ) { + jQuery._queueHooks( animation.elem, animation.opts.queue ).stop = + result.stop.bind( result ); + } + return result; + } + } + + jQuery.map( props, createTween, animation ); + + if ( isFunction( animation.opts.start ) ) { + animation.opts.start.call( elem, animation ); + } + + // Attach callbacks from options + animation + .progress( animation.opts.progress ) + .done( animation.opts.done, animation.opts.complete ) + .fail( animation.opts.fail ) + .always( animation.opts.always ); + + jQuery.fx.timer( + jQuery.extend( tick, { + elem: elem, + anim: animation, + queue: animation.opts.queue + } ) + ); + + return animation; +} + +jQuery.Animation = jQuery.extend( Animation, { + + tweeners: { + "*": [ function( prop, value ) { + var tween = this.createTween( prop, value ); + adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween ); + return tween; + } ] + }, + + tweener: function( props, callback ) { + if ( isFunction( props ) ) { + callback = props; + props = [ "*" ]; + } else { + props = props.match( rnothtmlwhite ); + } + + var prop, + index = 0, + length = props.length; + + for ( ; index < length; index++ ) { + prop = props[ index ]; + Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || []; + Animation.tweeners[ prop ].unshift( callback ); + } + }, + + prefilters: [ defaultPrefilter ], + + prefilter: function( callback, prepend ) { + if ( prepend ) { + Animation.prefilters.unshift( callback ); + } else { + Animation.prefilters.push( callback ); + } + } +} ); + +jQuery.speed = function( speed, easing, fn ) { + var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { + complete: fn || !fn && easing || + isFunction( speed ) && speed, + duration: speed, + easing: fn && easing || easing && !isFunction( easing ) && easing + }; + + // Go to the end state if fx are off + if ( jQuery.fx.off ) { + opt.duration = 0; + + } else { + if ( typeof opt.duration !== "number" ) { + if ( opt.duration in jQuery.fx.speeds ) { + opt.duration = jQuery.fx.speeds[ opt.duration ]; + + } else { + opt.duration = jQuery.fx.speeds._default; + } + } + } + + // Normalize opt.queue - true/undefined/null -> "fx" + if ( opt.queue == null || opt.queue === true ) { + opt.queue = "fx"; + } + + // Queueing + opt.old = opt.complete; + + opt.complete = function() { + if ( isFunction( opt.old ) ) { + opt.old.call( this ); + } + + if ( opt.queue ) { + jQuery.dequeue( this, opt.queue ); + } + }; + + return opt; +}; + +jQuery.fn.extend( { + fadeTo: function( speed, to, easing, callback ) { + + // Show any hidden elements after setting opacity to 0 + return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show() + + // Animate to the value specified + .end().animate( { opacity: to }, speed, easing, callback ); + }, + animate: function( prop, speed, easing, callback ) { + var empty = jQuery.isEmptyObject( prop ), + optall = jQuery.speed( speed, easing, callback ), + doAnimation = function() { + + // Operate on a copy of prop so per-property easing won't be lost + var anim = Animation( this, jQuery.extend( {}, prop ), optall ); + + // Empty animations, or finishing resolves immediately + if ( empty || dataPriv.get( this, "finish" ) ) { + anim.stop( true ); + } + }; + doAnimation.finish = doAnimation; + + return empty || optall.queue === false ? + this.each( doAnimation ) : + this.queue( optall.queue, doAnimation ); + }, + stop: function( type, clearQueue, gotoEnd ) { + var stopQueue = function( hooks ) { + var stop = hooks.stop; + delete hooks.stop; + stop( gotoEnd ); + }; + + if ( typeof type !== "string" ) { + gotoEnd = clearQueue; + clearQueue = type; + type = undefined; + } + if ( clearQueue ) { + this.queue( type || "fx", [] ); + } + + return this.each( function() { + var dequeue = true, + index = type != null && type + "queueHooks", + timers = jQuery.timers, + data = dataPriv.get( this ); + + if ( index ) { + if ( data[ index ] && data[ index ].stop ) { + stopQueue( data[ index ] ); + } + } else { + for ( index in data ) { + if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { + stopQueue( data[ index ] ); + } + } + } + + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && + ( type == null || timers[ index ].queue === type ) ) { + + timers[ index ].anim.stop( gotoEnd ); + dequeue = false; + timers.splice( index, 1 ); + } + } + + // Start the next in the queue if the last step wasn't forced. + // Timers currently will call their complete callbacks, which + // will dequeue but only if they were gotoEnd. + if ( dequeue || !gotoEnd ) { + jQuery.dequeue( this, type ); + } + } ); + }, + finish: function( type ) { + if ( type !== false ) { + type = type || "fx"; + } + return this.each( function() { + var index, + data = dataPriv.get( this ), + queue = data[ type + "queue" ], + hooks = data[ type + "queueHooks" ], + timers = jQuery.timers, + length = queue ? queue.length : 0; + + // Enable finishing flag on private data + data.finish = true; + + // Empty the queue first + jQuery.queue( this, type, [] ); + + if ( hooks && hooks.stop ) { + hooks.stop.call( this, true ); + } + + // Look for any active animations, and finish them + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && timers[ index ].queue === type ) { + timers[ index ].anim.stop( true ); + timers.splice( index, 1 ); + } + } + + // Look for any animations in the old queue and finish them + for ( index = 0; index < length; index++ ) { + if ( queue[ index ] && queue[ index ].finish ) { + queue[ index ].finish.call( this ); + } + } + + // Turn off finishing flag + delete data.finish; + } ); + } +} ); + +jQuery.each( [ "toggle", "show", "hide" ], function( _i, name ) { + var cssFn = jQuery.fn[ name ]; + jQuery.fn[ name ] = function( speed, easing, callback ) { + return speed == null || typeof speed === "boolean" ? + cssFn.apply( this, arguments ) : + this.animate( genFx( name, true ), speed, easing, callback ); + }; +} ); + +// Generate shortcuts for custom animations +jQuery.each( { + slideDown: genFx( "show" ), + slideUp: genFx( "hide" ), + slideToggle: genFx( "toggle" ), + fadeIn: { opacity: "show" }, + fadeOut: { opacity: "hide" }, + fadeToggle: { opacity: "toggle" } +}, function( name, props ) { + jQuery.fn[ name ] = function( speed, easing, callback ) { + return this.animate( props, speed, easing, callback ); + }; +} ); + +jQuery.timers = []; +jQuery.fx.tick = function() { + var timer, + i = 0, + timers = jQuery.timers; + + fxNow = Date.now(); + + for ( ; i < timers.length; i++ ) { + timer = timers[ i ]; + + // Run the timer and safely remove it when done (allowing for external removal) + if ( !timer() && timers[ i ] === timer ) { + timers.splice( i--, 1 ); + } + } + + if ( !timers.length ) { + jQuery.fx.stop(); + } + fxNow = undefined; +}; + +jQuery.fx.timer = function( timer ) { + jQuery.timers.push( timer ); + jQuery.fx.start(); +}; + +jQuery.fx.interval = 13; +jQuery.fx.start = function() { + if ( inProgress ) { + return; + } + + inProgress = true; + schedule(); +}; + +jQuery.fx.stop = function() { + inProgress = null; +}; + +jQuery.fx.speeds = { + slow: 600, + fast: 200, + + // Default speed + _default: 400 +}; + + +// Based off of the plugin by Clint Helfers, with permission. +// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/ +jQuery.fn.delay = function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; + type = type || "fx"; + + return this.queue( type, function( next, hooks ) { + var timeout = window.setTimeout( next, time ); + hooks.stop = function() { + window.clearTimeout( timeout ); + }; + } ); +}; + + +( function() { + var input = document.createElement( "input" ), + select = document.createElement( "select" ), + opt = select.appendChild( document.createElement( "option" ) ); + + input.type = "checkbox"; + + // Support: Android <=4.3 only + // Default value for a checkbox should be "on" + support.checkOn = input.value !== ""; + + // Support: IE <=11 only + // Must access selectedIndex to make default options select + support.optSelected = opt.selected; + + // Support: IE <=11 only + // An input loses its value after becoming a radio + input = document.createElement( "input" ); + input.value = "t"; + input.type = "radio"; + support.radioValue = input.value === "t"; +} )(); + + +var boolHook, + attrHandle = jQuery.expr.attrHandle; + +jQuery.fn.extend( { + attr: function( name, value ) { + return access( this, jQuery.attr, name, value, arguments.length > 1 ); + }, + + removeAttr: function( name ) { + return this.each( function() { + jQuery.removeAttr( this, name ); + } ); + } +} ); + +jQuery.extend( { + attr: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set attributes on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + // Fallback to prop when attributes are not supported + if ( typeof elem.getAttribute === "undefined" ) { + return jQuery.prop( elem, name, value ); + } + + // Attribute hooks are determined by the lowercase version + // Grab necessary hook if one is defined + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + hooks = jQuery.attrHooks[ name.toLowerCase() ] || + ( jQuery.expr.match.bool.test( name ) ? boolHook : undefined ); + } + + if ( value !== undefined ) { + if ( value === null ) { + jQuery.removeAttr( elem, name ); + return; + } + + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + elem.setAttribute( name, value + "" ); + return value; + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + ret = jQuery.find.attr( elem, name ); + + // Non-existent attributes return null, we normalize to undefined + return ret == null ? undefined : ret; + }, + + attrHooks: { + type: { + set: function( elem, value ) { + if ( !support.radioValue && value === "radio" && + nodeName( elem, "input" ) ) { + var val = elem.value; + elem.setAttribute( "type", value ); + if ( val ) { + elem.value = val; + } + return value; + } + } + } + }, + + removeAttr: function( elem, value ) { + var name, + i = 0, + + // Attribute names can contain non-HTML whitespace characters + // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 + attrNames = value && value.match( rnothtmlwhite ); + + if ( attrNames && elem.nodeType === 1 ) { + while ( ( name = attrNames[ i++ ] ) ) { + elem.removeAttribute( name ); + } + } + } +} ); + +// Hooks for boolean attributes +boolHook = { + set: function( elem, value, name ) { + if ( value === false ) { + + // Remove boolean attributes when set to false + jQuery.removeAttr( elem, name ); + } else { + elem.setAttribute( name, name ); + } + return name; + } +}; + +jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( _i, name ) { + var getter = attrHandle[ name ] || jQuery.find.attr; + + attrHandle[ name ] = function( elem, name, isXML ) { + var ret, handle, + lowercaseName = name.toLowerCase(); + + if ( !isXML ) { + + // Avoid an infinite loop by temporarily removing this function from the getter + handle = attrHandle[ lowercaseName ]; + attrHandle[ lowercaseName ] = ret; + ret = getter( elem, name, isXML ) != null ? + lowercaseName : + null; + attrHandle[ lowercaseName ] = handle; + } + return ret; + }; +} ); + + + + +var rfocusable = /^(?:input|select|textarea|button)$/i, + rclickable = /^(?:a|area)$/i; + +jQuery.fn.extend( { + prop: function( name, value ) { + return access( this, jQuery.prop, name, value, arguments.length > 1 ); + }, + + removeProp: function( name ) { + return this.each( function() { + delete this[ jQuery.propFix[ name ] || name ]; + } ); + } +} ); + +jQuery.extend( { + prop: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set properties on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + + // Fix name and attach hooks + name = jQuery.propFix[ name ] || name; + hooks = jQuery.propHooks[ name ]; + } + + if ( value !== undefined ) { + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + return ( elem[ name ] = value ); + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + return elem[ name ]; + }, + + propHooks: { + tabIndex: { + get: function( elem ) { + + // Support: IE <=9 - 11 only + // elem.tabIndex doesn't always return the + // correct value when it hasn't been explicitly set + // https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + // Use proper attribute retrieval(#12072) + var tabindex = jQuery.find.attr( elem, "tabindex" ); + + if ( tabindex ) { + return parseInt( tabindex, 10 ); + } + + if ( + rfocusable.test( elem.nodeName ) || + rclickable.test( elem.nodeName ) && + elem.href + ) { + return 0; + } + + return -1; + } + } + }, + + propFix: { + "for": "htmlFor", + "class": "className" + } +} ); + +// Support: IE <=11 only +// Accessing the selectedIndex property +// forces the browser to respect setting selected +// on the option +// The getter ensures a default option is selected +// when in an optgroup +// eslint rule "no-unused-expressions" is disabled for this code +// since it considers such accessions noop +if ( !support.optSelected ) { + jQuery.propHooks.selected = { + get: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent && parent.parentNode ) { + parent.parentNode.selectedIndex; + } + return null; + }, + set: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent ) { + parent.selectedIndex; + + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + } + }; +} + +jQuery.each( [ + "tabIndex", + "readOnly", + "maxLength", + "cellSpacing", + "cellPadding", + "rowSpan", + "colSpan", + "useMap", + "frameBorder", + "contentEditable" +], function() { + jQuery.propFix[ this.toLowerCase() ] = this; +} ); + + + + + // Strip and collapse whitespace according to HTML spec + // https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace + function stripAndCollapse( value ) { + var tokens = value.match( rnothtmlwhite ) || []; + return tokens.join( " " ); + } + + +function getClass( elem ) { + return elem.getAttribute && elem.getAttribute( "class" ) || ""; +} + +function classesToArray( value ) { + if ( Array.isArray( value ) ) { + return value; + } + if ( typeof value === "string" ) { + return value.match( rnothtmlwhite ) || []; + } + return []; +} + +jQuery.fn.extend( { + addClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).addClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + classes = classesToArray( value ); + + if ( classes.length ) { + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + if ( cur.indexOf( " " + clazz + " " ) < 0 ) { + cur += clazz + " "; + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + removeClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + if ( !arguments.length ) { + return this.attr( "class", "" ); + } + + classes = classesToArray( value ); + + if ( classes.length ) { + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + + // This expression is here for better compressibility (see addClass) + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + + // Remove *all* instances + while ( cur.indexOf( " " + clazz + " " ) > -1 ) { + cur = cur.replace( " " + clazz + " ", " " ); + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value, + isValidValue = type === "string" || Array.isArray( value ); + + if ( typeof stateVal === "boolean" && isValidValue ) { + return stateVal ? this.addClass( value ) : this.removeClass( value ); + } + + if ( isFunction( value ) ) { + return this.each( function( i ) { + jQuery( this ).toggleClass( + value.call( this, i, getClass( this ), stateVal ), + stateVal + ); + } ); + } + + return this.each( function() { + var className, i, self, classNames; + + if ( isValidValue ) { + + // Toggle individual class names + i = 0; + self = jQuery( this ); + classNames = classesToArray( value ); + + while ( ( className = classNames[ i++ ] ) ) { + + // Check each className given, space separated list + if ( self.hasClass( className ) ) { + self.removeClass( className ); + } else { + self.addClass( className ); + } + } + + // Toggle whole class name + } else if ( value === undefined || type === "boolean" ) { + className = getClass( this ); + if ( className ) { + + // Store className if set + dataPriv.set( this, "__className__", className ); + } + + // If the element has a class name or if we're passed `false`, + // then remove the whole classname (if there was one, the above saved it). + // Otherwise bring back whatever was previously saved (if anything), + // falling back to the empty string if nothing was stored. + if ( this.setAttribute ) { + this.setAttribute( "class", + className || value === false ? + "" : + dataPriv.get( this, "__className__" ) || "" + ); + } + } + } ); + }, + + hasClass: function( selector ) { + var className, elem, + i = 0; + + className = " " + selector + " "; + while ( ( elem = this[ i++ ] ) ) { + if ( elem.nodeType === 1 && + ( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) { + return true; + } + } + + return false; + } +} ); + + + + +var rreturn = /\r/g; + +jQuery.fn.extend( { + val: function( value ) { + var hooks, ret, valueIsFunction, + elem = this[ 0 ]; + + if ( !arguments.length ) { + if ( elem ) { + hooks = jQuery.valHooks[ elem.type ] || + jQuery.valHooks[ elem.nodeName.toLowerCase() ]; + + if ( hooks && + "get" in hooks && + ( ret = hooks.get( elem, "value" ) ) !== undefined + ) { + return ret; + } + + ret = elem.value; + + // Handle most common string cases + if ( typeof ret === "string" ) { + return ret.replace( rreturn, "" ); + } + + // Handle cases where value is null/undef or number + return ret == null ? "" : ret; + } + + return; + } + + valueIsFunction = isFunction( value ); + + return this.each( function( i ) { + var val; + + if ( this.nodeType !== 1 ) { + return; + } + + if ( valueIsFunction ) { + val = value.call( this, i, jQuery( this ).val() ); + } else { + val = value; + } + + // Treat null/undefined as ""; convert numbers to string + if ( val == null ) { + val = ""; + + } else if ( typeof val === "number" ) { + val += ""; + + } else if ( Array.isArray( val ) ) { + val = jQuery.map( val, function( value ) { + return value == null ? "" : value + ""; + } ); + } + + hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; + + // If set returns undefined, fall back to normal setting + if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) { + this.value = val; + } + } ); + } +} ); + +jQuery.extend( { + valHooks: { + option: { + get: function( elem ) { + + var val = jQuery.find.attr( elem, "value" ); + return val != null ? + val : + + // Support: IE <=10 - 11 only + // option.text throws exceptions (#14686, #14858) + // Strip and collapse whitespace + // https://html.spec.whatwg.org/#strip-and-collapse-whitespace + stripAndCollapse( jQuery.text( elem ) ); + } + }, + select: { + get: function( elem ) { + var value, option, i, + options = elem.options, + index = elem.selectedIndex, + one = elem.type === "select-one", + values = one ? null : [], + max = one ? index + 1 : options.length; + + if ( index < 0 ) { + i = max; + + } else { + i = one ? index : 0; + } + + // Loop through all the selected options + for ( ; i < max; i++ ) { + option = options[ i ]; + + // Support: IE <=9 only + // IE8-9 doesn't update selected after form reset (#2551) + if ( ( option.selected || i === index ) && + + // Don't return options that are disabled or in a disabled optgroup + !option.disabled && + ( !option.parentNode.disabled || + !nodeName( option.parentNode, "optgroup" ) ) ) { + + // Get the specific value for the option + value = jQuery( option ).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + return values; + }, + + set: function( elem, value ) { + var optionSet, option, + options = elem.options, + values = jQuery.makeArray( value ), + i = options.length; + + while ( i-- ) { + option = options[ i ]; + + /* eslint-disable no-cond-assign */ + + if ( option.selected = + jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1 + ) { + optionSet = true; + } + + /* eslint-enable no-cond-assign */ + } + + // Force browsers to behave consistently when non-matching value is set + if ( !optionSet ) { + elem.selectedIndex = -1; + } + return values; + } + } + } +} ); + +// Radios and checkboxes getter/setter +jQuery.each( [ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = { + set: function( elem, value ) { + if ( Array.isArray( value ) ) { + return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 ); + } + } + }; + if ( !support.checkOn ) { + jQuery.valHooks[ this ].get = function( elem ) { + return elem.getAttribute( "value" ) === null ? "on" : elem.value; + }; + } +} ); + + + + +// Return jQuery for attributes-only inclusion + + +support.focusin = "onfocusin" in window; + + +var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, + stopPropagationCallback = function( e ) { + e.stopPropagation(); + }; + +jQuery.extend( jQuery.event, { + + trigger: function( event, data, elem, onlyHandlers ) { + + var i, cur, tmp, bubbleType, ontype, handle, special, lastElement, + eventPath = [ elem || document ], + type = hasOwn.call( event, "type" ) ? event.type : event, + namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; + + cur = lastElement = tmp = elem = elem || document; + + // Don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // focus/blur morphs to focusin/out; ensure we're not firing them right now + if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { + return; + } + + if ( type.indexOf( "." ) > -1 ) { + + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split( "." ); + type = namespaces.shift(); + namespaces.sort(); + } + ontype = type.indexOf( ":" ) < 0 && "on" + type; + + // Caller can pass in a jQuery.Event object, Object, or just an event type string + event = event[ jQuery.expando ] ? + event : + new jQuery.Event( type, typeof event === "object" && event ); + + // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) + event.isTrigger = onlyHandlers ? 2 : 3; + event.namespace = namespaces.join( "." ); + event.rnamespace = event.namespace ? + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) : + null; + + // Clean up the event in case it is being reused + event.result = undefined; + if ( !event.target ) { + event.target = elem; + } + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data == null ? + [ event ] : + jQuery.makeArray( data, [ event ] ); + + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { + return; + } + + // Determine event propagation path in advance, per W3C events spec (#9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) + if ( !onlyHandlers && !special.noBubble && !isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + if ( !rfocusMorph.test( bubbleType + type ) ) { + cur = cur.parentNode; + } + for ( ; cur; cur = cur.parentNode ) { + eventPath.push( cur ); + tmp = cur; + } + + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( tmp === ( elem.ownerDocument || document ) ) { + eventPath.push( tmp.defaultView || tmp.parentWindow || window ); + } + } + + // Fire handlers on the event path + i = 0; + while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { + lastElement = cur; + event.type = i > 1 ? + bubbleType : + special.bindType || type; + + // jQuery handler + handle = ( + dataPriv.get( cur, "events" ) || Object.create( null ) + )[ event.type ] && + dataPriv.get( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + + // Native handler + handle = ontype && cur[ ontype ]; + if ( handle && handle.apply && acceptData( cur ) ) { + event.result = handle.apply( cur, data ); + if ( event.result === false ) { + event.preventDefault(); + } + } + } + event.type = type; + + // If nobody prevented the default action, do it now + if ( !onlyHandlers && !event.isDefaultPrevented() ) { + + if ( ( !special._default || + special._default.apply( eventPath.pop(), data ) === false ) && + acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name as the event. + // Don't do default actions on window, that's where global variables be (#6170) + if ( ontype && isFunction( elem[ type ] ) && !isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + tmp = elem[ ontype ]; + + if ( tmp ) { + elem[ ontype ] = null; + } + + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + + if ( event.isPropagationStopped() ) { + lastElement.addEventListener( type, stopPropagationCallback ); + } + + elem[ type ](); + + if ( event.isPropagationStopped() ) { + lastElement.removeEventListener( type, stopPropagationCallback ); + } + + jQuery.event.triggered = undefined; + + if ( tmp ) { + elem[ ontype ] = tmp; + } + } + } + } + + return event.result; + }, + + // Piggyback on a donor event to simulate a different one + // Used only for `focus(in | out)` events + simulate: function( type, elem, event ) { + var e = jQuery.extend( + new jQuery.Event(), + event, + { + type: type, + isSimulated: true + } + ); + + jQuery.event.trigger( e, null, elem ); + } + +} ); + +jQuery.fn.extend( { + + trigger: function( type, data ) { + return this.each( function() { + jQuery.event.trigger( type, data, this ); + } ); + }, + triggerHandler: function( type, data ) { + var elem = this[ 0 ]; + if ( elem ) { + return jQuery.event.trigger( type, data, elem, true ); + } + } +} ); + + +// Support: Firefox <=44 +// Firefox doesn't have focus(in | out) events +// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787 +// +// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1 +// focus(in | out) events fire after focus & blur events, +// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order +// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857 +if ( !support.focusin ) { + jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler on the document while someone wants focusin/focusout + var handler = function( event ) { + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) ); + }; + + jQuery.event.special[ fix ] = { + setup: function() { + + // Handle: regular nodes (via `this.ownerDocument`), window + // (via `this.document`) & document (via `this`). + var doc = this.ownerDocument || this.document || this, + attaches = dataPriv.access( doc, fix ); + + if ( !attaches ) { + doc.addEventListener( orig, handler, true ); + } + dataPriv.access( doc, fix, ( attaches || 0 ) + 1 ); + }, + teardown: function() { + var doc = this.ownerDocument || this.document || this, + attaches = dataPriv.access( doc, fix ) - 1; + + if ( !attaches ) { + doc.removeEventListener( orig, handler, true ); + dataPriv.remove( doc, fix ); + + } else { + dataPriv.access( doc, fix, attaches ); + } + } + }; + } ); +} +var location = window.location; + +var nonce = { guid: Date.now() }; + +var rquery = ( /\?/ ); + + + +// Cross-browser xml parsing +jQuery.parseXML = function( data ) { + var xml; + if ( !data || typeof data !== "string" ) { + return null; + } + + // Support: IE 9 - 11 only + // IE throws on parseFromString with invalid input. + try { + xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" ); + } catch ( e ) { + xml = undefined; + } + + if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) { + jQuery.error( "Invalid XML: " + data ); + } + return xml; +}; + + +var + rbracket = /\[\]$/, + rCRLF = /\r?\n/g, + rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, + rsubmittable = /^(?:input|select|textarea|keygen)/i; + +function buildParams( prefix, obj, traditional, add ) { + var name; + + if ( Array.isArray( obj ) ) { + + // Serialize array item. + jQuery.each( obj, function( i, v ) { + if ( traditional || rbracket.test( prefix ) ) { + + // Treat each array item as a scalar. + add( prefix, v ); + + } else { + + // Item is non-scalar (array or object), encode its numeric index. + buildParams( + prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]", + v, + traditional, + add + ); + } + } ); + + } else if ( !traditional && toType( obj ) === "object" ) { + + // Serialize object item. + for ( name in obj ) { + buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); + } + + } else { + + // Serialize scalar item. + add( prefix, obj ); + } +} + +// Serialize an array of form elements or a set of +// key/values into a query string +jQuery.param = function( a, traditional ) { + var prefix, + s = [], + add = function( key, valueOrFunction ) { + + // If value is a function, invoke it and use its return value + var value = isFunction( valueOrFunction ) ? + valueOrFunction() : + valueOrFunction; + + s[ s.length ] = encodeURIComponent( key ) + "=" + + encodeURIComponent( value == null ? "" : value ); + }; + + if ( a == null ) { + return ""; + } + + // If an array was passed in, assume that it is an array of form elements. + if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { + + // Serialize the form elements + jQuery.each( a, function() { + add( this.name, this.value ); + } ); + + } else { + + // If traditional, encode the "old" way (the way 1.3.2 or older + // did it), otherwise encode params recursively. + for ( prefix in a ) { + buildParams( prefix, a[ prefix ], traditional, add ); + } + } + + // Return the resulting serialization + return s.join( "&" ); +}; + +jQuery.fn.extend( { + serialize: function() { + return jQuery.param( this.serializeArray() ); + }, + serializeArray: function() { + return this.map( function() { + + // Can add propHook for "elements" to filter or add form elements + var elements = jQuery.prop( this, "elements" ); + return elements ? jQuery.makeArray( elements ) : this; + } ) + .filter( function() { + var type = this.type; + + // Use .is( ":disabled" ) so that fieldset[disabled] works + return this.name && !jQuery( this ).is( ":disabled" ) && + rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) && + ( this.checked || !rcheckableType.test( type ) ); + } ) + .map( function( _i, elem ) { + var val = jQuery( this ).val(); + + if ( val == null ) { + return null; + } + + if ( Array.isArray( val ) ) { + return jQuery.map( val, function( val ) { + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ); + } + + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ).get(); + } +} ); + + +var + r20 = /%20/g, + rhash = /#.*$/, + rantiCache = /([?&])_=[^&]*/, + rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg, + + // #7653, #8125, #8152: local protocol detection + rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, + rnoContent = /^(?:GET|HEAD)$/, + rprotocol = /^\/\//, + + /* Prefilters + * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) + * 2) These are called: + * - BEFORE asking for a transport + * - AFTER param serialization (s.data is a string if s.processData is true) + * 3) key is the dataType + * 4) the catchall symbol "*" can be used + * 5) execution will start with transport dataType and THEN continue down to "*" if needed + */ + prefilters = {}, + + /* Transports bindings + * 1) key is the dataType + * 2) the catchall symbol "*" can be used + * 3) selection will start with transport dataType and THEN go to "*" if needed + */ + transports = {}, + + // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression + allTypes = "*/".concat( "*" ), + + // Anchor tag for parsing the document origin + originAnchor = document.createElement( "a" ); + originAnchor.href = location.href; + +// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport +function addToPrefiltersOrTransports( structure ) { + + // dataTypeExpression is optional and defaults to "*" + return function( dataTypeExpression, func ) { + + if ( typeof dataTypeExpression !== "string" ) { + func = dataTypeExpression; + dataTypeExpression = "*"; + } + + var dataType, + i = 0, + dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || []; + + if ( isFunction( func ) ) { + + // For each dataType in the dataTypeExpression + while ( ( dataType = dataTypes[ i++ ] ) ) { + + // Prepend if requested + if ( dataType[ 0 ] === "+" ) { + dataType = dataType.slice( 1 ) || "*"; + ( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func ); + + // Otherwise append + } else { + ( structure[ dataType ] = structure[ dataType ] || [] ).push( func ); + } + } + } + }; +} + +// Base inspection function for prefilters and transports +function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) { + + var inspected = {}, + seekingTransport = ( structure === transports ); + + function inspect( dataType ) { + var selected; + inspected[ dataType ] = true; + jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) { + var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR ); + if ( typeof dataTypeOrTransport === "string" && + !seekingTransport && !inspected[ dataTypeOrTransport ] ) { + + options.dataTypes.unshift( dataTypeOrTransport ); + inspect( dataTypeOrTransport ); + return false; + } else if ( seekingTransport ) { + return !( selected = dataTypeOrTransport ); + } + } ); + return selected; + } + + return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" ); +} + +// A special extend for ajax options +// that takes "flat" options (not to be deep extended) +// Fixes #9887 +function ajaxExtend( target, src ) { + var key, deep, + flatOptions = jQuery.ajaxSettings.flatOptions || {}; + + for ( key in src ) { + if ( src[ key ] !== undefined ) { + ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; + } + } + if ( deep ) { + jQuery.extend( true, target, deep ); + } + + return target; +} + +/* Handles responses to an ajax request: + * - finds the right dataType (mediates between content-type and expected dataType) + * - returns the corresponding response + */ +function ajaxHandleResponses( s, jqXHR, responses ) { + + var ct, type, finalDataType, firstDataType, + contents = s.contents, + dataTypes = s.dataTypes; + + // Remove auto dataType and get content-type in the process + while ( dataTypes[ 0 ] === "*" ) { + dataTypes.shift(); + if ( ct === undefined ) { + ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" ); + } + } + + // Check if we're dealing with a known content-type + if ( ct ) { + for ( type in contents ) { + if ( contents[ type ] && contents[ type ].test( ct ) ) { + dataTypes.unshift( type ); + break; + } + } + } + + // Check to see if we have a response for the expected dataType + if ( dataTypes[ 0 ] in responses ) { + finalDataType = dataTypes[ 0 ]; + } else { + + // Try convertible dataTypes + for ( type in responses ) { + if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) { + finalDataType = type; + break; + } + if ( !firstDataType ) { + firstDataType = type; + } + } + + // Or just use first one + finalDataType = finalDataType || firstDataType; + } + + // If we found a dataType + // We add the dataType to the list if needed + // and return the corresponding response + if ( finalDataType ) { + if ( finalDataType !== dataTypes[ 0 ] ) { + dataTypes.unshift( finalDataType ); + } + return responses[ finalDataType ]; + } +} + +/* Chain conversions given the request and the original response + * Also sets the responseXXX fields on the jqXHR instance + */ +function ajaxConvert( s, response, jqXHR, isSuccess ) { + var conv2, current, conv, tmp, prev, + converters = {}, + + // Work with a copy of dataTypes in case we need to modify it for conversion + dataTypes = s.dataTypes.slice(); + + // Create converters map with lowercased keys + if ( dataTypes[ 1 ] ) { + for ( conv in s.converters ) { + converters[ conv.toLowerCase() ] = s.converters[ conv ]; + } + } + + current = dataTypes.shift(); + + // Convert to each sequential dataType + while ( current ) { + + if ( s.responseFields[ current ] ) { + jqXHR[ s.responseFields[ current ] ] = response; + } + + // Apply the dataFilter if provided + if ( !prev && isSuccess && s.dataFilter ) { + response = s.dataFilter( response, s.dataType ); + } + + prev = current; + current = dataTypes.shift(); + + if ( current ) { + + // There's only work to do if current dataType is non-auto + if ( current === "*" ) { + + current = prev; + + // Convert response if prev dataType is non-auto and differs from current + } else if ( prev !== "*" && prev !== current ) { + + // Seek a direct converter + conv = converters[ prev + " " + current ] || converters[ "* " + current ]; + + // If none found, seek a pair + if ( !conv ) { + for ( conv2 in converters ) { + + // If conv2 outputs current + tmp = conv2.split( " " ); + if ( tmp[ 1 ] === current ) { + + // If prev can be converted to accepted input + conv = converters[ prev + " " + tmp[ 0 ] ] || + converters[ "* " + tmp[ 0 ] ]; + if ( conv ) { + + // Condense equivalence converters + if ( conv === true ) { + conv = converters[ conv2 ]; + + // Otherwise, insert the intermediate dataType + } else if ( converters[ conv2 ] !== true ) { + current = tmp[ 0 ]; + dataTypes.unshift( tmp[ 1 ] ); + } + break; + } + } + } + } + + // Apply converter (if not an equivalence) + if ( conv !== true ) { + + // Unless errors are allowed to bubble, catch and return them + if ( conv && s.throws ) { + response = conv( response ); + } else { + try { + response = conv( response ); + } catch ( e ) { + return { + state: "parsererror", + error: conv ? e : "No conversion from " + prev + " to " + current + }; + } + } + } + } + } + } + + return { state: "success", data: response }; +} + +jQuery.extend( { + + // Counter for holding the number of active queries + active: 0, + + // Last-Modified header cache for next request + lastModified: {}, + etag: {}, + + ajaxSettings: { + url: location.href, + type: "GET", + isLocal: rlocalProtocol.test( location.protocol ), + global: true, + processData: true, + async: true, + contentType: "application/x-www-form-urlencoded; charset=UTF-8", + + /* + timeout: 0, + data: null, + dataType: null, + username: null, + password: null, + cache: null, + throws: false, + traditional: false, + headers: {}, + */ + + accepts: { + "*": allTypes, + text: "text/plain", + html: "text/html", + xml: "application/xml, text/xml", + json: "application/json, text/javascript" + }, + + contents: { + xml: /\bxml\b/, + html: /\bhtml/, + json: /\bjson\b/ + }, + + responseFields: { + xml: "responseXML", + text: "responseText", + json: "responseJSON" + }, + + // Data converters + // Keys separate source (or catchall "*") and destination types with a single space + converters: { + + // Convert anything to text + "* text": String, + + // Text to html (true = no transformation) + "text html": true, + + // Evaluate text as a json expression + "text json": JSON.parse, + + // Parse text as xml + "text xml": jQuery.parseXML + }, + + // For options that shouldn't be deep extended: + // you can add your own custom options here if + // and when you create one that shouldn't be + // deep extended (see ajaxExtend) + flatOptions: { + url: true, + context: true + } + }, + + // Creates a full fledged settings object into target + // with both ajaxSettings and settings fields. + // If target is omitted, writes into ajaxSettings. + ajaxSetup: function( target, settings ) { + return settings ? + + // Building a settings object + ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) : + + // Extending ajaxSettings + ajaxExtend( jQuery.ajaxSettings, target ); + }, + + ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), + ajaxTransport: addToPrefiltersOrTransports( transports ), + + // Main method + ajax: function( url, options ) { + + // If url is an object, simulate pre-1.5 signature + if ( typeof url === "object" ) { + options = url; + url = undefined; + } + + // Force options to be an object + options = options || {}; + + var transport, + + // URL without anti-cache param + cacheURL, + + // Response headers + responseHeadersString, + responseHeaders, + + // timeout handle + timeoutTimer, + + // Url cleanup var + urlAnchor, + + // Request state (becomes false upon send and true upon completion) + completed, + + // To know if global events are to be dispatched + fireGlobals, + + // Loop variable + i, + + // uncached part of the url + uncached, + + // Create the final options object + s = jQuery.ajaxSetup( {}, options ), + + // Callbacks context + callbackContext = s.context || s, + + // Context for global events is callbackContext if it is a DOM node or jQuery collection + globalEventContext = s.context && + ( callbackContext.nodeType || callbackContext.jquery ) ? + jQuery( callbackContext ) : + jQuery.event, + + // Deferreds + deferred = jQuery.Deferred(), + completeDeferred = jQuery.Callbacks( "once memory" ), + + // Status-dependent callbacks + statusCode = s.statusCode || {}, + + // Headers (they are sent all at once) + requestHeaders = {}, + requestHeadersNames = {}, + + // Default abort message + strAbort = "canceled", + + // Fake xhr + jqXHR = { + readyState: 0, + + // Builds headers hashtable if needed + getResponseHeader: function( key ) { + var match; + if ( completed ) { + if ( !responseHeaders ) { + responseHeaders = {}; + while ( ( match = rheaders.exec( responseHeadersString ) ) ) { + responseHeaders[ match[ 1 ].toLowerCase() + " " ] = + ( responseHeaders[ match[ 1 ].toLowerCase() + " " ] || [] ) + .concat( match[ 2 ] ); + } + } + match = responseHeaders[ key.toLowerCase() + " " ]; + } + return match == null ? null : match.join( ", " ); + }, + + // Raw string + getAllResponseHeaders: function() { + return completed ? responseHeadersString : null; + }, + + // Caches the header + setRequestHeader: function( name, value ) { + if ( completed == null ) { + name = requestHeadersNames[ name.toLowerCase() ] = + requestHeadersNames[ name.toLowerCase() ] || name; + requestHeaders[ name ] = value; + } + return this; + }, + + // Overrides response content-type header + overrideMimeType: function( type ) { + if ( completed == null ) { + s.mimeType = type; + } + return this; + }, + + // Status-dependent callbacks + statusCode: function( map ) { + var code; + if ( map ) { + if ( completed ) { + + // Execute the appropriate callbacks + jqXHR.always( map[ jqXHR.status ] ); + } else { + + // Lazy-add the new callbacks in a way that preserves old ones + for ( code in map ) { + statusCode[ code ] = [ statusCode[ code ], map[ code ] ]; + } + } + } + return this; + }, + + // Cancel the request + abort: function( statusText ) { + var finalText = statusText || strAbort; + if ( transport ) { + transport.abort( finalText ); + } + done( 0, finalText ); + return this; + } + }; + + // Attach deferreds + deferred.promise( jqXHR ); + + // Add protocol if not provided (prefilters might expect it) + // Handle falsy url in the settings object (#10093: consistency with old signature) + // We also use the url parameter if available + s.url = ( ( url || s.url || location.href ) + "" ) + .replace( rprotocol, location.protocol + "//" ); + + // Alias method option to type as per ticket #12004 + s.type = options.method || options.type || s.method || s.type; + + // Extract dataTypes list + s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnothtmlwhite ) || [ "" ]; + + // A cross-domain request is in order when the origin doesn't match the current origin. + if ( s.crossDomain == null ) { + urlAnchor = document.createElement( "a" ); + + // Support: IE <=8 - 11, Edge 12 - 15 + // IE throws exception on accessing the href property if url is malformed, + // e.g. http://example.com:80x/ + try { + urlAnchor.href = s.url; + + // Support: IE <=8 - 11 only + // Anchor's host property isn't correctly set when s.url is relative + urlAnchor.href = urlAnchor.href; + s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !== + urlAnchor.protocol + "//" + urlAnchor.host; + } catch ( e ) { + + // If there is an error parsing the URL, assume it is crossDomain, + // it can be rejected by the transport if it is invalid + s.crossDomain = true; + } + } + + // Convert data if not already a string + if ( s.data && s.processData && typeof s.data !== "string" ) { + s.data = jQuery.param( s.data, s.traditional ); + } + + // Apply prefilters + inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); + + // If request was aborted inside a prefilter, stop there + if ( completed ) { + return jqXHR; + } + + // We can fire global events as of now if asked to + // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118) + fireGlobals = jQuery.event && s.global; + + // Watch for a new set of requests + if ( fireGlobals && jQuery.active++ === 0 ) { + jQuery.event.trigger( "ajaxStart" ); + } + + // Uppercase the type + s.type = s.type.toUpperCase(); + + // Determine if request has content + s.hasContent = !rnoContent.test( s.type ); + + // Save the URL in case we're toying with the If-Modified-Since + // and/or If-None-Match header later on + // Remove hash to simplify url manipulation + cacheURL = s.url.replace( rhash, "" ); + + // More options handling for requests with no content + if ( !s.hasContent ) { + + // Remember the hash so we can put it back + uncached = s.url.slice( cacheURL.length ); + + // If data is available and should be processed, append data to url + if ( s.data && ( s.processData || typeof s.data === "string" ) ) { + cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data; + + // #9682: remove data so that it's not used in an eventual retry + delete s.data; + } + + // Add or update anti-cache param if needed + if ( s.cache === false ) { + cacheURL = cacheURL.replace( rantiCache, "$1" ); + uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce.guid++ ) + + uncached; + } + + // Put hash and anti-cache on the URL that will be requested (gh-1732) + s.url = cacheURL + uncached; + + // Change '%20' to '+' if this is encoded form body content (gh-2658) + } else if ( s.data && s.processData && + ( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) { + s.data = s.data.replace( r20, "+" ); + } + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + if ( jQuery.lastModified[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] ); + } + if ( jQuery.etag[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] ); + } + } + + // Set the correct header, if data is being sent + if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { + jqXHR.setRequestHeader( "Content-Type", s.contentType ); + } + + // Set the Accepts header for the server, depending on the dataType + jqXHR.setRequestHeader( + "Accept", + s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ? + s.accepts[ s.dataTypes[ 0 ] ] + + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : + s.accepts[ "*" ] + ); + + // Check for headers option + for ( i in s.headers ) { + jqXHR.setRequestHeader( i, s.headers[ i ] ); + } + + // Allow custom headers/mimetypes and early abort + if ( s.beforeSend && + ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) { + + // Abort if not done already and return + return jqXHR.abort(); + } + + // Aborting is no longer a cancellation + strAbort = "abort"; + + // Install callbacks on deferreds + completeDeferred.add( s.complete ); + jqXHR.done( s.success ); + jqXHR.fail( s.error ); + + // Get transport + transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); + + // If no transport, we auto-abort + if ( !transport ) { + done( -1, "No Transport" ); + } else { + jqXHR.readyState = 1; + + // Send global event + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); + } + + // If request was aborted inside ajaxSend, stop there + if ( completed ) { + return jqXHR; + } + + // Timeout + if ( s.async && s.timeout > 0 ) { + timeoutTimer = window.setTimeout( function() { + jqXHR.abort( "timeout" ); + }, s.timeout ); + } + + try { + completed = false; + transport.send( requestHeaders, done ); + } catch ( e ) { + + // Rethrow post-completion exceptions + if ( completed ) { + throw e; + } + + // Propagate others as results + done( -1, e ); + } + } + + // Callback for when everything is done + function done( status, nativeStatusText, responses, headers ) { + var isSuccess, success, error, response, modified, + statusText = nativeStatusText; + + // Ignore repeat invocations + if ( completed ) { + return; + } + + completed = true; + + // Clear timeout if it exists + if ( timeoutTimer ) { + window.clearTimeout( timeoutTimer ); + } + + // Dereference transport for early garbage collection + // (no matter how long the jqXHR object will be used) + transport = undefined; + + // Cache response headers + responseHeadersString = headers || ""; + + // Set readyState + jqXHR.readyState = status > 0 ? 4 : 0; + + // Determine if successful + isSuccess = status >= 200 && status < 300 || status === 304; + + // Get response data + if ( responses ) { + response = ajaxHandleResponses( s, jqXHR, responses ); + } + + // Use a noop converter for missing script + if ( !isSuccess && jQuery.inArray( "script", s.dataTypes ) > -1 ) { + s.converters[ "text script" ] = function() {}; + } + + // Convert no matter what (that way responseXXX fields are always set) + response = ajaxConvert( s, response, jqXHR, isSuccess ); + + // If successful, handle type chaining + if ( isSuccess ) { + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + modified = jqXHR.getResponseHeader( "Last-Modified" ); + if ( modified ) { + jQuery.lastModified[ cacheURL ] = modified; + } + modified = jqXHR.getResponseHeader( "etag" ); + if ( modified ) { + jQuery.etag[ cacheURL ] = modified; + } + } + + // if no content + if ( status === 204 || s.type === "HEAD" ) { + statusText = "nocontent"; + + // if not modified + } else if ( status === 304 ) { + statusText = "notmodified"; + + // If we have data, let's convert it + } else { + statusText = response.state; + success = response.data; + error = response.error; + isSuccess = !error; + } + } else { + + // Extract error from statusText and normalize for non-aborts + error = statusText; + if ( status || !statusText ) { + statusText = "error"; + if ( status < 0 ) { + status = 0; + } + } + } + + // Set data for the fake xhr object + jqXHR.status = status; + jqXHR.statusText = ( nativeStatusText || statusText ) + ""; + + // Success/Error + if ( isSuccess ) { + deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); + } else { + deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); + } + + // Status-dependent callbacks + jqXHR.statusCode( statusCode ); + statusCode = undefined; + + if ( fireGlobals ) { + globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError", + [ jqXHR, s, isSuccess ? success : error ] ); + } + + // Complete + completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); + + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); + + // Handle the global AJAX counter + if ( !( --jQuery.active ) ) { + jQuery.event.trigger( "ajaxStop" ); + } + } + } + + return jqXHR; + }, + + getJSON: function( url, data, callback ) { + return jQuery.get( url, data, callback, "json" ); + }, + + getScript: function( url, callback ) { + return jQuery.get( url, undefined, callback, "script" ); + } +} ); + +jQuery.each( [ "get", "post" ], function( _i, method ) { + jQuery[ method ] = function( url, data, callback, type ) { + + // Shift arguments if data argument was omitted + if ( isFunction( data ) ) { + type = type || callback; + callback = data; + data = undefined; + } + + // The url can be an options object (which then must have .url) + return jQuery.ajax( jQuery.extend( { + url: url, + type: method, + dataType: type, + data: data, + success: callback + }, jQuery.isPlainObject( url ) && url ) ); + }; +} ); + +jQuery.ajaxPrefilter( function( s ) { + var i; + for ( i in s.headers ) { + if ( i.toLowerCase() === "content-type" ) { + s.contentType = s.headers[ i ] || ""; + } + } +} ); + + +jQuery._evalUrl = function( url, options, doc ) { + return jQuery.ajax( { + url: url, + + // Make this explicit, since user can override this through ajaxSetup (#11264) + type: "GET", + dataType: "script", + cache: true, + async: false, + global: false, + + // Only evaluate the response if it is successful (gh-4126) + // dataFilter is not invoked for failure responses, so using it instead + // of the default converter is kludgy but it works. + converters: { + "text script": function() {} + }, + dataFilter: function( response ) { + jQuery.globalEval( response, options, doc ); + } + } ); +}; + + +jQuery.fn.extend( { + wrapAll: function( html ) { + var wrap; + + if ( this[ 0 ] ) { + if ( isFunction( html ) ) { + html = html.call( this[ 0 ] ); + } + + // The elements to wrap the target around + wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true ); + + if ( this[ 0 ].parentNode ) { + wrap.insertBefore( this[ 0 ] ); + } + + wrap.map( function() { + var elem = this; + + while ( elem.firstElementChild ) { + elem = elem.firstElementChild; + } + + return elem; + } ).append( this ); + } + + return this; + }, + + wrapInner: function( html ) { + if ( isFunction( html ) ) { + return this.each( function( i ) { + jQuery( this ).wrapInner( html.call( this, i ) ); + } ); + } + + return this.each( function() { + var self = jQuery( this ), + contents = self.contents(); + + if ( contents.length ) { + contents.wrapAll( html ); + + } else { + self.append( html ); + } + } ); + }, + + wrap: function( html ) { + var htmlIsFunction = isFunction( html ); + + return this.each( function( i ) { + jQuery( this ).wrapAll( htmlIsFunction ? html.call( this, i ) : html ); + } ); + }, + + unwrap: function( selector ) { + this.parent( selector ).not( "body" ).each( function() { + jQuery( this ).replaceWith( this.childNodes ); + } ); + return this; + } +} ); + + +jQuery.expr.pseudos.hidden = function( elem ) { + return !jQuery.expr.pseudos.visible( elem ); +}; +jQuery.expr.pseudos.visible = function( elem ) { + return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ); +}; + + + + +jQuery.ajaxSettings.xhr = function() { + try { + return new window.XMLHttpRequest(); + } catch ( e ) {} +}; + +var xhrSuccessStatus = { + + // File protocol always yields status code 0, assume 200 + 0: 200, + + // Support: IE <=9 only + // #1450: sometimes IE returns 1223 when it should be 204 + 1223: 204 + }, + xhrSupported = jQuery.ajaxSettings.xhr(); + +support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported ); +support.ajax = xhrSupported = !!xhrSupported; + +jQuery.ajaxTransport( function( options ) { + var callback, errorCallback; + + // Cross domain only allowed if supported through XMLHttpRequest + if ( support.cors || xhrSupported && !options.crossDomain ) { + return { + send: function( headers, complete ) { + var i, + xhr = options.xhr(); + + xhr.open( + options.type, + options.url, + options.async, + options.username, + options.password + ); + + // Apply custom fields if provided + if ( options.xhrFields ) { + for ( i in options.xhrFields ) { + xhr[ i ] = options.xhrFields[ i ]; + } + } + + // Override mime type if needed + if ( options.mimeType && xhr.overrideMimeType ) { + xhr.overrideMimeType( options.mimeType ); + } + + // X-Requested-With header + // For cross-domain requests, seeing as conditions for a preflight are + // akin to a jigsaw puzzle, we simply never set it to be sure. + // (it can always be set on a per-request basis or even using ajaxSetup) + // For same-domain requests, won't change header if already provided. + if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) { + headers[ "X-Requested-With" ] = "XMLHttpRequest"; + } + + // Set headers + for ( i in headers ) { + xhr.setRequestHeader( i, headers[ i ] ); + } + + // Callback + callback = function( type ) { + return function() { + if ( callback ) { + callback = errorCallback = xhr.onload = + xhr.onerror = xhr.onabort = xhr.ontimeout = + xhr.onreadystatechange = null; + + if ( type === "abort" ) { + xhr.abort(); + } else if ( type === "error" ) { + + // Support: IE <=9 only + // On a manual native abort, IE9 throws + // errors on any property access that is not readyState + if ( typeof xhr.status !== "number" ) { + complete( 0, "error" ); + } else { + complete( + + // File: protocol always yields status 0; see #8605, #14207 + xhr.status, + xhr.statusText + ); + } + } else { + complete( + xhrSuccessStatus[ xhr.status ] || xhr.status, + xhr.statusText, + + // Support: IE <=9 only + // IE9 has no XHR2 but throws on binary (trac-11426) + // For XHR2 non-text, let the caller handle it (gh-2498) + ( xhr.responseType || "text" ) !== "text" || + typeof xhr.responseText !== "string" ? + { binary: xhr.response } : + { text: xhr.responseText }, + xhr.getAllResponseHeaders() + ); + } + } + }; + }; + + // Listen to events + xhr.onload = callback(); + errorCallback = xhr.onerror = xhr.ontimeout = callback( "error" ); + + // Support: IE 9 only + // Use onreadystatechange to replace onabort + // to handle uncaught aborts + if ( xhr.onabort !== undefined ) { + xhr.onabort = errorCallback; + } else { + xhr.onreadystatechange = function() { + + // Check readyState before timeout as it changes + if ( xhr.readyState === 4 ) { + + // Allow onerror to be called first, + // but that will not handle a native abort + // Also, save errorCallback to a variable + // as xhr.onerror cannot be accessed + window.setTimeout( function() { + if ( callback ) { + errorCallback(); + } + } ); + } + }; + } + + // Create the abort callback + callback = callback( "abort" ); + + try { + + // Do send the request (this may raise an exception) + xhr.send( options.hasContent && options.data || null ); + } catch ( e ) { + + // #14683: Only rethrow if this hasn't been notified as an error yet + if ( callback ) { + throw e; + } + } + }, + + abort: function() { + if ( callback ) { + callback(); + } + } + }; + } +} ); + + + + +// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432) +jQuery.ajaxPrefilter( function( s ) { + if ( s.crossDomain ) { + s.contents.script = false; + } +} ); + +// Install script dataType +jQuery.ajaxSetup( { + accepts: { + script: "text/javascript, application/javascript, " + + "application/ecmascript, application/x-ecmascript" + }, + contents: { + script: /\b(?:java|ecma)script\b/ + }, + converters: { + "text script": function( text ) { + jQuery.globalEval( text ); + return text; + } + } +} ); + +// Handle cache's special case and crossDomain +jQuery.ajaxPrefilter( "script", function( s ) { + if ( s.cache === undefined ) { + s.cache = false; + } + if ( s.crossDomain ) { + s.type = "GET"; + } +} ); + +// Bind script tag hack transport +jQuery.ajaxTransport( "script", function( s ) { + + // This transport only deals with cross domain or forced-by-attrs requests + if ( s.crossDomain || s.scriptAttrs ) { + var script, callback; + return { + send: function( _, complete ) { + script = jQuery( " + + + + + + + + + + + +
+
+
+
+ +
+

Building with configure (*nix including GNU/Linux)

+

If you are going to build Universal Ctags on a popular GNU/Linux +distribution, you can install the tools and libraries that Universal Ctags +requires (or may use) as packages. See GNU/Linux distributions about +the packages.

+

Like most Autotools-based projects, you need to do:

+
$ git clone https://github.com/universal-ctags/ctags.git
+$ cd ctags
+$ ./autogen.sh
+$ ./configure --prefix=/where/you/want # defaults to /usr/local
+$ make
+$ make install # may require extra privileges depending on where to install
+
+
+

After installation the ctags executable will be in $prefix/bin/.

+

autogen.sh runs autoreconf internally. +If you use a (binary oriented) GNU/Linux distribution, autoreconf may +be part of the autoconf package. In addition you may have to install +automake and/or pkg-config, too.

+
+

GNU/Linux distributions

+

Before running ./autogen.sh, install some packages.

+

On Debian-based systems (including Ubuntu), do:

+
$ sudo apt install \
+    gcc make \
+    pkg-config autoconf automake \
+    python3-docutils \
+    libseccomp-dev \
+    libjansson-dev \
+    libyaml-dev \
+    libxml2-dev
+
+
+

On Fedora systems, do:

+
$ sudo dnf install \
+    gcc make \
+    pkgconfig autoconf automake \
+    python3-docutils \
+    libseccomp-devel \
+    jansson-devel \
+    libyaml-devel \
+    libxml2-devel
+
+
+
+
+

Changing the executable’s name

+

On some systems, like certain BSDs, there is already a ‘ctags’ program in the base +system, so it is somewhat inconvenient to have the same name for +Universal Ctags. During the configure stage you can now change +the name of the created executable.

+

To add a prefix ‘ex’ which will result in ‘ctags’ being renamed to ‘exctags’:

+
$ ./configure --program-prefix=ex
+
+
+

To completely change the program’s name run the following:

+
$ ./configure --program-transform-name='s/ctags/my_ctags/; s/etags/myemacs_tags/'
+
+
+

Please remember there is also an ‘etags’ installed alongside ‘ctags’ which you may also want to rename as shown above.

+
+
+

Cross-compilation

+

The way of cross-compilation is a bit complicated because the +build-system of ctags uses packcc, a code generator written in C +language. It means that two C compilers should be installed on you build machine; +one for compiling packcc, another for compiling ctags.

+

We provide two sets of configure variables to affect these two C compilers: +CC, CFLAGS, CPPFLAGS, LDFLAGS variables affect the compiler who compiles ctags. +CC_FOR_BUILD, CPPFLAGS_FOR_BUILD, CPPFLAGS_FOR_BUILD, LDFLAGS_FOR_BUILD variables +affect the compiler who compiles packcc.

+

When native-compiling, FOO_FOR_BUILD is the same as FOO.

+

Here is an example show you how to use these configure variables:

+
$ mkdir ./out
+$ configure \
+        --host=armv7a-linux-androideabi \
+        --prefix=`pwd`/out \
+        --enable-static \
+        --disable-seccomp \
+        CC=/usr/local/opt/android-sdk/ndk-bundle/toolchains/llvm/prebuilt/darwin-x86_64/bin/armv7a-linux-androideabi21-clang \
+        CFLAGS='-v' \
+        CPP='/usr/local/opt/android-sdk/ndk-bundle/toolchains/llvm/prebuilt/darwin-x86_64/bin/armv7a-linux-androideabi21-clang -E' \
+        CPPFLAGS='-I/Users/leleliu008/.ndk-pkg/pkg/jansson/armeabi-v7a/include -I/Users/leleliu008/.ndk-pkg/pkg/libyaml/armeabi-v7a/include -I/Users/leleliu008/.ndk-pkg/pkg/libxml2/armeabi-v7a/include -I/Users/leleliu008/.ndk-pkg/pkg/libiconv/armeabi-v7a/include --sysroot /usr/local/opt/android-sdk/ndk-bundle/toolchains/llvm/prebuilt/darwin-x86_64/sysroot -Qunused-arguments -Dftello=ftell -Dfseeko=fseek' \
+        LDFLAGS='-L/Users/leleliu008/.ndk-pkg/pkg/jansson/armeabi-v7a/lib -L/Users/leleliu008/.ndk-pkg/pkg/libyaml/armeabi-v7a/lib -L/Users/leleliu008/.ndk-pkg/pkg/libxml2/armeabi-v7a/lib -L/Users/leleliu008/.ndk-pkg/pkg/libiconv/armeabi-v7a/lib --sysroot /usr/local/opt/android-sdk/ndk-bundle/toolchains/llvm/prebuilt/darwin-x86_64/sysroot' \
+        AR=/usr/local/opt/android-sdk/ndk-bundle/toolchains/llvm/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-ar \
+        RANLIB=/usr/local/opt/android-sdk/ndk-bundle/toolchains/llvm/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-ranlib \
+        CC_FOR_BUILD=/usr/bin/cc \
+        CFLAGS_FOR_BUILD='-v' \
+        PKG_CONFIG_PATH=/Users/leleliu008/.ndk-pkg/pkg/libiconv/armeabi-v7a/lib/pkgconfig:/Users/leleliu008/.ndk-pkg/pkg/libxml2/armeabi-v7a/lib/pkgconfig:/Users/leleliu008/.ndk-pkg/pkg/libyaml/armeabi-v7a/lib/pkgconfig:/Users/leleliu008/.ndk-pkg/pkg/jansson/armeabi-v7a/lib/pkgconfig \
+        PKG_CONFIG_LIBDIR=/Users/leleliu008/.ndk-pkg/pkg
+...
+$ make
+...
+$ make install
+...
+$ ls out/bin
+ctags readtags
+
+
+

Simpler example for aarch64-linux-gnu can be found in circle.yml in the source tree.

+
+
+ + +
+
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/ctags/docs/building.html b/ctags/docs/building.html new file mode 100644 index 0000000..863a70b --- /dev/null +++ b/ctags/docs/building.html @@ -0,0 +1,121 @@ + + + + + + + + + Building ctags — Universal Ctags 0.3.0 documentation + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ctags/docs/contributions.html b/ctags/docs/contributions.html new file mode 100644 index 0000000..98ebbf2 --- /dev/null +++ b/ctags/docs/contributions.html @@ -0,0 +1,636 @@ + + + + + + + + + Contributions — Universal Ctags 0.3.0 documentation + + + + + + + + + + + + + + + +
+
+
+
+ +
+

Contributions

+
+
Maintainer
+

Masatake YAMATO <yamato@redhat.com>

+
+
+ +
+

You are welcome.

+

Supporting many parsers with few developers is impossible. We invite +the person who contributes a parser to u-ctags team, especially if the +target language is updated frequently. TypeScript is a typical +frequently updated language.

+

This is what we would like potential contributors to know. In this +section “you” means a contributor, and “we” means reviewers. “I” means +Masatake YAMATO, the author of this section.

+

This page gathers random notes for newly joined members.

+
+

Basic rules

+

You are the maintainer of your parser, of course.

+

You may update your parser as you want under the rules described +later.

+

You may review pull requests changing your parser.

+

A parser exists and is maintained independently form other +parsers. However, considering the consistency between parsers are not +bad.

+

You can put your name to docs/developers.rst.

+

Read docs.ctags.io.

+
+
+

Before You Start

+
+
+

When working on ctags I take into account the following uses for +tags:

+
    +
  1. inserting the name with completion,

  2. +
  3. jumping to the definition of the name (in an editor or similar tool),

  4. +
  5. navigating the source code tree,

  6. +
  7. summarizing the source code tree, and

  8. +
  9. answering a query about the source code tree.

  10. +
+

When I review new parser code, I expect the parser to contribute to +these purposes.

+
+

What should be tagged?

+

There are two classes of tags. The primary class is a definition tag. +If a name is defined in a file, the name and the line and the file +where the name is defined should be tagged (recorded). However, in +some languages answering, “What is a definition?” is not so obvious. +You may have to decide what is tagged in your parser thoughtfully. +The purposes listed at the top of this subsection should help you +decide.

+

The secondary class is a reference tag. This is newly introduced in +Universal Ctags and is not available in Exuberant Ctags. If a name is +used (or referenced) in a file, it can be tagged as a reference tag.

+

Don’t be confused by the two tag classes.

+
+
+

Defining kinds and roles

+

Defining kinds is the most important task in writing a new parser. +Once a kind is introduced, we cannot change it because it breaks +tags file compatibility.

+

See TAG ENTRIES in ctags(1) for more details of kinds +and roles.

+
+
+

Scope information and full qualified tags

+

Optional. +TBW.

+
+
+
+

Developing a parser

+
+

Origin of changes and license

+

Make clear where the patches come from and who wrote them.

+

If you backport patches from Geany or some other project, their +commit IDs should be logged, too.

+

Include a copyright notice when adding a new +{parsers,main}/*.[ch] file. +A new file also requires a license notice at the head of the file.

+

We expect your change (or new code) to be provided under the terms of +the General Public License version 2 or any later version. We would +like you to express “version 2 or any later version”.

+
+
+

Reference

+

In the comment at the head of your source file, include a URL for a +web page that explains the language your parser deals with. +Especially if the language is not well known.

+

Here is an example.

+
/*
+*
+*   Copyright (c) 2016, Masatake YAMATO
+*   Copyright (c) 2016, Red Hat, K.K.
+*
+*   This source code is released for free distribution under the terms of the
+*   GNU General Public License version 2 or (at your option) any later version.
+*
+*   This module contains functions for generating tags for property list defined
+*   in http://www.apple.com/DTDs/PropertyList-1.0.dtd.
+*/
+
+
+
+
+

C language

+

Don’t forget to use static modifiers. Don’t introduce unnecessary +global variables.

+

Remove unused variables and types. If you want to keep them in your +source code, include a descriptive comment.

+

Use the available facilities provided by the ctags core. If the +facilities are not enough for writing a parser, consider extending +the core first.

+

Use underscores in names only in file scope objects. +Don’t use them in function declarations, variable declarations or +macro names in header files.

+

Basic whitespace settings are specified in the EditorConfig configuration file (.editorconfig). +There are plugins available +for most popular editors to automatically configure these settings.

+

Style guidelines are largely captured in the Uncrustify configuration file +(.uncrustify.cfg). Formatting can be checked with:

+
$ uncrustify -c .uncrustify.cfg -f parsers/awk.c | diff -u parsers/awk.c -
+
+
+

Don’t mix whitespace cleanup fixes and other improvements in one +commit when changing the existing code. Style fixes, including +whitespace cleanup, should be in a separate commit. Mixing +functional changes with style fixes makes reviewing harder.

+

If possible, don’t use file static variables. Find an alternative way +that uses parameters.

+
+

Notes for GNU emacs users

+

If you use GNU emacs, utilize the .editorconfig configuration based +on non-GNU C style. Here non-GNU C style means +“align a keyword for control flow and { of the block start”.

+

GNU style:

+
if (...)
+    {
+        ...
+
+
+

non-GNU style:

+
if (...)
+{
+        ...
+
+
+

For combining the style and .editorconfig configuration, put +following code snippet to your .emacs:

+
(add-hook 'hack-local-variables-hook
+        (lambda () (editorconfig-apply)))
+
+
+

.dir-locals.el in ctags source tree applies “linux” style of cc-mode. +Above code snippet applies the .editorconfig configuration AFTER +installing the “linux” style to the current buffer.

+

I like GNU style, but for keeping consistency in existing code of +Exuberant Ctags, the origin of Universal Ctags, I introduced the style +and configuration to my .emacs. Please, do the same.

+
+
+
+

Compatibility

+

We are trying to maintain compatibility with Exuberant-ctags in the +following two areas.

+
    +
  • Command line option

  • +
  • Tag file compatibility

  • +
+
+
+

Command line options

+

Don’t introduce --<LANG>-foo=… style options. They are less +suitable for command-line completion by the zsh/bash completion +engines. Instead, introduce --foo-<LANG>=… style options.

+

Add an entry to docs/news.rst if you change the behavior of an option +or introduce a new option. If you think the option is stable enough, +add it to ctags.1.in, too.

+

Use underscore as a prefix for experimental options. Once an option +is introduced, it must be maintained. We don’t want to remove it +later. If you are not sure of the usefulness of the option, use an +underscore at the start of a long option name like: --_echo.

+

Write a test case for Tmain or Units.

+

Don’t remove an option, especially if it exists in Exuberant Ctags.

+
+
+

Writing parser

+

There are two ways to write a parser, writing in C and using optlib parser.

+

Universal Ctags extends the optlib parser feature so extensively that it can +implement most of functions of a parser. +optlib parser is also suitable for prototyping.

+

See ctags-optlib(7) and Extending ctags with Regex parser (optlib) for details. +See Translating an option file into C source code (optlib2c) how to add a optlib parser on ctags.

+

For writing a parser in C see Writing a parser in C.

+
+
+

Build script

+

To add your optlib parser, foo.ctags, into ctags do the following steps;

+
    +
  • put foo.ctags file on optlib/ directory

  • +
  • add foo.ctags on OPTLIB2C_INPUT variable in makefiles/optlib2c_input.mak

  • +
  • add fooParser on PARSER_LIST macro variable in main/parser_p.h

  • +
  • add foo on the list in the section “New parsers” in docs/news.rst

  • +
  • add "..\optlib\foo.c" in win32/ctags_vs2013.vcxproj

  • +
  • add "..\optlib\foo.c" in win32/ctags_vs2013.vcxproj.filters

  • +
+

Translated C code is also committed to our git repository. The translated code +is useful for building ctags on the platforms where optlib2c doesn’t run.

+

To add your parser file, foo.c, into ctags do the following steps;

+
    +
  • put foo.c file on parsers/ directory

  • +
  • add foo.c on PARSER_SRCS variable in sources.mak

  • +
  • add foo on the list in the section “New parsers” in docs/news.rst

  • +
  • add "..\parsers\foo.c" in win32/ctags_vs2013.vcxproj

  • +
  • add "..\parsers\foo.c" in win32/ctags_vs2013.vcxproj.filters

  • +
+

Without updating win32 files our CI process run on Appveyor will fail.

+

See this pull request +for the Meson parser as an example of optlib parser.

+
+
+
+

Testing

+

Add test cases, and run both existing cases and your new cases.

+

If you add a new parser or modify an existing parser, add new test +cases to “Units”. If you modify the core, add new test cases to +“Tmain”. The way to write and run test cases is described in +Testing ctags and Testing a parser section of this guide.

+

With the exception of the tmain test harness, you can specify VG=1 +for running test cases under the Valgrind memory debugger.

+

A parse should not enter an infinite loop for bad input. +A parse should not crash for bad input. +A parse should return control to its caller for bad input.

+

Describe what kind of tests are passed in the commit message. +e.g.

+
make units LANGUAGES=TTCN VG=1 is passed.
+make fuzz LANGUAGES=TTCN VG=1  is passed.
+make chop LANGUAGES=TTCN VG=1  is passed.
+
+
+
+

Test cases

+

Add a test case to Unit when creating or modifying a parser.

+

Add a test case to Tmain when modifying the core.

+

Add a test case to Tinst when modifying the install target in the +Makefile.

+
+
+

Testing your parser

+

If possible, prepare a simple test and a complex one. The simple one +for helping us, the maintainers, understand the intent of the +modification.

+

If there are more than 3 test cases for a parser, a parser specific +test case directory should be prepared like Units/parser-c.r.

+
+
+

Add realistic examples for you parser to codebase

+

At codebase, we +collect realistic examples that can be used for evaluating your parser +especially about its performance aspect. Consider contributing to the +repository when adding a new parser to Universal Ctags.

+
+
+
+

Writing Documents

+
    +
  • man/*.rst files are the source files of our man pages. +The man pages are for users. See “How to add a new man page for your parser”.

  • +
  • docs/*.rst files explain experimental +new features. The files are for developers. The parts of contents +of docs/*.rst should be moved to man/*.rst in the future.

  • +
  • Update docs/news.rst especially if you add a new parser.

  • +
  • Write docs/parser-<NAME-OF-YOUR-PARSER>.rst as you want. +A FAQ and the design or your parser are common topics. +Consider the maintenance of your parser after you left the +project for some reason.

  • +
+
+

How to add a new man page for your parser

+
    +
  1. write what the users of your parser may want to (or should) know to man/ctags-lang-LANGUAGE.7.rst.in

  2. +
  3. add man/ctags-lang-LANGUAGE.7.rst to the list of AC_CONFIG_FILES in configure.ac.

  4. +
  5. add man/ctags-lang-LANGUAGE.7 to man_MANS of Makefile.am.

  6. +
  7. add man/ctags-lang-LANGUAGE.7.rst.in to IN_SOURCE_FILES of man/Makefile.

  8. +
  9. run cd man; make QUICK=1 update-docs. This step generates the rst file at docs/man/ctags-lang-LANGUAGE.7.rst.

  10. +
  11. add ctags-lang-LANGUAGE(7) to (toctree of) docs/man-pages.rst.

  12. +
  13. +
    do git add for
      +
    • man/ctags-lang-LANGUAGE.7.rst.in

    • +
    • configure.ac

    • +
    • Makefile.am

    • +
    • man/Makefile

    • +
    • docs/man/ctags-lang-LANGUAGE.7.rst

    • +
    • docs/man-pages.rst

    • +
    +
    +
    +
  14. +
  15. git commit with a log header: “docs(man): add a man page for LANGUAGE”.

  16. +
  17. make a pull request

  18. +
+
+
+
+

Committing and submitting a pull request

+
    +
  • Make a pull request even if the change is small enough.

  • +
  • Wait for one day till merging even if the change is small enough.

  • +
  • Wait for 3 days at least for non-small change to your parser.

  • +
  • Wait for 7 days at least and get an LGTM (Looks Good To Me) comment from a +member of the team if your commit changes the other parts than your parser and +the changes are not obvious.

  • +
  • Add a test case to your pull request. To make git-bisect happy, +don’t add a test case for a feature or a bugfix before adding the +code for the feature or the bugfix.

  • +
  • Even if a pull request includes multiple commits, each commit must +be semantically well separated. Sometimes you may want to adjust +whitespaces in the code. Adjusting whitespaces is o.k., but don’t +mix the other change with it. Make a commit just for the whitespaces +adjustment.

  • +
+
+

Title of commit log and pull request

+
    +
  • “Misc Fixes” is allowed as far as each commit in a pull request is +semantically well separated. Sometimes, you may fix various minor +things randomly. Making pull requests for each of them is +boring. You may want to make “mix fixes” pull request especially if +your code is young.

  • +
  • Use [WIP] (Work In Progress) prefix as the title of your pull request, if you don’t +want people to take time for reviewing your code. Removing [WIP] +implies “ready to be reviewed.”

  • +
  • Use [FYI] (For Your Information) prefix as the title to show your idea or sketch represented +in C language.

  • +
  • Use the name of your parser as the prefix of a commit log.

    +
    C++: record template type parameters to detect the end of template prefix
    +
    +If we know Foo is a name of type, it becomes easier to detect whether
    +">>" in "Foo>>" is a shift operator or the end marker of the template
    +prefix.
    +
    +
    +

    In the above example, “C++: ” is the prefix.

    +
  • +
  • Use the name of your parser as the prefix of a pull request if your +change is about a parser.

  • +
  • Use following prefixes for the changes other than parsers.

    +
    +
    main:

    Changes for files under main/ directory

    +
    +
    Units:

    Changes for the test cases under Units/ directory

    +
    +
    Tmain

    Changes for the test cases under Tmain/ directory

    +
    +
    docs(web)

    Changes for the docs/*.rst

    +
    +
    docs(man)

    Changes for the man/*.rst

    +
    +
    +

    See also the output of git log command.

    +
  • +
  • Combine prefixes with a comma if a change modifies multiple parts of our source tree

    +

    Here is an example.

    +
    commit 64a05963c108af4b7832a2215006ff5cafcaaebb
    +Author: Masatake YAMATO <yamato@redhat.com>
    +Date:   Tue Mar 19 12:19:37 2019 +0900
    +
    +main,Flex,JavaScript,SQL,refactor: introduce a helper function to skip two character sequence
    +
    +...
    +
    +
    +
  • +
  • Use following prefixes if the change as no run-time impact.

    +
    +
    cosmetic
      +
    • Remove whitespaces at the end of lines

    • +
    • Adjust indentation

    • +
    • Remove an empty line

    • +
    • +
    +
    +
    style
      +
    • Rename symbol names

    • +
    • +
    +
    +
    refactor
      +
    • Code transformation that doesn’t intent changing run-time behavior

    • +
    +
    +
    +

    These prefixes reduce the load of reviewers.

    +
  • +
  • Use [INCOMPATIBLE] as a prefix for both pull request and commit log +if the change breaks the compatibility with Exuberant Ctags. Write +an explanation in man/ctags-incompatibilities.7.rst.in about the +detail of breakage.

  • +
  • Use [SELF-INCOMPATIBLE] as a prefix for both pull request and commit +log if the change breaks the compatibility with Universal Ctags +itself.

  • +
+
+
+

Commit log

+

(For new parsers the following criteria is not applicable.)

+

Make clear the original motivation for the change and/or the impact +on the tags file.

+

If you fix a bug reported somewhere on the web, its URL should be +logged, too.

+

If the bug is reported in the Exuberant Ctags tracker on the +SourceForge web site, log it as sf-bugs:N, sf-patches:N, +sf-support-requests:N, or sf-feature-requests:N. +docs/tracking.rst also should be updated.

+
+
+

Squashing commits

+

When you submit a pull request you might receive some comments from a +reviewer and, in response, update your patches. After updating, we +would like you to squash your patches into logical units of work +before we merge them to keep the repository history as simple as +possible.

+
    +
  • Use git rebase -i and git push --force to refine your change in +the meaning of “semantically well separated.” “semantically well +separated” is important than “recording the history of your try and +error.”

  • +
+

Quoted from @steveno in #393 :

+
+

You can check out this page for a good example of how to squash +commits +http://gitready.com/advanced/2009/02/10/squashing-commits-with-rebase.html

+

Once you’ve squashed all your commits, simply do a git push -f to +your fork, and GitHub will update the pull request for you +automatically.

+
+
+
+
+

Rules for reviewing a pull request

+
    +
  • Put your rough schedule as a comment if you don’t have time, but you +want to review.

  • +
+
+
+ + +
+
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/ctags/docs/developers.html b/ctags/docs/developers.html new file mode 100644 index 0000000..6d6f3b1 --- /dev/null +++ b/ctags/docs/developers.html @@ -0,0 +1,167 @@ + + + + + + + + + Who we are — Universal Ctags 0.3.0 documentation + + + + + + + + + + + + + + +
+
+
+
+ +
+

Who we are

+

Please, add your name, background and interests here If you are +interested in contributing to Universal Ctags steadily. So we can +dispatch a task and/or an issue to the right person!

+

(Keep the list in alphabetical order.)

+

Cameron Eagans <me@cweagans.net>

+
+

I’ve been a PHP developer for almost 10 years, and have been using Vim +almost as long. My goal is to help guide the direction of the PHP +parser, as well as maintain the ctags website and help guide new +contributors to tasks that they may be able to help with. With time, +I may end up contributing directly to ctags development, but my C skills +are not so great at the moment.

+
+

Colomban Wendling <colomban@geany.org>

+
+

I am a developer of Geany, a lightweight IDE/editor that uses CTags +parsers to provide various code insights for a large variety of +languages. I don’t use CTags directly but through a (currently) +internal library. Hence, my fields of interest are the quality of the +parsers (good and comprehensive results) and their code (speed, proof +against any inputs, absence of memory leaks, regression tests), and a +CTags library applications could use more readily. I am mostly a C +developer, but as the maintainer of the CTags parsers in Geany I work +on all parsers.

+
+

Frank Fesevur <ffes@users.sourceforge.net>

+
+

My current use of ctags is for a Notepad++ plug-in I’m writing. +The plug-in is not yet released because of problems with the +Windows version of ctags. Those problems are fixed by now. +I am a Windows developer, but also an occasional Ubuntu and +Raspbian user at home. I wrote the windres parser.

+
+

Karol Samborski <edv.karol@gmail.com>

+
+

I like programming in multiple languages such as Haskell, C/C++, +TypeScript, PHP to name a few. Ctags are useful for me as I code mostly in +Vim. My goal here is to take care of the TypeScript parser.

+
+

Ken Takata <kentkt@csc.jp>

+
+

I use ctags with Vim mainly on Windows and Cygwin. +I’m the one of the heaviest contributors of Vim. +I set up the AppVeyor environment and I’m also maintaining the +ctags-win32 project.

+
+

Masatake YAMATO <yamato@redhat.com>

+
+

I’m using ctags in batch jobs running on my source code base +where most of all source code in Fedora are deployed. I’m an +Emacs user, so generally I don’t use ctags interactively +except when hacking Universal Ctags. Therefore my primary goal +is to improve the robustness of parsers: I introduced Units +test facility and badinput command for achieving the goal. +The secondary goal is to support more languages and formats: I +introduced optlib. I’m working on Fedora. I don’t +have access to the other platforms.

+
+

Qingming He <906459647@qq.com>

+
+

I’m mainly a Fortran developer and I use ctags combined with Emacs to +handle my projects. My goal is to improve the Fortran parser to make +it support Fortran standards from 77 to 2008 and maybe 2015 to be +released in the near future. I’m also interested in improving the lisp +parsers (elisp and scheme).

+
+

Szymon Tomasz Stefanek <s.stefanek@gmail.com>

+
+

I’m a multilanguage developer and I use ctags with my own text editor +which has some IDE capabilities. I’m the maintainer of the new C/C++ parser.

+
+

Vitor Antunes <vitor.hda@gmail.com>

+
+

I’ve been working with Verilog for most of the last 10 +years and am an avid Vim user. My goal is to improve the +Verilog parser such that Vim can get the most out of it +in plugins like Tagbar and to support the Omni +completion plugin I am writing.

+
+
+ + +
+
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/ctags/docs/extending.html b/ctags/docs/extending.html new file mode 100644 index 0000000..c334e39 --- /dev/null +++ b/ctags/docs/extending.html @@ -0,0 +1,157 @@ + + + + + + + + + Extending ctags with a parser written in C — Universal Ctags 0.3.0 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + + + \ No newline at end of file diff --git a/ctags/docs/genindex.html b/ctags/docs/genindex.html new file mode 100644 index 0000000..c9695da --- /dev/null +++ b/ctags/docs/genindex.html @@ -0,0 +1,80 @@ + + + + + + + + Index — Universal Ctags 0.3.0 documentation + + + + + + + + + + + + + +
+
+
+
+ + +

Index

+ +
+ +
+ + +
+
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/ctags/docs/index.html b/ctags/docs/index.html new file mode 100644 index 0000000..d849c9c --- /dev/null +++ b/ctags/docs/index.html @@ -0,0 +1,285 @@ + + + + + + + + + Universal Ctags Hacking Guide — Universal Ctags 0.3.0 documentation + + + + + + + + + + + + + + +
+
+
+
+ +
+

Universal Ctags Hacking Guide

+
+
Version
+

Draft

+
+
Authors
+

Universal Ctags developers

+
+
Web Page
+

https://ctags.io/

+
+
+

Universal Ctags (abbreviated as u-ctags) is a maintained implementation of +ctags. +ctags generates an index (or tag) file of language objects found in source +files for programming languages. +This index makes it easy for text editors and other tools to locate the indexed +items.

+

Exuberant Ctags (e-ctags) maintained by Darren Hiebert, the ancestor of +Universal Ctags, improved traditional ctags with multi-language support, the +ability for the user to define new languages searched by regular expressions +(called optlib in Universal Ctags), and the ability to generate emacs-style TAGS +files. +But the activity of the project unfortunately stalled.

+

Universal Ctags has the objective of continuing the development of Exuberant +Ctags. +Reza Jelveh <reza.jelveh@gmail.com> initially created a personal fork of +Exuberant Ctags on GitHub. +As interest and participation grew, it was decided to move development to a +dedicated project as Universal Ctags. +The goal of this project is to maintain a common/unified working space where +people interested in making ctags better can work together.

+

Some of major features of Universal Ctags are;

+
    +
  • +
    more numbers of improved language support
      +
    • new extended C/C++ language parser, etc.

    • +
    +
    +
    +
  • +
  • fully extended optlib (a feature to define a new language parser from a +command line)

  • +
  • interactive mode (experimental)

  • +
+

The primary documents of Universal Ctags are man pages. Users should first +consult the ctags(1), and other man pages if +necessary.

+

This guide, which also includes the man pages, is primarily for developers and +provides additional information to the man pages, including experimental +features.

+

This is a draft document. Proofreading and pull-requests are welcome!

+
+ +
+
+ + +
+
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/ctags/docs/interactive-mode.html b/ctags/docs/interactive-mode.html new file mode 100644 index 0000000..c580295 --- /dev/null +++ b/ctags/docs/interactive-mode.html @@ -0,0 +1,185 @@ + + + + + + + + + Interactive mode — Universal Ctags 0.3.0 documentation + + + + + + + + + + + + + + + +
+
+
+
+ +
+

Interactive mode

+

Universal Ctags can be run with --_interactive, which enters a REPL that +can be used programmatically to control ctags generation. In this mode, json +commands are received over stdin, and corresponding responses are emitted over +stdout.

+

This feature needs ctags to be built with json support and this requires libjansson to be installed +at build-time. If it’s supported it will be listed in the output of --list-features:

+
$ ctags --list-features | grep json
+json
+
+
+

Communication with Universal Ctags over stdio uses the json lines format, where each +json object appears on a single line and is terminated with a newline.

+

When ctags --_interactive is invoked, it will emit a single json object to stdout announcing +its name and version. This signals the start of the interactive loop, and the user can begin sending +commands over stdin.

+
$ ctags --_interactive
+{"_type": "program", "name": "Universal Ctags", "version": "0.0.0"}
+
+
+

The following commands are currently supported in interactive mode:

+ +
+

generate-tags

+

The generate-tags command takes two arguments:

+
    +
  • filename: name of the file to generate tags for (required)

  • +
  • size: size in bytes of the file, if the contents will be received over stdin (optional)

  • +
+

The simplest way to generate tags for a file is by passing its path on filesystem(file request). The response will include +one json object per line representing each tag, followed by a single json object with the completed +field emitted once the file has been fully processed.

+
$ echo '{"command":"generate-tags", "filename":"test.rb"}' | ctags --_interactive
+{"_type": "program", "name": "Universal Ctags", "version": "0.0.0"}
+{"_type": "tag", "name": "foobar", "path": "test.rb", "pattern": "/^  def foobar$/", "kind": "method", "scope": "Test", "scopeKind": "class"}
+{"_type":"completed", "command": "generate-tags"}
+
+
+

The generate-tags command can also be used to generate tags for code which is not present on filesystem(inline request). For example, +an IDE might want to generate ctags for an unsaved buffer while the user is editing code. When size is specified, +the corresponding number of bytes are read over stdin after the json object and newline.

+
$ (
+  echo '{"command":"generate-tags", "filename":"test.rb", "size": 17}'
+  echo 'def foobaz() end'
+) | ctags --_interactive
+{"_type": "program", "name": "Universal Ctags", "version": "0.0.0"}
+{"_type": "tag", "name": "foobaz", "path": "test.rb", "pattern": "/^def foobaz() end$/", "kind": "method"}
+{"_type": "completed", "command": "generate-tags"}
+
+
+
+
+

sandbox submode

+

sandbox submode can be used with --_interactive=sandbox. This +submode will activate a sandbox, to this limits the damage that the +can be achieved when exploiting a buffer overflow in Universal Ctags.

+

In the sandbox submode ctags can generate tags only for inline +requests because ctags has to use open system call to handle file +requests. The open system call is not allowed in the sandbox.

+

This feature uses Seccomp BPF (SECure COMPuting with filters), +and is only supported on Linux. To use the sandbox submode libseccomp is needed at build-time. If ctags was +built with seccomp support, sandbox is listed in the output of +--list-features option.

+
$ ctags --list-features | grep sandbox
+sandbox
+
+
+
$ (
+  echo '{"command":"generate-tags", "filename":"test.rb", "size": 17}'
+  echo 'def foobaz() end'
+) | ctags --_interactive=sandbox
+{"_type": "program", "name": "Universal Ctags", "version": "0.0.0"}
+{"_type": "tag", "name": "foobaz", "path": "test.rb", "pattern": "/^def foobaz() end$/", "kind": "method"}
+{"_type": "completed", "command": "generate-tags"}
+
+
+
+
+ + +
+
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/ctags/docs/internal.html b/ctags/docs/internal.html new file mode 100644 index 0000000..6767bc7 --- /dev/null +++ b/ctags/docs/internal.html @@ -0,0 +1,854 @@ + + + + + + + + + Input text stream — Universal Ctags 0.3.0 documentation + + + + + + + + + + + + + + + +
+
+
+
+ +
+

Input text stream

+
+_images/input-text-stream.svg +
+

Function prototypes for handling input text stream are declared in +main/read.h. The file exists in Exuberant Ctags, too. However, the +names functions are changed when overhauling --line-directive +option. (In addition macros were converted to functions for making +data structures for the input text stream opaque.)

+

Ctags has 3 groups of functions for handling input: input, bypass, and +raw. Parser developers should use input group. The rest of two +are for ctags main part.

+
+

inputFile type and the functions of input group

+
+

Note

+

The original version of this section was written +before inputFile type and File variable are made private.

+
+

inputFile is the type for representing the input file and stream for +a parser. It was declared in main/read.h but now it is defined in +main/read.c.

+

Ctags uses a file static variable File having type inputFile for +maintaining the input file and stream. File is also defined in +main/read.c as inputFile is.

+

fp and line are the essential fields of File. fp having type +well known MIO declared in main/mio.h. By calling functions of input group +(getcFromInputFile and readLineFromInputFile), a parser gets input +text from fp.

+

The functions of input group updates fields input and source of File variable. +These two fields has type inputFileInfo. These two fields are for mainly +tracking the name of file and the current line number. Usually ctags uses +only input field. source field is used only when #line directive is found +in the current input text stream.

+

A case when a tool generates the input file from another file, a tool +can record the original source file to the generated file with using +the #line directive. source field is used for tracking/recording the +information appeared on #line directives.

+

Regex pattern matching are also done behind calling the functions of +this group.

+
+
+

The functions of bypass group

+

The functions of bypass group (readLineFromBypass and +readLineFromBypassSlow) are used for reading text from fp field of +File static variable without updating input and source fields of +File variable.

+

Parsers may not need the functions of this group. The functions are +used in ctags main part. The functions are used to make pattern +fields of tags file, for example.

+
+
+

The functions of raw group

+

The functions of this group (readLineRaw and readLineRawWithNoSeek) +take a parameter having type MIO; and don’t touch File static +variable.

+

Parsers may not need the functions of this group. The functions are +used in ctags main part. The functions are used to load option files, +for example.

+
+
+
+

Output tag stream

+
+_images/output-tag-stream.svg +
+

Ctags provides makeTagEntry to parsers as an entry point for writing +tag information to MIO. makeTagEntry calls writeTagEntry if the +parser does not set useCork field. writeTagEntry calls writerWriteTag. +writerWriteTag just calls writeEntry of writer backends. +writerTable variable holds the four backends: ctagsWriter, etagsWriter, +xrefWriter, and jsonWriter. +One of them is chosen depending on the arguments passed to ctags.

+

If useCork is set, the tag information goes to a queue on memory. +The queue is flushed when useCork in unset. See “cork API” for more +details.

+
+

cork API

+
+

Background and Idea

+

cork API is introduced for recording scope information easier.

+

Before introducing cork API, a scope information must be recorded as +strings. It is flexible but memory management is required. +Following code is taken from clojure.c (with some modifications).

+
if (vStringLength (parent) > 0)
+{
+        current.extensionFields.scope[0] = ClojureKinds[K_NAMESPACE].name;
+        current.extensionFields.scope[1] = vStringValue (parent);
+}
+
+makeTagEntry (&current);
+
+
+

parent, scope [0] and scope [1] are vStrings. The parser must manage +their life cycles; the parser cannot free them till the tag referring them via +its scope fields are emitted, and must free them after emitting.

+

cork API provides more solid way to hold scope information. cork API +expects parent, which represents scope of a tag(current) +currently parser dealing, is recorded to a tags file before recording +the current tag via makeTagEntry function.

+

For passing the information about parent to makeTagEntry, +tagEntryInfo object was created. It was used just for recording; and +freed after recording. In cork API, it is not freed after recording; +a parser can reused it as scope information.

+
+
+

How to use

+

See a commit titled with “clojure: use cork”. +I applied cork API to the clojure parser.

+

Cork API can be enabled and disabled per parser, +and is disabled by default. So there is no impact till you +enables it in your parser.

+

useCork field is introduced in parserDefinition type:

+
typedef struct {
+...
+                unsigned int useCork;
+...
+} parserDefinition;
+
+
+

Set CORK_QUEUE to useCork like:

+
extern parserDefinition *ClojureParser (void)
+{
+        ...
+        parserDefinition *def = parserNew ("Clojure");
+        ...
+        def->useCork = CORK_QUEUE;
+        return def;
+}
+
+
+

When ctags running a parser with useCork being CORK_QUEUE, all output +requested via makeTagEntry function calling is stored to an internal +queue, not to tags file. When parsing an input file is done, the +tag information stored automatically to the queue are flushed to +tags file in batch.

+

When calling makeTagEntry with a tagEntryInfo object (parent), +it returns an integer. The integer can be used as handle for referring +the object after calling.

+
static int parent = CORK_NIL;
+...
+parent = makeTagEntry (&e);
+
+
+

The handle can be used by setting to a scopeIndex +field of current tag, which is in the scope of parent.

+
current.extensionFields.scopeIndex = parent;
+
+
+

When passing current to makeTagEntry, the scopeIndex is +referred for emitting the scope information of current.

+

scopeIndex must be set to CORK_NIL if a tag is not in any scope. +When using scopeIndex of current, NULL must be assigned to both +current.extensionFields.scope[0] and +current.extensionFields.scope[1]. initTagEntry function does this +initialization internally, so you generally you don’t have to write +the initialization explicitly.

+
+
+

Automatic full qualified tag generation

+

If a parser uses the cork API for recording and emitting scope +information, ctags can reuse it for generating full qualified (FQ) +tags. Set requestAutomaticFQTag field of parserDefinition to +TRUE then the main part of ctags emits FQ tags on behalf of the parser +if --extras=+q is given.

+

An example can be found in DTS parser:

+
extern parserDefinition* DTSParser (void)
+{
+        static const char *const extensions [] = { "dts", "dtsi", NULL };
+        parserDefinition* const def = parserNew ("DTS");
+        ...
+        def->requestAutomaticFQTag = TRUE;
+        return def;
+}
+
+
+

Setting requestAutomaticFQTag to TRUE implies setting +useCork to CORK_QUEUE.

+
+
+
+
+

tokenInfo API

+

In Exuberant Ctags, a developer can write a parser anyway; only input +stream and tagEntryInfo data structure is given.

+

However, while maintaining Universal Ctags I (Masatake YAMATO) think +we should have a framework for writing parser. Of course the framework +is optional; you can still write a parser without the framework.

+

To design a framework, I have studied how @b4n (Colomban Wendling) +writes parsers. tokenInfo API is the first fruit of my study.

+

TBW

+
+
+

Multiple parsers

+
+

Guest parser (promise API)

+

See “Guest parser: Applying a parser to specified areas of input file” about the concept of guest parsers.

+
+

Background and Idea

+

More than one programming languages can be used in one input text stream. +promise API allows a host parser running a guest parser in the specified area of input text stream.

+

e.g. Code written in c language (C code) is embedded +in code written in Yacc language (Yacc code). Let’s think about this +input stream.

+
/* foo.y */
+ %token
+         END_OF_FILE 0
+         ERROR               255
+         BELL                1
+
+ %{
+ /* C language */
+ int counter;
+ %}
+ %right      EQUALS
+ %left       PLUS MINUS
+ ...
+ %%
+ CfgFile             :       CfgEntryList
+                         { InterpretConfigs($1); }
+                 ;
+
+ ...
+ %%
+ int
+ yyerror(char *s)
+ {
+     (void)fprintf(stderr,"%s: line %d of %s\n",s,lineNum,
+                                         (scanFile?scanFile:"(unknown)"));
+     if (scanStr)
+         (void)fprintf(stderr,"last scanned symbol is: %s\n",scanStr);
+     return 1;
+ }
+
+
+

In the input the area started from %{ to %} and the area started from +the second %% to the end of file are written in C. Yacc can be called +host language, and C can be called guest language.

+

Ctags may choose the Yacc parser for the input. However, the parser +doesn’t know about C syntax. Implementing C parser in the Yacc parser +is one of approach. However, ctags has already C parser. The Yacc +parser should utilize the existing C parser. The promise API allows this.

+

See also “Guest parser: Applying a parser to specified areas of input file” about more concept and examples of the +guest parser.

+
+
+

Usage

+

See a commit titled with “Yacc: run C parser in the areas where code +is written in C”. +I applied promise API to the Yacc parser.

+

The parser for host language must track and record the start and the +end of a guest language. Pairs of line number and byte offset +represents the start and end. When the start and end are +fixed, call makePromise with (1) the guest parser name, (2) start, +and (3) end. (This description is a bit simplified the real usage.)

+

Let’s see the actual code from “parsers/yacc.c”.

+
struct cStart {
+        unsigned long input;
+        unsigned long source;
+};
+
+
+

Both fields are for recording start. input field +is for recording the value returned from getInputLineNumber. +source is for getSourceLineNumber. See “inputFile” for the +difference of the two.

+

enter_c_prologue shown in the next is a function called when %{ is +found in the current input text stream. Remember, in yacc syntax, %{ +is a marker of C code area.

+
static void enter_c_prologue (const char *line CTAGS_ATTR_UNUSED,
+                             const regexMatch *matches CTAGS_ATTR_UNUSED,
+                             unsigned int count CTAGS_ATTR_UNUSED,
+                             void *data)
+{
+       struct cStart *cstart = data;
+
+
+       readLineFromInputFile ();
+       cstart->input  = getInputLineNumber ();
+       cstart->source = getSourceLineNumber ();
+}
+
+
+

The function just records the start line. It calls +readLineFromInputFile because the C code may start the next line of +the line where the marker is.

+

leave_c_prologue shown in the next is a function called when %}, +the end marker of C code area, is found in the current input text stream.

+
static void leave_c_prologue (const char *line CTAGS_ATTR_UNUSED,
+                             const regexMatch *matches CTAGS_ATTR_UNUSED,
+                             unsigned int count CTAGS_ATTR_UNUSED,
+                             void *data)
+{
+       struct cStart *cstart = data;
+       unsigned long c_end;
+
+       c_end = getInputLineNumber ();
+       makePromise ("C", cstart->input, 0, c_end, 0, cstart->source);
+}
+
+
+

After recording the line number of the end of the C code area, +leave_c_prologue calls makePromise.

+

Of course "C" stands for C language, the name of guest parser. +Available parser names can be listed by running ctags with +--list-languages option. In this example two 0 characters are provided as +the 3rd and 5th argument. They are byte offsets of the start and the end of the +C language area from the beginning of the line which is 0 in this case. In +general, the guest language’s section does not have to start at the beginning of +the line in which case the two offsets have to be provided. Compilers reading +the input character by character can obtain the current offset by calling +getInputLineOffset().

+
+
+

Internal design

+
+_images/promise.svg +
+

A host parser cannot run a guest parser directly. What the host parser +can do is just asking the ctags main part scheduling of running the +guest parser for specified area which defined with the start and +end. These scheduling requests are called promises.

+

After running the host parser, before closing the input stream, the +ctags main part checks the existence of promise(s). If there is, the +main part makes a sub input stream and run the guest parser specified +in the promise. The sub input stream is made from the original input +stream by narrowing as requested in the promise. The main part +iterates the above process till there is no promise.

+

Theoretically a guest parser can be nested; it can make a promise. +The level 2 guest is also just scheduled. (However, I have never +tested such a nested guest parser).

+

Why not running the guest parser directly from the context of the host +parser? Remember many parsers have their own file static variables. If +a parser is called from the parser, the variables may be crashed.

+
+
+
+

API for subparser

+

See “Subparser: Tagging definitions of higher (upper) level language” about the concept of subparser.

+
+

Note

+

Consider using optlib when implementing a subparser. It is much more +easy and simple. See “Defining a subparser” for details.

+
+
+

Outline

+

You have to work on both sides: a base parser and subparsers.

+

A base parser must define a data structure type (baseMethodTable) for +its subparsers by extending struct subparser defined in +main/subparser.h. A subparser defines a variable (subparser var) +having type baseMethodTable by filling its fields and registers +subparser var to the base parser using dependency API.

+

The base parser calls functions pointed by baseMethodTable of +subparsers during parsing. A function for probing a higher level +language may be included in baseMethodTable. What kind of fields +should be included in baseMethodTable is up to the design of a base +parser and the requirements of its subparsers. A method for +probing is one of them.

+

Registering a subparser var to a base parser is enough for the +bottom up choice. For handling the top down choice (e.g. specifying +--language-force=<subparser> in a command line), more code is needed.

+

In the top down choice, the subparser must call scheduleRunningBasepaser, +declared in main/subparser.h, in its parser method. +Here, parser method means a function assigned to the parser member of +the parserDefinition of the subparser. +scheduleRunningBaseparser takes an integer argument +that specifies the dependency used for registering the subparser var.

+

By extending struct subparser you can define a type for +your subparser. Then make a variable for the type and +declare a dependency on the base parser.

+
+
+

Fields of subparser type

+

Here the source code of Autoconf/m4 parsers is referred as an example.

+

main/types.h:

+
struct sSubparser;
+typedef struct sSubparser subparser;
+
+
+

main/subparser.h:

+
typedef enum eSubparserRunDirection {
+        SUBPARSER_BASE_RUNS_SUB = 1 << 0,
+        SUBPARSER_SUB_RUNS_BASE = 1 << 1,
+        SUBPARSER_BI_DIRECTION  = SUBPARSER_BASE_RUNS_SUB|SUBPARSER_SUB_RUNS_BASE,
+} subparserRunDirection;
+
+struct sSubparser {
+        ...
+
+        /* public to the parser */
+        subparserRunDirection direction;
+
+        void (* inputStart) (subparser *s);
+        void (* inputEnd) (subparser *s);
+        void (* exclusiveSubparserChosenNotify) (subparser *s, void *data);
+};
+
+
+

A subparser must fill the fields of subparser.

+

direction field specifies how the subparser is called. See +“Direction flags” in “Running multiple parsers on an input file” about +direction flags, and see “Direction flags” in “Extending ctags with Regex parser (optlib)” for +examples of using the direction flags.

+ ++++ + + + + + + + + + + + + + + + + +

direction field

Direction Flag

SUBPARSER_BASE_RUNS_SUB

shared (default)

SUBPARSER_SUB_RUNS_BASE

dedicated

SUBPARSER_BI_DIRECTION

bidirectional

+

If a subparser runs exclusively and is chosen in top down way, set +SUBPARSER_SUB_RUNS_BASE flag. If a subparser runs coexisting way and +is chosen in bottom up way, set SUBPARSER_BASE_RUNS_SUB. Use +SUBPARSER_BI_DIRECTION if both cases can be considered.

+

SystemdUnit parser runs as a subparser of iniconf base parser. +SystemdUnit parser specifies SUBPARSER_SUB_RUNS_BASE because +unit files of systemd have very specific file extensions though +they are written in iniconf syntax. Therefore we expect SystemdUnit +parser is chosen in top down way. The same logic is applicable to +YumRepo parser.

+

Autoconf parser specifies SUBPARSER_BI_DIRECTION. For input +file having name configure.ac, by pattern matching, Autoconf parser +is chosen in top down way. In other hand, for file name foo.m4, +Autoconf parser can be chosen in bottom up way.

+

inputStart is called before the base parser starting parsing a new input file. +inputEnd is called after the base parser finishing parsing the input file. +Universal Ctags main part calls these methods. Therefore, a base parser doesn’t +have to call them.

+

exclusiveSubparserChosenNotify is called when a parser is chosen +as an exclusive parser. Calling this method is a job of a base parser.

+
+
+

Extending subparser type

+

The m4 parser extends subparser type like following:

+

parsers/m4.h:

+
typedef struct sM4Subparser m4Subparser;
+struct sM4Subparser {
+        subparser subparser;
+
+        bool (* probeLanguage) (m4Subparser *m4, const char* token);
+
+        /* return value: Cork index */
+        int  (* newMacroNotify) (m4Subparser *m4, const char* token);
+
+        bool (* doesLineCommentStart)   (m4Subparser *m4, int c, const char *token);
+        bool (* doesStringLiteralStart) (m4Subparser *m4, int c);
+};
+
+
+

Put subparser as the first member of the extended struct (here sM4Subparser). +In addition the first field, 4 methods are defined in the extended struct.

+

Till choosing a subparser for the current input file, the m4 parser calls +probeLanguage method of its subparsers each time when find a token +in the input file. A subparser returns true if it recognizes the +input file is for the itself by analyzing tokens passed from the +base parser.

+

parsers/autoconf.c:

+
extern parserDefinition* AutoconfParser (void)
+{
+        static const char *const patterns [] = { "configure.in", NULL };
+        static const char *const extensions [] = { "ac", NULL };
+        parserDefinition* const def = parserNew("Autoconf");
+
+        static m4Subparser autoconfSubparser = {
+                .subparser = {
+                        .direction = SUBPARSER_BI_DIRECTION,
+                        .exclusiveSubparserChosenNotify = exclusiveSubparserChosenCallback,
+                },
+                .probeLanguage  = probeLanguage,
+                .newMacroNotify = newMacroCallback,
+                .doesLineCommentStart = doesLineCommentStart,
+                .doesStringLiteralStart = doesStringLiteralStart,
+        };
+
+
+

probeLanguage function defined in autoconf.c is connected to +the probeLanguage member of autoconfSubparser. The probeLanguage function +of Autoconf is very simple:

+

parsers/autoconf.c:

+
static bool probeLanguage (m4Subparser *m4, const char* token)
+{
+        return strncmp (token, "m4_", 3) == 0
+                || strncmp (token, "AC_", 3) == 0
+                || strncmp (token, "AM_", 3) == 0
+                || strncmp (token, "AS_", 3) == 0
+                || strncmp (token, "AH_", 3) == 0
+                ;
+}
+
+
+

This function checks the prefix of passed tokens. If known +prefix is found, Autoconf assumes this is an Autoconf input +and returns true.

+

parsers/m4.c:

+
if (m4tmp->probeLanguage
+        && m4tmp->probeLanguage (m4tmp, token))
+{
+        chooseExclusiveSubparser ((m4Subparser *)tmp, NULL);
+        m4found = m4tmp;
+}
+
+
+

The m4 parsers calls probeLanguage function of a subparser. If true +is returned chooseExclusiveSubparser function which is defined +in the main part. chooseExclusiveSubparser calls +exclusiveSubparserChosenNotify method of the chosen subparser.

+

The method is implemented in Autoconf subparser like following:

+

parsers/autoconf.c:

+
static void exclusiveSubparserChosenCallback (subparser *s, void *data)
+{
+        setM4Quotes ('[', ']');
+}
+
+
+

It changes quote characters of the m4 parser.

+
+
+

Making a tag in a subparser

+

Via calling callback functions defined in subparsers, their base parser +gives chance to them making tag entries.

+

The m4 parser calls newMacroNotify method when it finds an m4 macro is used. +The Autoconf parser connects newMacroCallback function defined in parser/autoconf.c.

+

parsers/autoconf.c:

+
static int newMacroCallback (m4Subparser *m4, const char* token)
+{
+        int keyword;
+        int index = CORK_NIL;
+
+        keyword = lookupKeyword (token, getInputLanguage ());
+
+        /* TODO:
+           AH_VERBATIM
+         */
+        switch (keyword)
+        {
+        case KEYWORD_NONE:
+                break;
+        case KEYWORD_init:
+                index = makeAutoconfTag (PACKAGE_KIND);
+                break;
+
+...
+
+extern parserDefinition* AutoconfParser (void)
+{
+        ...
+        static m4Subparser autoconfSubparser = {
+                .subparser = {
+                        .direction = SUBPARSER_BI_DIRECTION,
+                        .exclusiveSubparserChosenNotify = exclusiveSubparserChosenCallback,
+                },
+                .probeLanguage  = probeLanguage,
+                .newMacroNotify = newMacroCallback,
+
+
+

In newMacroCallback function, the Autoconf parser receives the name of macro +found by the base parser and analysis whether the macro is interesting +in the context of Autoconf language or not. If it is interesting name, +the Autoconf parser makes a tag for it.

+
+
+

Calling methods of subparsers from a base parser

+

A base parser can use foreachSubparser macro for accessing its +subparsers. A base should call enterSubparser before calling a +method of a subparser, and call leaveSubparser after calling the +method. The macro and functions are declare in main/subparser.h .

+

parsers/m4.c:

+
static m4Subparser * maySwitchLanguage (const char* token)
+{
+        subparser *tmp;
+        m4Subparser *m4found = NULL;
+
+        foreachSubparser (tmp, false)
+        {
+                m4Subparser *m4tmp = (m4Subparser *)tmp;
+
+                enterSubparser(tmp);
+                if (m4tmp->probeLanguage
+                        && m4tmp->probeLanguage (m4tmp, token))
+                {
+                        chooseExclusiveSubparser (tmp, NULL);
+                        m4found = m4tmp;
+                }
+                leaveSubparser();
+
+                if (m4found)
+                        break;
+        }
+
+        return m4found;
+}
+
+
+

foreachSubparser takes a variable having type subparser. +For each iteration, the value for the variable is updated.

+

enterSubparser takes a variable having type subparser. With the +calling enterSubparser, the current language (the value returned from +getInputLanguage) can be temporary switched to the language specified +with the variable. One of the effect of switching is that language +field of tags made in the callback function called between +enterSubparser and leaveSubparser is adjusted.

+
+
+

Registering a subparser to its base parser

+

Use DEPTYPE_SUBPARSER dependency in a subparser for registration.

+

parsers/autoconf.c:

+
extern parserDefinition* AutoconfParser (void)
+{
+        parserDefinition* const def = parserNew("Autoconf");
+
+        static m4Subparser autoconfSubparser = {
+                .subparser = {
+                        .direction = SUBPARSER_BI_DIRECTION,
+                        .exclusiveSubparserChosenNotify = exclusiveSubparserChosenCallback,
+                },
+                .probeLanguage  = probeLanguage,
+                .newMacroNotify = newMacroCallback,
+                .doesLineCommentStart = doesLineCommentStart,
+                .doesStringLiteralStart = doesStringLiteralStart,
+        };
+        static parserDependency dependencies [] = {
+                [0] = { DEPTYPE_SUBPARSER, "M4", &autoconfSubparser },
+        };
+
+        def->dependencies = dependencies;
+        def->dependencyCount = ARRAY_SIZE (dependencies);
+
+
+

DEPTYPE_SUBPARSER is specified in the 0th element of dependencies +function static variable. In the next a literal string “M4” is +specified and autoconfSubparser follows. The intent of the code is +registering autoconfSubparser subparser definition to a base parser +named “M4”.

+

dependencies function static variable must be assigned to +dependencies fields of a variable of parserDefinition. +The main part of Universal Ctags refers the field when +initializing parsers.

+

[0] emphasizes this is “the 0th element”. The subparser may refer +the index of the array when the subparser calls +scheduleRunningBaseparser.

+
+
+

Scheduling running the base parser

+

For the case that a subparser is chosen in top down, the subparser +must call scheduleRunningBaseparser in the main parser method.

+

parsers/autoconf.c:

+
static void findAutoconfTags(void)
+{
+        scheduleRunningBaseparser (0);
+}
+
+extern parserDefinition* AutoconfParser (void)
+{
+        ...
+        parserDefinition* const def = parserNew("Autoconf");
+        ...
+        static parserDependency dependencies [] = {
+                [0] = { DEPTYPE_SUBPARSER, "M4", &autoconfSubparser },
+        };
+
+        def->dependencies = dependencies;
+        ...
+        def->parser = findAutoconfTags;
+        ...
+        return def;
+}
+
+
+

A subparser can do nothing actively. A base parser makes its subparser +work by calling methods of the subparser. Therefore a subparser must +run its base parser when the subparser is chosen in a top down way, +The main part prepares scheduleRunningBaseparser function for the purpose.

+

A subparser should call the function from parser method of parserDefinition +of the subparser. scheduleRunningBaseparser takes an integer. It specifies +an index of the dependency which is used for registering the subparser.

+
+
+
+
+

PackCC compiler-compiler

+

PackCC is a compiler-compiler; it translates .peg grammar file to .c +file. PackCC was originally written by Arihiro Yoshida. Its source +repository is at https://github.com/arithy/packcc.

+

The source tree of PackCC is grafted at misc/packcc directory. +Building PackCC and ctags are integrated in the build-scripts of +Universal Ctags.

+

Refer peg/valink.peg as a +sample of a parser using PackCC.

+
+
+

Automatic parser guessing (TBW)

+
+
+

Managing regular expression parsers (TBW)

+
+
+

Ghost kind in regex parser (TBW)

+
+ + +
+
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/ctags/docs/man-pages.html b/ctags/docs/man-pages.html new file mode 100644 index 0000000..2dd1007 --- /dev/null +++ b/ctags/docs/man-pages.html @@ -0,0 +1,336 @@ + + + + + + + + + Man pages — Universal Ctags 0.3.0 documentation + + + + + + + + + + + + + + + +
+
+
+
+ +
+

Man pages

+
+ +
+
+ + +
+
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/ctags/docs/man/ctags-client-tools.7.html b/ctags/docs/man/ctags-client-tools.7.html new file mode 100644 index 0000000..8acd0ef --- /dev/null +++ b/ctags/docs/man/ctags-client-tools.7.html @@ -0,0 +1,615 @@ + + + + + + + + + ctags-client-tools — Universal Ctags 0.3.0 documentation + + + + + + + + + + + + + + + +
+
+
+
+ +
+

ctags-client-tools

+

Hints for developing a tool using ctags command and tags output

+
+
Version
+

5.9.0

+
+
Manual group
+

Universal Ctags

+
+
Manual section
+

7

+
+
+
+

SYNOPSIS

+
+
ctags [options] [file(s)]
+
etags [options] [file(s)]
+
+
+
+

DESCRIPTION

+

Client tool means a tool running the ctags command +and/or reading a tags file generated by ctags command. +This man page gathers hints for people who develop client tools.

+
+
+

PSEUDO-TAGS

+

Pseudo-tags, stored in a tag file, indicate how +ctags generated the tags file: whether the +tags file is sorted or not, which version of tags file format is used, +the name of tags generator, and so on. The opposite term for +pseudo-tags is regular-tags. A regular-tag is for a language +object in an input file. A pseudo-tag is for the tags file +itself. Client tools may use pseudo-tags as reference for processing +regular-tags.

+

A pseudo-tag is stored in a tags file in the same format as +regular-tags as described in tags(5), except that pseudo-tag names +are prefixed with “!_”. For the general information about +pseudo-tags, see “TAG FILE INFORMATION” in tags(5).

+

An example of a pseudo tag:

+
!_TAG_PROGRAM_NAME      Universal Ctags /Derived from Exuberant Ctags/
+
+
+

The value, “2”, associated with the pseudo tag “TAG_PROGRAM_NAME”, is +used in the field for input file. The description, “Derived from +Exuberant Ctags”, is used in the field for pattern.

+

Universal Ctags extends the naming scheme of the classical pseudo-tags +available in Exuberant Ctags for emitting language specific +information as pseudo tags:

+
!_{pseudo-tag-name}!{language-name}     {associated-value}      /{description}/
+
+
+

The language-name is appended to the pseudo-tag name with a separator, “!”.

+

An example of pseudo tag with a language suffix:

+
!_TAG_KIND_DESCRIPTION!C        f,function      /function definitions/
+
+
+

This pseudo-tag says “the function kind of C language is enabled +when generating this tags file.” --pseudo-tags is the option for +enabling/disabling individual pseudo-tags. When enabling/disabling a +pseudo tag with the option, specify the tag name only +“TAG_KIND_DESCRIPTION”, without the prefix (“!_”) or the suffix (“!C”).

+
+

Options for Pseudo-tags

+
+
--extras=+p (or --extras=+{pseudo})

Forces writing pseudo-tags.

+

ctags emits pseudo-tags by default when writing tags +to a regular file (e.g. “tags’.) However, when specifying -o - +or -f - for writing tags to standard output, +ctags doesn’t emit pseudo-tags. --extras=+p or +--extras=+{pseudo} will force pseudo-tags to be written.

+
+
--list-pseudo-tags

Lists available types of pseudo-tags and shows whether they are enabled or disabled.

+

Running ctags with --list-pseudo-tags option +lists available pseudo-tags. Some of pseudo-tags newly introduced +in Universal Ctags project are disabled by default. Use +--pseudo-tags=... to enable them.

+
+
--pseudo-tags=[+|-]names|*

Specifies a list of pseudo-tag types to include in the output.

+

The parameters are a set of pseudo tag names. Valid pseudo tag names +can be listed with --list-pseudo-tags. Surround each name in the set +with braces, like “{TAG_PROGRAM_AUTHOR}”. You don’t have to include the “!_” +pseudo tag prefix when specifying a name in the option argument for --pseudo-tags= +option.

+

pseudo-tags don’t have a notation using one-letter flags.

+

If a name is preceded by either the ‘+’ or ‘-’ characters, that +tags’s effect has been added or removed. Otherwise the names replace +any current settings. All entries are included if ‘*’ is given.

+
+
--fields=+E (or --fields=+{extras})

Attach “extras:pseudo” field to pseudo-tags.

+

An example of pseudo tags with the field:

+
!_TAG_PROGRAM_NAME      Universal Ctags /Derived from Exuberant Ctags/  extras:pseudo
+
+
+

If the name of a normal tag in a tag file starts with “!_”, a +client tool cannot distinguish whether the tag is a regular-tag or +pseudo-tag. The fields attached with this option help the tool +distinguish them.

+
+
+
+
+

List of notable pseudo-tags

+

Running ctags with --list-pseudo-tags option lists available types +of pseudo-tags with short descriptions. This subsection shows hints +for using notable ones.

+
+
TAG_EXTRA_DESCRIPTION (new in Universal Ctags)

Indicates the names and descriptions of enabled extras:

+
!_TAG_EXTRA_DESCRIPTION       {extra-name}    /description/
+!_TAG_EXTRA_DESCRIPTION!{language-name}       {extra-name}    /description/
+
+
+

If your tool relies on some extra tags (extras), refer to +the pseudo-tags of this type. A tool can reject the tags file that +doesn’t include expected extras, and raise an error in an early +stage of processing.

+

An example of the pseudo-tags:

+
$ ctags --extras=+p --pseudo-tags='{TAG_EXTRA_DESCRIPTION}' -o - input.c
+!_TAG_EXTRA_DESCRIPTION       anonymous       /Include tags for non-named objects like lambda/
+!_TAG_EXTRA_DESCRIPTION       fileScope       /Include tags of file scope/
+!_TAG_EXTRA_DESCRIPTION       pseudo  /Include pseudo tags/
+!_TAG_EXTRA_DESCRIPTION       subparser       /Include tags generated by subparsers/
+...
+
+
+

A client tool can know “{anonymous}”, “{fileScope}”, “{pseudo}”, +and “{subparser}” extras are enabled from the output.

+
+
TAG_FIELD_DESCRIPTION (new in Universal Ctags)

Indicates the names and descriptions of enabled fields:

+
!_TAG_FIELD_DESCRIPTION       {field-name}    /description/
+!_TAG_FIELD_DESCRIPTION!{language-name}       {field-name}    /description/
+
+
+

If your tool relies on some fields, refer to the pseudo-tags of +this type. A tool can reject a tags file that doesn’t include +expected fields, and raise an error in an early stage of +processing.

+

An example of the pseudo-tags:

+
$ ctags --fields-C=+'{macrodef}' --extras=+p --pseudo-tags='{TAG_FIELD_DESCRIPTION}' -o - input.c
+!_TAG_FIELD_DESCRIPTION       file    /File-restricted scoping/
+!_TAG_FIELD_DESCRIPTION       input   /input file/
+!_TAG_FIELD_DESCRIPTION       name    /tag name/
+!_TAG_FIELD_DESCRIPTION       pattern /pattern/
+!_TAG_FIELD_DESCRIPTION       typeref /Type and name of a variable or typedef/
+!_TAG_FIELD_DESCRIPTION!C     macrodef        /macro definition/
+...
+
+
+

A client tool can know “{file}”, “{input}”, “{name}”, “{pattern}”, +and “{typeref}” fields are enabled from the output. +The fields are common in languages. In addition to the common fields, +the tool can known “{macrodef}” field of C language is also enabled.

+
+
TAG_FILE_ENCODING (new in Universal Ctags)

TBW

+
+
TAG_FILE_FORMAT

See also tags(5).

+
+
TAG_FILE_SORTED

See also tags(5).

+
+
TAG_KIND_DESCRIPTION (new in Universal Ctags)

Indicates the names and descriptions of enabled kinds:

+
!_TAG_KIND_DESCRIPTION!{language-name}        {kind-letter},{kind-name}       /description/
+
+
+

If your tool relies on some kinds, refer to the pseudo-tags of +this type. A tool can reject the tags file that doesn’t include +expected kinds, and raise an error in an early stage of +processing.

+

Kinds are language specific, so a language name is always +appended to the tag name as suffix.

+

An example of the pseudo-tags:

+
$ ctags --extras=+p --kinds-C=vfm --pseudo-tags='{TAG_KIND_DESCRIPTION}' -o - input.c
+!_TAG_KIND_DESCRIPTION!C      f,function      /function definitions/
+!_TAG_KIND_DESCRIPTION!C      m,member        /struct, and union members/
+!_TAG_KIND_DESCRIPTION!C      v,variable      /variable definitions/
+...
+
+
+

A client tool can know “{function}”, “{member}”, and “{variable}” +kinds of C language are enabled from the output.

+
+
TAG_KIND_SEPARATOR (new in Universal Ctags)

TBW

+
+
TAG_OUTPUT_EXCMD (new in Universal Ctags)

Indicates the specified type of EX command with --excmd option.

+
+
TAG_OUTPUT_FILESEP (new in Universal Ctags)

TBW

+
+
TAG_OUTPUT_MODE (new in Universal Ctags)

TBW

+
+
TAG_PATTERN_LENGTH_LIMIT (new in Universal Ctags)

TBW

+
+
TAG_PROC_CWD (new in Universal Ctags)

Indicates the working directory of ctags during processing.

+

This pseudo-tag helps a client tool solve the absolute paths for +the input files for tag entries even when they are tagged with +relative paths.

+

An example of the pseudo-tags:

+
$ cat tags
+!_TAG_PROC_CWD        /tmp/   //
+main  input.c /^int main (void) { return 0; }$/;"     f       typeref:typename:int
+...
+
+
+

From the regular tag for “main”, the client tool can know the +“main” is at “input.c”. However, it is a relative path. So if the +directory where ctags run and the directory +where the client tool runs are different, the client tool cannot +find “input.c” from the file system. In that case, +TAG_PROC_CWD gives the tool a hint; “input.c” may be at “/tmp”.

+
+
TAG_PROGRAM_NAME

TBW

+
+
TAG_ROLE_DESCRIPTION (new in Universal Ctags)

Indicates the names and descriptions of enabled roles:

+
!_TAG_ROLE_DESCRIPTION!{language-name}!{kind-name}    {role-name}     /description/
+
+
+

If your tool relies on some roles, refer to the pseudo-tags of +this type. Note that a role owned by a disabled kind is not listed +even if the role itself is enabled.

+
+
+
+
+
+

REDUNDANT-KINDS

+

TBW

+
+
+

MULTIPLE-LANGUAGES FOR AN INPUT FILE

+

Universal ctags can run multiple parsers. +That means a parser, which supports multiple parsers, may output tags for +different languages. language/l field can be used to show the language +for each tag.

+
$ cat /tmp/foo.html
+<html>
+<script>var x = 1</script>
+<h1>title</h1>
+</html>
+$ ./ctags -o - --extras=+g /tmp/foo.html
+title   /tmp/foo.html   /^  <h1>title<\/h1>$/;" h
+x       /tmp/foo.html   /var x = 1/;"   v
+$ ./ctags -o - --extras=+g --fields=+l /tmp/foo.html
+title   /tmp/foo.html   /^  <h1>title<\/h1>$/;" h       language:HTML
+x       /tmp/foo.html   /var x = 1/;"   v       language:JavaScript
+
+
+
+
+

UTILIZING READTAGS

+

See readtags(1) to know how to use readtags. This section is for discussing +some notable topics for client tools.

+
+

Build Filter/Sorter Expressions

+

Certain escape sequences in expressions are recognized by readtags. For +example, when searching for a tag that matches a\?b, if using a filter +expression like '(eq? $name "a\?b")', since \? is translated into a +single ? by readtags, it actually searches for a?b.

+

Another problem is if a single quote appear in filter expressions (which is +also wrapped by single quotes), it terminates the expression, producing broken +expressions, and may even cause unintended shell injection. Single quotes can +be escaped using '"'"'.

+

So, client tools need to:

+
    +
  • Replace \ by \\

  • +
  • Replace ' by '"'"'

  • +
+

inside the expressions. If the expression also contains strings, " in the +strings needs to be replaced by \".

+

Client tools written in Lisp could build the expression using lists. prin1 +(in Common Lisp style Lisps) and write (in Scheme style Lisps) can +translate the list into a string that can be directly used. For example, in +EmacsLisp:

+
(let ((name "hi"))
+  (prin1 `(eq? $name ,name)))
+=> "(eq\\? $name "hi")"
+
+
+

The “?” is escaped, and readtags can handle it. Scheme style Lisps should do +proper escaping so the expression readtags gets is just the expression passed +into write. Common Lisp style Lisps may produce unrecognized escape +sequences by readtags, like \#. Readtags provides some aliases for these +Lisps:

+
    +
  • Use true for #t.

  • +
  • Use false for #f.

  • +
  • Use nil or () for ().

  • +
  • Use (string->regexp "PATTERN") for #/PATTERN/. Use +(string->regexp "PATTERN" :case-fold true) for #/PATTERN/i. Notice +that string->regexp doesn’t require escaping “/” in the pattern.

  • +
+

Notice that even when the client tool uses this method, ' still needs to be +replaced by '"'"' to prevent broken expressions and shell injection.

+

Another thing to notice is that missing fields are represented by #f, and +applying string operators to them will produce an error. You should always +check if a field is missing before applying string operators. See the +“Filtering” section in readtags(1) to know how to do this. Run “readtags -H +filter” to see which operators take string arguments.

+
+
+

Parse Readtags Output

+

In the output of readtags, tabs can appear in all field values (e.g., the tag +name itself could contain tabs), which makes it hard to split the line into +fields. Client tools should use the -E option, which keeps the escape +sequences in the tags file, so the only field that could contain tabs is the +pattern field.

+

The pattern field could:

+
    +
  • Use a line number. It will look like number;" (e.g. 10;").

  • +
  • Use a search pattern. It will look like /pattern/;" or ?pattern?;". +Notice that the search pattern could contain tabs.

  • +
  • Combine these two, like number;/pattern/;" or number;?pattern?;".

  • +
+

These are true for tags files using extended format, which is the default one. +The legacy format (i.e. --format=1) doesn’t include the semicolons. It’s +old and barely used, so we won’t discuss it here.

+

Client tools could split the line using the following steps:

+
    +
  • Find the first 2 tabs in the line, so we get the name and input field.

  • +
  • From the 2nd tab:

    +
      +
    • If a / follows, then the pattern delimiter is /.

    • +
    • If a ? follows, then the pattern delimiter is ?.

    • +
    • If a number follows, then:

      +
        +
      • If a ;/ follows the number, then the delimiter is /.

      • +
      • If a ;? follows the number, then the delimiter is ?.

      • +
      • If a ;" follows the number, then the field uses only line number, and +there’s no pattern delimiter (since there’s no regex pattern). In this +case the pattern field ends at the 3rd tab.

      • +
      +
    • +
    +
  • +
  • After the opening delimiter, find the next unescaped pattern delimiter, and +that’s the closing delimiter. It will be followed by ;" and then a tab. +That’s the end of the pattern field. By “unescaped pattern delimiter”, we +mean there’s an even number (including 0) of backslashes before it.

  • +
  • From here, split the rest of the line into fields by tabs.

  • +
+

Then, the escape sequences in fields other than the pattern field should be +translated. See “Proposal” in tags(5) to know about all the escape sequences.

+
+
+

Make Use of the Pattern Field

+

The pattern field specifies how to find a tag in its source file. The code +generating this field seems to have a long history, so there are some pitfalls +and it’s a bit hard to handle. A client tool could simply require the line: +field and jump to the line it specifies, to avoid using the pattern field. But +anyway, we’ll discuss how to make the best use of it here.

+

You should take the words here merely as suggestions, and not standards. A +client tool could definitely develop better (or simpler) ways to use the +pattern field.

+

From the last section, we know the pattern field could contain a line number +and a search pattern. When it only contains the line number, handling it is +easy: you simply go to that line.

+

The search pattern resembles an EX command, but as we’ll see later, it’s +actually not a valid one, so some manual work are required to process it.

+

The search pattern could look like /pat/, called “forward search pattern”, +or ?pat?, called “backward search pattern”. Using a search pattern means +even if the source file is updated, as long as the part containing the tag +doesn’t change, we could still locate the tag correctly by searching.

+

When the pattern field only contains the search pattern, you just search for +it. The search direction (forward/backward) doesn’t matter, as it’s decided +solely by whether the -B option is enabled, and not the actual context. You +could always start the search from say the beginning of the file.

+

When both the search pattern and the line number are presented, you could make +good use of the line number, by going to the line first, then searching for the +nearest occurence of the pattern. A way to do this is to search both forward +and backward for the pattern, and when there is a occurence on both sides, go +to the nearer one.

+

What’s good about this is when there are multiple identical lines in the source +file (e.g. the COMMON block in Fortran), this could help us find the correct +one, even after the source file is updated and the tag position is shifted by a +few lines.

+

Now let’s discuss how to search for the pattern. After you trim the / or +? around it, the pattern resembles a regex pattern. It should be a regex +pattern, as required by being a valid EX command, but it’s actually not, as +you’ll see below.

+

It could begin with a ^, which means the pattern starts from the beginning +of a line. It could also end with an unescaped $ which means the pattern +ends at the end of a line. Let’s keep this information, and trim them too.

+

Now the remaining part is the actual string containing the tag. Some characters +are escaped:

+
    +
  • \.

  • +
  • $, but only at the end of the string.

  • +
  • /, but only in forward search patterns.

  • +
  • ?, but only in backward search patterns.

  • +
+

You need to unescape these to get the literal string. Now you could convert +this literal string to a regexp that matches it (by escaping, like +re.escape in Python or regexp-quote in Elisp), and assemble it with +^ or $ if the pattern originally has it, and finally search for the tag +using this regexp.

+
+
+

Remark: About a Previous Format of the Pattern Field

+

In some earlier versions of Universal Ctags, the line number in the pattern +field is the actual line number minus one, for forward search patterns; or plus +one, for backward search patterns. The idea is to resemble an EX command: you +go to the line, then search forward/backward for the pattern, and you can +always find the correct one. But this denies the purpose of using a search +pattern: to tolerate file updates. For example, the tag is at line 50, +according to this scheme, the pattern field should be:

+
49;/pat/;"
+
+
+

Then let’s assume that some code above are removed, and the tag is now at +line 45. Now you can’t find it if you search forward from line 49.

+

Due to this reason, Universal Ctags turns to use the actual line number. A +client tool could distinguish them by the TAG_OUTPUT_EXCMD pseudo tag, it’s +“combine” for the old scheme, and “combineV2” for the present scheme. But +probably there’s no need to treat them differently, since “search for the +nearest occurence from the line” gives good result on both schemes.

+
+
+
+

JSON OUTPUT

+

Universal Ctags supports JSON (strictly +speaking JSON Lines) output format if the +ctags executable is built with libjansson. JSON output goes to +standard output by default.

+
+

Format

+

Each JSON line represents a tag.

+
$ ctags --extras=+p --output-format=json --fields=-s input.py
+{"_type": "ptag", "name": "JSON_OUTPUT_VERSION", "path": "0.0", "pattern": "in development"}
+{"_type": "ptag", "name": "TAG_FILE_SORTED", "path": "1", "pattern": "0=unsorted, 1=sorted, 2=foldcase"}
+...
+{"_type": "tag", "name": "Klass", "path": "/tmp/input.py", "pattern": "/^class Klass:$/", "language": "Python", "kind": "class"}
+{"_type": "tag", "name": "method", "path": "/tmp/input.py", "pattern": "/^    def method(self):$/", "language": "Python", "kind": "member", "scope": "Klass", "scopeKind": "class"}
+...
+
+
+

A key not starting with _ is mapped to a field of ctags. +“--output-format=json --list-fields” options list the fields.

+

A key starting with _ represents meta information of the JSON +line. Currently only _type key is used. If the value for the key +is tag, the JSON line represents a normal tag. If the value is +ptag, the line represents a pseudo-tag.

+

The output format can be changed in the +future. JSON_OUTPUT_VERSION pseudo-tag provides a change +client-tools to handle the changes. Current version is “0.0”. A +client-tool can extract the version with path key from the +pseudo-tag.

+

The JSON output format is newly designed and has no limitation found +in the default tags file format.

+
    +
  • The values for kind key are represented in long-name flags. +No one-letter is here.

  • +
  • Scope names and scope kinds have distinguished keys: scope and scopeKind. +They are combined in the default tags file format.

  • +
+
+
+

Data type used in a field

+

Values for the most of all keys are represented in JSON string type. +However, some of them are represented in string, integer, and/or boolean type.

+

--output-format=json --list-fields” options show What kind of data type +used in a field of JSON.

+
$ ctags --output-format=json --list-fields
+#LETTER NAME           ENABLED LANGUAGE         JSTYPE FIXED DESCRIPTION
+F       input          yes     NONE             s--    no    input file
+...
+P       pattern        yes     NONE             s-b    no    pattern
+...
+f       file           yes     NONE             --b    no    File-restricted scoping
+...
+e       end            no      NONE             -i-    no    end lines of various items
+...
+
+
+

JSTYPE column shows the data types.

+
+
s

string

+
+
i

integer

+
+
b

boolean (true or false)

+
+
+

For an example, the value for pattern field of ctags takes a string or a boolean value.

+
+
+
+

SEE ALSO

+

ctags(1), ctags-lang-python(7), ctags-incompatibilities(7), tags(5), readtags(1)

+
+
+ + +
+
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/ctags/docs/man/ctags-faq.7.html b/ctags/docs/man/ctags-faq.7.html new file mode 100644 index 0000000..433e5e7 --- /dev/null +++ b/ctags/docs/man/ctags-faq.7.html @@ -0,0 +1,510 @@ + + + + + + + + + ctags-faq — Universal Ctags 0.3.0 documentation + + + + + + + + + + + + + + + +
+
+
+
+ +
+

ctags-faq

+

Universal Ctags FAQ

+
+
Version
+

5.9.0

+
+
Manual group
+

Universal Ctags

+
+
Manual section
+

7

+
+
+

This is the Universal Ctags FAQ (Frequently-Asked Questions). +It is based on Exuberant Ctags FAQ

+ +
+

DESCRIPTION

+
+

What is the difference between Universal Ctags and Exuberant Ctags?

+

Universal Ctags is an unofficial fork of Exuberant Ctags. +The differences are summarized in ctags-incompatibilities(7) man page.

+

The most notable one is that Universal Ctags doesn’t read ~/.ctags file. +Instead, it reads *.ctags under ~/.ctags.d directory.

+
+
+

How can I avoid having to specify my favorite option every time?

+

Either by setting the environment variable CTAGS to your custom +options, or putting them into a ~/.ctags.d/anyname.ctags file in your home +directory.

+
+
+

What are these strange bits of text beginning with ;" which follow many of the lines in the tag file?

+

These are extension flags. They are added in order to provide extra +information about the tag that may be utilized by the editor in order to +more intelligently handle tags. They are appended to the EX command part of +the tag line in a manner that provides backwards compatibility with existing +implementations of the Vi editor. The semicolon is an EX command separator +and the double quote begins an EX comment. Thus, the extension flags appear +as an EX comment and should be ignored by the editor when it processes the +EX command.

+

Some non-vi editors, however, implement only the bare minimum of EX commands +in order to process the search command or line number in the third field of +the tag file. If you encounter this problem, use the option --format=1 to +generate a tag file without these extensions (remember that you can set the +CTAGS environment variable to any default arguments you wish to supply). Then +ask the supplier of your editor to implement handling of this feature of EX +commands.

+
+
+

Why can’t I jump to class::member?

+

Because, by default, ctags only generates tags for the separate identifiers +found in the source files. If you specify the --extra=+q option, then +ctags will also generate a second, class-qualified tag for each class member +(data and function/method) in the form class::member for C++, and in the form +class.method for Eiffel and Java.

+
+
+

Why do I end up on the wrong line when I jump to a tag?

+

By default, ctags encodes the line number in the file where macro (#define) +tags are found. This was done to remain compatible with the original UNIX +version of ctags. If you change the file containing the tag without +rebuilding the tag file, the location of tag in the tag file may no longer +match the current location.

+

In order to avoid this problem, you can specify the option --excmd=p, +which causes ctags to use a search pattern to locate macro tags. I have +never uncovered the reason why the original UNIX ctags used line numbers +exclusively for macro tags, but have so far resisted changing the default +behavior of Exuberant (and Universal) Ctags to behave differently.

+
+
+

How do I jump to the tag I want instead of the wrong one by the same name?

+

A tag file is simple a list of tag names and where to find them. If there +are duplicate entries, you often end up going to the wrong one because the +tag file is sorted and your editor locates the first one in the tag file.

+

Standard Vi provides no facilities to alter this behavior. However, Vim +has some nice features to minimize this problem, primarily by examining all +matches and choosing the best one under the circumstances. Vim also provides +commands which allow for selection of the desired matching tag.

+
+
+

How can I locate all references to a specific function or variable?

+

There are several packages already available which provide this capability. +Namely, these are: GLOBAL source code tag system, GNU id-utils, cscope, +and cflow. As of this writing, they can be found in the following locations:

+ +
+
+

Why does appending tags to a tag file tag so long?

+

Sometimes, in an attempt to build a global tag file for all source files in +a large source tree of many directories, someone will make an attempt to run +ctags in append (-a) mode on every directory in the hierarchy. Each time +ctags is invoked, its default behavior is to sort the tag file once the tags +for that execution have been added. As the cumulative tag file grows, the sort +time increases arithmetically.

+

The best way to avoid this problem (and the most efficient) is to make +use of the --recurse (or -R) option of ctags by executing the following +command in the root of the directory hierarchy (thus running ctags only once):

+
+
ctags -R
+
+
+
+

If you really insist on running ctags separately on each directory, you can +avoid the sort pass each time by specifying the option --sort=no. Once the +tag file is completely built, use the sort command to manually sort the +final tag file, or let the final invocation of ctags sort the file.

+
+
+

How should I set up tag files for a multi-level directory hierarchy?

+

There are a few ways of approaching this:

+
    +
  1. A local tag file in each directory containing only the tags for source +files in that directory.

  2. +
  3. One single big, global tag file present in the root directory of your +hierarchy, containing all tags present in all source files in the +hierarchy.

  4. +
  5. A local tag file in each directory containing only the tags for source +files in that directory, in addition to one single global tag file +present in the root directory of your hierarchy, containing all +non-static tags present in all source files in the hierarchy.

  6. +
  7. A local tag file in each directory of the hierarchy, each one +containing all tags present in source files in that directory and all +non-static tags in every directory below it (note that this implies +also having one big tag file in the root directory of the hierarchy).

  8. +
+

Each of these approaches has its own set of advantages and disadvantages, +depending upon your particular conditions. Which approach is deemed best +depends upon the following factors:

+
    +
  1. The ability of your editor to use multiple tag files.

    +

    If your editor cannot make use of multiple tag files (original vi +implementations could not), then one large tag file is the only way to +go if you ever desire to jump to tags located in other directories. If +you never need to jump to tags in another directory (i.e. the source +in each directory is entirely self-contained), then a local tag file +in each directory will fit your needs.

    +
  2. +
  3. The time is takes for your editor to look up a tag in the tag file.

    +

    The significance of this factor depends upon the size of your source +tree and on whether the source files are located on a local or remote +file system. For source and tag files located on a local file system, +looking up a tag is not as big a hit as one might first imagine, since +vi implementations typically perform a binary search on a sorted tag +file. This may or may not be true for the editor you use. For files +located on a remote file system, reading a large file is an expensive +operation.

    +
  4. +
  5. Whether or not you expect the source code to change and the time it +takes to rebuild a tag file to account for changes to the source code.

    +

    While Universal Ctags is particularly fast in scanning source code +(around 1-2 MB/sec), a large project may still result in objectionable +delays if one wishes to keep their tag file(s) up to date on a +frequent basis, or if the files are located on a remote file system.

    +
  6. +
  7. The presence of duplicate tags in the source code and the ability to +handle them.

    +

    The impact of this factor is influenced by the following three issues:

    +
      +
    1. How common are duplicate tags in your project?

    2. +
    3. Does your editor provide any facilities for dealing with duplicate +tags?

      +

      While standard vi does not, many modern vi implementations, such +as Vim have good facilities for selecting the desired match from +the list of duplicates. If your editor does not support duplicate +tags, then it will typically send you to only one of them, whether +or not that is the one you wanted (and not even notifying you that +there are other potential matches).

      +
    4. +
    5. What is the significance of duplicate tags?

      +

      For example, if you have two tags of the same name from entirely +isolated software components, jumping first to the match found +in component B while working in component A may be entirely +misleading, distracting or inconvenient (to keep having to choose +which one if your editor provides you with a list of matches). +However, if you have two tags of the same name for parallel builds +(say two initialization routines for different hosts), you may +always want to specify which one you want.

      +
    6. +
    +
  8. +
+

Of the approaches listed above, I tend to favor Approach 3. My editor of +choice is Vim, which provides a rich set of features for handling multiple +tag files, which partly influences my choice. If you are working with +source files on a remote file system, then I would recommend either +Approach 3 or Approach 4, depending upon the hit when reading the global +tag file.

+

The advantages of Approach 3 are many (assuming that your editor has +the ability to support both multiple tag files and duplicate tags). All +lookups of tag located in the current directory are fast and the local +tag file can be quickly and easily regenerated in one second or less +(I have even mapped a keystroke to do this easily). A lookup of a +(necessarily non-static) tag found in another directory fails a lookup in +the local tag file, but is found in the global tag file, which satisfies +all cross-directory lookups. The global tag file can be automatically +regenerated periodically with a cron job (and perhaps the local tag files +also).

+

Now I give an example of how you would implement Approach 3. Means of +implementing the other approaches can be performed in a similar manner.

+

Here is a visual representation of an example directory hierarchy:

+
project
+`-----misccomp
+|       `...
+`-----sysint
+        `-----client
+        |       `-----hdrs
+        |       `-----lib
+        |       `-----src
+        |       `-----test
+        `-----common
+        |       `-----hdrs
+        |       `-----lib
+        |       `-----src
+        |       `-----test
+        `-----server
+                `-----hdrs
+                `-----lib
+                `-----src
+                `-----test
+
+
+

Here is a recommended solution (conceptually) to build the tag files:

+
    +
  1. Within each of the leaf nodes (i.e. hdrs, lib, src, test) build a tag +file using “ctags *.[ch]”. This can be easily be done for the whole +hierarchy by making a shell script, call it dirtags, containing the +following lines:

    +
    +
    #!/bin/sh
    +cd $1
    +ctags *
    +
    +
    +
    +

    Now execute the following command:

    +
    +
    find * -type d -exec dirtags {} \;
    +
    +
    +
    +

    These tag files are trivial (and extremely quick) to rebuild while +making changes within a directory. The following Vim key mapping is +quite useful to rebuild the tag file in the directory of the current +source file:

    +
    +
    :nmap ,t :!(cd %:p:h;ctags *.[ch])&<CR><CR>
    +
    +
    +
    +
  2. +
  3. Build the global tag file:

    +
    +
    cd ~/project
    +ctags --file-scope=no -R
    +
    +
    +
    +

    thus constructing a tag file containing only non-static tags for all +source files in all descendent directories.

    +
  4. +
  5. Configure your editor to read the local tag file first, then consult +the global tag file when not found in the local tag file. In Vim, +this is done as follows:

    +
    +
    :set tags=./tags,tags,~/project/tags
    +
    +
    +
    +
  6. +
+

If you wish to implement Approach 4, you would need to replace the +dirtags script of step 1 with the following:

+
+
#!/bin/sh
+cd $1
+ctags *
+# Now append the non-static tags from descendent directories
+find * -type d -prune -print | ctags -aR --file-scope=no -L-
+
+
+
+

And replace the configuration of step 3 with this:

+
+
:set tags=./tags;$HOME,tags
+
+
+
+

As a caveat, it should be noted that step 2 builds a global tag file whose +file names will be relative to the directory in which the global tag file +is being built. This takes advantage of the Vim tagrelative option, +which causes the path to be interpreted a relative to the location of the +tag file instead of the current directory. For standard vi, which always +interprets the paths as relative to the current directory, we need to +build the global tag file with absolute path names. This can be +accomplished by replacing step 2 with the following:

+
+
cd ~/project
+ctags --file-scope=no -R `pwd`
+
+
+
+
+
+

Does Universal Ctags support Unicode file names?

+

Yes, Unicode file names are supported on unix-like platforms (Linux, macOS, +Cygwin, etc.).

+

However, on Windows, you need to use Windows 10 version 1903 or later to use +Unicode file names. (This is an experimental feature, though.) On older versions +on Windows, Universal Ctags only support file names represented in the current +code page. If you still want to use Unicode file names on them, use Cygwin or +MSYS2 version of Universal Ctags as a workaround.

+
+
+

Why does zsh cause “zsh: no matches found” error?

+

zsh causes error on the following cases;

+
+
ctags --extra=+* ...
+ctags --exclude=foo/* ...
+
+
+
+

This is the 2nd most significant incompatibility feature of zsh.

+

Cited from “Z-Shell Frequently-Asked Questions”, “2.1: Differences from sh and +ksh”;

+
+

… The next most classic difference is that unmatched glob patterns cause +the command to abort; set NO_NOMATCH for those.

+
+

You may add “setopt nonomatch” on your ~/.zshrc. Or you can escape glob +patterns with backslash;

+
+
ctags --extra=+\* ...
+ctags --exclude=foo/\* ...
+
+
+
+

Or quote them;

+
+
ctags '--extra=+*' ...
+ctags '--exclude=foo/*' ...
+
+
+
+
+
+
+

SEE ALSO

+

The official Universal Ctags web site at:

+

https://ctags.io/

+

ctags(1), tags(5)

+
+
+

AUTHOR

+

This FAQ is based on Exuberant Ctags FAQ by +Darren Hiebert and vberthoux@users.sourceforge.net

+

Universal Ctags project: https://ctags.io/

+
+
+ + +
+
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/ctags/docs/man/ctags-incompatibilities.7.html b/ctags/docs/man/ctags-incompatibilities.7.html new file mode 100644 index 0000000..4e15f59 --- /dev/null +++ b/ctags/docs/man/ctags-incompatibilities.7.html @@ -0,0 +1,337 @@ + + + + + + + + + ctags-incompatibilities — Universal Ctags 0.3.0 documentation + + + + + + + + + + + + + + + +
+
+
+
+ +
+

ctags-incompatibilities

+

Incompatibilities between Universal Ctags and Exuberant Ctags

+
+
Version
+

5.9.0

+
+
Manual group
+

Universal Ctags

+
+
Manual section
+

7

+
+
+
+

SYNOPSIS

+
+
ctags [options] [file(s)]
+
etags [options] [file(s)]
+
+
+
+

DESCRIPTION

+

This page describes major incompatible changes introduced to +Universal Ctags forked from Exuberant Ctags.

+
+

Option files loading at starting up time (preload files)

+

Universal Ctags doesn’t load ~/.ctags at starting up time. +File paths for preload files are changed. +See “FILES” section of ctags(1).

+
+
+

Environment variables for arranging command lines

+

Universal Ctags doesn’t read CTAGS and/or ETAGS environment +variables.

+
+
+

Incompatibilities in command line interface

+
+

Ordering in a command line

+

The command line format of Universal Ctags is “ctags [options] +[source_file(s)]” following the standard POSIX convention.

+

Exuberant Ctags accepts a option following a source file.

+
$ ctags -o - foo.c --list-kinds=Sh
+f  functions
+
+
+

Universal Ctags warns and ignores the option --list-kinds=Sh as follows.

+
$ ctags -o - foo.c --list-kinds=Sh
+ctags: Warning: cannot open input file "--list-kinds=Sh" : No such file or directory
+a       foo.c   /^void a () {}$/;"      f       typeref:typename:void
+b       foo.c   /^void b () {}$/;"      f       typeref:typename:void
+
+
+
+
+

The order of application of patterns and extensions in --langmap

+

When applying mappings for a name of given source file, +Exuberant Ctags tests file name patterns AFTER file extensions +(e-map-order). Universal Ctags does this differently; it tests file +name patterns BEFORE file extensions (u-map-order).

+

This incompatible change is introduced to deal with the following +situation:

+
+
    +
  • build.xml as a source file,

  • +
  • The Ant parser declares it handles a file name pattern build.xml, and

  • +
  • The XML parser declares it handles a file extension .xml.

  • +
+
+

Which parser should be used for parsing build.xml? The assumption +of Universal Ctags is the user may want to use the Ant parser; the +file name pattern it declares is more specific than the file extension +that the XML parser declares. However, e-map-order chooses the XML +parser.

+

So Universal Ctags uses the u-map-order even though it introduces an +incompatibility.

+

--list-map-extensions=<language> and --list-map-patterns=<language> +options are helpful to verify and the file extensions and the file +name patterns of given <language>.

+
+
+

Remove --file-tags and --file-scope options

+

Even in Exuberant Ctags, --file-tags is not documented in its man page. +Instead of specifying --file-tags or --file-tags=yes, use +--extras=+f or --extras=+{inputFile}.

+

Instead of specifying --file-tags=no, use +--extras=-f or --extras=-{inputFile}.

+

Universal Ctags introduces F/fileScope extra as the replacement for +--file-scope option.

+

Instead of specifying --file-tags or --file-tags=yes, use +--extras=+F or --extras=+{fileScope}.

+

Instead of specifying --file-tags=no, use +--extras=-F or --extras=-{fileScope}.

+
+
+
+

Incompatibilities in language and kind definitions

+
+

Language name defined with --langdef=name option

+

The characters you can use are more restricted than Exuberant Ctags. +For more details, see the description of --langdef=name in ctags-optlib(7).

+
+
+

Obsoleting --<LANG>-kinds option

+

Some options have <LANG> as parameterized parts in their name like +--foo-<LANG>=... or --<LANG>-foo=.... The most of all such +options in Exuberant Ctags have the former form, --foo-<LANG>=.... +The exception is --<LANG>-kinds.

+

Universal Ctags uses the former form for all <LANG> parameterized +option. Use --kinds-<LANG> instead of --<LANG>-kinds in +Universal Ctags. --<LANG>-kinds still works but it will be +removed in the future.

+

The former form may be friendly to shell completion engines.

+
+
+

Disallowing to define a kind with file as name

+

The kind name file is reserved. Using it as part of kind spec in +--regex-<LANG> option is now disallowed.

+
+
+

Disallowing to define a kind with ‘F’ as letter

+

The kind letter ‘F’ is reserved. Using it as part of a kind spec in +--regex-<LANG> option is now disallowed.

+
+
+

Disallowing to use other than alphabetical character as kind letter

+

Exuberant Ctags accepts a character other than alphabetical character +as kind letter in --regex-<LANG>=... option. Universal Ctags +accepts only an alphabetical character.

+
+
+

Acceptable characters as parts of a kind name

+

Exuberant Ctags accepts any character as a part of a kind name +defined with --regex-<LANG>=/regex/replacement/kind-spec/.

+

Universal Ctags accepts only an alphabetical character as +the initial letter of a kind name. +Universal Ctags accepts only an alphabetical character or +numerical character as the rest letters.

+

An example:

+
--regex-Foo=/abstract +class +([a-z]+)/\1/a,abstract class/i
+
+
+

Universal Ctags rejects this because the kind name, abstract class, +includes a whitespace character.

+

This requirement is for making the output of Universal Ctags follow +the tags file format.

+
+
+

A combination of a kind letter and a kind name

+

In Universal Ctags, the combination of +a kind letter and a kind name must be unique in a language.

+

You cannot define more than one kind reusing a kind letter with +different kind names. You cannot define more than one kind reusing a +kind name with different kind letters.

+

An example:

+
--regex-Foo=/abstract +class +([a-z]+)/\1/a,abstractClass/i
+--regex-Foo=/attribute +([a-z]+)/\1/a,attribute/i
+
+
+

Universal Ctags rejects this because the kind letter, ‘a’, used twice +for defining a kind abstractClass and attribute.

+
+
+
+

Incompatibilities in tags file format

+
+

Using numerical character in the name part of tag tagfield

+

The version 2 tags file format, the default output format of +Exuberant Ctags, accepts only alphabetical characters in the name part +of tag tagfield.

+

Universal Ctags introduces an exception to this specification; it may +use numerical characters in addition to alphabetical characters as the +letters other than initial letter of the name part.

+

The kinds heading1, heading2, and heading3 in the HTML parser +are the examples.

+
+
+

Truncating the pattern for long input lines

+

To prevent generating overly large tags files, a pattern field is +truncated, by default, when its size exceeds 96 bytes. A different +limit can be specified with --pattern-length-limit=N. Specifying +0 as N results no truncation as Exuberant Ctags does not.

+
+
+

Kind letters and names

+

A kind letter ‘F’ and a kind name file are reserved in the +main part. A parser cannot have a kind conflicting with +these reserved ones. Some incompatible changes are introduced +to follow the above rule.

+
    +
  • Cobol’s file kind is renamed to fileDesc because the +kind name file is reserved.

  • +
  • Ruby’s ‘F’ (singletonMethod) is changed to ‘S’.

  • +
  • SQL’s ‘F’ (field) is changed to ‘E’.

  • +
+
+
+
+
+

SEE ALSO

+

ctags(1), ctags-optlib(7), and tags(5).

+
+
+ + +
+
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/ctags/docs/man/ctags-lang-iPythonCell.7.html b/ctags/docs/man/ctags-lang-iPythonCell.7.html new file mode 100644 index 0000000..84be1b1 --- /dev/null +++ b/ctags/docs/man/ctags-lang-iPythonCell.7.html @@ -0,0 +1,186 @@ + + + + + + + + + ctags-lang-iPythonCell — Universal Ctags 0.3.0 documentation + + + + + + + + + + + + + + + +
+
+
+
+ +
+

ctags-lang-iPythonCell

+

The man page of the iPythonCell parser for Universal Ctags

+
+
Version
+

5.9.0

+
+
Manual group
+

Universal Ctags

+
+
Manual section
+

7

+
+
+
+

SYNOPSIS

+
+
ctags … --extras={subparser} --languages=+iPythonCell,Python \
+
+
[--extras-IPythonCell=+{doubleSharps}] \
+
[--regex-IPythonCell=/<PATTERN>/\n/c/] …
+
+
+
+
+

DESCRIPTION

+

iPythonCell is a subparser stacked on top of the Python parser. +It works when:

+
    +
  • The Python parser is enabled,

  • +
  • the subparser extra is enabeld, and

  • +
  • the iPythonCell parser itself is enabled.

  • +
+

iPythonCell extracts cells explained as in vim-ipython-cell +(https://github.com/hanschen/vim-ipython-cell/blob/master/README.md).

+
+
+

KIND(S)

+

The iPythonCell parser defines only a cell kind.

+
+
+

EXTRA(S)

+

Tagging cells staring with ##... is disabled by default because +the pattern is too generic; with that pattern unwanted tags can be extracted.

+

Enable doubleSharps language specific extra for tagging cells +staring with ##....

+
+
+

CUSTOMIZING

+

If your favorite cell pattern is not supported in the parser, you can +define the pattern in your .ctagd.d/your.ctags or command lines. +Here is an example how to support “# CTAGS: ...”:

+

“input.py”

+
x=1
+# CTAGS: DEFINE F
+def F():
+        # CTAGS: DO NOTING
+        pass
+
+
+

“output.tags” +with “--options=NONE --sort=no --extras=+{subparser} --regex-IPythonCell=/[ t]*# CTAGS:[ ]?(.*)$/1/c/ -o - input.py”

+
x    input.py        /^x=1$/;"       v
+DEFINE F     input.py        /^# CTAGS: DEFINE F$/;" c
+F    input.py        /^def F():$/;"  f
+DO NOTING    input.py        /^      # CTAGS: DO NOTING$/;"  c
+
+
+

You can put “--regex-IPythonCell=/[ \t]*# CTAGS:[ ]?(.*)$/\1/c/” in your.ctags +to avoid specifying the pattern repeatedly.

+
+
+

SEE ALSO

+

ctags(1), ctags-client-tools(7), ctags-lang-python(7)

+
+
+ + +
+
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/ctags/docs/man/ctags-lang-inko.7.html b/ctags/docs/man/ctags-lang-inko.7.html new file mode 100644 index 0000000..78d9968 --- /dev/null +++ b/ctags/docs/man/ctags-lang-inko.7.html @@ -0,0 +1,141 @@ + + + + + + + + + ctags-lang-inko — Universal Ctags 0.3.0 documentation + + + + + + + + + + + + + + + +
+
+
+
+ +
+

ctags-lang-inko

+
+
Version
+

5.9.0

+
+
Manual group
+

Universal Ctags

+
+
Manual section
+

7

+
+
+
+

SYNOPSIS

+
+
ctags … --languages=+Inko …
+
ctags … --language-force=Inko …
+
ctags … --map-Inko=+.inko …
+
+
+
+

DESCRIPTION

+

This man page describes the Inko parser for Universal Ctags.

+

The input file is expected to be valid Inko source code, otherwise the output of +ctags is undefined.

+

Tags are generated for objects, traits, methods, attributes, and constants. +String literals are ignored.

+
+
+

SEE ALSO

+

ctags(1), ctags-client-tools(7)

+
+
+ + +
+
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/ctags/docs/man/ctags-lang-julia.7.html b/ctags/docs/man/ctags-lang-julia.7.html new file mode 100644 index 0000000..a420c5e --- /dev/null +++ b/ctags/docs/man/ctags-lang-julia.7.html @@ -0,0 +1,332 @@ + + + + + + + + + ctags-lang-julia — Universal Ctags 0.3.0 documentation + + + + + + + + + + + + + + + +
+
+
+
+ +
+

ctags-lang-julia

+

Random notes about tagging Julia source code with Universal-ctags

+
+
Version
+

5.9.0

+
+
Manual group
+

Universal-ctags

+
+
Manual section
+

7

+
+
+
+

SYNOPSIS

+
+
ctags … --languages=+Julia …
+
ctags … --language-force=Julia …
+
ctags … --map-Julia=+.jl …
+
+
+
+

DESCRIPTION

+

This man page gathers random notes about tagging Julia source code.

+
+
+

TAGGING import AND using EXPRESSIONS

+
+

Summary

+

using X

+
+
++++++ + + + + + + + + + + + + + + +

name

kind

role

other noticeable fields

X

module

used

N/A

+
+

using X: a, b

+
+
++++++ + + + + + + + + + + + + + + + + + + + +

name

kind

role

other noticeable fields

X

module

namespace

N/A

a, b

unknown

used

scope:module:X

+
+

import X

+
+
++++++ + + + + + + + + + + + + + + +

name

kind

role

other noticeable fields

X

module

imported

N/A

+
+

import X.a, Y.b

+
+
++++++ + + + + + + + + + + + + + + + + + + + + + + + + +

name

kind

role

other noticeable fields

X, Y

module

namespace

N/A

a

unknown

imported

scope:module:X

b

unknown

imported

scope:module:Y

+
+

import X: a, b

+
+
++++++ + + + + + + + + + + + + + + + + + + + +

name

kind

role

other noticeable fields

X

module

namespace

N/A

a,b

unknown

imported

scope:module:X

+
+
+
+

Examples

+

“input.jl”

+
using X0
+
+
+

“output.tags” +with “--options=NONE -o - --extras=+r --fields=+rzK input.jl”

+
X0      input.jl        /^using X0$/;"  kind:module     roles:used
+
+
+

--extras=+r (or --extras=+{reference}) option is needed for this tag, +since it’s a reference tag. This is because module X is not defined here. +It is defined in another file. Enable roles: field with --fields=+r is +for recording that the module is “used”, i.e., loaded by using.

+

“input.jl”

+
import X1.a, X2.b, X3
+
+
+

“output.tags” +with “--options=NONE -o - --extras=+r --fields=+rzKZ input.jl”

+
X1      input.jl        /^import X1.a, X2.b, X3$/;"     kind:module     roles:namespace
+X2      input.jl        /^import X1.a, X2.b, X3$/;"     kind:module     roles:namespace
+X3      input.jl        /^import X1.a, X2.b, X3$/;"     kind:module     roles:imported
+a       input.jl        /^import X1.a, X2.b, X3$/;"     kind:unknown    scope:module:X1 roles:imported
+b       input.jl        /^import X1.a, X2.b, X3$/;"     kind:unknown    scope:module:X2 roles:imported
+
+
+

Why X1 and X2 have role “namespace”, while X3 have role “imported”? +It’s because the symbol a in module X1, and b in module X2 are +brought to the current scope, but X1 and X2 themselves are not. We use +“namespace” role for such modules.

+

X3 is different. The symbol X3, together with all exported symbols in +X3, is brought to current scope. For such modules, we use “imported” or +“used” role depending whether they are loaded by import or using.

+

Also, notice that a and b have the “unknown” kind. This is because we +cannot know whether it’s a function, constant, or macro, etc.

+
+
+
+

SEE ALSO

+

ctags(1), ctags-client-tools(7)

+
+
+ + +
+
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/ctags/docs/man/ctags-lang-python.7.html b/ctags/docs/man/ctags-lang-python.7.html new file mode 100644 index 0000000..fcd72c4 --- /dev/null +++ b/ctags/docs/man/ctags-lang-python.7.html @@ -0,0 +1,476 @@ + + + + + + + + + ctags-lang-python — Universal Ctags 0.3.0 documentation + + + + + + + + + + + + + + + +
+
+
+
+ +
+

ctags-lang-python

+

Random notes about tagging python source code with Universal Ctags

+
+
Version
+

5.9.0

+
+
Manual group
+

Universal Ctags

+
+
Manual section
+

7

+
+
+
+

SYNOPSIS

+
+
ctags … --languages=+Python …
+
ctags … --language-force=Python …
+
ctags … --map-Python=+.py …
+
+
+
+

DESCRIPTION

+

This man page gathers random notes about tagging python source code.

+
+
+

TAGGING import STATEMENTS

+
+

Summary

+

import X

+
+
++++++ + + + + + + + + + + + + + + +

name

kind

role

other noticeable fields

X

module

imported

N/A

+
+

import X as Y

+
+
++++++ + + + + + + + + + + + + + + + + + + + +

name

kind

role

other noticeable fields

X

module

indirectlyImported

N/A

Y

namespace

definition

nameref:module:X

+
+

from X import *

+
+
++++++ + + + + + + + + + + + + + + +

name

kind

role

other noticeable fields

X

module

namespace

N/A

+
+

from X import Y

+
+
++++++ + + + + + + + + + + + + + + + + + + + +

name

kind

role

other noticeable fields

X

module

namespace

N/A

Y

unknown

imported

scope:module:X

+
+

from X import Y as Z

+
+
++++++ + + + + + + + + + + + + + + + + + + + + + + + + +

name

kind

role

other noticeable fields

X

module

namespace

N/A

Y

unknown

indirectlyImported

scope:module:X

Z

unknown

definition

nameref:unknown:X

+
+
+
+

Examples

+

“input.py”

+
import X0
+
+
+

“output.tags” +with “--options=NONE -o - --extras=+r --fields=+rzK input.py”

+
X0      input.py        /^import X0$/;" kind:module     roles:imported
+
+
+

A tag for an imported module has module kind with imported role. The +module is not defined here; it is defined in another file. So the tag for the +imported module is a reference tag; specify --extras=+r (or +--extras=+{reference}) option for tagging it. “roles:” field enabled with +--fields=+r is for recording the module is “imported” to the tag file.

+

“input.py”

+
import X1 as Y1
+
+
+

“output.tags” +with “--options=NONE -o - --extras=+r --fields=+rzK --fields-Python=+{nameref} input.py”

+
X1      input.py        /^import X1 as Y1$/;"   kind:module     roles:indirectlyImported
+Y1      input.py        /^import X1 as Y1$/;"   kind:namespace  roles:def       nameref:module:X1
+
+
+

“Y1” introduces a new name and is defined here. So “Y1” is tagged as a +definition tag. “X1” is imported in a way that its name cannot be used +in this source file. For letting client tools know that the name cannot be used, +indirectlyImported role is assigned for “X1”. “Y1” is the name for +accessing objects defined in the module imported via “X1”. For recording this +relationship, nameref: field is attached to the tag of “Y1”. Instead of +module kind, namespace kind is assigned to “Y1” because “Y1” itself +isn’t a module.

+

“input.py”

+
from X2 import *
+
+
+

“output.tags” +with “--options=NONE -o - --extras=+r --fields=+rzK input.py”

+
X2      input.py        /^from X2 import *$/;"  kind:module     roles:namespace
+
+
+

The module is not defined here; it is defined in another file. So the tag for +the imported module is a reference tag. Unlike “X0” in “import X0”, “X2” may not +be used because the names defined in “X2” can be used in this source file. To represent +the difference namespace role is attached to “X2” instead of imported.

+

“input.py”

+
from X3 import Y3
+
+
+

“output.tags” +with “--options=NONE -o - --extras=+r --fields=+rzKZ input.py”

+
X3      input.py        /^from X3 import Y3$/;" kind:module     roles:namespace
+Y3      input.py        /^from X3 import Y3$/;" kind:unknown    scope:module:X3 roles:imported
+
+
+

“Y3” is a name for a language object defined in “X3” module. “scope:module:X3” +attached to “Y3” represents this relation between “Y3” and “X3”. ctags +assigns unknown kind to “Y3” because ctags cannot know whether “Y3” is a +class, a variable, or a function from the input file.

+

“input.py”

+
from X4 import Y4 as Z4
+
+
+

“output.tags” +with “--options=NONE -o - --extras=+r --fields=+rzKZ input.py”

+
X4      input.py        /^from X4 import Y4 as Z4$/;"   kind:module     roles:namespace
+Y4      input.py        /^from X4 import Y4 as Z4$/;"   kind:unknown    scope:module:X4 roles:indirectlyImported
+Z4      input.py        /^from X4 import Y4 as Z4$/;"   kind:unknown    roles:def       nameref:unknown:Y4
+
+
+

“Y4” is similar to “Y3” of “from X3 import Y3” but the name cannot be used here. +indirectlyImported role assigned to “Y4” representing this. “Z4” is the name for +accessing the language object named in “Y4” in “X4” module. “nameref:unknown:Y4” +attached to “Z4” and “scope:module:X4” attached to “Y4” represent the relations.

+
+
+
+

LAMBDA EXPRESSION AND TYPE HINT

+
+

Summary

+

id = lambda var0: var0

+
+
++++++ + + + + + + + + + + + + + + +

name

kind

role

other noticeable fields

id

function

definition

signature:(var0)

+
+

id_t: Callable[[int], int] = lambda var1: var1

+
+
++++++ + + + + + + + + + + + + + + + + + + + +

name

kind

role

other noticeable fields

id_t

variable

definition

typeref:typename:Callable[[int], int] nameref:function:anonFuncN

anonFuncN

function

definition

signature:(var1)

+
+
+
+

Examples

+

“input.py”

+
from typing import Callable
+id = lambda var0: var0
+id_t: Callable[[int], int] = lambda var1: var1
+
+
+

“output.tags” +with “--options=NONE -o - --sort=no --fields=+KS --fields-Python=+{nameref} --extras=+{anonymous} input.py”

+
id      input.py        /^id = lambda var0: var0$/;"    function        signature:(var0)
+id_t    input.py        /^id_t: Callable[[int], int] = lambda var1: var1$/;"\
+        variable        typeref:typename:Callable[[int], int]   nameref:function:anonFunc84011d2c0101
+anonFunc84011d2c0101    input.py        /^id_t: Callable[[int], int] = lambda var1: var1$/;"\
+        function        signature:(var1)
+
+
+

If a variable (“id”) with no type hint is initialized with a lambda expression, +ctags assigns function kind for the tag of “id”.

+

If a variable (“id_t”) with a type hint is initialized with a lambda expression, +ctags assigns variable kind for the tag of “id_t” with typeref: and +nameref: fields. ctags fills typeref: field with the value of the type +hint. The way of filling nameref: is a bit complicated.

+

For the lambda expression used in initializing the type-hint’ed variable, ctags +creates anonymous extra tag (“anonFunc84011d2c0101”). ctags fills the +nameref: field of “id_t” with the name of anonymous extra tag: +“nameref:function:anonFunc84011d2c0101”.

+

You may think why ctags does so complicated, and why ctags doesn’t emit +following tags output for the input:

+
id      input.py        /^id = \\$/;"   function        signature:(var0)
+id_t    input.py        /^id_t: \\$/;"  function        typeref:typename:Callable[[int], int]   signature:(var1)
+
+
+

There is a reason. The other languages of ctags obey the following rule: ctags fills +typeref: field for a tag of a callable object (like function) with the type +of its return value. If we consider “id_t” is a function, its typeref: field +should have “typename:int”. However, for filling typeref: with “typename:int”, +ctags has to analyze “Callable[[int], int]” deeper. We don’t want to do so.

+
+
+
+

SEE ALSO

+

ctags(1), ctags-client-tools(7), ctags-lang-iPythonCell(7)

+
+
+ + +
+
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/ctags/docs/man/ctags-lang-r.7.html b/ctags/docs/man/ctags-lang-r.7.html new file mode 100644 index 0000000..f7f93e7 --- /dev/null +++ b/ctags/docs/man/ctags-lang-r.7.html @@ -0,0 +1,210 @@ + + + + + + + + + ctags-lang-r — Universal Ctags 0.3.0 documentation + + + + + + + + + + + + + + + +
+
+
+
+ +
+

ctags-lang-r

+

Random notes about tagging R source code with Universal Ctags

+
+
Version
+

5.9.0

+
+
Manual group
+

Universal Ctags

+
+
Manual section
+

7

+
+
+
+

SYNOPSIS

+
+
ctags … --languages=+R …
+
ctags … --language-force=R …
+
ctags … --map-Python=+.r …
+
+
+
+

DESCRIPTION

+

This man page gathers random notes about tagging R source code +with Universal Ctags.

+
+
+

Kinds

+

If a variable gets a value returned from a well-known constructor +and the variable appears for the first time in the current input file, +the R parser makes a tag for the variable and attaches a kind +associated with the constructor to the tag regardless of whether +the variable appears in the top-level context or a function.

+

Well-known constructor and kind mapping

+
+
++++ + + + + + + + + + + + + + + + + + + + +

Constructor

kind

function()

function

c()

vector

list()

list

data.frame()

dataframe

+
+

If a variable doesn’t get a value returned from one of well-known +constructors, the R parser attaches globalVar or functionVar kind +to the tag for the variable depending on the context.

+

Here is an example demonstrating the usage of the kinds:

+

“input.r”

+
G <- 1
+v <- c(1, 2)
+l <- list(3, 4)
+d <- data.frame(n = v)
+f <- function(a) {
+        g <- function (b) a + b
+        w <- c(1, 2)
+        m <- list (3, 4)
+        e <- data.frame(n = w)
+        L <- 2
+}
+
+
+

“output.tags” +with “--options=NONE --sort=no --fields=+KZ -o - input.r”

+
G       input.r /^G <- 1$/;"    globalVar
+v       input.r /^v <- c(1, 2)$/;"      vector
+l       input.r /^l <- list(3, 4)$/;"   list
+d       input.r /^d <- data.frame(n = v)$/;"    dataframe
+n       input.r /^d <- data.frame(n = v)$/;"    nameattr        scope:dataframe:d
+f       input.r /^f <- function(a) {$/;"        function
+g       input.r /^      g <- function (b) a + b$/;"     function        scope:function:f
+w       input.r /^      w <- c(1, 2)$/;"        vector  scope:function:f
+m       input.r /^      m <- list (3, 4)$/;"    list    scope:function:f
+e       input.r /^      e <- data.frame(n = w)$/;"      dataframe       scope:function:f
+n       input.r /^      e <- data.frame(n = w)$/;"      nameattr        scope:dataframe:f.e
+L       input.r /^      L <- 2$/;"      functionVar     scope:function:f
+
+
+
+
+

SEE ALSO

+

ctags(1)

+
+
+ + +
+
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/ctags/docs/man/ctags-lang-sql.7.html b/ctags/docs/man/ctags-lang-sql.7.html new file mode 100644 index 0000000..6046469 --- /dev/null +++ b/ctags/docs/man/ctags-lang-sql.7.html @@ -0,0 +1,237 @@ + + + + + + + + + ctags-lang-sql — Universal Ctags 0.3.0 documentation + + + + + + + + + + + + + + + +
+
+
+
+ +
+

ctags-lang-sql

+

The man page of the SQL parser for Universal Ctags

+
+
Version
+

5.9.0

+
+
Manual group
+

Universal Ctags

+
+
Manual section
+

7

+
+
+
+

SYNOPSIS

+
+
ctags … [--extras={guest}] --languages=+SQL …
+
+
+
+

DESCRIPTION

+

The SQL parser supports various SQL dialects. PostgreSQL is one of them.

+

PostgreSQL allows user-defined functions to be written in other +languages (procedural languages) besides SQL and C [PL].

+

The SQL parser makes tags for language objects in the user-defined +functions written in the procedural languages if the guest extra +is enabled.

+

The SQL parser looks for a token coming after LANGUAGE keyword in +the source code to choose a proper guest parser.

+
... LANGUAGE plpythonu AS '... user-defined function ' ...
+... AS $$ user-defined function $$ LANGUAGE plv8 ...
+
+
+

In the above examples, plpythonu and plv8 are the names of +procedural languages. The SQL parser trims pl at the start and u +at the end of the name before finding a parser ctags having. For +plpythonu and `plv8, the SQL parser extracts python and +v8 as the candidates of guest parsers.

+

For plpythonu, ctags can run its Python parser. ctags doesn’t +have a parser named v8. However, JavaScript parser of ctags has +v8 as an alias. So ctags can run the JavaScript parser as the +guest parser for plv8.

+
+
+

EXAMPLES

+

tagging code including a user-defined function in a string literal [GH3006]:

+

“input.sql”

+
CREATE OR REPLACE FUNCTION fun1() RETURNS VARCHAR AS '
+DECLARE
+        test1_var1 VARCHAR(64) := $$ABC$$;
+        test1_var2 VARCHAR(64) := $xyz$XYZ$xyz$;
+        test1_var3     INTEGER := 1;
+BEGIN
+        RETURN  TO_CHAR(test_var3, ''000'') || test1_var1 || test1_var2;
+END;
+' LANGUAGE plpgsql;
+
+
+

“output.tags” +with “--options=NONE -o - --sort=no --extras=+{guest} input.sql”

+
fun1    input.sql       /^CREATE OR REPLACE FUNCTION fun1() RETURNS VARCHAR AS '$/;"    f
+test1_var1      input.sql       /^      test1_var1 VARCHAR(64) := $$ABC$$;$/;"  v
+test1_var2      input.sql       /^      test1_var2 VARCHAR(64) := $xyz$XYZ$xyz$;$/;"    v
+test1_var3      input.sql       /^      test1_var3     INTEGER := 1;$/;"        v
+
+
+

tagging code including a user-defined function in a dollar quote [GH3006]:

+

“input.sql”

+
CREATE OR REPLACE FUNCTION fun2() RETURNS VARCHAR LANGUAGE plpgsql AS $$
+DECLARE
+        test2_var1 VARCHAR(64) := 'ABC2';
+        test2_var2 VARCHAR(64) := 'XYZ2';
+        test2_var3        INTEGER := 2;
+BEGIN
+        RETURN  TO_CHAR(test2_var3, '000') || test2_var1 || test2_var2;
+END;
+$$;
+
+
+

“output.tags” +with “--options=NONE -o - --sort=no --extras=+{guest} input.sql”

+
fun2    input.sql       /^CREATE OR REPLACE FUNCTION fun2() RETURNS VARCHAR LANGUAGE plpgsql AS $\$$/;" f
+test2_var1      input.sql       /^      test2_var1 VARCHAR(64) := 'ABC2';$/;"   v
+test2_var2      input.sql       /^      test2_var2 VARCHAR(64) := 'XYZ2';$/;"   v
+test2_var3      input.sql       /^      test2_var3        INTEGER := 2;$/;"     v
+
+
+

tagging code including a user-defined written in JavaScript:

+
-- Derived from https://github.com/plv8/plv8/blob/r3.0alpha/sql/plv8.sql
+CREATE FUNCTION test(keys text[], vals text[]) RETURNS text AS
+$$
+        var o = {};
+        for (var i = 0; i < keys.length; i++)
+                o[keys[i]] = vals[i];
+        return JSON.stringify(o);
+$$
+LANGUAGE plv8 IMMUTABLE STRICT;
+
+
+

“output.tags” +with “--options=NONE -o - --sort=no --extras=+{guest} input.sql”

+
test    input.sql       /^CREATE FUNCTION test(keys text[], vals text[]) RETURNS text AS$/;"    f
+o       input.sql       /^      var o = {};$/;" v
+
+
+
+
+

KNOWN BUGS

+

Escape sequences (‘’) in a string literal may make a guest parser confused.

+
+
+

SEE ALSO

+

ctags(1), ctags-client-tools(7)

+
+
+

REFERENCES

+
+
PL
+

PostgreSQL 9.5.25 Documentation, “Chapter 39. Procedural Languages”, https://www.postgresql.org/docs/9.5/xplang.html

+
+
GH3006(1,2)
+

@bagl’s comment submitted to https://github.com/universal-ctags/ctags/issues/3006

+
+
+
+
+ + +
+
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/ctags/docs/man/ctags-lang-verilog.7.html b/ctags/docs/man/ctags-lang-verilog.7.html new file mode 100644 index 0000000..2114fac --- /dev/null +++ b/ctags/docs/man/ctags-lang-verilog.7.html @@ -0,0 +1,318 @@ + + + + + + + + + ctags-lang-verilog — Universal Ctags 0.3.0 documentation + + + + + + + + + + + + + + + +
+
+
+
+ +
+

ctags-lang-verilog

+

The man page about SystemVerilog/Verilog parser for Universal Ctags

+
+
Version
+

5.9.0

+
+
Manual group
+

Universal Ctags

+
+
Manual section
+

7

+
+
+
+

SYNOPSIS

+
+
ctags … [--kinds-systemverilog=+Q] [--fields-SystemVerilog=+{parameter}] …
+
ctags … [--fields-Verilog=+{parameter}] …
+
+
+
+++++ + + + + + + + + + + + + + + + + +

Language

Language ID

File Mapping

SystemVerilog

SystemVerilog

.sv, .svh, svi

Verilog

Verilog

.v

+
+
+
+

DESCRIPTION

+

This man page describes about the SystemVerilog/Verilog parser for Universal Ctags. +SystemVerilog parser supports IEEE Std 1800-2017 keywords. +Verilog parser supports IEEE Std 1364-2005 keywords.

+
+

Supported Kinds

+
$ ctags --list-kinds-full=SystemVerilog
+#LETTER NAME       ENABLED REFONLY NROLES MASTER DESCRIPTION
+A       assert     yes     no      0      NONE   assertions (assert, assume, cover, restrict)
+C       class      yes     no      0      NONE   classes
+E       enum       yes     no      0      NONE   enumerators
+H       checker    yes     no      0      NONE   checkers
+I       interface  yes     no      0      NONE   interfaces
+K       package    yes     no      0      NONE   packages
+L       clocking   yes     no      0      NONE   clocking
+M       modport    yes     no      0      NONE   modports
+N       nettype    yes     no      0      NONE   nettype declarations
+O       constraint yes     no      0      NONE   constraints
+P       program    yes     no      0      NONE   programs
+Q       prototype  no      no      0      NONE   prototypes (extern, pure)
+R       property   yes     no      0      NONE   properties
+S       struct     yes     no      0      NONE   structs and unions
+T       typedef    yes     no      0      NONE   type declarations
+V       covergroup yes     no      0      NONE   covergroups
+b       block      yes     no      0      NONE   blocks (begin, fork)
+c       constant   yes     no      0      NONE   constants (define, parameter, specparam, enum values)
+e       event      yes     no      0      NONE   events
+f       function   yes     no      0      NONE   functions
+i       instance   yes     no      0      NONE   instances of module or interface
+l       ifclass    yes     no      0      NONE   interface class
+m       module     yes     no      0      NONE   modules
+n       net        yes     no      0      NONE   net data types
+p       port       yes     no      0      NONE   ports
+q       sequence   yes     no      0      NONE   sequences
+r       register   yes     no      0      NONE   variable data types
+t       task       yes     no      0      NONE   tasks
+w       member     yes     no      0      NONE   struct and union members
+
+
+

Note that prototype (Q) is disabled by default.

+
$ ctags --list-kinds-full=Verilog
+#LETTER NAME     ENABLED REFONLY NROLES MASTER DESCRIPTION
+b       block    yes     no      0      NONE   blocks (begin, fork)
+c       constant yes     no      0      NONE   constants (define, parameter, specparam)
+e       event    yes     no      0      NONE   events
+f       function yes     no      0      NONE   functions
+i       instance yes     no      0      NONE   instances of module
+m       module   yes     no      0      NONE   modules
+n       net      yes     no      0      NONE   net data types
+p       port     yes     no      0      NONE   ports
+r       register yes     no      0      NONE   variable data types
+t       task     yes     no      0      NONE   tasks
+
+
+
+
+

Supported Language Specific Fields

+
$ ctags --list-fields=Verilog
+#LETTER NAME      ENABLED LANGUAGE JSTYPE FIXED DESCRIPTION
+-       parameter no      Verilog  --b    no    parameter whose value can be overridden.
+$ ctags --list-fields=SystemVerilog
+#LETTER NAME      ENABLED LANGUAGE      JSTYPE FIXED DESCRIPTION
+-       parameter no      SystemVerilog --b    no    parameter whose value can be overridden.
+
+
+
+

parameter field

+

If the field parameter is enabled, a field parameter: is added on a parameter whose +value can be overridden on an instantiated module, interface, or program. +This is useful for a editor plugin or extension to enable auto-instantiation of modules with +parameters which can be overridden.

+
$ ctags ... --fields-Verilog=+{parameter} ...
+$ ctags ... --fields-SystemVerilog=+{parameter} ...
+
+
+

On the following source code fields parameter: are added on +parameters P*, not on ones L*. Note that L4 and L6 is declared by +parameter statement, but fields parameter: are not added, +because they cannot be overridden.

+

“input.sv”

+
// compilation unit scope
+parameter L1 = "synonym for the localparam";
+
+module with_parameter_port_list #(
+        P1,
+        localparam L2 = P1+1,
+        parameter P2)
+        ( /*port list...*/ );
+        parameter  L3 = "synonym for the localparam";
+        localparam L4 = "localparam";
+        // ...
+endmodule
+
+module with_empty_parameter_port_list #()
+        ( /*port list...*/ );
+        parameter  L5 = "synonym for the localparam";
+        localparam L6 = "localparam";
+        // ...
+endmodule
+
+module no_parameter_port_list
+        ( /*port list...*/ );
+        parameter  P3 = "parameter";
+        localparam L7 = "localparam";
+        // ...
+endmodule
+
+
+
$ ctags -uo - --fields-SystemVerilog=+{parameter} input.sv
+L1      input.sv        /^parameter L1 = "synonym for the localparam";$/;"      c       parameter:
+with_parameter_port_list        input.sv        /^module with_parameter_port_list #($/;"        m
+P1      input.sv        /^      P1,$/;" c       module:with_parameter_port_list parameter:
+L2      input.sv        /^      localparam L2 = P1+1,$/;"       c       module:with_parameter_port_list
+P2      input.sv        /^      parameter P2)$/;"       c       module:with_parameter_port_list parameter:
+L3      input.sv        /^      parameter  L3 = "synonym for the localparam";$/;"       c       module:with_parameter_port_list
+L4      input.sv        /^      localparam L4 = "localparam";$/;"       c       module:with_parameter_port_list
+with_empty_parameter_port_list  input.sv        /^module with_empty_parameter_port_list #()$/;" m
+L5      input.sv        /^      parameter  L5 = "synonym for the localparam";$/;"       c       module:with_empty_parameter_port_list
+L6      input.sv        /^      localparam L6 = "localparam";$/;"       c       module:with_empty_parameter_port_list
+no_parameter_port_list  input.sv        /^module no_parameter_port_list$/;"     m
+P3      input.sv        /^      parameter  P3 = "parameter";$/;"        c       module:no_parameter_port_list   parameter:
+L7      input.sv        /^      localparam L7 = "localparam";$/;"       c       module:no_parameter_port_list
+
+
+
+
+
+

TIPS

+

If you want to map files *.v to SystemVerilog, add +--langmap=SystemVerilog:.v option.

+
+
+
+

KNOWN ISSUES

+

See https://github.com/universal-ctags/ctags/issues/2674 for more information.

+
+
+

SEE ALSO

+ +
+
+ + +
+
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/ctags/docs/man/ctags-optlib.7.html b/ctags/docs/man/ctags-optlib.7.html new file mode 100644 index 0000000..0f73ed2 --- /dev/null +++ b/ctags/docs/man/ctags-optlib.7.html @@ -0,0 +1,520 @@ + + + + + + + + + ctags-optlib — Universal Ctags 0.3.0 documentation + + + + + + + + + + + + + + + +
+
+
+
+ +
+

ctags-optlib

+

Universal Ctags parser definition language

+
+
Version
+

5.9.0

+
+
Manual group
+

Universal Ctags

+
+
Manual section
+

7

+
+
+
+

SYNOPSIS

+
+
ctags [options] [file(s)]
+
etags [options] [file(s)]
+
+
+
+

DESCRIPTION

+

Exuberant Ctags, the ancestor of Universal Ctags, has provided +the way to define a new parser from command line. Universal Ctags +extends and refines this feature. optlib parser is the name for such +parser in Universal Ctags. “opt” intends a parser is defined with +combination of command line options. “lib” intends an optlib parser +can be more than ad-hoc personal configuration.

+

This man page is for people who want to define an optlib parser. The +readers should read ctags(1) of Universal Ctags first.

+

Following options are for defining (or customizing) a parser:

+
    +
  • --langdef=<name>

  • +
  • --map-<LANG>=[+|-]<extension>|<pattern>

  • +
  • --kinddef-<LANG>=<letter>,<name>,<description>

  • +
  • --regex-<LANG>=/<line_pattern>/<name_pattern>/<kind-spec>/[<flags>]

  • +
  • --mline-regex-<LANG>=/<line_pattern>/<name_pattern>/<kind-spec>/[<flags>]

  • +
+

Following options are for controlling loading parser definition:

+
    +
  • --options=<pathname>

  • +
  • --options-maybe=<pathname>

  • +
  • --optlib-dir=[+]<directory>

  • +
+

The design of options and notations for defining a parser in +Exuberant Ctags may focus on reducing the number of typing by user. +Reducing the number of typing is important for users who want to +define (or customize) a parser quickly.

+

On the other hand, the design in Universal Ctags focuses on +maintainability. The notation of Universal Ctags is redundant than +that of Exuberant Ctags; the newly introduced kind should be declared +explicitly, (long) names are approved than one-letter flags +specifying kinds, and naming rules are stricter.

+

This man page explains only stable options and flags. Universal Ctags +also introduces experimental options and flags which have names starting +with _. For documentation on these options and flags, visit +Universal Ctags web site at https://ctags.io/.

+
+

Storing a parser definition to a file

+

Though it is possible to define a parser from command line, you don’t +want to type the same command line each time when you need the parser. +You can store options for defining a parser into a file.

+

ctags loads files (preload files) listed in “FILES” +section of ctags(1) at program starting up. You can put your parser +definition needed usually to the files.

+

--options=<pathname>, --options-maybe=<pathname>, and +--optlib-dir=[+]<directory> are for loading optlib files you need +occasionally. See “Option File Options” section of ctags(1) for +these options.

+

As explained in “FILES” section of ctags(1), options for defining a +parser listed line by line in an optlib file. Prefixed white spaces are +ignored. A line starting with ‘#’ is treated as a comment. Escaping +shell meta character is not needed.

+

Use .ctags as file extension for optlib file. You can define +multiple parsers in an optlib file but it is better to make a file for +each parser definition.

+

--_echo=<msg> and --_force-quit=<num> options are for debugging +optlib parser.

+
+
+

Overview for defining a parser

+
    +
  1. Design the parser

    +

    You need know both the target language and the ctags’ +concepts (definition, reference, kind, role, field, extra). About +the concepts, ctags(1) of Universal Ctags may help you.

    +
  2. +
  3. Give a name to the parser

    +

    Use --langdef=<name> option. <name> is referred as <LANG> in +the later steps.

    +
  4. +
  5. Give a file pattern or file extension for activating the parser

    +

    Use --map-<LANG>=[+|-]<extension>|<pattern>.

    +
  6. +
  7. Define kinds

    +

    Use --kinddef-<LANG>=<letter>,<name>,<description> option. +Universal Ctags introduces this option. Exuberant Ctags doesn’t +have. In Exuberant Ctags, a kind is defined as a side effect of +specifying --regex-<LANG>= option. So user doesn’t have a +chance to recognize how important the definition of kind.

    +
  8. +
  9. Define patterns

    +

    Use --regex-<LANG>=/<line_pattern>/<name_pattern>/<kind-spec>/[<flags>] +option for a single-line regular expression. You can also use +--mline-regex-<LANG>=/<line_pattern>/<name_pattern>/<kind-spec>/[<flags>] +option for a multi-line regular expression.

    +

    As <kind-spec>, you can use the one-letter flag defined with +--kinddef-<LANG>=<letter>,<name>,<description> option.

    +
  10. +
+
+
+
+

OPTIONS

+
+
--langdef=<name>

Defines a new user-defined language, <name>, to be parsed with regular +expressions. Once defined, <name> may be used in other options taking +language names.

+

<name> must consist of alphanumeric characters, ‘#’, or ‘+’ +(‘[a-zA-Z0-9#+]+’). The graph characters other than ‘#’ and +‘+’ are disallowed (or reserved). Some of them ([-=:{.]) are +disallowed because they can make the command line parser of +ctags confused. The rest of them are just +reserved for future extending ctags.

+

all is an exception. all as <name> is not acceptable. It is +a reserved word. See the description of +--kinds-(<LANG>|all)=[+|-](<kinds>|*) option in ctags(1) about how the +reserved word is used.

+

The names of built-in parsers are capitalized. When +ctags evaluates an option in a command line, and +chooses a parser, ctags uses the names of +parsers in a case-insensitive way. Therefore, giving a name +started from a lowercase character doesn’t help you to avoid the +parser name confliction. However, in a tags file, +ctags prints parser names in a case-sensitive +way; it prints a parser name as specified in --langdef=<name> +option. Therefore, we recommend you to give a name started from a +lowercase character to your private optlib parser. With this +convention, people can know where a tag entry in a tag file comes +from a built-in parser or a private optlib parser.

+
+
--kinddef-<LANG>=<letter>,<name>,<description>

Define a kind for <LANG>. +Be not confused this with --kinds-<LANG>.

+

<letter> must be an alphabetical character (‘[a-zA-EG-Z]’) +other than “F”. “F” has been reserved for representing a file +since Exuberant Ctags.

+

<name> must start with an alphabetic character, and the rest +must be alphanumeric (‘[a-zA-Z][a-zA-Z0-9]*’). Do not use +“file” as <name>. It has been reserved for representing a file +since Exuberant Ctags.

+

Note that using a number character in a <name> violates the +version 2 of tags file format though ctags +accepts it. For more detail, see tags(5).

+

<description> comes from any printable ASCII characters. The +exception is { and \. { is reserved for adding flags +this option in the future. So put \ before { to include +{ to a description. To include \ itself to a description, +put \ before \.

+

Both <letter>, <name> and their combination must be unique in +a <LANG>.

+

This option is newly introduced in Universal Ctags. This option +reduces the typing defining a regex pattern with +--regex-<LANG>=, and keeps the consistency of kind +definitions in a language.

+

The <letter> can be used as an argument for --kinds-<LANG> +option to enable or disable the kind. Unless K field is +enabled, the <letter> is used as value in the “kind” extension +field in tags output.

+

The <name> surrounded by braces can be used as an argument for +--kind-<LANG> option. If K field is enabled, the <name> +is used as value in the “kind” extension field in tags output.

+

The <description> and <letter> are listed in --list-kinds +output. All three elements of the kind-spec are listed in +--list-kinds-full output. Don’t use braces in the +<description>. They will be used meta characters in the future.

+
+
--regex-<LANG>=/<line_pattern>/<name_pattern>/<kind-spec>/[<flags>]

Define a single-line regular expression.

+

The /<line_pattern>/<name_pattern>/ pair defines a regular expression +replacement pattern, similar in style to sed substitution +commands, s/regexp/replacement/, with which to generate tags from source files mapped to +the named language, <LANG>, (case-insensitive; either a built-in +or user-defined language).

+

The regular expression, <line_pattern>, defines +an extended regular expression (roughly that used by egrep(1)), +which is used to locate a single source line containing a tag and +may specify tab characters using \t.

+

When a matching line is +found, a tag will be generated for the name defined by +<name_pattern>, which generally will contain the special +back-references \1 through \9 to refer to matching sub-expression +groups within <line_pattern>.

+

The ‘/’ separator characters shown in the +parameter to the option can actually be replaced by any +character. Note that whichever separator character is used will +have to be escaped with a backslash (’\’) character wherever it is +used in the parameter as something other than a separator. The +regular expression defined by this option is added to the current +list of regular expressions for the specified language unless the +parameter is omitted, in which case the current list is cleared.

+

Unless modified by <flags>, <line_pattern> is interpreted as a POSIX +extended regular expression. The <name_pattern> should expand for all +matching lines to a non-empty string of characters, or a warning +message will be reported unless {placeholder} regex flag is +specified.

+

A kind specifier (<kind-spec>) for tags matching regexp may +follow <name_pattern>, which will determine what kind of tag is +reported in the kind extension field (see tags(5)).

+

<kind-spec> has two forms: one-letter form and full form.

+

The one-letter form in the form of <letter>. It just refers a kind +<letter> defined with --kinddef-<LANG>. This form is recommended in +Universal Ctags.

+

The full form of <kind-spec> is in the form of +<letter>,<name>,<description>. Either the kind <name> and/or the +<description> can be omitted. See the description of +--kinddef-<LANG>=<letter>,<name>,<description> option about the +elements.

+

The full form is supported only for keeping the compatibility with Exuberant +Ctags which does not have --kinddef-<LANG> option. Supporting the +form will be removed from Universal Ctags in the future.

+

About <flags>, see “FLAGS FOR --regex-<LANG> OPTION”.

+

For more information on the regular expressions used by +ctags, see either the regex(5,7) man page, or +the GNU info documentation for regex (e.g. “info regex”).

+
+
--list-regex-flags

Lists the flags that can be used in --regex-<LANG> option.

+
+
--list-mline-regex-flags

Lists the flags that can be used in --mline-regex-<LANG> option.

+
+
--mline-regex-<LANG>=/<line_pattern>/<name_pattern>/<kind-spec>/[<flags>]

Define a multi-line regular expression.

+

This option is similar to --regex-<LANG> option except the pattern is +applied to the whole file’s contents, not line by line.

+
+
--_echo=<message>

Print <message> to the standard error stream. This is helpful to +understand (and debug) optlib loading feature of Universal Ctags.

+
+
--_force-quit[=<num>]

Exits immediately when this option is processed. If <num> is used +as exit status. The default is 0. This is helpful to debug optlib +loading feature of Universal Ctags.

+
+
+
+

FLAGS FOR --regex-<LANG> OPTION

+

You can specify more than one flag, <letter>|{<name>}, at the end of --regex-<LANG> to +control how Universal Ctags uses the pattern.

+

Exuberant Ctags uses a <letter> to represent a flag. In +Universal Ctags, a <name> surrounded by braces (name form) can be used +in addition to <letter>. The name form makes a user reading an optlib +file easier.

+

The most of all flags newly added in Universal Ctags +don’t have the one-letter representation. All of them have only the name +representation. --list-regex-flags lists all the flags.

+
+
basic (one-letter form b)

The pattern is interpreted as a POSIX basic regular expression.

+
+
exclusive (one-letter form x)

Skip testing the other patterns if a line is matched to this +pattern. This is useful to avoid using CPU to parse line comments.

+
+
extend (one-letter form e)

The pattern is interpreted as a POSIX extended regular +expression (default).

+
+
icase (one-letter form i)

The regular expression is to be applied in a case-insensitive +manner.

+
+
placeholder

Don’t emit a tag captured with a regex pattern. The replacement +can be an empty string. See the following description of +scope=... flag about how this is useful.

+
+
+

scope=(ref|push|pop|clear|set)

+
+

Specify what to do with the internal scope stack.

+

A parser programmed with --regex-<LANG> has a stack (scope +stack) internally. You can use it for tracking scope +information. The scope=... flag is for manipulating and +utilizing the scope stack.

+

If {scope=push} is specified, a tag captured with +--regex-<LANG> is pushed to the stack. {scope=push} +implies {scope=ref}.

+

You can fill the scope field of captured tag with +{scope=ref}. If {scope=ref} flag is given, +ctags attaches the tag at the top to the tag +captured with --regex-<LANG> as the value for the scope: +field.

+

ctags pops the tag at the top of the stack when +--regex-<LANG> with {scope=pop} is matched to the input +line.

+

Specifying {scope=clear} removes all the tags in the scope. +Specifying {scope=set} removes all the tags in the scope, and +then pushes the captured tag as {scope=push} does.

+

In some cases, you may want to use --regex-<LANG> only for its +side effects: using it only to manipulate the stack but not for +capturing a tag. In such a case, make <name_pattern> component of +--regex-<LANG> option empty while specifying {placeholder} +as a regex flag. For example, a non-named tag can be put on +the stack by giving a regex flag “{scope=push}{placeholder}”.

+

You may wonder what happens if a regex pattern with +{scope=ref} flag matches an input line but the stack is empty, +or a non-named tag is at the top. If the regex pattern contains a +{scope=ref} flag and the stack is empty, the {scope=ref} +flag is ignored and nothing is attached to the scope: field.

+

If the top of the stack contains an unnamed tag, +ctags searches deeper into the stack to find the +top-most named tag. If it reaches the bottom of the stack without +finding a named tag, the {scope=ref} flag is ignored and +nothing is attached to the scope: field.

+

When a named tag on the stack is popped or cleared as the side +effect of a pattern matching, ctags attaches the +line number of the match to the end: field of +the named tag.

+

ctags clears all of the tags on the stack when it +reaches the end of the input source file. The line number of the +end is attached to the end: field of the cleared tags.

+
+
+
warning=<message>

print the given <message> at WARNING level

+
+
fatal=<message>

print the given <message> and exit

+
+
+
+
+
+

EXAMPLES

+
+

Perl Pod

+

This is the definition (pod.ctags) used in ctags for parsing Pod +(https://perldoc.perl.org/perlpod.html) file.

+
--langdef=pod
+--map-pod=+.pod
+
+--kinddef-pod=c,chapter,chapters
+--kinddef-pod=s,section,sections
+--kinddef-pod=S,subsection,subsections
+--kinddef-pod=t,subsubsection,subsubsections
+
+--regex-pod=/^=head1[ \t]+(.+)/\1/c/
+--regex-pod=/^=head2[ \t]+(.+)/\1/s/
+--regex-pod=/^=head3[ \t]+(.+)/\1/S/
+--regex-pod=/^=head4[ \t]+(.+)/\1/t/
+
+
+
+
+

Using scope regex flags

+

Let’s think about writing a parser for a very small subset of the Ruby +language.

+

input source file (input.srb):

+
class Example
+  def methodA
+        puts "in class_method"
+  end
+  def methodB
+        puts "in class_method"
+  end
+end
+
+
+

The parser for the input should capture Example with class kind, +methodA, and methodB with method kind. methodA and methodB +should have Example as their scope. end: fields of each tag +should have proper values.

+

optlib file (sub-ruby.ctags):

+
--langdef=subRuby
+--map-subRuby=.srb
+--kinddef-subRuby=c,class,classes
+--kinddef-subRuby=m,method,methods
+--regex-subRuby=/^class[ \t]+([a-zA-Z][a-zA-Z0-9]+)/\1/c/{scope=push}
+--regex-subRuby=/^end///{scope=pop}{placeholder}
+--regex-subRuby=/^[ \t]+def[ \t]+([a-zA-Z][a-zA-Z0-9_]+)/\1/m/{scope=push}
+--regex-subRuby=/^[ \t]+end///{scope=pop}{placeholder}
+
+
+

command line and output:

+
$ ctags --quiet --fields=+eK \
+--options=./sub-ruby.ctags -o - input.srb
+Example input.srb       /^class Example$/;"     class   end:8
+methodA input.srb       /^  def methodA$/;"     method  class:Example   end:4
+methodB input.srb       /^  def methodB$/;"     method  class:Example   end:7
+
+
+
+
+
+

SEE ALSO

+

The official Universal Ctags web site at:

+

https://ctags.io/

+

ctags(1), tags(5), regex(3), regex(7), egrep(1)

+
+
+

AUTHOR

+

Universal Ctags project +https://ctags.io/ +(This man page partially derived from ctags(1) of +Executable-ctags)

+

Darren Hiebert <dhiebert@users.sourceforge.net> +http://DarrenHiebert.com/

+
+
+ + +
+
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/ctags/docs/man/ctags.1.html b/ctags/docs/man/ctags.1.html new file mode 100644 index 0000000..18730d5 --- /dev/null +++ b/ctags/docs/man/ctags.1.html @@ -0,0 +1,1989 @@ + + + + + + + + + ctags — Universal Ctags 0.3.0 documentation + + + + + + + + + + + + + + + +
+
+
+
+ +
+

ctags

+

Generate tag files for source code

+
+
Version
+

5.9.0

+
+
Manual group
+

Universal Ctags

+
+
Manual section
+

1

+
+
+
+

SYNOPSIS

+
+
ctags [<options>] [<source_file(s)>]
+
etags [<options>] [<source_file(s)>]
+
+
+
+

DESCRIPTION

+

The ctags and etags (see -e option) programs +(hereinafter collectively referred to as ctags, +except where distinguished) generate an index (or “tag”) file for a +variety of language objects found in source file(s). This tag file allows +these items to be quickly and easily located by a text editor or other +utilities (client tools). A tag signifies a language object for which an index entry is +available (or, alternatively, the index entry created for that object).

+

Alternatively, ctags can generate a cross reference +file which lists, in human readable form, information about the various +language objects found in a set of source files.

+

Tag index files are supported by numerous editors, which allow the user to +locate the object associated with a name appearing in a source file and +jump to the file and line which defines the name. See the manual of your +favorite editor about utilizing ctags command and +the tag index files in the editor.

+

ctags is capable of generating different kinds of tags +for each of many different languages. For a complete list of supported +languages, the names by which they are recognized, and the kinds of tags +which are generated for each, see the --list-languages and --list-kinds-full +options.

+

This man page describes Universal Ctags, an implementation of ctags +derived from Exuberant Ctags. The major incompatible changes between +Universal Ctags and Exuberant Ctags are enumerated in +ctags-incompatibilities(7).

+

One of the advantages of Exuberant Ctags is that it allows a user to +define a new parser from the command line. Extending this capability is one +of the major features of Universal Ctags. ctags-optlib(7) +describes how the capability is extended.

+

Newly introduced experimental features are not explained here. If you +are interested in such features and ctags internals, +visit https://docs.ctags.io/.

+
+
+

COMMAND LINE INTERFACE

+

Despite the wealth of available options, defaults are set so that +ctags is most commonly executed without any options (e.g. +“ctags *”, or “ctags -R”), which will +create a tag file in the current directory for all recognized source +files. The options described below are provided merely to allow custom +tailoring to meet special needs.

+

Note that spaces separating the single-letter options from their parameters +are optional.

+

Note also that the boolean parameters to the long form options (those +beginning with -- and that take a [=(yes|no)] parameter) may be omitted, +in which case =yes is implied. (e.g. --sort is equivalent to --sort=yes). +Note further that =1, =on, and =true are considered synonyms for =yes, +and that =0, =off, and =false are considered synonyms for =no.

+

Some options are either ignored or useful only when used while running in +etags mode (see -e option). Such options will be noted.

+

<options> must precede the <source_file(s)> following the standard POSIX +convention.

+

Options taking language names will accept those names in either upper or +lower case. See the --list-languages option for a complete list of the +built-in language names.

+
+

Letters and names

+

Some options take one-letter flags as parameters (e.g. --kinds-<LANG> option). +Specifying just letters help a user create a complicated command line +quickly. However, a command line including sequences of one-letter flags +becomes difficult to understand.

+

Universal Ctags accepts long-name flags in +addition to such one-letter flags. The long-name and one-letter flags can be mixed in an +option parameter by surrounding each long-name by braces. Thus, for an +example, the following three notations for --kinds-C option have +the same meaning:

+
--kinds-C=+pLl
+--kinds-C=+{prototype}{label}{local}
+--kinds-C=+{prototype}L{local}
+
+
+

Note that braces may be meta characters in your shell. Put +single quotes in such case.

+

--list-... options shows one-letter flags and associated long-name flags.

+
+
+

List options

+

Universal Ctags introduces many --list-... options that provide +the internal data of Universal Ctags (See “Listing Options”). Both users and client tools may +use the data. --with-list-header and --machinable options +adjust the output of the most of --list-... options.

+

The default setting (--with-list-header=yes and --machinable=no) +is for using interactively from a terminal. The header that explains +the meaning of columns is simply added to the output, and each column is +aligned in all lines. The header line starts with a hash (’#’) character.

+

For scripting in a client tool, --with-list-header=no and +--machinable=yes may be useful. The header is not added to the +output, and each column is separated by tab characters.

+

Note the order of columns will change in the future release. +However, labels in the header will not change. So by scanning +the header, a client tool can find the index for the target +column.

+
+
+
+

OPTIONS

+

ctags has more options than listed here. +Options starting with an underscore character, such as --_echo=<msg>, +are not listed here. They are experimental or for debugging purpose.

+

Notation: <foo> is for a variable string foo, [ ... ] for optional, +| for selection, and ( ... ) for grouping. For example +--foo[=(yes|no)]'' means ``--foo, -foo=yes, or -foo=no.

+
+

Input/Output File Options

+
+
--exclude=<pattern>

Add <pattern> to a list of excluded files and directories. This option may +be specified as many times as desired. For each file name considered +by ctags, each pattern specified using this option +will be compared against both the complete path (e.g. +some/path/base.ext) and the base name (e.g. base.ext) of the file, thus +allowing patterns which match a given file name irrespective of its +path, or match only a specific path.

+

If appropriate support is available +from the runtime library of your C compiler, then pattern may +contain the usual shell wildcards (not regular expressions) common on +Unix (be sure to quote the option parameter to protect the wildcards from +being expanded by the shell before being passed to ctags; +also be aware that wildcards can match the slash character, ‘/’). +You can determine if shell wildcards are available on your platform by +examining the output of the --list-features option, which will include +wildcards in the compiled feature list; otherwise, pattern is matched +against file names using a simple textual comparison.

+

If <pattern> begins with the character ‘@’, then the rest of the string +is interpreted as a file name from which to read exclusion patterns, +one per line. If pattern is empty, the list of excluded patterns is +cleared.

+

Note that at program startup, the default exclude list contains names of +common hidden and system files, patterns for binary files, and directories +for which it is generally not desirable to descend while processing the +--recurse option. To see the list of built-in exclude patterns, use +--list-excludes.

+

See also the description for --exclude-exception= option.

+
+
--exclude-exception=<pattern>

Add <pattern> to a list of included files and directories. The pattern +affects the files and directories that are excluded by the pattern +specified with --exclude= option.

+

For an example, you want ctags to ignore all files +under foo directory except foo/main.c, use the following command +line: --exclude=foo/* --exclude-exception=foo/main.c.

+
+
--filter[=(yes|no)]

Makes ctags behave as a filter, reading source +file names from standard input and printing their tags to standard +output on a file-by-file basis. If --sort is enabled, tags are sorted +only within the source file in which they are defined. File names are +read from standard input in line-oriented input mode (see note for -L +option) and only after file names listed on the command line or from +any file supplied using the -L option. When this option is enabled, +the options -f, -o, and --totals are ignored. This option is quite +esoteric and is disabled by default.

+
+
--filter-terminator=<string>

Specifies a <string> to print to standard output following the tags for +each file name parsed when the --filter option is enabled. This may +permit an application reading the output of ctags +to determine when the output for each file is finished.

+

Note that if the +file name read is a directory and --recurse is enabled, this string will +be printed only once at the end of all tags found for by descending +the directory. This string will always be separated from the last tag +line for the file by its terminating newline.

+

This option is quite esoteric and is empty by default.

+
+
--links[=(yes|no)]

Indicates whether symbolic links (if supported) should be followed. +When disabled, symbolic links are ignored. This option is on by default.

+
+
--maxdepth=<N>

Limits the depth of directory recursion enabled with the --recurse +(-R) option.

+
+
--recurse[=(yes|no)]

Recurse into directories encountered in the list of supplied files.

+

If the list of supplied files is empty and no file list is specified with +the -L option, then the current directory (i.e. ‘.’) is assumed. +Symbolic links are followed by default (See --links option). If you don’t like these behaviors, either +explicitly specify the files or pipe the output of find(1) into +“ctags -L -” instead. See, also, the --exclude and +--maxdepth to limit recursion.

+

Note: This option is not supported on +all platforms at present. It is available if the output of the --help +option includes this option.

+
+
+
+
-R

Equivalent to --recurse.

+
+
-L <file>

Read from <file> a list of file names for which tags should be generated.

+

If file is specified as ‘-’, then file names are read from standard +input. File names read using this option are processed following file +names appearing on the command line. Options are also accepted in this +input. If this option is specified more than once, only the last will +apply.

+

Note: file is read in line-oriented mode, where a new line is +the only delimiter and non-trailing white space is considered significant, +in order that file names containing spaces may be supplied +(however, trailing white space is stripped from lines); this can affect +how options are parsed if included in the input.

+
+
--append[=(yes|no)]

Indicates whether tags generated from the specified files should be +appended to those already present in the tag file or should replace them. +This option is no by default.

+
+
-a

Equivalent to --append.

+
+
-f <tagfile>

Use the name specified by <tagfile> for the tag file (default is “tags”, +or “TAGS” when running in etags mode). If <tagfile> is specified as ‘-‘, +then the tags are written to standard output instead.

+

ctags +will stubbornly refuse to take orders if tagfile exists and +its first line contains something other than a valid tags line. This +will save your neck if you mistakenly type “ctags -f +*.c”, which would otherwise overwrite your first C file with the tags +generated by the rest! It will also refuse to accept a multi-character +file name which begins with a ‘-’ (dash) character, since this most +likely means that you left out the tag file name and this option tried to +grab the next option as the file name. If you really want to name your +output tag file -ugly, specify it as “-f ./-ugly”.

+

This option must +appear before the first file name. If this option is specified more +than once, only the last will apply.

+
+
-o <tagfile>

Equivalent to “-f tagfile”.

+
+
+
+
+

Output Format Options

+
+
--format=(1|2)

Change the format of the output tag file. Currently the only valid +values for level are 1 or 2. Level 1 specifies the original tag file +format and level 2 specifies a new extended format containing extension +fields (but in a manner which retains backward-compatibility with +original vi(1) implementations). The default level is 2. +[Ignored in etags mode]

+
+
--output-format=(u-ctags|e-ctags|etags|xref|json)

Specify the output format. The default is u-ctags. +See tags(5) for u-ctags and e-ctags. +See -e for etags, and -x for xref. +json format is available only if +the ctags executable is built with libjansson. +See ctags-client-tools(7) for more about json format.

+
+
-e

Same as --output-format=etags. +Enable etags mode, which will create a tag file for use with the Emacs +editor. Alternatively, if ctags is invoked by a +name containing the string “etags” (either by renaming, +or creating a link to, the executable), etags mode will be enabled.

+
+
-x

Same as --output-format=xref. +Print a tabular, human-readable cross reference (xref) file to standard +output instead of generating a tag file. The information contained in +the output includes: the tag name; the kind of tag; the line number, +file name, and source line (with extra white space condensed) of the +file which defines the tag. No tag file is written and all options +affecting tag file output will be ignored.

+

Example applications for this +feature are generating a listing of all functions located in a source +file (e.g. “ctags -x --kinds-c=f file”), or generating +a list of all externally visible global variables located in a source +file (e.g. “ctags -x --kinds-c=v --extras=-F file”).

+
+
--sort=(yes|no|foldcase)

Indicates whether the tag file should be sorted on the tag name +(default is yes). Note that the original vi(1) required sorted tags. +The foldcase value specifies case insensitive (or case-folded) sorting. +Fast binary searches of tag files sorted with case-folding will require +special support from tools using tag files, such as that found in the +ctags readtags library, or Vim version 6.2 or higher +(using “set ignorecase”). +[Ignored in etags mode]

+
+
-u

Equivalent to --sort=no (i.e. “unsorted”).

+
+
--etags-include=<file>

Include a reference to <file> in the tag file. This option may be specified +as many times as desired. This supports Emacs’ capability to use a +tag file which includes other tag files. [Available only in etags mode]

+
+
--input-encoding=<encoding>

Specifies the <encoding> of the input files. +If this option is specified, Universal Ctags converts the input from this +encoding to the encoding specified by --output-encoding=encoding.

+
+
--input-encoding-<LANG>=<encoding>

Specifies a specific input <encoding> for <LANG>. It overrides the global +default value given with --input-encoding.

+
+
--output-encoding=<encoding>

Specifies the <encoding> of the tags file. +Universal Ctags converts the encoding of input files from the encoding +specified by --input-encoding=<encoding> to this encoding.

+

In addition <encoding> is specified at the top the tags file as the +value for the TAG_FILE_ENCODING pseudo-tag. The default value of +<encoding> is UTF-8.

+
+
+
+
+

Language Selection and Mapping Options

+
+
--language-force=(<language>|auto)

By default, ctags automatically selects the language +of a source file, ignoring those files whose language cannot be +determined (see “Determining file language”). This option forces the specified +language (case-insensitive; either built-in or user-defined) to be used +for every supplied file instead of automatically selecting the language +based upon its extension.

+

In addition, the special value auto indicates +that the language should be automatically selected (which effectively +disables this option).

+
+
--languages=[+|-](<list>|all)

Specifies the languages for which tag generation is enabled, with <list> +containing a comma-separated list of language names (case-insensitive; +either built-in or user-defined).

+

If the first language of <list> is not +preceded by either a ‘+’ or ‘-’, the current list (the current settings +of enabled/disabled languages managed in ctags internally) +will be cleared before adding or removing the languages in <list>. Until a ‘-’ is +encountered, each language in the <list> will be added to the current list.

+

As either the ‘+’ or ‘-’ is encountered in the <list>, the languages +following it are added or removed from the current list, respectively. +Thus, it becomes simple to replace the current list with a new one, or +to add or remove languages from the current list.

+

The actual list of +files for which tags will be generated depends upon the language +extension mapping in effect (see the --langmap option). Note that the most of +languages, including user-defined languages, are enabled unless explicitly +disabled using this option. Language names included in list may be any +built-in language or one previously defined with --langdef.

+

The default +is all, which is also accepted as a valid argument. See the +--list-languages option for a list of the all (built-in and user-defined) +language names.

+

Note --languages= option works cumulative way; the option can be +specified with different arguments multiple times in a command line.

+
+
--alias-<LANG>=[+|-](<pattern>|default)

Adds (’+’) or removes (’-’) an alias <pattern> to a language specified +with <LANG>. ctags refers to the alias pattern in +“Determining file language” stage.

+

The parameter <pattern> is not a list. Use this option multiple +times in a command line to add or remove multiple alias +patterns.

+

To restore the default language aliases, specify default.

+

Using all for <LANG> has meaning in following two cases:

+
+
--alias-all=

This clears aliases setting of all languages.

+
+
--alias-all=default

This restores the default languages aliases for all languages.

+
+
+
+
--guess-language-eagerly

Looks into the file contents for heuristically guessing the proper language parser. +See “Determining file language”.

+
+
-G

Equivalent to --guess-language-eagerly.

+
+
--langmap=<map>[,<map>[...]]

Controls how file names are mapped to languages (see the --list-maps +option). Each comma-separated <map> consists of the language name (either +a built-in or user-defined language), a colon, and a list of file +extensions and/or file name patterns. A file extension is specified by +preceding the extension with a period (e.g. .c). A file name pattern +is specified by enclosing the pattern in parentheses (e.g. +([Mm]akefile)).

+

If appropriate support is available from the runtime +library of your C compiler, then the file name pattern may contain the usual +shell wildcards common on Unix (be sure to quote the option parameter to +protect the wildcards from being expanded by the shell before being +passed to ctags). You can determine if shell wildcards +are available on your platform by examining the output of the +--list-features option, which will include wildcards in the compiled +feature list; otherwise, the file name patterns are matched against +file names using a simple textual comparison.

+

When mapping a file extension with --langmap option, +it will first be unmapped from any other languages. (--map-<LANG> +option provides more fine-grained control.)

+

If the first character in a <map> is a plus sign (’+’), then the extensions and +file name patterns in that map will be appended to the current map +for that language; otherwise, the map will replace the current map. +For example, to specify that only files with extensions of .c and .x are +to be treated as C language files, use --langmap=c:.c.x; to also add +files with extensions of .j as Java language files, specify +--langmap=c:.c.x,java:+.j. To map makefiles (e.g. files named either +Makefile, makefile, or having the extension .mak) to a language +called make, specify --langmap=make:([Mm]akefile).mak. To map files +having no extension, specify a period not followed by a non-period +character (e.g. ‘.’, ..x, .x.).

+

To clear the mapping for a +particular language (thus inhibiting automatic generation of tags for +that language), specify an empty extension list (e.g. --langmap=fortran:). +To restore the default language mappings for a particular language, +supply the keyword default for the mapping. To specify restore the +default language mappings for all languages, specify --langmap=default.

+

Note that file name patterns are tested before file extensions when inferring +the language of a file. This order of Universal Ctags is different from +Exuberant Ctags. See ctags-incompatibilities(7) for the background of +this incompatible change.

+
+
--map-<LANG>=[+|-]<extension>|<pattern>

This option provides the way to control mapping(s) of file names to +languages in a more fine-grained way than --langmap option.

+

In ctags, more than one language can map to a +file name <pattern> or file <extension> (N:1 map). Alternatively, +--langmap option handle only 1:1 map, only one language +mapping to one file name <pattern> or file <extension>. A typical N:1 +map is seen in C++ and ObjectiveC language; both languages have +a map to .h as a file extension.

+

A file extension is specified by preceding the extension with a period (e.g. .c). +A file name pattern is specified by enclosing the pattern in parentheses (e.g. +([Mm]akefile)). A prefixed plus (’+’) sign is for adding, and +minus (’-’) is for removing. No prefix means replacing the map of <LANG>.

+

Unlike --langmap, <extension> (or <pattern>) is not a list. +--map-<LANG> takes one extension (or pattern). However, +the option can be specified with different arguments multiple times +in a command line.

+
+
+
+
+

Tags File Contents Options

+

See “TAG ENTRIES” about fields, kinds, roles, and extras.

+
+
--excmd=(number|pattern|mix|combine)

Determines the type of EX command used to locate tags in the source +file. [Ignored in etags mode]

+

The valid values for type (either the entire word or the first letter +is accepted) are:

+
+
number

Use only line numbers in the tag file for locating tags. This has +four advantages:

+
    +
  1. Significantly reduces the size of the resulting tag file.

  2. +
  3. Eliminates failures to find tags because the line defining the +tag has changed, causing the pattern match to fail (note that +some editors, such as vim, are able to recover in many such +instances).

  4. +
  5. Eliminates finding identical matching, but incorrect, source +lines (see “BUGS”).

  6. +
  7. Retains separate entries in the tag file for lines which are +identical in content. In pattern mode, duplicate entries are +dropped because the search patterns they generate are identical, +making the duplicate entries useless.

  8. +
+

However, this option has one significant drawback: changes to the +source files can cause the line numbers recorded in the tag file +to no longer correspond to the lines in the source file, causing +jumps to some tags to miss the target definition by one or more +lines. Basically, this option is best used when the source code +to which it is applied is not subject to change. Selecting this +option type causes the following options to be ignored: -B, -F.

+

number type is ignored in Xref and JSON output formats. Use +--_xformat="...%n" for Xref output format, or --fields=+n-P for +JSON output format.

+
+
pattern

Use only search patterns for all tags, rather than the line numbers +usually used for macro definitions. This has the advantage of +not referencing obsolete line numbers when lines have been added or +removed since the tag file was generated.

+
+
mixed

In this mode, patterns are generally used with a few exceptions. +For C, line numbers are used for macro definition tags. For Fortran, line numbers +are used for common blocks because their corresponding source lines +are generally identical, making pattern searches useless +for finding all matches.

+

This was the default format generated by the original ctags and is, +therefore, retained as the default for this option.

+
+
combine

Concatenate the line number and pattern with a semicolon in between.

+
+
+
+
-n

Equivalent to --excmd=number.

+
+
-N

Equivalent to --excmd=pattern.

+
+
--extras=[+|-][<flags>|*]

Specifies whether to include extra tag entries for certain kinds of +information. See also “Extras” subsection to know what are extras.

+

The parameter <flags> is a set of one-letter flags (and/or long-name flags), each +representing one kind of extra tag entry to include in the tag file. +If flags is preceded by either the ‘+’ or ‘-’ character, the effect of +each flag is added to, or removed from, those currently enabled; +otherwise the flags replace any current settings. All entries are +included if ‘*’ is given.

+

This --extras= option is for controlling extras common in all +languages (or language-independent extras). Universal Ctags also +supports language-specific extras. (See “Language-specific fields and +extras” about the concept). Use --extras-<LANG>= option for +controlling them.

+
+
--extras-(<LANG>|all)=[+|-][<flags>|*]

Specifies whether to include extra tag entries for certain kinds of +information for language <LANG>. Universal Ctags +introduces language-specific extras. See “Language-specific fields and +extras” about the concept. This option is for controlling them.

+

Specifies all as <LANG> to apply the parameter <flags> to all +languages; all extras are enabled with specifying ‘*’ as the +parameter flags. If specifying nothing as the parameter flags +(--extras-all=), all extras are disabled. These two combinations +are useful for testing.

+

Check the output of the --list-extras=<LANG> option for the +extras of specific language <LANG>.

+
+
--fields=[+|-][<flags>|*]

Specifies which language-independent fields are to be included in the tag +entries. Language-independent fields are extension fields which are common +in all languages. See “TAG FILE FORMAT” section, and “Extension fields” +subsection, for details of extension fields.

+

The parameter <flags> is a set of one-letter or long-name flags, +each representing one type of extension field to include. +Each flag or group of flags may be preceded by either ‘+’ to add it +to the default set, or ‘-’ to exclude it. In the absence of any +preceding ‘+’ or ‘-’ sign, only those fields explicitly listed in flags +will be included in the output (i.e. overriding the default set). All +fields are included if ‘*’ is given.

+

This option is ignored if the +option --format=1 (legacy tag file format) has been specified.

+

Use --fields-<LANG>= option for controlling language-specific fields.

+
+
--fields-(<LANG>|all)=[+|-][<flags>|*]

Specifies which language-specific fields are to be included in +the tag entries. Universal Ctags +supports language-specific fields. (See “Language-specific fields and +extras” about the concept).

+

Specify all as <LANG> to apply the parameter <flags> to all +languages; all fields are enabled with specifying ‘*’ as the +parameter flags. If specifying nothing as the parameter <flags> +(i.e. --fields-all=), all fields are disabled. These two combinations +are useful for testing.

+

See the description of --fields=[+|-][<flags>|*] about <flags>.

+

Use --fields= option for controlling language-independent fields.

+
+
--kinds-(<LANG>|all)=[+|-](<kinds>|*)

Specifies a list of language-specific <kinds> of tags (or kinds) to +include in the output file for a particular language, where <LANG> is +case-insensitive and is one of the built-in language names (see the +--list-languages option for a complete list).

+

The parameter <kinds> is a group +of one-letter or long-name flags designating kinds of tags (particular to the language) +to either include or exclude from the output. The specific sets of +flags recognized for each language, their meanings and defaults may be +list using the --list-kinds-full option.

+

Each letter or group of letters +may be preceded by either ‘+’ to add it to, or ‘-’ to remove it from, +the default set. In the absence of any preceding ‘+’ or ‘-’ sign, only +those kinds explicitly listed in kinds will be included in the output +(i.e. overriding the default for the specified language).

+

Specify ‘*’ as the parameter to include all kinds implemented +in <LANG> in the output. Furthermore if all is given as <LANG>, +specification of the parameter kinds affects all languages defined +in ctags. Giving all makes sense only when ‘*’ or +‘F’ is given as the parameter kinds.

+

As an example for the C language, in order to add prototypes and +external variable declarations to the default set of tag kinds, +but exclude macros, use --kinds-c=+px-d; to include only tags for +functions, use --kinds-c=f.

+

Some kinds of C and C++ languages are synchronized; enabling +(or disabling) a kind in one language enables the kind having +the same one-letter and long-name in the other language. See also the +description of MASTER column of --list-kinds-full.

+
+
+
+
--pattern-length-limit=<N>

Truncate patterns of tag entries after <N> characters. Disable by setting to 0 +(default is 96).

+

An input source file with long lines and multiple tag matches per +line can generate an excessively large tags file with an +unconstrained pattern length. For example, running ctags on a +minified JavaScript source file often exhibits this behavior.

+

The truncation avoids cutting in the middle of a UTF-8 code point +spanning multiple bytes to prevent writing invalid byte sequences from +valid input files. This handling allows for an extra 3 bytes above the +configured limit in the worse case of a 4 byte code point starting +right before the limit. Please also note that this handling is fairly +naive and fast, and although it is resistant against any input, it +requires a valid input to work properly; it is not guaranteed to work +as the user expects when dealing with partially invalid UTF-8 input. +This also partially affect non-UTF-8 input, if the byte sequence at +the truncation length looks like a multibyte UTF-8 sequence. This +should however be rare, and in the worse case will lead to including +up to an extra 3 bytes above the limit.

+
+
--pseudo-tags=[+|-](<pseudo-tag>|*)

Enable/disable emitting pseudo-tag named <pseudo-tag>. +If ‘*’ is given, enable/disable emitting all pseudo-tags.

+
+
--put-field-prefix

Put UCTAGS as prefix for the name of fields newly introduced in +Universal Ctags.

+

Some fields are newly introduced in Universal Ctags and more will +be introduced in the future. Other tags generators may also +introduce their specific fields.

+

In such a situation, there is a concern about conflicting field +names; mixing tags files generated by multiple tags generators +including Universal Ctags is difficult. This option provides a +workaround for such station.

+
$ ctags --fields='{line}{end}' -o - hello.c
+main    hello.c /^main(int argc, char **argv)$/;"       f       line:3  end:6
+$ ctags --put-field-prefix --fields='{line}{end}' -o - hello.c
+main    hello.c /^main(int argc, char **argv)$/;"       f       line:3  UCTAGSend:6
+
+
+

In the above example, the prefix is put to end field which is +newly introduced in Universal Ctags.

+
+
--roles-(<LANG>|all).(<kind>|all)=[+|-][<roles>|*]

Specifies a list of kind-specific roles of tags to include in the +output file for a particular language. +<kind> specifies the kind where the <roles> are defined. +<LANG> specifies the language where the kind is defined. +Each role in <roles> must be surrounded by braces (e.g. {system} +for a role named “system”).

+

Like --kinds-<LANG> option, ‘+’ is for adding the role to the +list, and ‘-’ is for removing from the list. ‘*’ is for including +all roles of the kind to the list. The option with no argument +makes the list empty.

+

Both a one-letter flag or a long name flag surrounded by braces are +acceptable for specifying a kind (e.g. --roles-C.h=+{system}{local} +or --roles-C.{header}=+{system}{local}). ‘*’ can be used for <KIND> +only for adding/removing all roles of all kinds in a language to/from +the list (e.g. --roles-C.*=* or --roles-C.*=).

+

all can be used for <LANG> only for adding/removing all roles of +all kinds in all languages to/from the list +(e.g. --roles-all.*=* or --roles-all.*=).

+
+
--tag-relative=(yes|no|always|never)

Specifies how the file paths recorded in the tag file. +The default is yes when running in etags mode (see +the -e option), no otherwise.

+
+
yes

indicates that the file paths recorded in the tag file should be +relative to the directory containing the tag file +unless the files supplied on the command line +are specified with absolute paths.

+
+
no

indicates that the file paths recorded in the tag file should be +relative to the current directory +unless the files supplied on the command line +are specified with absolute paths.

+
+
always

indicates the recorded file paths should be relative +even if source file names are passed in with absolute paths.

+
+
never

indicates the recorded file paths should be absolute +even if source file names are passed in with relative paths.

+
+
+
+
--use-slash-as-filename-separator[=(yes|no)]

Uses slash (’/’) character as filename separators instead of backslash +(’\’) character when printing input: field. +The default is yes for the default “u-ctags” output format, and +no for the other formats.

+

This option is available on MS Windows only.

+
+
-B

Use backward searching patterns (e.g. ?pattern?). [Ignored in etags mode]

+
+
-F

Use forward searching patterns (e.g. /pattern/) (default). [Ignored +in etags mode]

+
+
+
+
+

Option File Options

+
+
--options=<pathname>

Read additional options from file or directory.

+

ctags searches <pathname> in the optlib path list +first. If ctags cannot find a file or directory +in the list, ctags reads a file or directory +at the specified <pathname>.

+

If a file is specified, it should contain one option per line. If +a directory is specified, files suffixed with .ctags under it +are read in alphabetical order.

+

As a special case, if --options=NONE is specified as the first +option on the command line, preloading is disabled; the option +will disable the automatic reading of any configuration options +from a file (see “FILES”).

+
+
--options-maybe=<pathname>

Same as --options but doesn’t cause an error if file +(or directory) specified with <pathname> doesn’t exist.

+
+
--optlib-dir=[+]<directory>

Add an optlib <directory> to or reset the optlib path list. +By default, the optlib path list is empty.

+
+
+
+
+

optlib Options

+

See ctags-optlib(7) for details of each option.

+
+
--kinddef-<LANG>=<letter>,<name>,<description>

Define a kind for <LANG>. +Don’t be confused this with --kinds-<LANG>.

+
+
--langdef=<name>

Defines a new user-defined language, <name>, to be parsed with regular +expressions.

+
+
--mline-regex-<LANG>=/<line_pattern>/<name_pattern>/<kind-spec>/[<flags>]

Define multi-line regular expression for locating tags in specific language.

+
+
--regex-<LANG>=/<line_pattern>/<name_pattern>/<kind-spec>/[<flags>]

Define single-line regular expression for locating tags in specific language.

+
+
+
+
+

Language Specific Options

+
+
--if0[=(yes|no)]

Indicates a preference as to whether code within an “#if 0” branch of a +preprocessor conditional should be examined for non-macro tags (macro +tags are always included). Because the intent of this construct is to +disable code, the default value of this option is no (disabled).

+

Note that this +indicates a preference only and does not guarantee skipping code within +an “#if 0” branch, since the fall-back algorithm used to generate +tags when preprocessor conditionals are too complex follows all branches +of a conditional.

+
+
--line-directives[=(yes|no)]

Specifies whether #line directives should be recognized. These are +present in the output of a preprocessor and contain the line number, and +possibly the file name, of the original source file(s) from which the +preprocessor output file was generated. This option is off by default.

+

When enabled, this option will +cause ctags to generate tag entries marked with the +file names and line numbers of their locations original source file(s), +instead of their actual locations in the preprocessor output. The actual +file names placed into the tag file will have the same leading path +components as the preprocessor output file, since it is assumed that +the original source files are located relative to the preprocessor +output file (unless, of course, the #line directive specifies an +absolute path).

+

Note: This option is generally +only useful when used together with the --excmd=number (-n) option. +Also, you may have to use either the --langmap or --language-force option +if the extension of the preprocessor output file is not known to +ctags.

+
+
-D <macro>=<definition>

Defines a C preprocessor <macro>. This emulates the behavior of the +corresponding gcc option. All types of macros are supported, +including the ones with parameters and variable arguments. +Stringification, token pasting and recursive macro expansion are also +supported. +This extends the function provided by -I option.

+
+
-h (<list>|default)

Specifies a <list> of file extensions, separated by periods, which are +to be interpreted as include (or header) files. To indicate files having +no extension, use a period not followed by a non-period character +(e.g. ‘.’, ..x, .x.).

+

This option only affects how the scoping of +particular kinds of tags are interpreted (i.e. whether or not they are +considered as globally visible or visible only within the file in which +they are defined); it does not map the extension to any particular +language. Any tag which is located in a non-include file and cannot be +seen (e.g. linked to) from another file is considered to have file-limited +(e.g. static) scope. No kind of tag appearing in an include file +will be considered to have file-limited scope.

+

If the first character in the list is ‘+’, then the extensions in the list will be +appended to the current list; otherwise, the list will replace the +current list. See, also, the fileScope/F flag of --extras option.

+

The default list is +.h.H.hh.hpp.hxx.h++.inc.def. To restore the default list, specify “-h +default”.

+

Note that if an extension supplied to this option is not +already mapped to a particular language (see “Determining file language”, above), +you will also need to use either the --map-<LANG>, --langmap or +--language-force option.

+
+
-I <identifier-list>

Specifies a <identifier-list> of identifiers which are to be specially handled while +parsing C and C++ source files. This option is specifically provided +to handle special cases arising through the use of preprocessor macros. +When the identifiers listed are simple identifiers, these identifiers +will be ignored during parsing of the source files.

+

If an identifier is +suffixed with a ‘+’ character (i.e. “-I FOO+”), ctags will also +ignore any parenthesis-enclosed argument list which may immediately +follow the identifier in the source files. See the example of “-I +MODULE_VERSION+” below.

+

If two identifiers are +separated with the ‘=’ character (i.e. -I FOO=BAR), the first identifiers is replaced by +the second identifiers for parsing purposes. The list of identifiers may +be supplied directly on the command line or read in from a separate file. +See the example of “-I CLASS=class” below.

+

If the first character of <identifier-list> is ‘@’, ‘.’ or a pathname +separator (’/’ or ‘\’), or the first two characters specify a drive +letter (e.g. C:), the parameter <identifier-list> will be interpreted as +a filename from which to read a list of identifiers, one per input line.

+

Otherwise, <identifier-list> is a list of identifiers (or identifier +pairs) to be specially handled, each delimited by either a comma or +by white space (in which case the list should be quoted to keep the +entire list as one command line argument).

+

Multiple -I options may be +supplied. To clear the list of ignore identifiers, supply a single +dash (’-’) for <identifier-list>.

+

This feature is useful when preprocessor macros are used in such a way +that they cause syntactic confusion due to their presence. Indeed, +this is the best way of working around a number of problems caused by +the presence of syntax-busting macros in source files (see “CAVEATS”). +Some examples will illustrate this point.

+
int foo ARGDECL4(void *, ptr, long int, nbytes)
+
+
+

In the above example, the macro ARGDECL4 would be mistakenly +interpreted to be the name of the function instead of the correct name +of foo. Specifying “-I ARGDECL4” results in the correct behavior.

+
/* creates an RCS version string in module */
+MODULE_VERSION("$Revision$")
+
+
+

In the above example the macro invocation looks too much like a function +definition because it is not followed by a semicolon (indeed, it +could even be followed by a global variable definition that would look +much like a K&R style function parameter declaration). In fact, this +seeming function definition could possibly even cause the rest of the +file to be skipped over while trying to complete the definition. +Specifying “-I MODULE_VERSION+” would avoid such a problem.

+
CLASS Example {
+        // your content here
+};
+
+
+

The example above uses CLASS as a preprocessor macro which expands to +something different for each platform. For instance CLASS may be +defined as class __declspec(dllexport) on Win32 platforms and simply +class on UNIX. Normally, the absence of the C++ keyword class +would cause the source file to be incorrectly parsed. Correct behavior +can be restored by specifying “-I CLASS=class”.

+
+
--param-<LANG>:<name>=<argument>

Set a <LANG> specific parameter, a parameter specific to the <LANG>.

+

Available parameters can be listed with --list-params.

+
+
+
+
+

Listing Options

+
+
--list-aliases[=(<language>|all)]

Lists the aliases for either the specified <language> or all +languages, and then exits. +all is used as default value if the option argument is omitted. +The aliases are used when heuristically testing a language parser for a +source file.

+
+
--list-excludes

Lists the current exclusion patterns used to exclude files.

+
+
--list-extras[=(<language>|all)]

Lists the extras recognized for either the specified <language> or +all languages. See “Extras” subsection to know what are extras. +all is used as default value if the option argument is omitted.

+

An extra can be enabled or disabled with --extras= for common +extras in all languages, or --extras-<LANG>= for the specified +language. These option takes one-letter flag or long-name flag as a parameter +for specifying an extra.

+

The meaning of columns in output are as follows:

+
+
LETTER

One-letter flag. ‘-’ means the extra does not have one-letter flag.

+
+
NAME

Long-name flag. The long-name is used in extras field.

+
+
ENABLED

Whether the extra is enabled or not. It takes yes or no.

+
+
LANGUAGE

The name of language if the extra is owned by a parser. +NONE means the extra is common in parsers.

+
+
DESCRIPTION

Human readable description for the extra.

+
+
+
+
--list-features

Lists the compiled features.

+
+
--list-fields[=(<language>|all)]

Lists the fields recognized for either the specified <language> or +all languages. See “Extension fields” subsection to know what are fields. +all is used as default value if the option argument is omitted.

+

The meaning of columns are as follows:

+
+
LETTER

One-letter flag. ‘-’ means the field does not have one-letter flag.

+
+
NAME

Long-name of field.

+
+
ENABLED

Whether the field is enabled or not. It takes yes or no.

+
+
LANGUAGE

The name of language if the field is owned by a parser. +NONE means that the field is a language-independent field which is +common in all languages.

+
+
JSTYPE

JSON type used in printing the value of field when --output-format=json +is specified. See ctags-client-tools(7).

+
+
FIXED

Whether this field can be disabled or not in tags output.

+

Some fields are printed always in tags output. +They have yes as the value for this column.

+

Unlike the tag output mode, JSON output mode allows disabling +any fields.

+
+
OP

How this field can be accessed from optscript code. +This field is for Universal Ctags developers.

+
+
DESCRIPTION

Human readable description for the field.

+
+
+
+
--list-kinds[=(<language>|all)]

Subset of --list-kinds-full. This option is kept for +backward-compatibility with Exuberant Ctags.

+

This option prints only LETTER, DESCRIPTION, and ENABLED fields +of --list-kinds-full output. However, the presentation of +ENABLED column is different from that of --list-kinds-full +option; [off] follows after description if the kind is disabled, +and nothing follows if enabled. The most of all kinds are enabled +by default.

+

The critical weakness of this option is that this option does not +print the name of kind. Universal Ctags introduces +--list-kinds-full because it considers that names are +important.

+

This option does not work with --machinable nor +--with-list-header.

+
+
--list-kinds-full[=(<language>|all)]

Lists the tag kinds recognized for either the specified <language> +or all languages, and then exits. See “Kinds” subsection to +learn what kinds are. +all is used as default value if the option argument is omitted.

+

Each kind of tag recorded in the tag file is represented by a +one-letter flag, or a long-name flag. They are also used to filter the tags +placed into the output through use of the --kinds-<LANG> +option.

+

The meaning of columns are as follows:

+
+
LANGUAGE

The name of language having the kind.

+
+
LETTER

One-letter flag. This must be unique in a language.

+
+
NAME

The long-name flag of the kind. This can be used as the alternative +to the one-letter flag described above. If enabling K field with +--fields=+K, ctags uses long-names instead of +one-letters in tags output. To enable/disable a kind with +--kinds-<LANG> option, long-name surrounded by braces instead +of one-letter. See “Letters and names” for details. This must be +unique in a language.

+
+
ENABLED

Whether the kind is enabled or not. It takes yes or no.

+
+
REFONLY

Whether the kind is specialized for reference tagging or not. +If the column is yes, the kind is for reference tagging, and +it is never used for definition tagging. See also “TAG ENTRIES”.

+
+
NROLES

The number of roles this kind has. See also “Roles”.

+
+
MASTER

The master parser controlling enablement of the kind. +A kind belongs to a language (owner) in Universal Ctags; +enabling and disabling a kind in a language has no effect on +a kind in another language even if both kinds has the +same one-letter flag and/or the same long-name flag. In other words, +the namespace of kinds are separated by language.

+

However, Exuberant Ctags does not separate the kinds of C and +C++. Enabling/disabling kindX in C language enables/disables a +kind in C++ language having the same long-name flag with kindX. To +emulate this behavior in Universal Ctags, a concept named +master parser is introduced. Enabling/disabling some kinds +are synchronized under the control of a master language.

+
$ ctags --kinds-C=+'{local}' --list-kinds-full \
+  | grep -E '^(#|C\+\+ .* local)'
+#LANGUAGE  LETTER NAME   ENABLED REFONLY NROLES MASTER DESCRIPTION
+C++        l      local  yes     no      0      C      local variables
+$ ctags --kinds-C=-'{local}' --list-kinds-full \
+  | grep -E '^(#|C\+\+ .* local)'
+#LANGUAGE  LETTER NAME   ENABLED REFONLY NROLES MASTER DESCRIPTION
+C++        l      local  no      no      0      C      local variables
+
+
+

You see ENABLED field of local kind of C++ language is changed +Though local kind of C language is enabled/disabled. If you swap the languages, you +see the same result.

+
+
DESCRIPTION

Human readable description for the kind.

+
+
+
+
--list-languages

Lists the names of the languages understood by ctags, +and then exits. These language names are case insensitive and may be +used in many other options like --language-force, +--languages, --kinds-<LANG>, --regex-<LANG>, and so on.

+

Each language listed is disabled if followed by [disabled]. +To use the parser for such a language, specify the language as an +argument of --languages=+ option.

+

--machinable and --with-list-header options are ignored if they are +specified with this option.

+
+
--list-map-extensions[=(<language>|all)]

Lists the file extensions which associate a file +name with a language for either the specified <language> or all +languages, and then exits. +all is used as default value if the option argument is omitted.

+
+
--list-map-patterns[=(<language>|all)]

Lists the file name patterns which associate a file +name with a language for either the specified <language> or all +languages, and then exits. +all is used as default value if the option argument is omitted.

+
+
--list-maps[=(<language>|all)]

Lists file name patterns and the file extensions which associate a file +name with a language for either the specified <language> or all +languages, and then exits. +all is used as default value if the option argument is omitted.

+

To list the file extensions or file name patterns individually, use +--list-map-extensions or --list-map-patterns option. +See the --langmap option, and “Determining file language”, above.

+

This option does not work with --machinable nor +--with-list-header.

+
+
--list-mline-regex-flags

Output list of flags which can be used in a multiline regex parser +definition. +See ctags-optlib(7).

+
+
--list-params[=(<language>|all)]

Lists the parameters for either the specified <language> or all +languages, and then exits. +all is used as default value if the option argument is omitted.

+
+
--list-pseudo-tags

Output list of pseudo-tags.

+
+
--list-regex-flags

Lists the flags that can be used in --regex-<LANG> option. +See ctags-optlib(7).

+
+
--list-roles[=(<language>|all)[.(<kind-specs>|*)]]

List the roles for either the specified <language> or all languages. +all is used as default value if the option argument is omitted.

+

If the parameter <kindspecs> is given after the parameter +<language> or all with concatenating with ‘.’, list only roles +defined in the kinds. Both one-letter flags and long name flags surrounded +by braces are acceptable as the parameter <kindspecs>.

+

The meaning of columns are as follows:

+
+
LANGUAGE

The name of language having the role.

+
+
KIND(L/N)

The one-letter flag and the long-name flag of kind having the role.

+
+
NAME

The long-name flag of the role.

+
+
ENABLED

Whether the kind is enabled or not. It takes yes or no.

+
+
DESCRIPTION

Human readable description for the role.

+
+
+
+
--list-subparsers[=(<baselang>|all)]

Lists the subparsers for a base language for either the specified +<baselang> or all languages, and then exits. +all is used as default value if the option argument is omitted.

+
+
--machinable[=(yes|no)]

Use tab character as separators for --list- option output. It +may be suitable for scripting. See “List options” for considered +use cases. Disabled by default.

+
+
--with-list-header[=(yes|no)]

Print headers describing columns in --list- option output. +See also “List options”.

+
+
+
+
+

Miscellaneous Options

+
+
--help

Prints to standard output a detailed usage description, and then exits.

+
+
-?

Equivalent to --help.

+
+
--help-full

Prints to standard output a detailed usage description including experimental +features, and then exits. Visit https://docs.ctags.io/ for information +about the latest exciting experimental features.

+
+
--license

Prints a summary of the software license to standard output, and then exits.

+
+
--print-language

Just prints the language parsers for specified source files, and then exits.

+
+
--quiet[=(yes|no)]

Write fewer messages (default is no).

+
+
--totals[=(yes|no|extra)]

Prints statistics about the source files read and the tag file written +during the current invocation of ctags. This option +is no by default.

+

The extra value prints parser specific statistics for parsers +gathering such information.

+
+
--verbose[=(yes|no)]

Enable verbose mode. This prints out information on option processing +and a brief message describing what action is being taken for each file +considered by ctags. Normally, ctags +does not read command line arguments until after options are read +from the configuration files (see “FILES”, below). +However, if this option is the first argument on +the command line, it will take effect before any options are read from +these sources. The default is no.

+
+
-V

Equivalent to --verbose.

+
+
--version

Prints a version identifier for ctags to standard +output, and then exits. This is guaranteed to always contain the string +“Universal Ctags”.

+
+
+
+
+

Obsoleted Options

+

These options are kept for backward-compatibility with Exuberant Ctags.

+
+
-w

This option is silently ignored for backward-compatibility with the +ctags of SVR4 Unix.

+
+
--file-scope[=(yes|no)]

This options is removed. Use --extras=[+|-]F or +--extras=[+|-]{fileScope} instead.

+
+
--extra=[+|-][<flags>|*]

Equivalent to --extras=[+|-][<flags>|*], which was introduced to make +the option naming convention align to the other options like +--kinds-<LANG>= and --fields=.

+
+
--<LANG>-kinds=[+|-](<kinds>|*)

This option is obsolete. Use --kinds-<LANG>=... instead.

+
+
+
+
+
+

OPERATIONAL DETAILS

+

As ctags considers each source file name in turn, it tries to +determine the language of the file by applying tests described in +“Determining file language”.

+

If a language was identified, the file is opened and then the appropriate +language parser is called to operate on the currently open file. The parser +parses through the file and adds an entry to the tag file for each +language object it is written to handle. See “TAG FILE FORMAT”, below, +for details on these entries.

+
+

Notes for C/C++ Parser

+

This implementation of ctags imposes no formatting +requirements on C code as do legacy implementations. Older implementations +of ctags tended to rely upon certain formatting assumptions in order to +help it resolve coding dilemmas caused by preprocessor conditionals.

+

In general, ctags tries to be smart about conditional +preprocessor directives. If a preprocessor conditional is encountered +within a statement which defines a tag, ctags follows +only the first branch of that conditional (except in the special case of +#if 0, in which case it follows only the last branch). The reason for +this is that failing to pursue only one branch can result in ambiguous +syntax, as in the following example:

+
#ifdef TWO_ALTERNATIVES
+struct {
+#else
+union {
+#endif
+        short a;
+        long b;
+}
+
+
+

Both branches cannot be followed, or braces become unbalanced and +ctags would be unable to make sense of the syntax.

+

If the application of this heuristic fails to properly parse a file, +generally due to complicated and inconsistent pairing within the +conditionals, ctags will retry the file using a +different heuristic which does not selectively follow conditional +preprocessor branches, but instead falls back to relying upon a closing +brace (’}’) in column 1 as indicating the end of a block once any brace +imbalance results from following a #if conditional branch.

+

ctags will also try to specially handle arguments lists +enclosed in double sets of parentheses in order to accept the following +conditional construct:

+
extern void foo __ARGS((int one, char two));
+
+
+

Any name immediately preceding the ‘((’ will be automatically ignored and +the previous name will be used.

+

C++ operator definitions are specially handled. In order for consistency +with all types of operators (overloaded and conversion), the operator +name in the tag file will always be preceded by the string “operator ” +(i.e. even if the actual operator definition was written as “operator<<”).

+

After creating or appending to the tag file, it is sorted by the tag name, +removing identical tag lines.

+
+
+

Determining file language

+
+

File name mapping

+

Unless the --language-force option is specified, the language of each source +file is automatically selected based upon a mapping of file names to +languages. The mappings in effect for each language may be displayed using +the --list-maps option and may be changed using the --langmap or +--map-<LANG> options.

+

If the name of a file is not mapped to a language, ctags tries +to heuristically guess the language for the file by inspecting its content.

+

All files that have no file name mapping and no guessed parser are +ignored. This permits running ctags on all files in +either a single directory (e.g. “ctags *”), or on +all files in an entire source directory tree +(e.g. “ctags -R”), since only those files whose +names are mapped to languages will be scanned.

+

An extension may be mapped to multiple parsers. For example, .h +are mapped to C++, C and ObjectiveC. These mappings can cause +issues. ctags tries to select the proper parser +for the source file by applying heuristics to its content, however +it is not perfect. In case of issues one can use --language-force=<language>, +--langmap=<map>[,<map>[...]], or the --map-<LANG>=[+|-]<extension>|<pattern> +options. (Some of the heuristics are applied whether --guess-language-eagerly +is given or not.)

+
+
+

Heuristically guessing

+

If ctags cannot select a parser from the mapping of file names, +various heuristic tests are conducted to determine the language:

+
+
template file name testing

If the file name has an .in extension, ctags applies +the mapping to the file name without the extension. For example, +config.h is tested for a file named config.h.in.

+
+
“interpreter” testing

The first line of the file is checked to see if the file is a #! +script for a recognized language. ctags looks for +a parser having the same name.

+

If ctags finds no such parser, +ctags looks for the name in alias lists. For +example, consider if the first line is #!/bin/sh. Though +ctags has a “shell” parser, it doesn’t have a “sh” +parser. However, sh is listed as an alias for shell, therefore +ctags selects the “shell” parser for the file.

+

An exception is env. If env is specified (for example +“#!/usr/bin/env python”), ctags +reads more lines to find real interpreter specification.

+

To display the list of aliases, use --list-aliases option. +To add an item to the list or to remove an item from the list, use the +--alias-<LANG>=+<pattern> or --alias-<LANG>=-<pattern> option +respectively.

+
+
“zsh autoload tag” testing

If the first line starts with #compdef or #autoload, +ctags regards the line as “zsh”.

+
+
“emacs mode at the first line” testing

The Emacs editor has multiple editing modes specialized for programming +languages. Emacs can recognize a marker called modeline in a file +and utilize the marker for the mode selection. This heuristic test does +the same as what Emacs does.

+

ctags treats MODE as a name of interpreter and applies the same +rule of “interpreter” testing if the first line has one of +the following patterns:

+
-*- mode: MODE -*-
+
+
+

or

+
-*- MODE -*-
+
+
+
+
“emacs mode at the EOF” testing

Emacs editor recognizes another marker at the end of file as a +mode specifier. This heuristic test does the same as what Emacs does.

+

ctags treats MODE as a name of an interpreter and applies the same +rule of “interpreter” heuristic testing, if the lines at the tail of the file +have the following pattern:

+
Local Variables:
+...
+mode: MODE
+...
+End:
+
+
+

3000 characters are sought from the end of file to find the pattern.

+
+
“vim modeline” testing

Like the modeline of the Emacs editor, Vim editor has the same concept. +ctags treats TYPE as a name of interpreter and applies the same +rule of “interpreter” heuristic testing if the last 5 lines of the file +have one of the following patterns:

+
filetype=TYPE
+
+
+

or

+
ft=TYPE
+
+
+
+
“PHP marker” testing

If the first line is started with <?php, +ctags regards the line as “php”.

+
+
+

Looking into the file contents is a more expensive operation than file +name matching. So ctags runs the testings in limited +conditions. “interpreter” testing is enabled only when a file is an +executable or the --guess-language-eagerly (-G in short) option is +given. The other heuristic tests are enabled only when -G option is +given.

+

The --print-language option can be used just to print the results of +parser selections for given files instead of generating a tags file.

+

Examples:

+
$ ctags --print-language config.h.in input.m input.unknown
+config.h.in: C++
+input.m: MatLab
+input.unknown: NONE
+
+
+

NONE means that ctags does not select any parser for the file.

+
+
+
+
+

TAG FILE FORMAT

+

This section describes the tag file format briefly. See tags(5) and +ctags-client-tools(7) for more details.

+

When not running in etags mode, each entry in the tag file consists of a +separate line, each looking like this, called regular tags, in the most general case:

+
<tag_name><TAB><file_name><TAB><ex_cmd>;"<TAB><extension_fields>
+
+
+

The fields and separators of these lines are specified as follows:

+
+
    +
  1. <tag_name>: tag name

  2. +
  3. <TAB>: single tab character

  4. +
  5. <file_name>: name of the file in which the object associated with the tag is located

  6. +
  7. <TAB>: single tab character

  8. +
  9. <ex_cmd>: EX command used to locate the tag within the file; generally a +search pattern (either /pattern/ or ?pattern?) or line number (see +--excmd=<type> option).

  10. +
  11. ;"<TAB><extension_fields>: a set of extension fields. See +“Extension fields” for more details.

    +

    Tag file format 2 (see --format) extends the EX command +to include the extension fields embedded in an EX comment immediately appended +to the EX command, which leaves it backward-compatible with original +vi(1) implementations.

    +
  12. +
+
+

A few special tags, called pseudo tags, are written into the tag file for internal purposes.

+
!_TAG_FILE_FORMAT       2       /extended format; --format=1 will not append ;" to lines/
+!_TAG_FILE_SORTED       1       /0=unsorted, 1=sorted, 2=foldcase/
+...
+
+
+

--pseudo-tags=[+|-](<pseudo-tag>|*) option enables or disables emitting pseudo-tags.

+

See the output of “ctags --list-pseudo-tags” for the list of +the kinds. +See also tags(5) and ctags-client-tools(7) for more details of the pseudo tags.

+

These tags are composed in such a way that they always sort to the top of +the file. Therefore, the first two characters of these tags are used a magic +number to detect a tag file for purposes of determining whether a +valid tag file is being overwritten rather than a source file.

+

Note that the name of each source file will be recorded in the tag file +exactly as it appears on the command line. Therefore, if the path you +specified on the command line was relative to the current directory, then +it will be recorded in that same manner in the tag file. See, however, +the --tag-relative=(yes|no|always|never) option for how this behavior can be +modified.

+
+
+

TAG ENTRIES

+

A tag is an index for a language object. The concept of a tag and related +items in Exuberant Ctags are refined and extended in Universal Ctags.

+

A tag is categorized into definition tags or reference tags. +In general, Exuberant Ctags only tags definitions of +language objects: places where newly named language objects are introduced. +Universal Ctags, on the other hand, can also tag references of language +objects: places where named language objects are used. However, support +for generating reference tags is new and limited to specific areas of +specific languages in the current version.

+
+

Extension fields

+

A tag can record various information, called extension fields.

+

Extension fields are tab-separated key-value pairs appended to the end of +the EX command as a comment, as described above. These key value pairs +appear in the general form key:value.

+

In addition, information on the scope of the tag definition may be +available, with the key portion equal to some language-dependent construct +name and its value the name declared for that construct in the program. +This scope entry indicates the scope in which the tag was found. +For example, a tag generated for a C structure member would have a scope +looking like struct:myStruct.

+

--fields=[+|-][<flags>|*] and --fields-(<LANG>|all)=[+|-][<flags>|*] options specifies +which available extension fields are to be included in the tag entries.

+

See the output of “ctags --list-fields” for the list of +extension fields. +The essential fields are name, input, pattern, and line. +The meaning of major fields is as follows (long-name flag/one-letter flag):

+
+
access/a

Indicates the visibility of this class member, where value is specific +to the language.

+
+
end/e

Indicates the line number of the end lines of the language object.

+
+
extras/E

Extra tag type information. See “Extras” for details.

+
+
file/f

Indicates that the tag has file-limited visibility. This key has no +corresponding value. Enabled by default.

+
+
implementation/m

When present, this indicates a limited implementation (abstract vs. +concrete) of a routine or class, where value is specific to the +language (virtual or pure virtual for C++; abstract for Java).

+
+
inherits/i

When present, value is a comma-separated list of classes from which +this class is derived (i.e. inherits from).

+
+
input/F

The name of source file where name is defined or referenced.

+
+
k

Kind of tag as one-letter. Enabled by default. +This field has no long-name. +See also kind/z flag.

+
+
K

Kind of tag as long-name. +This field has no long-name. +See also kind/z flag.

+
+
kind/z

Include the kind: key in kind field. See also k and K flags.

+
+
language/l

Language of source file containing tag

+
+
line/n

The line number where name is defined or referenced in input.

+
+
name/N

The name of language objects.

+
+
pattern/P

Can be used to search the name in input

+
+
roles/r

Roles assigned to the tag. See “Roles” for more details.

+
+
s

Scope of tag definition. Enabled by default. +This field has no long-name. +See also scope/Z flag.

+
+
scope/Z

Prepend the scope: key to scope (s) field. +See also s flag.

+
+
scopeKind/p

Kind of scope as long-name

+
+
signature/S

When present, value is a language-dependent representation of the +signature of a routine (e.g. prototype or parameter list). A routine signature in its complete form +specifies the return type of a routine and its formal argument list. +This extension field is presently supported only for C-based +languages and does not include the return type.

+
+
typeref/t

Type and name of a variable, typedef, or return type of +callable like function as typeref: field. +Enabled by default.

+
+
+
+

Kinds

+

kind is a field which represents the kind of language object +specified by a tag. Kinds used and defined are very different between +parsers. For example, C language defines macro, function, +variable, typedef, etc.

+

--kinds-(<LANG>|all)=[+|-](<kinds>|*) option specifies a list of language-specific +kinds of tags (or kinds) to include in the output file for a particular +language.

+

See the output of “ctags --list-kinds-full” for the complete +list of the kinds.

+

Its value is either one of the +corresponding one-letter flags or a long-name flag. It is permitted +(and is, in fact, the default) for the key portion of this field to be +omitted. The optional behaviors are controlled with the --fields option as follows.

+
$ ctags -o - kinds.c
+foo     kinds.c /^int foo() {$/;"       f       typeref:typename:int
+$ ctags --fields=+k -o - kinds.c
+foo     kinds.c /^int foo() {$/;"       f       typeref:typename:int
+$ ctags --fields=+K -o - kinds.c
+foo     kinds.c /^int foo() {$/;"       function        typeref:typename:int
+$ ctags --fields=+z -o - kinds.c
+foo     kinds.c /^int foo() {$/;"       kind:f  typeref:typename:int
+$ ctags --fields=+zK -o - kinds.c
+foo     kinds.c /^int foo() {$/;"       kind:function   typeref:typename:int
+
+
+
+
+

Roles

+

Role is a newly introduced concept in Universal Ctags. Role is a +concept associated with reference tags, and is not implemented widely yet.

+

As described previously in “Kinds”, the kind field represents the type +of language object specified with a tag, such as a function vs. a variable. +Specific kinds are defined for reference tags, such as the C++ kind header for +header file, or Java kind package for package statements. For such reference +kinds, a roles field can be added to distinguish the role of the reference +kind. In other words, the kind field identifies the what of the language +object, whereas the roles field identifies the how of a referenced language +object. Roles are only used with specific kinds.

+

For a definition tag, this field takes def as a value.

+

For example, Baz is tagged as a reference tag with kind package and with +role imported with the following code.

+
package Bar;
+import Baz;
+
+class Foo {
+                // ...
+}
+
+
+
$ ctags --fields=+KEr -uo - roles.java
+Bar     roles.java     /^package Bar;$/;"      package roles:def
+Foo     roles.java     /^class Foo {$/;"       class   roles:def
+$ ctags --fields=+EKr --extras=+r -uo - roles.java
+Bar     roles.java     /^package Bar;$/;"      package roles:def
+Baz     roles.java     /^import Baz;$/;"       package roles:imported  extras:reference
+Foo     roles.java     /^class Foo {$/;"       class   roles:def
+
+
+

--roles-(<LANG>|all).(<kind>|all)=[+|-][<roles>|*] option specifies a list of kind-specific +roles of tags to include in the output file for a particular language.

+

Inquire the output of “ctags --list-roles” for the list of +roles.

+
+
+
+

Extras

+

Generally, ctags tags only language objects appearing +in source files, as is. In other words, a value for a name: field +should be found on the source file associated with the name:. An +extra type tag (extra) is for tagging a language object with a processed +name, or for tagging something not associated with a language object. A typical +extra tag is qualified, which tags a language object with a +class-qualified or scope-qualified name.

+

--extras-(<LANG>|all)=[+|-][<flags>|*] option specifies +whether to include extra tag entries for certain kinds of information.

+

Inquire the output of ctags --list-extras for the list of extras. +The meaning of major extras is as follows (long-name flag/one-letter flag):

+
+
anonymous/none

Include an entry for the language object that has no name like lambda +function. This extra has no one-letter flag and is enabled by +default.

+

The extra tag is useful as a placeholder to fill scope fields +for language objects defined in a language object with no name.

+
struct {
+        double x, y;
+} p = { .x = 0.0, .y = 0.0 };
+
+
+

x’ and ‘y’ are the members of a structure. When filling the scope +fields for them, ctags has trouble because the struct +where ‘x’ and ‘y’ belong to has no name. For overcoming the trouble, +ctags generates an anonymous extra tag for the struct +and fills the scope fields with the name of the extra tag.

+
$ ctags --fields=-f -uo - input.c
+__anon9f26d2460108      input.c /^struct {$/;"  s
+x       input.c /^      double x, y;$/;"        m       struct:__anon9f26d2460108
+y       input.c /^      double x, y;$/;"        m       struct:__anon9f26d2460108
+p       input.c /^} p = { .x = 0.0, .y = 0.0 };$/;"     v       typeref:struct:__anon9f26d2460108
+
+
+

The above tag output has __anon9f26d2460108 as an anonymous extra tag. +The typeref field of ‘p’ also receives the benefit of it.

+
+
fileScope/F

Indicates whether tags scoped only for a single file (i.e. tags which +cannot be seen outside of the file in which they are defined, such as +language objects with static modifier of C language) should be included +in the output. See also the -h option.

+

This extra tag is enabled by default. Add --extras=-F option not to +output tags scoped only for a single-file. This is the replacement for +--file-scope option of Exuberant Ctags.

+
static int f() {
+        return 0;
+}
+int g() {
+        return 0;
+}
+
+
+
$ ctags -uo - filescope.c
+f       filescope.c     /^static int f() {$/;"  f       typeref:typename:int    file:
+g       filescope.c     /^int g() {$/;" f       typeref:typename:int
+$ ctags --extras=-F -uo - filescope.c
+g       filescope.c     /^int g() {$/;" f       typeref:typename:int
+
+
+
+
inputFile/f

Include an entry for the base file name of every source file +(e.g. example.c), which addresses the first line of the file. +This flag is the replacement for --file-tags hidden option of +Exuberant Ctags.

+

If the end: field is enabled, the end line number of the file can be +attached to the tag. (However, ctags omits the end: field +if no newline is in the file like an empty file.)

+

By default, ctags doesn’t create the inputFile/f extra +tag for the source file when ctags doesn’t find a parser +for it. Enabling Unknown parser with --languages=+Unknown forces +ctags to create the extra tags for any source files.

+

The etags mode enables the Unknown parser implicitly.

+
+
pseudo/p

Include pseudo-tags. Enabled by default unless the tag file is +written to standard output. See ctags-client-tools(7) about +the detail of pseudo-tags.

+
+
qualified/q

Include an extra class-qualified or namespace-qualified tag entry +for each tag which is a member of a class or a namespace.

+

This may allow easier location of a specific tags when +multiple occurrences of a tag name occur in the tag file. +Note, however, that this could potentially more than double +the size of the tag file.

+

The actual form of the qualified tag depends upon the language +from which the tag was derived (using a form that is most +natural for how qualified calls are specified in the +language). For C++ and Perl, it is in the form +class::member; for Eiffel and Java, it is in the form +class.member.

+

Note: Using backslash characters as separators forming +qualified name in PHP. However, in tags output of +Universal Ctags, a backslash character in a name is escaped +with a backslash character. See tags(5) about the escaping.

+

The following example demonstrates the qualified extra tag.

+
class point {
+        double x;
+};
+
+
+

For the above source file, ctags tags point and x by +default. If the qualified extra is enabled from the command line +(--extras=+q), then point.x is also tagged even though the string +“point.x” is not in the source code.

+
$ ctags --fields=+K -uo - qualified.java
+point   qualified.java  /^class point {$/;"     class
+x       qualified.java  /^      double x;$/;"   field   class:point
+$ ctags --fields=+K --extras=+q -uo - qualified.java
+point   qualified.java  /^class point {$/;"     class
+x       qualified.java  /^      double x;$/;"   field   class:point
+point.x qualified.java  /^      double x;$/;"   field   class:point
+
+
+
+
reference/r

Include reference tags. See “TAG ENTRIES” about reference tags.

+

The following example demonstrates the reference extra tag.

+
#include <stdio.h>
+#include "utils.h"
+#define X
+#undef X
+
+
+

The roles:system or roles:local fields will be +added depending on whether the include file name begins with ‘<’ or not.

+

#define X” emits a definition tag. On the other hand “#undef X” emits a +reference tag.

+
$ ctags --fields=+EKr -uo - inc.c
+X       inc.c   /^#define X$/;" macro   file:   roles:def       extras:fileScope
+$ ctags --fields=+EKr --extras=+r -uo - inc.c
+stdio.h inc.c   /^#include <stdio.h>/;" header  roles:system    extras:reference
+utils.h inc.c   /^#include "utils.h"/;" header  roles:local     extras:reference
+X       inc.c   /^#define X$/;" macro   file:   roles:def       extras:fileScope
+X       inc.c   /^#undef X$/;"  macro   file:   roles:undef     extras:fileScope,reference
+
+
+
+
+
+
+

Language-specific fields and extras

+

Exuberant Ctags has the concept of fields and extras. They are common +between parsers of different languages. Universal Ctags extends this concept +by providing language-specific fields and extras.

+
+
+
+

HOW TO USE WITH VI

+

vi(1) will, by default, expect a tag file by the name tags in the current +directory. Once the tag file is built, the following commands exercise +the tag indexing feature:

+
+
vi -t tag

Start vi and position the cursor at the file and line where tag +is defined.

+
+
:ta tag

Find a tag.

+
+
Ctrl-]

Find the tag under the cursor.

+
+
Ctrl-T

Return to previous location before jump to tag (not widely implemented).

+
+
+
+
+

HOW TO USE WITH GNU EMACS

+

emacs(1) will, by default, expect a tag file by the name TAGS in the +current directory. Once the tag file is built, the following commands +exercise the tag indexing feature:

+
+
M-x visit-tags-table <RET> FILE <RET>

Select the tag file, FILE, to use.

+
+
M-. [TAG] <RET>

Find the first definition of TAG. The default tag is the identifier +under the cursor.

+
+
M-*

Pop back to where you previously invoked M-..

+
+
C-u M-.

Find the next definition for the last tag.

+
+
+

For more commands, see the Tags topic in the Emacs info document.

+
+
+

HOW TO USE WITH NEDIT

+

NEdit version 5.1 and later can handle the new extended tag file format +(see --format).

+
    +
  • To make NEdit use the tag file, select “File->Load Tags File”.

  • +
  • To jump to the definition for a tag, highlight the word, then press Ctrl-D.

  • +
+

NEdit 5.1 can read multiple tag files from different +directories. Setting the X resource nedit.tagFile to the name of a tag +file instructs NEdit to automatically load that tag file at startup time.

+
+
+

CAVEATS

+

Because ctags is neither a preprocessor nor a compiler, +use of preprocessor macros can fool ctags into either +missing tags or improperly generating inappropriate tags. Although +ctags has been designed to handle certain common cases, +this is the single biggest cause of reported problems. In particular, +the use of preprocessor constructs which alter the textual syntax of C +can fool ctags. You can work around many such problems +by using the -I option.

+

Note that since ctags generates patterns for locating +tags (see the --excmd option), it is entirely possible that the wrong line +may be found by your editor if there exists another source line which is +identical to the line containing the tag. The following example +demonstrates this condition:

+
int variable;
+
+/* ... */
+void foo(variable)
+int variable;
+{
+        /* ... */
+}
+
+
+

Depending upon which editor you use and where in the code you happen to be, +it is possible that the search pattern may locate the local parameter +declaration before it finds the actual global variable definition, +since the lines (and therefore their search patterns) are +identical.

+

This can be avoided by use of the --excmd=n option.

+
+
+

BUGS

+

ctags has more options than ls(1).

+

ctags assumes the input file is written in the correct +grammar. Otherwise output of ctags is undefined. In other words it has garbage +in, garbage out (GIGO) feature.

+

When parsing a C++ member function definition (e.g. className::function), +ctags cannot determine whether the scope specifier +is a class name or a namespace specifier and always lists it as a class name +in the scope portion of the extension fields. Also, if a C++ function +is defined outside of the class declaration (the usual case), the access +specification (i.e. public, protected, or private) and implementation +information (e.g. virtual, pure virtual) contained in the function +declaration are not known when the tag is generated for the function +definition. It will, however be available for prototypes (e.g. --kinds-c++=+p).

+

No qualified tags are generated for language objects inherited into a class.

+
+
+

ENVIRONMENT VARIABLES

+
+
TMPDIR

On Unix-like hosts where mkstemp(3) is available, the value of this +variable specifies the directory in which to place temporary files. +This can be useful if the size of a temporary file becomes too large +to fit on the partition holding the default temporary directory +defined at compilation time.

+

ctags creates temporary +files only if either (1) an emacs-style tag file is being +generated, (2) the tag file is being sent to standard output, or +(3) the program was compiled to use an internal sort algorithm to sort +the tag files instead of the sort(1) utility of the operating system. +If the sort(1) utility of the operating system is being used, it will +generally observe this variable also.

+

Note that if ctags +is setuid, the value of TMPDIR will be ignored.

+
+
+
+
+

FILES

+
+
tags

The default tag file created by ctags.

+
+
TAGS

The default tag file created by etags.

+
+
+

$XDG_CONFIG_HOME/ctags/*.ctags, or $HOME/.config/ctags/*.ctags if +$XDG_CONFIG_HOME is not defined +(on other than MS Windows)

+

$HOME/.ctags.d/*.ctags

+

$HOMEDRIVE$HOMEPATH/ctags.d/*.ctags (on MS Windows only)

+

.ctags.d/*.ctags

+

ctags.d/*.ctags

+
+

If any of these configuration files exist, each will be expected to +contain a set of default options which are read in the order listed +when ctags starts, but before any command line options +are read. This makes it possible to set up personal or project-level defaults.

+

It +is possible to compile ctags to read an additional +configuration file before any of those shown above, which will be +indicated if the output produced by the --version option lists the +custom-conf feature.

+

Options appearing on the command line will override options +specified in these files. Only options will be read from these +files.

+

Note that the option +files are read in line-oriented mode in which spaces are significant +(since shell quoting is not possible) but spaces at the beginning +of a line are ignored. Each line of the file is read as +one command line parameter (as if it were quoted with single quotes). +Therefore, use new lines to indicate separate command-line arguments.

+

A line starting with ‘#’ is treated as a comment.

+

*.ctags files in a directory are loaded in alphabetical order.

+
+
+
+

SEE ALSO

+

See ctags-optlib(7) for defining (or extending) a parser +in a configuration file.

+

See tags(5) for the format of tag files.

+

See ctags-incompatibilities(7) about known incompatible changes +with Exuberant Ctags.

+

See ctags-client-tools(7) if you are interested in writing +a tool for processing tags files.

+

See ctags-lang-python(7) about python input specific notes.

+

See readtags(1) about a client tool for binary searching a +name in a sorted tags file.

+

The official Universal Ctags web site at: https://ctags.io/

+

Also ex(1), vi(1), elvis(1), or, better yet, vim(1), the official editor of ctags. +For more information on vim(1), see the Vim web site at: https://www.vim.org/

+
+
+

AUTHOR

+

Universal Ctags project +https://ctags.io/

+

Darren Hiebert <dhiebert@users.sourceforge.net> +http://DarrenHiebert.com/

+
+
+

MOTIVATION

+

“Think ye at all times of rendering some service to every member of the +human race.”

+

“All effort and exertion put forth by man from the fullness of his heart is +worship, if it is prompted by the highest motives and the will to do +service to humanity.”

+

-- From the Baha’i Writings

+
+
+

CREDITS

+

This version of ctags (Universal Ctags) derived from +the repository, known as fishman-ctags, started by Reza Jelveh.

+

The fishman-ctags was derived from Exuberant Ctags.

+

Some parsers are taken from tagmanager of the Geany (https://www.geany.org/) +project.

+

Exuberant Ctags was originally derived from and +inspired by the ctags program by Steve Kirkendall <kirkenda@cs.pdx.edu> +that comes with the Elvis vi clone (though virtually none of the original +code remains).

+

Credit is also due Bram Moolenaar <Bram@vim.org>, the author of vim, +who has devoted so much of his time and energy both to developing the editor +as a service to others, and to helping the orphans of Uganda.

+

The section entitled “HOW TO USE WITH GNU EMACS” was shamelessly stolen +from the info page for GNU etags.

+
+
+ + +
+
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/ctags/docs/man/readtags.1.html b/ctags/docs/man/readtags.1.html new file mode 100644 index 0000000..0a8e867 --- /dev/null +++ b/ctags/docs/man/readtags.1.html @@ -0,0 +1,449 @@ + + + + + + + + + readtags — Universal Ctags 0.3.0 documentation + + + + + + + + + + + + + + + +
+
+
+
+ +
+

readtags

+

Find tag file entries matching specified names

+
+
Version
+

5.9.0

+
+
Manual group
+

Universal Ctags

+
+
Manual section
+

1

+
+
+
+

SYNOPSIS

+
+
readtags -h | --help
+
readtags (-H | --help-expression) (filter|sorter)
+
readtags [OPTION]… ACTION
+
+
+
+

DESCRIPTION

+

The readtags program filters, sorts and prints tag entries in a tags file. +The basic filtering is done using actions, by which you can list all +regular tags, pseudo tags or regular tags matching specific name. Then, further +filtering and sorting can be done using post processors, namely filter +expressions and sorter expressions.

+
+
+

ACTIONS

+
+
-l, --list

List regular tags.

+
+
[-] NAME

List regular tags matching NAME. +“-” as NAME indicates arguments after this as NAME even if they start with -.

+
+
-D, --list-pseudo-tags

Equivalent to --list-pseudo-tags.

+
+
+
+
+

OPTIONS

+
+

Controlling the Tags Reading Behavior

+

The behavior of reading tags can be controlled using these options:

+
+
-t TAGFILE, --tag-file TAGFILE

Use specified tag file (default: “tags”).

+
+
-s[0|1|2], --override-sort-detection METHOD

Override sort detection of tag file. +METHOD: unsorted|sorted|foldcase

+
+
+

The NAME action will perform binary search on sorted (including “foldcase”) +tags files, which is much faster then on unsorted tags files.

+
+
+

Controlling the NAME Action Behavior

+

The behavior of the NAME action can be controlled using these options:

+
+
-i, --icase-match

Perform case-insensitive matching in the NAME action.

+
+
-p, --prefix-match

Perform prefix matching in the NAME action.

+
+
+
+
+

Controlling the Output

+

By default, the output of readtags contains only the name, input and pattern +field. The Output can be tweaked using these options:

+
+
-d, --debug

Turn on debugging output.

+
+
-E, --escape-output

Escape characters like tabs in output as described in tags(5).

+
+
-e, --extension-fields

Include extension fields in output.

+
+
-n, --line-number

Also include the line number field when -e option is give.

+
+
+

About the -E option: certain characters are escaped in a tags file, to make +it machine-readable. e.g., ensuring no tabs character appear in fields other +than the pattern field. By default, readtags translates them to make it +human-readable, but when utilizing readtags output in a script or a client +tool, -E option should be used. See ctags-client-tools(7) for more +discussion on this.

+
+
+

Filtering and Sorting

+

Further filtering and sorting on the tags listed by actions are performed using:

+
+
-Q EXP, --filter EXP

Filter the tags listed by ACTION with EXP before printing.

+
+
-S EXP, --sorter EXP

Sort the tags listed by ACTION with EXP before printing.

+
+
+

These are discussed in the EXPRESSION section.

+
+
+

Examples

+
    +
  • List all tags in “/path/to/tags”:

    +
    $ readtags -t /path/to/tags -l
    +
    +
    +
  • +
  • List all tags in “tags” that start with “mymethod”:

    +
    $ readtags -p - mymethod
    +
    +
    +
  • +
  • List all tags matching “mymethod”, case insensitively:

    +
    $ readtags -i - mymethod
    +
    +
    +
  • +
  • List all tags start with “myvar”, and printing all fields (i.e., the whole line):

    +
    $ readtags -p -ne - myvar
    +
    +
    +
  • +
+
+
+
+

EXPRESSION

+

Scheme-style expressions are used for the -Q and -S options. For those +who doesn’t know Scheme or Lisp, just remember:

+
    +
  • A function call is wrapped in a pair of parenthesis. The first item in it is +the function/operator name, the others are arguments.

  • +
  • Function calls can be nested.

  • +
  • Missing values and boolean false are represented by #f. #t and all +other values are considered to be true.

  • +
+

So, (+ 1 (+ 2 3)) means add 2 and 3 first, then add the result with 1. +(and "string" 1 #t) means logical AND on "string", 1 and #t, +and the result is true since there is no #f.

+
+

Filtering

+

The tag entries that make the filter expression produces true value are printed +by readtags.

+

The basic operators for filtering are eq?, prefix?, suffix?, +substr?, and #/PATTERN/. Language common fields can be accessed using +variables starting with $, e.g., $language represents the language field. +For example:

+
    +
  • List all tags start with “myfunc” in Python code files:

    +
    $ readtags -p -Q '(eq? $language "Python")' - myfunc
    +
    +
    +
  • +
+

downcase or upcase operators can be used to perform case-insensitive +matching:

+
    +
  • List all tags containing “my”, case insensitively:

    +
    +
    $ readtags -Q '(substr? (downcase $name) "my")' -l
    +
    +
    +
    +
  • +
+

We have logical operators like and, or and not. The value of a +missing field is #f, so we could deal with missing fields:

+
    +
  • List all tags containing “impl” in Python code files, but allow the +language: field to be missing:

    +
    $ readtags -Q '(and (substr? $name "impl")\
    +                    (or (not $language)\
    +                        (eq? $language "Python")))' -l
    +
    +
    +
  • +
+

#/PATTERN/ is for the case when string predicates (prefix?, suffix?, +and substr?) are not enough. You can use “Posix extended regular expression” +as PATTERN.

+
    +
  • List all tags inherits from the class “A”:

    +
    $ readtags -Q '(#/(^|,) ?A(,|$)/ $inherits)' -l
    +
    +
    +
  • +
+

Here $inherits is a comma-separated class list like “A,B,C”, “P, A, Q”, or +just “A”. Notice that this filter works on both situations where there’s a +space after each comma or there’s not.

+

Case-insensitive matching can be performed by #/PATTERN/i:

+
    +
  • List all tags inherits from the class “A” or “a”:

    +
    $ readtags -Q '(#/(^|,) ?A(,|$)/i $inherits)' -l
    +
    +
    +
  • +
+

To include “/” in a pattern, prefix \ to the “/”.

+

NOTE: The above regular expression pattern for inspecting inheritances is just +an example to show how to use #/PATTERN/ expression. Tags file generators +have no consensus about the format of inherits:, e.g., whether there should +be a space after a comma. Even parsers in ctags have no consensus. Noticing the +format of the inherits: field of specific languages is needed for such +queries.

+

The expressions #/PATTERN/ and #/PATTERN/i are for interactive use. +Readtags also offers an alias string->regexp, so #/PATTERN/ is equal to +(string->regexp "PATTERN"), and #/PATTERN/i is equal to +(string->regexp "PATTERN" :case-fold #t). string->regexp doesn’t need +to prefix \ for including “/” in a pattern. string->regexp may simplify +a client tool building an expression. See also ctags-client-tools(7) for +building expressions in your tool.

+

Let’s now consider missing fields. The tags file may have tag entries that has +no inherits: field. In that case $inherits is #f, and the regular +expression matching raises an error, since string operators only work for +strings. To avoid this problem:

+
    +
  • Safely list all tags inherits from the class “A”:

    +
    $ readtags -Q '(and $inherits (#/(^|,) ?A(,|$)/ $inherits))' -l
    +
    +
    +
  • +
+

This makes sure $inherits is not missing first, then match it by regexp.

+

Sometimes you want to keep tags where the field is missing. For example, your +want to exclude reference tags, which is marked by the extras: field, then +you want to keep tags who doesn’t have extras: field since they are also +not reference tags. Here’s how to do it:

+
    +
  • List all tags but the reference tags:

    +
    $ readtags -Q '(or (not $extras) (#/(^|,) ?reference(,|$)/ $extras))' -l
    +
    +
    +
  • +
+

Notice that (not $extras) produces #t when $extras is missing, so +the whole or expression produces #t.

+

Run “readtags -H filter” to know about all valid functions and variables.

+
+
+

Sorting

+

When sorting, the sorter expression is evaluated on two tag entries to decide +which should sort before the other one, until the order of all tag entries is +decided.

+

In a sorter expression, $ and & are used to access the fields in the +two tag entries, and let’s call them $-entry and &-entry. The sorter expression +should have a value of -1, 0 or 1. The value -1 means the $-entry should be put +above the &-entry, 1 means the contrary, and 0 makes their order in the output +uncertain.

+

The core operator of sorting is <>. It’s used to compare two strings or two +numbers (numbers are for the line: or end: fields). In (<> a b), if +a < b, the result is -1; a > b produces 1, and a = b +produces 0. Strings are compared using the strcmp function, see strcmp(3).

+

For example, sort by names, and make those shorter or alphabetically smaller +ones appear before the others:

+
$ readtags -S '(<> $name &name)' -l
+
+
+

This reads “If the tag name in the $-entry is smaller, it goes before the +&-entry”.

+

The <or> operator is used to chain multiple expressions until one returns +-1 or 1. For example, sort by input file names, then line numbers if in the +same file:

+
$ readtags -S '(<or> (<> $input &input) (<> $line &line))' -l
+
+
+

The *- operator is used to flip the compare result. i.e., (*- (<> a b)) +is the same as (<> b a).

+

Filter expressions can be used in sorter expressions. The technique is use +if to produce integers that can be compared based on the filter, like:

+
(<> (if filter-expr-on-$-entry -1 1)
+    (if filter-expr-on-&-entry -1 1))
+
+
+

So if $-entry satisfies the filter, while &-entry doesn’t, it’s the same as +(<> -1 1), which produces -1.

+

For example, we want to put tags with “file” kind below other tags, then the +sorter would look like:

+
(<> (if (eq? $kind "file") 1 -1)
+    (if (eq? &kind "file") 1 -1))
+
+
+

A quick read tells us: If $-entry has “file” kind, and &-entry doesn’t, the +sorter becomes (<> 1 -1), which produces 1, so the $-entry is put below +the &-entry, exactly what we want.

+
+
+

Inspecting the Behavior of Expressions

+

The print operator can be used to print the value of an expression. For +example:

+
$ readtags -Q '(print $name)' -l
+
+
+

prints the name of each tag entry before it. Since the return value of +print is not #f, all the tag entries are printed. We could control this +using the begin or begin0 operator. begin returns the value of its +last argument, and begin0 returns the value of its first argument. For +example:

+
$ readtags -Q '(begin0 #f (print (prefix? "ctags" "ct")))' -l
+
+
+

prints a bunch of “#t” (depending on how many lines are in the tags file), and +the actual tag entries are not printed.

+
+
+
+

SEE ALSO

+

See tags(5) for the details of tags file format.

+

See ctags-client-tools(7) for the tips writing a +tool utilizing tags file.

+

The official Universal Ctags web site at:

+

https://ctags.io/

+

The git repository for the library used in readtags command:

+

https://github.com/universal-ctags/libreadtags

+
+
+

CREDITS

+

Universal Ctags project +https://ctags.io/

+

Darren Hiebert <dhiebert@users.sourceforge.net> +http://DarrenHiebert.com/

+

The readtags command and libreadtags maintained at Universal Ctags +are derived from readtags.c and readtags.h developd at +http://ctags.sourceforge.net.

+
+
+ + +
+
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/ctags/docs/man/tags.5.html b/ctags/docs/man/tags.5.html new file mode 100644 index 0000000..e9747f4 --- /dev/null +++ b/ctags/docs/man/tags.5.html @@ -0,0 +1,619 @@ + + + + + + + + + tags — Universal Ctags 0.3.0 documentation + + + + + + + + + + + + + + + +
+
+
+
+ +
+

tags

+

Vi tags file format extended in ctags projects

+
+
Version
+

2+

+
+
Manual group
+

Universal Ctags

+
+
Manual section
+

5

+
+
+
+

DESCRIPTION

+

The contents of next section is a copy of FORMAT file in Exuberant +Ctags source code in its subversion repository at sourceforge.net.

+

Exceptions introduced in Universal Ctags are explained inline with +“EXCEPTION” marker.

+
+
+
+

Proposal for extended Vi tags file format

+
+
Version: 0.06 DRAFT
+
Date: 1998 Feb 8
+
Author: Bram Moolenaar <Bram at vim.org> and Darren Hiebert <dhiebert at users.sourceforge.net>
+
+
+

Introduction

+

The file format for the “tags” file, as used by Vi and many of its +descendants, has limited capabilities.

+

This additional functionality is desired:

+
    +
  1. Static or local tags. +The scope of these tags is the file where they are defined. The same tag +can appear in several files, without really being a duplicate.

  2. +
  3. Duplicate tags. +Allow the same tag to occur more then once. They can be located in +a different file and/or have a different command.

  4. +
  5. Support for C++. +A tag is not only specified by its name, but also by the context (the +class name).

  6. +
  7. Future extension. +When even more additional functionality is desired, it must be possible to +add this later, without breaking programs that don’t support it.

  8. +
+
+
+

From proposal to standard

+

To make this proposal into a standard for tags files, it needs to be supported +by most people working on versions of Vi, ctags, etc.. Currently this +standard is supported by:

+
+
Darren Hiebert <dhiebert at users.sourceforge.net>

Exuberant Ctags

+
+
Bram Moolenaar <Bram at vim.org>

Vim (Vi IMproved)

+
+
+

These have been or will be asked to support this standard:

+
+
Nvi

Keith Bostic <bostic at bsdi.com>

+
+
Vile

Tom E. Dickey <dickey at clark.net>

+
+
NEdit

Mark Edel <edel at ltx.com>

+
+
CRiSP

Paul Fox <fox at crisp.demon.co.uk>

+
+
Lemmy

James Iuliano <jai at accessone.com>

+
+
Zeus

Jussi Jumppanen <jussij at ca.com.au>

+
+
Elvis

Steve Kirkendall <kirkenda at cs.pdx.edu>

+
+
FTE

Marko Macek <Marko.Macek at snet.fri.uni-lj.si>

+
+
+
+
+

Backwards compatibility

+

A tags file that is generated in the new format should still be usable by Vi. +This makes it possible to distribute tags files that are usable by all +versions and descendants of Vi.

+

This restricts the format to what Vi can handle. The format is:

+
    +
  1. The tags file is a list of lines, each line in the format:

    +
    {tagname}<Tab>{tagfile}<Tab>{tagaddress}
    +
    +
    +
    +
    {tagname}

    Any identifier, not containing white space..

    +

    EXCEPTION: Universal Ctags violates this item of the proposal; +tagname may contain spaces. However, tabs are not allowed.

    +
    +
    <Tab>

    Exactly one TAB character (although many versions of Vi can +handle any amount of white space).

    +
    +
    {tagfile}

    The name of the file where {tagname} is defined, relative to +the current directory (or location of the tags file?).

    +
    +
    {tagaddress}

    Any Ex command. When executed, it behaves like ‘magic’ was +not set.

    +
    +
    +
  2. +
  3. The tags file is sorted on {tagname}. This allows for a binary search in +the file.

  4. +
  5. Duplicate tags are allowed, but which one is actually used is +unpredictable (because of the binary search).

  6. +
+

The best way to add extra text to the line for the new functionality, without +breaking it for Vi, is to put a comment in the {tagaddress}. This gives the +freedom to use any text, and should work in any traditional Vi implementation.

+

For example, when the old tags file contains:

+
main    main.c  /^main(argc, argv)$/
+DEBUG   defines.c       89
+
+
+

The new lines can be:

+
main    main.c  /^main(argc, argv)$/;"any additional text
+DEBUG   defines.c       89;"any additional text
+
+
+

Note that the ‘;’ is required to put the cursor in the right line, and then +the ‘”’ is recognized as the start of a comment.

+

For Posix compliant Vi versions this will NOT work, since only a line number +or a search command is recognized. I hope Posix can be adjusted. Nvi suffers +from this.

+
+
+

Security

+

Vi allows the use of any Ex command in a tags file. This has the potential of +a trojan horse security leak.

+

The proposal is to allow only Ex commands that position the cursor in a single +file. Other commands, like editing another file, quitting the editor, +changing a file or writing a file, are not allowed. It is therefore logical +to call the command a tagaddress.

+

Specifically, these two Ex commands are allowed:

+
    +
  • A decimal line number:

    +
    89
    +
    +
    +
  • +
  • A search command. It is a regular expression pattern, as used by Vi, +enclosed in // or ??:

    +
    /^int c;$/
    +?main()?
    +
    +
    +
  • +
+

There are two combinations possible:

+
    +
  • Concatenation of the above, with ‘;’ in between. The meaning is that the +first line number or search command is used, the cursor is positioned in +that line, and then the second search command is used (a line number would +not be useful). This can be done multiple times. This is useful when the +information in a single line is not unique, and the search needs to start +in a specified line.

    +
    /struct xyz {/;/int count;/
    +389;/struct foo/;/char *s;/
    +
    +
    +
  • +
  • A trailing comment can be added, starting with ‘;”’ (two characters: +semi-colon and double-quote). This is used below.

    +
    89;" foo bar
    +
    +
    +
  • +
+

This might be extended in the future. What is currently missing is a way to +position the cursor in a certain column.

+
+
+

Goals

+

Now the usage of the comment text has to be defined. The following is aimed +at:

+
    +
  1. Keep the text short, because:

    +
      +
    • The line length that Vi can handle is limited to 512 characters.

    • +
    • Tags files can contain thousands of tags. I have seen tags files of +several Mbytes.

    • +
    • More text makes searching slower.

    • +
    +
  2. +
  3. Keep the text readable, because:

    +
      +
    • It is often necessary to check the output of a new ctags program.

    • +
    • Be able to edit the file by hand.

    • +
    • Make it easier to write a program to produce or parse the file.

    • +
    +
  4. +
  5. Don’t use special characters, because:

    +
      +
    • It should be possible to treat a tags file like any normal text file.

    • +
    +
  6. +
+
+
+

Proposal

+

Use a comment after the {tagaddress} field. The format would be:

+
{tagname}<Tab>{tagfile}<Tab>{tagaddress}[;"<Tab>{tagfield}..]
+
+
+
+
{tagname}

Any identifier, not containing white space..

+

EXCEPTION: Universal Ctags violates this item of the proposal; +name may contain spaces. However, tabs are not allowed. +Conversion, for some characters including <Tab> in the “value”, +explained in the last of this section is applied.

+
+
<Tab>

Exactly one TAB character (although many versions of Vi can +handle any amount of white space).

+
+
{tagfile}

The name of the file where {tagname} is defined, relative to +the current directory (or location of the tags file?).

+
+
{tagaddress}

Any Ex command. When executed, it behaves like ‘magic’ was +not set. It may be restricted to a line number or a search +pattern (Posix).

+
+
+

Optionally:

+
+
;”

semicolon + doublequote: Ends the tagaddress in way that looks +like the start of a comment to Vi.

+
+
{tagfield}

See below.

+
+
+

A tagfield has a name, a colon, and a value: “name:value”.

+
    +
  • The name consist only out of alphabetical characters. Upper and lower case +are allowed. Lower case is recommended. Case matters (“kind:” and “Kind: +are different tagfields).

    +

    EXCEPTION: Universal Ctags allows users to use a numerical character +in the name other than its initial letter.

    +
  • +
  • The value may be empty. +It cannot contain a <Tab>.

    +
      +
    • When a value contains a \t, this stands for a <Tab>.

    • +
    • When a value contains a \r, this stands for a <CR>.

    • +
    • When a value contains a \n, this stands for a <NL>.

    • +
    • When a value contains a \\, this stands for a single \ character.

    • +
    +

    Other use of the backslash character is reserved for future expansion. +Warning: When a tagfield value holds an MS-DOS file name, the backslashes +must be doubled!

    +

    EXCEPTION: Universal Ctags introduces more conversion rules.

    +
      +
    • When a value contains a \a, this stands for a <BEL> (0x07).

    • +
    • When a value contains a \b, this stands for a <BS> (0x08).

    • +
    • When a value contains a \v, this stands for a <VT> (0x0b).

    • +
    • When a value contains a \f, this stands for a <FF> (0x0c).

    • +
    • The characters in range 0x01 to 0x1F included, and 0x7F are +converted to \x prefixed hexadecimal number if the characters are +not handled in the above “value” rules.

    • +
    • The leading space (0x20) and ! (0x21) in {tagname} are converted +to \x prefixed hexadecimal number (\x20 and \x21) if the +tag is not a pseudo-tag. As described later, a pseudo-tag starts with +!. These rules are for distinguishing pseudo-tags and non pseudo-tags +(regular tags) when tags lines in a tag file are sorted.

    • +
    +
  • +
+

Proposed tagfield names:

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

FIELD-NAME

DESCRIPTION

arity

Number of arguments for a function tag.

class

Name of the class for which this tag is a member or method.

enum

Name of the enumeration in which this tag is an enumerator.

file

Static (local) tag, with a scope of the specified file. When +the value is empty, {tagfile} is used.

function

Function in which this tag is defined. Useful for local +variables (and functions). When functions nest (e.g., in +Pascal), the function names are concatenated, separated with +‘/’, so it looks like a path.

kind

Kind of tag. The value depends on the language. For C and +C++ these kinds are recommended:

+
+
c

class name

+
+
d

define (from #define XXX)

+
+
e

enumerator

+
+
f

function or method name

+
+
F

file name

+
+
g

enumeration name

+
+
m

member (of structure or class data)

+
+
p

function prototype

+
+
s

structure name

+
+
t

typedef

+
+
u

union name

+
+
v

variable

+
+
+

When this field is omitted, the kind of tag is undefined.

+

struct

Name of the struct in which this tag is a member.

union

Name of the union in which this tag is a member.

+

Note that these are mostly for C and C++. When tags programs are written for +other languages, this list should be extended to include the used field names. +This will help users to be independent of the tags program used.

+

Examples:

+
asdf    sub.cc  /^asdf()$/;"    new_field:some\svalue   file:
+foo_t   sub.h   /^typedef foo_t$/;"     kind:t
+func3   sub.p   /^func3()$/;"   function:/func1/func2   file:
+getflag sub.c   /^getflag(arg)$/;"      kind:f  file:
+inc     sub.cc  /^inc()$/;"     file: class:PipeBuf
+
+
+

The name of the “kind:” field can be omitted. This is to reduce the size of +the tags file by about 15%. A program reading the tags file can recognize the +“kind:” field by the missing ‘:’. Examples:

+
foo_t   sub.h   /^typedef foo_t$/;"     t
+getflag sub.c   /^getflag(arg)$/;"      f       file:
+
+
+

Additional remarks:

+
    +
  • When a tagfield appears twice in a tag line, only the last one is used.

  • +
+

Note about line separators:

+

Vi traditionally runs on Unix systems, where the line separator is a single +linefeed character <NL>. On MS-DOS and compatible systems <CR><NL> is the +standard line separator. To increase portability, this line separator is also +supported.

+

On the Macintosh a single <CR> is used for line separator. Supporting this on +Unix systems causes problems, because most fgets() implementation don’t see +the <CR> as a line separator. Therefore the support for a <CR> as line +separator is limited to the Macintosh.

+

Summary:

+ +++++ + + + + + + + + + + + + + + + + + + + + +

line separator

generated on

accepted on

<LF>

Unix

Unix, MS-DOS, Macintosh

<CR>

Macintosh

Macintosh

<CR><LF>

MS-DOS

Unix, MS-DOS, Macintosh

+

The characters <CR> and <LF> cannot be used inside a tag line. This is not +mentioned elsewhere (because it’s obvious).

+

Note about white space:

+

Vi allowed any white space to separate the tagname from the tagfile, and the +filename from the tagaddress. This would need to be allowed for backwards +compatibility. However, all known programs that generate tags use a single +<Tab> to separate fields.

+

There is a problem for using file names with embedded white space in the +tagfile field. To work around this, the same special characters could be used +as in the new fields, for example \s. But, unfortunately, in MS-DOS the +backslash character is used to separate file names. The file name +c:\vim\sap contains \s, but this is not a <Space>. The number of +backslashes could be doubled, but that will add a lot of characters, and make +parsing the tags file slower and clumsy.

+

To avoid these problems, we will only allow a <Tab> to separate fields, and +not support a file name or tagname that contains a <Tab> character. This +means that we are not 100% Vi compatible. However, there is no known tags +program that uses something else than a <Tab> to separate the fields. Only +when a user typed the tags file himself, or made his own program to generate a +tags file, we could run into problems. To solve this, the tags file should be +filtered, to replace the arbitrary white space with a single <Tab>. This Vi +command can be used:

+
:%s/^\([^ ^I]*\)[ ^I]*\([^ ^I]*\)[ ^I]*/\1^I\2^I/
+
+
+

(replace ^I with a real <Tab>).

+

TAG FILE INFORMATION:

+

Pseudo-tag lines can be used to encode information into the tag file regarding +details about its content (e.g. have the tags been sorted?, are the optional +tagfields present?), and regarding the program used to generate the tag file. +This information can be used both to optimize use of the tag file (e.g. +enable/disable binary searching) and provide general information (what version +of the generator was used).

+

The names of the tags used in these lines may be suitably chosen to ensure +that when sorted, they will always be located near the first lines of the tag +file. The use of “!_TAG_” is recommended. Note that a rare tag like “!” +can sort to before these lines. The program reading the tags file should be +smart enough to skip over these tags.

+

The lines described below have been chosen to convey a select set of +information.

+

Tag lines providing information about the content of the tag file:

+
!_TAG_FILE_FORMAT   {version-number}        /optional comment/
+!_TAG_FILE_SORTED   {0|1}                   /0=unsorted, 1=sorted/
+
+
+

The {version-number} used in the tag file format line reserves the value of +“1” for tag files complying with the original UNIX vi/ctags format, and +reserves the value “2” for tag files complying with this proposal. This value +may be used to determine if the extended features described in this proposal +are present.

+

Tag lines providing information about the program used to generate the tag +file, and provided solely for documentation purposes:

+
!_TAG_PROGRAM_AUTHOR        {author-name}   /{email-address}/
+!_TAG_PROGRAM_NAME  {program-name}  /optional comment/
+!_TAG_PROGRAM_URL   {URL}   /optional comment/
+!_TAG_PROGRAM_VERSION       {version-id}    /optional comment/
+
+
+

EXCEPTION: Universal Ctags introduces more kinds of pseudo-tags. +See ctags-client-tools(7) about them.

+
+
+
+
+

Exceptions in Universal Ctags

+

Universal Ctags supports this proposal with some +exceptions.

+
+

Exceptions

+
    +
  1. {tagname} in tags file generated by Universal Ctags may contain +spaces and several escape sequences. Parsers for documents like Tex and +reStructuredText, or liberal languages such as JavaScript need these +exceptions. See {tagname} of Proposal section for more detail about the +conversion.

  2. +
  3. “name” part of {tagfield} in a tag generated by Universal Ctags may +contain numeric characters, but the first character of the “name” +must be alphabetic.

    +
  4. +
+
+
+

Compatible output and weakness

+

Default behavior (--output-format=u-ctags option) has the +exceptions. In other hand, with --output-format=e-ctags option +ctags has no exception; Universal Ctags command may use the same file +format as Exuberant Ctags. However, --output-format=e-ctags throws +away a tag entry which name includes a space or a tab +character. TAG_OUTPUT_MODE pseudo-tag tells which format is +used when ctags generating tags file.

+
+
+
+

SEE ALSO

+

ctags(1), ctags-client-tools(7), ctags-incompatibilities(7), readtags(1)

+
+
+ + +
+
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/ctags/docs/news.html b/ctags/docs/news.html new file mode 100644 index 0000000..f3f84a9 --- /dev/null +++ b/ctags/docs/news.html @@ -0,0 +1,673 @@ + + + + + + + + + Other changes — Universal Ctags 0.3.0 documentation + + + + + + + + + + + + + + + +
+
+
+
+ +
+

Other changes

+
+
Maintainer
+

Masatake YAMATO <yamato@redhat.com>

+
+
+ +
+

Many changes have been introduced in Universal Ctags. Use git-log to +review changes not enumerated here, especially in language parsers.

+
+

New and extended options

+
+

--exclude-exception, an option complementing --exclude

+

See Input/Output File Options in ctags(1).

+
+
+

--maxdepth option

+

See Input/Output File Options in ctags(1).

+
+
+

--input-encoding=ENCODING and --output-encoding=ENCODING

+

People may use their own native language in source code comments (or +sometimes in identifiers) and in such cases encoding may become an issue. +Nowadays UTF-8 is the most widely used encoding, but some source codes +still use legacy encodings like latin1, cp932 and so on. These options +are useful for such files.

+

ctags doesn’t consider the input encoding; it just reads input as a +sequence of bytes and uses them as is when writing tags entries.

+

On the other hand Vim does consider input encoding. When loading a +file, Vim converts the file contents into an internal format with one +of the encodings specified in its fileencodings option.

+

As a result of this difference, Vim cannot always move the cursor to +the definition of a tag as users expect when attempting to match the +patterns in a tags file.

+

The good news is that there is a way to notify Vim of the encoding +used in a tags file with the TAG_FILE_ENCODING pseudo-tag.

+

Two new options have been introduced (--input-encoding=IN and +--output-encoding=OUT).

+

Using the encoding specified with these options ctags converts input +from IN to OUT. ctags uses the converted strings when writing +the pattern parts of each tag line. As a result the tags output is +encoded in OUT encoding.

+

In addition OUT is specified at the top the tags file as the +value for the TAG_FILE_ENCODING pseudo-tag. The default value of +OUT is UTF-8.

+

NOTE: Converted input is NOT passed to language parsers. +The parsers still deal with input as a byte sequence.

+

With --input-encoding-<LANG>=IN, you can specify a specific input +encoding for LANG. It overrides the global default value given +with --input-encoding.

+

The example usage can be found in Tmain/{input,output}-encoding-option.d.

+

Acceptable IN and OUT values can be listed with iconv -l or +iconv --list. It is platform dependant.

+

To enable the option, libiconv is needed on your platform. +On Windows mingw (without msys2), you must specify WITH_ICONV=yes +like this:

+
C:\dev\ctags>mingw32-make -f mk_mingw.mak WITH_ICONV=yes
+
+
+

--list-features helps you to know whether your ctags executable +links to libiconv or not. You will find iconv in the output if it +links to.

+

See also Output Format Options in ctags(1).

+
+
+

--map-<LANG> option

+

--map-<LANG> is newly introduced to control the file name +to language mappings (langmap) with finer granularity than +--langmap allows.

+

A langmap entry is defined as a pair; the name of the language and a +file name extension (or pattern).

+

Here we use “spec” as a generic term representing both file name +extensions and patterns.

+

--langmap maps specs to languages exclusively:

+
$ ctags --langdef=FOO --langmap=FOO:+.ABC \
+          --langdef=BAR --langmap=BAR:+.ABC  \
+          --list-maps | grep '\*.ABC$'
+BAR      *.ABC
+
+
+

Though language FOO is added before BAR, only BAR is set as a +handler for the spec *.ABC.

+

Universal Ctags enables multiple parsers to be configured for a spec. +The appropriate parser for a given input file can then be chosen by a +variety of internal guessing strategies (see Determining file language).

+

Let’s see how specs can be mapped non-exclusively with +--map-<LANG>:

+
$ ctags --langdef=FOO --map-FOO=+.ABC \
+          --langdef=BAR --map-BAR=+.ABC \
+          --list-maps | grep '\*.ABC$'
+FOO      *.ABC
+BAR      *.ABC
+
+
+

Both FOO and BAR are registered as handlers for the spec *.ABC.

+

--map-<LANG> can also be used for removing a langmap entry.:

+
$ ctags --langdef=FOO --map-FOO=+.ABC \
+          --langdef=BAR --map-BAR=+.ABC \
+          --map-FOO=-.ABC --list-maps | grep '\*.ABC$'
+BAR      *.ABC
+
+$ ctags --langdef=FOO --map-FOO=+.ABC \
+          --langdef=BAR --map-BAR=+.ABC \
+          --map-BAR=-.ABC --list-maps | grep '\*.ABC$'
+FOO      *.ABC
+
+$ ctags --langdef=FOO --map-FOO=+.ABC \
+         --langdef=BAR --map-BAR=+.ABC \
+         --map-BAR=-.ABC --map-FOO=-.ABC  --list-maps | grep '\*.ABC$'
+(NOTHING)
+
+
+

--langmap provides a way to manipulate the langmap in a +spec-centric manner and --map-<LANG> provides a way to manipulate +the langmap in a parser-centric manner.

+

See also Language Selection and Mapping Options in ctags(1).

+
+
+

Guessing parser from file contents (-G option)

+

See Determining file language in ctags(1).

+
+
+

Including line number to pattern field

+

Use --excmd=number. +See Tags File Contents Options in ctags(1).

+
+
+

Long names in kinds, fields, and extra options

+

A letter is used for specifying a kind, a field, or an extra entry. +In Universal Ctags a name can also be used.

+

Surround the name with braces ({ and }) in values assigned to the +options, --kind-<LANG>=, --fields=, or --extras=.

+
$ ctags --kinds-C=+L-d ...
+
+
+

This command line uses the letters, L for enabling the label kind +and d for disabling the macro kind of C. The command line can be +rewritten with the associated names.

+
$ ctags --kinds-C='+{label}-{macro}' ...
+
+
+

The quotes are needed because braces are interpreted as meta +characters by the shell.

+

The available names can be listed with --list-kinds-full, +--list-fields, or --list-extras.

+

See also Tags File Contents Options in ctags(1).

+
+
+

Wildcard in options

+

For the purpose of gathering as much as information as possible from +source code the “wildcard”(*) option value has been introduced.

+
+
--extras=*

Enables all extra tags.

+
+
--fields=*

Enables all available fields.

+
+
--kinds-<LANG>=*

Enables all available kinds for LANG.

+
+
--kinds-all=*

Enables all available kinds for all available language parsers.

+
+
+

See also Tags File Contents Options in ctags(1).

+
+
+

Extra tag entries (--extras)

+

--extra option in Exuberant Ctags is renamed to --extras (plural) in +Universal Ctags for making consistent with --kinds-<LANG> and --fields.

+

These extra tag entries are newly introduced.

+
+
F

Replacement for --file-scope.

+
+
p

Include pseudo-tags.

+
+
+

See also Tags File Contents Options in ctags(1).

+
+
+

Kinds synchronization

+

See the description about --kinds-<LANG> and --list-kinds-full +option on Tags File Contents Options in ctags(1).

+
+
+

Enabling/disabling pseudo-tags (--pseudo-tags option)

+

See Tags File Contents Options in ctags(1) and +ctags-client-tools(7) about the option.

+
+
+

--put-field-prefix options

+

See Tags File Contents Options in ctags(1).

+
+
+

“always” and “never” as an argument for --tag-relative

+

--tag-relative option is extend. +See Tags File Contents Options in ctags(1).

+
+
+

Defining a parser specific extra

+

A new --_extradef-<LANG>=name,description option allows you to +defining a parser specific extra which turning on and off can be +referred from a regex based parser for <LANG>.

+

See Conditional tagging with extras for more details.

+
+
+

Defining a CPreProcessor macro from command line

+

Newly introduced -D option extends the function provided by +-I option.

+

-D emulates the behaviour of the corresponding gcc option: +it defines a C preprocessor macro.

+

See Tags File Contents Options in ctags(1) and +The new C/C++ parser for more details.

+
+
+

Options for inspecting ctags internals

+

Exuberant Ctags provides a way to inspect its internals via +--list-kinds, --list-languages, and --list-maps.

+

This idea has been expanded in Universal Ctags with +--list-kinds-full, --list-map-extensions, --list-extras, +--list-features, --list-fields, --list-map-patterns, and +--list-pseudo-tags being added.

+

The original three --list- options are not changed for +compatibility reasons, however, the newly introduced options are +recommended for all future use.

+

By default, interactive use is assumed and ctags tries aligning the +list output in columns for easier reading.

+

When --machinable is given before a --list- option, ctags +outputs the list in a format more suitable for processing by scripts. +Tab characters are used as separators between columns. The alignment +of columns is never considered when --machinable is given.

+

Currently only --list-extras, --list-fields and +--list-kinds-full support --machinable output.

+

These new --list- options also print a column header, a line +representing the name of each column. The header may help users and +scripts to understand and recognize the columns. Ignoring the column +header is easy because it starts with a # character.

+

--with-list-header=no suppresses output of the column header.

+

See also Listing Options in ctags(1).

+
+
+

Notice messages and --quiet

+

There were 3 classes of message in Exuberant Ctags. +In addition to them Universal Ctags introduced a new class of message, notice.

+
+
fatal

A critical error has occurred and ctags aborts the execution.

+
+
warning

An error has occurred but ctags continues the execution.

+
+
notice (new)

It is less important than warning but more important for users than verbose.

+
+
verbose

Mainly used for debugging purposes.

+
+
+

Generally the user can ignore notice class messages and --quiet +can be used to disable them.

+

verbose class messages are disabled by default, and --verbose or -V +can be used to enable them.

+

See also Miscellaneous Options in ctags(1).

+
+
+

Skipping utf-8 BOM

+

The three bytes sequence(\xEF\xBB\xBF) at the head of an input +file is skipped when parsing.

+

TODO:

+
    +
  • Do the same in guessing and selecting parser stage.

  • +
  • Refect the BOM detection to encoding option

  • +
+
+
+

Interactive mode

+

A new --_interactive option launches a JSON based command REPL which +can be used to control ctags generation programmatically.

+

See Interactive mode for more details.

+
+
+
+

Incompatible changes in command line

+
+

-D option

+

For a ctags binary that had debugging output enabled in the build config +stage, -D was used for specifying the level of debugging +output. It is changed to -d. This change is not critical because +-D option was not described in ctags.1 man page.

+

Instead -D is used for defining a macro in CPreProcessor parser.

+
+
+
+

Changes imported from Exuberant Ctags

+

See “Exuberant Ctags” in “Tracking other projects” for detailed +information regarding imported changes.

+

Some changes have also been imported from Fedora and Debian.

+
+ +
+

Readtags

+
+

Printing line numbers with -n

+

See readtags(1).

+
+
+

Filtering in readtags command

+

See readtags(1).

+

readtags has ability to find tag entries by name.

+

The concept of filtering is inspired by the display filter of +Wireshark. You can specify more complex conditions for searching.

+

All symbols starting with $ represent a field of a tag entry which +is being tested against the S expression. Most will evaluate as a +string or #f. It evaluates to #f when the field doesn’t exist.

+

The scope field holds structured data: the kind and name of the +upper scope combined with :. The hold the value is stored to +$scope. The kind part is mapped to $scope-kind, and the name part +to $scope-name.

+

$scope-kind and $scope-name can only be used if the input tags +file is generated by ctags with --fields=+Z.

+

$ is a generic accessor for accessing extension fields. +$ takes one argument: the name of an extension field. +It returns the value of the field as a string if a value +is given, or #f.

+

Following examples shows how prefix?, suffix?, and +substr? work.

+
(prefix? "TARGET" "TA")
+=> #t
+
+(prefix? "TARGET" "RGET")
+=> #f
+
+(prefix? "TARGET" "RGE")
+=> #f
+
+(suffix? "TARGET" "TA")
+=> #f
+
+(suffix? "TARGET" "RGET")
+=> #t
+
+(suffix? "TARGET" "RGE")
+=> #f
+
+(substr? "TARGET" "TA")
+=> #t
+
+(suffix? "TARGET" "RGET")
+=> #t
+
+(suffix? "TARGET" "RGE")
+=> #t
+
+(and (suffix? "TARGET" "TARGET")
+     (prefix? "TARGET" "TARGET")
+     (substr? "TARGET" "TARGET")
+=> #t
+
+
+
+
+

Sorting in readtags command

+

readtags can sort the tag entries before printing. +You can specify the way to sort with -S option. Like -Q option, -S +also takes an S expression.

+

See readtags(1).

+
+
+

Listing pseudo tags with -D

+

See readtags(1).

+
+
+
+ + +
+
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/ctags/docs/objects.inv b/ctags/docs/objects.inv new file mode 100644 index 0000000..8afde2b Binary files /dev/null and b/ctags/docs/objects.inv differ diff --git a/ctags/docs/option-file.html b/ctags/docs/option-file.html new file mode 100644 index 0000000..412d8d5 --- /dev/null +++ b/ctags/docs/option-file.html @@ -0,0 +1,284 @@ + + + + + + + + + Option files — Universal Ctags 0.3.0 documentation + + + + + + + + + + + + + + + +
+
+
+
+ +
+

Option files

+

An “option file” is a file in which command line options are written line +by line. ctags loads it and runs as if the options in the file were +passed through command line.

+

The following file is an example of an option file:

+
# Exclude directories that don't contain real code
+--exclude=Units
+        # indentation is ignored
+        --exclude=tinst-root
+--exclude=Tmain
+
+
+

The character # can be used as a start marker of a line comment. +Whitespaces at the start of lines are ignored during loading.

+

And it works exactly as if we had called:

+
ctags --exclude=Units --exclude=tinst-root --exclude=Tmain
+
+
+
+

Order of loading option files

+

Option files are loaded by ctags automatically at start-up time.

+

Which files are loaded at start-up time are very different from Exuberant Ctags. +See Difference from Exuberant Ctags for the differences and their intentions.

+

At start-up time, ctags loads files having .ctags as a +file extension under the following statically defined directories:

+
    +
  1. $XDG_CONFIG_HOME/ctags/, or $HOME/.config/ctags/ if $XDG_CONFIG_HOME is not defined (on other than Windows)

  2. +
  3. $HOME/.ctags.d/

  4. +
  5. $HOMEDRIVE$HOMEPATH/ctags.d/ (on Windows)

  6. +
  7. ./.ctags.d/

  8. +
  9. ./ctags.d/

  10. +
+

ctags visits the directories in the order listed above for preloading files. +ctags loads files having .ctags as file extension in alphabetical +order (strcmp(3) is used for comparing, so for example +.ctags.d/ZZZ.ctags will be loaded before .ctags.d/aaa.ctags in an ordinary locale).

+

If a option file includes --options=PATHNAME option, specified files are +loaded immediately as described in the next section. ctags load a option +file only once if it is specified multiple times.

+

Finally if --options=PATHNAME option is specified on ctags command line, +option files specified are load.

+
+
+

--options=PATHNAME option

+

Exuberant Ctags also has the --options option, but you can only specify a +single file to load. Universal Ctags extends the option in two aspects:

+
    +
  • You can specify a directory, to load all the files in that directory.

  • +
  • You can specify a PATH list to look in. See next section for details.

  • +
+
+

Specifying a directory

+

If you specify a directory instead of a file as the argument for the +--options=PATHNAME, ctags will load all files having a +.ctags extension under said directory in alphabetical order.

+
+
+

Specifying an optlib PATH list

+

Much like a command line shell, ctags has an optlib PATH list in which it +can look for a file (or directory) to load.

+

When loading a file (or directory) specified with --options=PATHNAME, +ctags first checks if PATHNAME is an absolute path or a relative path. +An absolute path starts with ‘/’ or ‘.’. +If PATHNAME is an absolute path, ctags tries to load it immediately.

+

If, on the contrary, is a relative path, ctags does two things: First, +looks for the file (or directory) in optlib PATH list and tries to load it.

+

If the file doesn’t exist in the PATH list, ctags treats PATHNAME as a +path relative to the working directory and loads the file.

+

By default, optlib PATH list is empty. To set or add a directory +path to the list, use --optlib-dir=PATH.

+

For setting (adding one after clearing):

+
--optlib-dir=PATH
+
+
+

For adding on the beginning of the PATH list:

+
--optlib-dir=+PATH
+
+
+
+
+
+

Tips for writing an option file

+
    +
  • Use --quiet --options=NONE to disable preloading.

  • +
  • --_echo=MSG and --_force-quit=[NUM] options are introduced for +debugging the process of loading option files. See “OPTIONS” +section of ctags-optlib(7).

  • +
  • Universal Ctags has an optlib2c script that translates an option file +into C source code. Your optlib parser can thus easily become a built-in parser. +See Translating an option file into C source code (optlib2c) for details.

  • +
+
+
+

Difference from Exuberant Ctags

+

Quoted from man page of Exuberant Ctags:

+
+
+
FILES
    +
  • /ctags.cnf (on MSDOS, MSWindows only)

  • +
  • /etc/ctags.conf

  • +
  • /usr/local/etc/ctags.conf

  • +
  • $HOME/.ctags

  • +
  • $HOME/ctags.cnf (on MSDOS, MSWindows only)

  • +
  • .ctags

  • +
  • ctags.cnf (on MSDOS, MSWindows only)

  • +
+
+
+

If any of these configuration files exist, each will +be expected to contain a set of default options +which are read in the order listed when ctags +starts, but before the CTAGS environment variable is +read or any command line options are read. This +makes it possible to set up site-wide, personal or +project-level defaults. It is possible to compile +ctags to read an additional configuration file +before any of those shown above, which will be +indicated if the output produced by the --version +option lists the “custom-conf” feature. Options +appearing in the CTAGS environment variable or on +the command line will override options specified in +these files. Only options will be read from these +files. Note that the option files are read in +line-oriented mode in which spaces are significant +(since shell quoting is not possible). Each line of +the file is read as one command line parameter (as +if it were quoted with single quotes). Therefore, +use new lines to indicate separate command-line +arguments.

+
+

What follows explains the differences and their intentions…

+
+

Directory oriented configuration management

+

Exuberant Ctags provides a way to customize ctags with options like +--langdef=<LANG> and --regex-<LANG>. These options are +powerful and make ctags popular for programmers.

+

Universal Ctags extends this idea; we have added new options for +defining a parser, and have extended existing options. Defining +a new parser with the options is more than “customizing” in +Universal Ctags.

+

To make easier the maintenance a parser defined using the options, you can put +each language parser in a different options file. Universal Ctags doesn’t +preload a single file. Instead, Universal Ctags loads all the files having the +.ctags extension under the previously specified directories. If you +have multiple parser definitions, put them in different files.

+
+
+

Avoiding option incompatibility issues

+

The Universal Ctags options are different from those of Exuberant Ctags, +therefore Universal Ctags doesn’t load any of the files Exuberant Ctags loads at +start-up. Otherwise there would be incompatibility issues if Exuberant Ctags +loaded an option file that used a newly introduced option in Universal Ctags, +and vice versa.

+
+
+

No system wide configuration

+

To make the preload path list short and because it was rarely ever used, +Universal Ctags does not load any option files for system wide configuration. +(i.e., no /etc/ctags.d)

+
+
+

Using .ctags for the file extension

+

Extensions .cnf and .conf are obsolete. +Use the unified extension .ctags only.

+
+
+
+ + +
+
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/ctags/docs/optlib.html b/ctags/docs/optlib.html new file mode 100644 index 0000000..d0b29c7 --- /dev/null +++ b/ctags/docs/optlib.html @@ -0,0 +1,1610 @@ + + + + + + + + + Extending ctags with Regex parser (optlib) — Universal Ctags 0.3.0 documentation + + + + + + + + + + + + + + + +
+
+
+
+ +
+

Extending ctags with Regex parser (optlib)

+
+
Maintainer
+

Masatake YAMATO <yamato@redhat.com>

+
+
+ +

Exuberant Ctags allows a user to add a new parser to ctags with --langdef=<LANG> +and --regex-<LANG>=... options. +Universal Ctags follows and extends the design of Exuberant Ctags in more +powerful ways and call the feature as optlib parser, which is described in in +ctags-optlib(7) and the following sections.

+

ctags-optlib(7) is the primary document of the optlib +parser feature. The following sections provide additional information and more +advanced features. Note that some of the features are experimental, and will be +marked as such in the documentation.

+

Lots of optlib parsers are included in Universal Ctags, +optlib/*.ctags. +They will be good examples when you develop your own parsers.

+

A optlib parser can be translated into C source code. Your optlib parser can +thus easily become a built-in parser. See “Translating an option file into C source code (optlib2c)” for details.

+
+

Regular expression (regex) engine

+

Universal Ctags currently uses the same regex engine as Exuberant Ctags: +the POSIX.2 regex engine in GNU glibc-2.10.1. By default it uses the Extended +Regular Expressions (ERE) syntax, as used by most engines today; however it does +not support many of the “modern” extensions such as lazy captures, +non-capturing grouping, atomic grouping, possessive quantifiers, look-ahead/behind, +etc. It is also notoriously slow when backtracking, and has some known “quirks” +with respect to escaping special characters in bracket expressions.

+

For example, a pattern of [^\]]+ is invalid in POSIX.2, because the ‘]’ is +not special inside a bracket expression, and thus should not be escaped. +Most regex engines ignore this subtle detail in POSIX.2, and instead allow +escaping it with ‘\]’ inside the bracket expression and treat it as the +literal character ‘]’. GNU glibc, however, does not generate an error but +instead considers it undefined behavior, and in fact it will match very odd +things. Instead you must use the more unintuitive [^]]+ syntax. The same +is technically true of other special characters inside a bracket expression, +such as [^\)]+, which should instead be [^)]+. The [^\)]+ will +appear to work usually, but only because what it is really doing is matching any +character but ‘\or)’. The only exceptions for using ‘\’ inside a +bracket expression are for ‘\t’ and ‘\n’, which ctags converts to their +single literal character control codes before passing the pattern to glibc.

+

Another detail to keep in mind is how the regex engine treats newlines. +Universal Ctags compiles the regular expressions in the --regex-<LANG> and +--mline-regex-<LANG> options with REG_NEWLINE set. What that means is documented +in the +POSIX spec. +One obvious effect is that the regex special dot any-character ‘.’ does not match +newline characters, the ‘^’ anchor does match right after a newline, and +the ‘$’ anchor matches right before a newline. A more subtle issue is this text from the +chapter “Regular Expressions”; +“the use of literal <newline>s or any escape sequence equivalent produces undefined +results”. What that means is using a regex pattern with [^\n]+ is invalid, +and indeed in glibc produces very odd results. Never use\n’ in patterns +for --regex-<LANG>, and never use them in non-matching bracket expressions +for --mline-regex-<LANG> patterns. For the experimental --_mtable-regex-<LANG> +you can safely use ‘\n’ because that regex is not compiled with REG_NEWLINE.

+

You should always test your regex patterns against test files with strings that +do and do not match. Pay particular emphasis to when it should not match, and +how much it matches when it should. A common error is forgetting that a +POSIX.2 ERE engine is always greedy; the ‘*’ and ‘+’ quantifiers match +as much as possible, before backtracking from the end of their match.

+

For example this pattern:

+
foo.*bar
+
+
+

Will match this entire string, not just the first part:

+
foobar, bar, and even more bar
+
+
+
+
+

Regex option argument flags

+

Many regex-based options described in this document support additional arguments +in the form of long flags. Long flags are specified with surrounding ‘{’ and +‘}’.

+

The general format and placement is as follows:

+
--regex-<LANG>=<PATTERN>/<NAME>/[<KIND>/]LONGFLAGS
+
+
+

Some examples:

+
--regex-Pod=/^=head1[ \t]+(.+)/\1/c/
+--regex-Foo=/set=[^;]+/\1/v/{icase}
+--regex-Man=/^\.TH[[:space:]]{1,}"([^"]{1,})".*/\1/t/{exclusive}{icase}{scope=push}
+--regex-Gdbinit=/^#//{exclusive}
+
+
+

Note that the last example only has two ‘/’ forward-slashes following +the regex pattern, as a shortened form when no kind-spec exists.

+

The --mline-regex-<LANG> option also follows the above format. The +experimental --_mtable-regex-<LANG> option follows a slightly +modified version as well.

+
+

Regex control flags

+

The regex matching can be controlled by adding flags to the --regex-<LANG>, +--mline-regex-<LANG>, and experimental --_mtable-regex-<LANG> options. +This is done by either using the single character short flags b, e and +i flags as explained in the ctags.1 man page, or by using long flags +described earlier. The long flags require more typing but are much more +readable.

+

The mapping between the older short flag names and long flag names is:

+ +++++ + + + + + + + + + + + + + + + + + + + + +

short flag

long flag

description

b

basic

Posix basic regular expression syntax.

e

extend

Posix extended regular expression syntax (default).

i

icase

Case-insensitive matching.

+

So the following --regex-<LANG> expression:

+
--kinddef-m4=d,definition,definitions
+--regex-m4=/^m4_define\(\[([^]$\(]+).+$/\1/d/x
+
+
+

is the same as:

+
--kinddef-m4=d,definition,definitions
+--regex-m4=/^m4_define\(\[([^]$\(]+).+$/\1/d/{extend}
+
+
+

The characters ‘{’ and ‘}’ may not be suitable for command line +use, but long flags are mostly intended for option files.

+
+
+

Exclusive flag in regex

+

By default, lines read from the input files will be matched against all the +regular expressions defined with --regex-<LANG>. Each successfully matched +regular expression will emit a tag.

+

In some cases another policy, exclusive-matching, is preferable to the +all-matching policy. Exclusive-matching means the rest of regular +expressions are not tried if one of regular expressions is matched +successfully, for that input line.

+

For specifying exclusive-matching the flags exclusive (long) and x +(short) were introduced. For example, this is used in +optlib/gdbinit.ctags for ignoring comment lines in gdb files, +as follows:

+
--regex-Gdbinit=/^#//{exclusive}
+
+
+

Comments in gdb files start with ‘#’ so the above line is the first regex +match line in gdbinit.ctags, so that subsequent regex matches are +not tried for the input line.

+

If an empty name pattern (//) is used for the --regex-<LANG> option, +ctags warns it as a wrong usage of the option. However, if the flags +exclusive or x is specified, the warning is suppressed. +This is useful to ignore matched patterns as above.

+

NOTE: This flag does not make sense in the multi-line --mline-regex-<LANG> +option nor the multi-table --_mtable-regex-<LANG> option.

+
+
+

Experimental flags

+
+

Note

+

These flags are experimental. They apply to all regex option +types: basic --regex-<LANG>, multi-line --mline-regex-<LANG>, +and the experimental multi-table --_mtable-regex-<LANG> option.

+
+

_extra

+
+

This flag indicates the tag should only be generated if the given +extra type is enabled, as explained in “Conditional tagging with extras”.

+
+

_field

+
+

This flag allows a regex match to add additional custom fields to the +generated tag entry, as explained in “Adding custom fields to the tag output”.

+
+

_role

+
+

This flag allows a regex match to generate a reference tag entry and +specify the role of the reference, as explained in “Capturing reference tags”.

+
+

_anonymous=PREFIX

+
+

This flag allows a regex match to generate an anonymous tag entry. +ctags gives a name starting with PREFIX and emits it. +This flag is useful to record the position for a language object +having no name. A lambda function in a functional programming +language is a typical example of a language object having no name.

+

Consider following input (input.foo):

+
(let ((f (lambda (x) (+ 1 x))))
+        ...
+        )
+
+
+

Consider following optlib file (foo.ctags):

+
--langdef=Foo
+--map-Foo=+.foo
+--kinddef-Foo=l,lambda,lambda functions
+--regex-Foo=/.*\(lambda .*//l/{_anonymous=L}
+
+
+

You can get following tags file:

+
$ u-ctags  --options=foo.ctags -o - /tmp/input.foo
+Le4679d360100   /tmp/input.foo  /^(let ((f (lambda (x) (+ 1 x))))$/;"   l
+
+
+
+
+

Conditional tagging with extras

+

If a matched pattern should only be tagged when an extra flag is enabled, +mark the pattern with {_extra=XNAME} where XNAME is the name of the +extra. You must define a XNAME with the +--_extradef-<LANG>=XNAME,DESCRIPTION option before defining a regex flag +marked {_extra=XNAME}.

+
if __name__ == '__main__':
+        do_something()
+
+
+

To capture the lines above in a python program (input.py), an extra flag can +be used.

+
--_extradef-Python=main,__main__ entry points
+--regex-Python=/^if __name__ == '__main__':/__main__/f/{_extra=main}
+
+
+

The above optlib (python-main.ctags) introduces main extra to the Python parser. +The pattern matching is done only when the main is enabled.

+
$ ctags --options=python-main.ctags -o - --extras-Python='+{main}' input.py
+__main__        input.py        /^if __name__ == '__main__':$/;"        f
+
+
+
+
+

Adding custom fields to the tag output

+

Exuberant Ctags allows just one of the specified groups in a regex pattern to +be used as a part of the name of a tag entry.

+

Universal Ctags allows using the other groups in the regex pattern. +An optlib parser can have its specific fields. The groups can be used as a +value of the fields of a tag entry.

+

Let’s think about Unknown, an imaginary language. +Here is a source file (input.unknown) written in Unknown:

+
public func foo(n, m);
+protected func bar(n);
+private func baz(n,...);
+
+
+

With --regex-Unknown=... Exuberant Ctags can capture foo, bar, and baz +as names. Universal Ctags can attach extra context information to the +names as values for fields. Let’s focus on bar. protected is a +keyword to control how widely the identifier bar can be accessed. +(n) is the parameter list of bar. protected and (n) are +extra context information of bar.

+

With the following optlib file (unknown.ctags), ctags can attach +protected to the field protection and (n) to the field signature.

+
--langdef=unknown
+--kinddef-unknown=f,func,functions
+--map-unknown=+.unknown
+
+--_fielddef-unknown=protection,access scope
+--_fielddef-unknown=signature,signatures
+
+--regex-unknown=/^((public|protected|private) +)?func ([^\(]+)\((.*)\)/\3/f/{_field=protection:\1}{_field=signature:(\4)}
+--fields-unknown=+'{protection}{signature}'
+
+
+

For the line protected func bar(n); you will get following tags output:

+
bar     input.unknown   /^protected func bar(n);$/;"    f       protection:protected    signature:(n)
+
+
+

Let’s see the detail of unknown.ctags.

+
--_fielddef-unknown=protection,access scope
+
+
+

--_fielddef-<LANG>=name,description defines a new field for a parser +specified by <LANG>. Before defining a new field for the parser, +the parser must be defined with --langdef=<LANG>. protection is +the field name used in tags output. access scope is the description +used in the output of --list-fields and --list-fields=Unknown.

+
--_fielddef-unknown=signature,signatures
+
+
+

This defines a field named signature.

+
--regex-unknown=/^((public|protected|private) +)?func ([^\(]+)\((.*)\)/\3/f/{_field=protection:\1}{_field=signature:(\4)}
+
+
+

This option requests making a tag for the name that is specified with the group 3 of the +pattern, attaching the group 1 as a value for protection field to the tag, and attaching +the group 4 as a value for signature field to the tag. You can use the long regex flag +_field for attaching fields to a tag with the following notation rule:

+
{_field=FIELDNAME:GROUP}
+
+
+

--fields-<LANG>=[+|-]{FIELDNAME} can be used to enable or disable specified field.

+

When defining a new parser specific field, it is disabled by default. Enable the +field explicitly to use the field. See “Parser specific fields” +about --fields-<LANG> option.

+

passwd parser is a simple example that uses --fields-<LANG> option.

+
+
+

Capturing reference tags

+

To make a reference tag with an optlib parser, specify a role with +_role long regex flag. Let’s see an example:

+
--langdef=FOO
+--kinddef-FOO=m,module,modules
+--_roledef-FOO.m=imported,imported module
+--regex-FOO=/import[ \t]+([a-z]+)/\1/m/{_role=imported}
+--extras=+r
+--fields=+r
+
+
+

A role must be defined before specifying it as value for _role flag. +--_roledef-<LANG>.<KIND>=<ROLE>,<ROLEDESC> option is for defining a role. +See the line, --regex-FOO=.... In this parser FOO, the name of an +imported module is captured as a reference tag with role imported.

+

For specifying <KIND> where the role is defined, you can use either a +kind letter or a kind name surrounded by ‘{’ and ‘}’.

+

The option has two parameters separated by a comma:

+

<ROLE>

+
+

the role name, and

+
+

<ROLEDESC>

+
+

the description of the role.

+
+

The first parameter is the name of the role. The role is defined in +the kind <KIND> of the language <LANG>. In the example, +imported role is defined in the module kind, which is specified +with m. You can use {module}, the name of the kind instead.

+

The kind specified in --_roledef-<LANG>.<KIND> option must be +defined before using the option. See the description of +--kinddef-<LANG> for defining a kind.

+

The roles are listed with --list-roles=<LANG>. The name and description +passed to --_roledef-<LANG>.<KIND> option are used in the output like:

+
$ ctags --langdef=FOO --kinddef-FOO=m,module,modules \
+                        --_roledef-FOO.m='imported,imported module' --list-roles=FOO
+#KIND(L/N) NAME     ENABLED DESCRIPTION
+m/module   imported on      imported module
+
+
+

If specifying _role regex flag multiple times with different roles, you can +assign multiple roles to a reference tag. See following input of C language

+
x  = 0;
+i += 1;
+
+
+

An ultra fine grained C parser may capture the variable x with +lvalue role and the variable i with lvalue and incremented +roles.

+

You can implement such roles by extending the built-in C parser:

+
# c-extra.ctags
+--_roledef-C.v=lvalue,locator values
+--_roledef-C.v=incremented,incremented with ++ operator
+--regex-C=/([a-zA-Z_][a-zA-Z_0-9]*) *=/\1/v/{_role=lvalue}
+--regex-C=/([a-zA-Z_][a-zA-Z_0-9]*) *\+=/\1/v/{_role=lvalue}{_role=incremented}
+
+
+
$ ctags with --options=c-extra.ctags --extras=+r --fields=+r
+i       input.c /^i += 1;$/;"   v       roles:lvalue,incremented
+x       input.c /^x = 0;$/;"    v       roles:lvalue
+
+
+
+
+
+

Scope tracking in a regex parser

+

About the {scope=..} flag itself for scope tracking, see “FLAGS FOR +--regex-<LANG> OPTION” section of ctags-optlib(7).

+

Example 1:

+
# in /tmp/input.foo
+class foo:
+def bar(baz):
+        print(baz)
+class goo:
+def gar(gaz):
+        print(gaz)
+
+
+
# in /tmp/foo.ctags:
+--langdef=Foo
+--map-Foo=+.foo
+--kinddef-Foo=c,class,classes
+--kinddef-Foo=d,definition,definitions
+
+--regex-Foo=/^class[[:blank:]]+([[:alpha:]]+):/\1/c/{scope=set}
+--regex-Foo=/^[[:blank:]]+def[[:blank:]]+([[:alpha:]]+).*:/\1/d/{scope=ref}
+
+
+
$ ctags --options=/tmp/foo.ctags -o - /tmp/input.foo
+bar     /tmp/input.foo  /^    def bar(baz):$/;" d       class:foo
+foo     /tmp/input.foo  /^class foo:$/;"        c
+gar     /tmp/input.foo  /^    def gar(gaz):$/;" d       class:goo
+goo     /tmp/input.foo  /^class goo:$/;"        c
+
+
+

Example 2:

+
// in /tmp/input.pp
+class foo {
+        int bar;
+}
+
+
+
# in /tmp/pp.ctags:
+--langdef=pp
+--map-pp=+.pp
+--kinddef-pp=c,class,classes
+--kinddef-pp=v,variable,variables
+
+--regex-pp=/^[[:blank:]]*\}//{scope=pop}{exclusive}
+--regex-pp=/^class[[:blank:]]*([[:alnum:]]+)[[[:blank:]]]*\{/\1/c/{scope=push}
+--regex-pp=/^[[:blank:]]*int[[:blank:]]*([[:alnum:]]+)/\1/v/{scope=ref}
+
+
+
$ ctags --options=/tmp/pp.ctags -o - /tmp/input.pp
+bar     /tmp/input.pp   /^    include bar$/;"   v       class:foo
+foo     /tmp/input.pp   /^class foo {$/;"       c
+
+
+

NOTE: This flag doesn’t work well with --mline-regex-<LANG>=.

+
+
+
+

Overriding the letter for file kind

+

One of the built-in tag kinds in Universal Ctags is the F file kind. +Overriding the letter for file kind is not allowed in Universal Ctags.

+
+

Warning

+

Don’t use F as a kind letter in your parser. (See issue #317 on github)

+
+
+
+

Generating fully qualified tags automatically from scope information

+

If scope fields are filled properly with {scope=...} regex flags, +you can use the field values for generating fully qualified tags. +About the {scope=..} flag itself, see “FLAGS FOR --regex-<LANG> +OPTION” section of ctags-optlib(7).

+

Specify {_autoFQTag} to the end of --langdef=<LANG> option like +--langdef=Foo{_autoFQTag} to make ctags generate fully qualified +tags automatically.

+

.’ is the (ctags global) default separator combining names into a +fully qualified tag. You can customize separators with +--_scopesep-<LANG>=... option.

+

input.foo:

+
class X
+   var y
+end
+
+
+

foo.ctags:

+
--langdef=foo{_autoFQTag}
+--map-foo=+.foo
+--kinddef-foo=c,class,classes
+--kinddef-foo=v,var,variables
+--regex-foo=/class ([A-Z]*)/\1/c/{scope=push}
+--regex-foo=/end///{placeholder}{scope=pop}
+--regex-foo=/[ \t]*var ([a-z]*)/\1/v/{scope=ref}
+
+
+

Output:

+
$ u-ctags --quiet --options=./foo.ctags -o - input.foo
+X       input.foo       /^class X$/;"   c
+y       input.foo       /^      var y$/;"       v       class:X
+
+$ u-ctags --quiet --options=./foo.ctags --extras=+q -o - input.foo
+X       input.foo       /^class X$/;"   c
+X.y     input.foo       /^      var y$/;"       v       class:X
+y       input.foo       /^      var y$/;"       v       class:X
+
+
+

X.y is printed as a fully qualified tag when --extras=+q is given.

+
+

Customizing scope separators

+

Use --_scopesep-<LANG>=[<parent-kindLetter>]/<child-kindLetter>:<sep> +option for customizing if the language uses {_autoFQTag}.

+

parent-kindLetter

+
+

The kind letter for a tag of outer-scope.

+

You can use ‘*’ for specifying as wildcards that means +any kinds for a tag of outer-scope.

+

If you omit parent-kindLetter, the separator is used as +a prefix for tags having the kind specified with child-kindLetter. +This prefix can be used to refer to global namespace or similar concepts if the +language has one.

+
+

child-kindLetter

+
+

The kind letter for a tag of inner-scope.

+

You can use ‘*’ for specifying as wildcards that means +any kinds for a tag of inner-scope.

+
+

sep

+
+

In a qualified tag, if the outer-scope has kind and parent-kindLetter +the inner-scope has child-kindLetter, then sep is instead in +between the scope names in the generated tags file.

+
+

specifying ‘*’ as both parent-kindLetter and child-kindLetter +sets sep as the language default separator. It is used as fallback.

+

Specifying ‘*’ as child-kindLetter and omitting parent-kindLetter +sets sep as the language default prefix. It is used as fallback.

+

NOTE: There is no ctags global default prefix.

+

NOTE: _scopesep-<LANG>=... option affects only a parser that +enables _autoFQTag. A parser building full qualified tags +manually ignores the option.

+

Let’s see an example. +The input file is written in Tcl. Tcl parser is not an optlib +parser. However, it uses the _autoFQTag feature internally. +Therefore, _scopesep-Tcl= option works well. Tcl parser +defines two kinds n (namespace) and p (procedure).

+

By default, Tcl parser uses :: as scope separator. The parser also +uses :: as root prefix.

+
namespace eval N {
+        namespace eval M {
+                proc pr0 {s} {
+                        puts $s
+                }
+        }
+}
+
+proc pr1 {s} {
+        puts $s
+}
+
+
+

M is defined under the scope of N. pr0 is defined under the scope +of M. N and pr1 are at top level (so they are candidates to be added +prefixes). M and N are language objects with n (namespace) kind. +pr0 and pr1 are language objects with p (procedure) kind.

+
$ ctags -o - --extras=+q input.tcl
+::N     input.tcl       /^namespace eval N {$/;"        n
+::N::M  input.tcl       /^      namespace eval M {$/;"  n       namespace:::N
+::N::M::pr0     input.tcl       /^              proc pr0 {s} {$/;"      p       namespace:::N::M
+::pr1   input.tcl       /^proc pr1 {s} {$/;"    p
+M       input.tcl       /^      namespace eval M {$/;"  n       namespace:::N
+N       input.tcl       /^namespace eval N {$/;"        n
+pr0     input.tcl       /^              proc pr0 {s} {$/;"      p       namespace:::N::M
+pr1     input.tcl       /^proc pr1 {s} {$/;"    p
+
+
+

Let’s change the default separator to ->:

+
$ ctags -o - --extras=+q --_scopesep-Tcl='*/*:->' input.tcl
+::N     input.tcl       /^namespace eval N {$/;"        n
+::N->M  input.tcl       /^      namespace eval M {$/;"  n       namespace:::N
+::N->M->pr0     input.tcl       /^              proc pr0 {s} {$/;"      p       namespace:::N->M
+::pr1   input.tcl       /^proc pr1 {s} {$/;"    p
+M       input.tcl       /^      namespace eval M {$/;"  n       namespace:::N
+N       input.tcl       /^namespace eval N {$/;"        n
+pr0     input.tcl       /^              proc pr0 {s} {$/;"      p       namespace:::N->M
+pr1     input.tcl       /^proc pr1 {s} {$/;"    p
+
+
+

Let’s define ‘^’ as default prefix:

+
$ ctags -o - --extras=+q --_scopesep-Tcl='*/*:->' --_scopesep-Tcl='/*:^' input.tcl
+M       input.tcl       /^      namespace eval M {$/;"  n       namespace:^N
+N       input.tcl       /^namespace eval N {$/;"        n
+^N      input.tcl       /^namespace eval N {$/;"        n
+^N->M   input.tcl       /^      namespace eval M {$/;"  n       namespace:^N
+^N->M->pr0      input.tcl       /^              proc pr0 {s} {$/;"      p       namespace:^N->M
+^pr1    input.tcl       /^proc pr1 {s} {$/;"    p
+pr0     input.tcl       /^              proc pr0 {s} {$/;"      p       namespace:^N->M
+pr1     input.tcl       /^proc pr1 {s} {$/;"    p
+
+
+

Let’s override the specification of separator for combining a +namespace and a procedure with ‘+’: (About the separator for +combining a namespace and another namespace, ctags uses the default separator.)

+
$ ctags -o - --extras=+q --_scopesep-Tcl='*/*:->' --_scopesep-Tcl='/*:^' --_scopesep-Tcl='n/p:+' input.tcl
+M       input.tcl       /^      namespace eval M {$/;"  n       namespace:^N
+N       input.tcl       /^namespace eval N {$/;"        n
+^N      input.tcl       /^namespace eval N {$/;"        n
+^N->M   input.tcl       /^      namespace eval M {$/;"  n       namespace:^N
+^N->M+pr0       input.tcl       /^              proc pr0 {s} {$/;"      p       namespace:^N->M
+^pr1    input.tcl       /^proc pr1 {s} {$/;"    p
+pr0     input.tcl       /^              proc pr0 {s} {$/;"      p       namespace:^N->M
+pr1     input.tcl       /^proc pr1 {s} {$/;"    p
+
+
+

Let’s override the definition of prefix for a namespace with ‘@’: +(About the prefix for procedures, ctags uses the default prefix.)

+
$ ctags -o - --extras=+q --_scopesep-Tcl='*/*:->' --_scopesep-Tcl='/*:^' --_scopesep-Tcl='n/p:+' --_scopesep-Tcl='/n:@' input.tcl
+@N      input.tcl       /^namespace eval N {$/;"        n
+@N->M   input.tcl       /^      namespace eval M {$/;"  n       namespace:@N
+@N->M+pr0       input.tcl       /^              proc pr0 {s} {$/;"      p       namespace:@N->M
+M       input.tcl       /^      namespace eval M {$/;"  n       namespace:@N
+N       input.tcl       /^namespace eval N {$/;"        n
+^pr1    input.tcl       /^proc pr1 {s} {$/;"    p
+pr0     input.tcl       /^              proc pr0 {s} {$/;"      p       namespace:@N->M
+pr1     input.tcl       /^proc pr1 {s} {$/;"    p
+
+
+
+
+
+

Multi-line pattern match

+

We often need to scan multiple lines to generate a tag, whether due to +needing contextual information to decide whether to tag or not, or to +constrain generating tags to only certain cases, or to grab multiple +substrings to generate the tag name.

+

Universal Ctags has two ways to accomplish this: multi-line regex options, +and an experimental multi-table regex options described later.

+

The newly introduced --mline-regex-<LANG> is similar to --regex-<LANG> +except the pattern is applied to the whole file’s contents, not line by line.

+

This example is based on an issue #219 posted by +@andreicristianpetcu:

+
// in input.java:
+
+@Subscribe
+public void catchEvent(SomeEvent e)
+{
+   return;
+}
+
+@Subscribe
+public void
+recover(Exception e)
+{
+    return;
+}
+
+
+

The above java code is similar to the Java Spring +framework. The @Subscribe annotation is a keyword for the framework, and the +developer would like to have a tag generated for each method annotated with +@Subscribe, using the name of the method followed by a dash followed by the +type of the argument. For example the developer wants the tag name +Event-SomeEvent generated for the first method shown above.

+

To accomplish this, the developer creates a spring.ctags file with +the following:

+
# in spring.ctags:
+--langdef=javaspring
+--map-javaspring=+.java
+--mline-regex-javaspring=/@Subscribe([[:space:]])*([a-z ]+)[[:space:]]*([a-zA-Z]*)\(([a-zA-Z]*)/\3-\4/s,subscription/{mgroup=3}
+--fields=+ln
+
+
+

And now using spring.ctags the tag file has this:

+
$ ctags -o - --options=./spring.ctags input.java
+Event-SomeEvent input.java      /^public void catchEvent(SomeEvent e)$/;"       s       line:2  language:javaspring
+recover-Exception       input.java      /^    recover(Exception e)$/;"  s       line:10 language:javaspring
+
+
+
+

Multiline pattern flags

+
+

Note

+

These flags also apply to the experimental --_mtable-regex-<LANG> +option described later.

+
+

{mgroup=N}

+
+

This flag indicates the pattern should be applied to the whole file +contents, not line by line. N is the number of a capture group in the +pattern, which is used to record the line number location of the tag. In the +above example 3 is specified. The start position of the regex capture +group 3, relative to the whole file is used.

+
+
+

Warning

+

You must add an {mgroup=N} flag to the multi-line +--mline-regex-<LANG> option, even if the N is 0 (meaning the +start position of the whole regex pattern). You do not need to add it for +the multi-table --_mtable-regex-<LANG>.

+
+

{_advanceTo=N[start|end]}

+
+

A regex pattern is applied to whole file’s contents iteratively. This long +flag specifies from where the pattern should be applied in the next +iteration for regex matching. When a pattern matches, the next pattern +matching starts from the start or end of capture group N. By default it +advances to the end of the whole match (i.e., {_advanceTo=0end} is +the default).

+

Let’s think about following input

+
def def abc
+
+
+

Consider two sets of options, foo.ctags and bar.ctags.

+
# foo.ctags:
+--langdef=foo
+--langmap=foo:.foo
+--kinddef-foo=a,something,something
+--mline-regex-foo=/def *([a-z]+)/\1/a/{mgroup=1}
+
+
+
# bar.ctags:
+--langdef=bar
+--langmap=bar:.bar
+--kinddef-bar=a,something,something
+--mline-regex-bar=/def *([a-z]+)/\1/a/{mgroup=1}{_advanceTo=1start}
+
+
+

foo.ctags emits following tags output:

+
def  input.foo       /^def def abc$/;"       a
+
+
+

bar.ctags emits following tags output:

+
def  input-0.bar     /^def def abc$/;"       a
+abc  input-0.bar     /^def def abc$/;"       a
+
+
+

_advanceTo=1start is specified in bar.ctags. +This allows ctags to capture abc.

+

At the first iteration, the patterns of both +foo.ctags and bar.ctags match as follows

+
0   1       (start)
+v   v
+def def abc
+       ^
+       0,1  (end)
+
+
+

def at the group 1 is captured as a tag in +both languages. At the next iteration, the positions +where the pattern matching is applied to are not the +same in the languages.

+

foo.ctags

+
       0end (default)
+       v
+def def abc
+
+
+

bar.ctags

+
    1start (as specified in _advanceTo long flag)
+    v
+def def abc
+
+
+

This difference of positions makes the difference of tags output.

+

A more relevant use-case is when {_advanceTo=N[start|end]} is used in +the experimental --_mtable-regex-<LANG>, to “advance” back to the +beginning of a match, so that one can generate multiple tags for the same +input line(s).

+
+
+

Note

+

This flag doesn’t work well with scope related flags and exclusive flags.

+
+
+
+
+

Advanced pattern matching with multiple regex tables

+
+

Note

+

This is a highly experimental feature. This will not go into +the man page of 6.0. But let’s be honest, it’s the most exciting feature!

+
+

In some cases, the --regex-<LANG> and --mline-regex-<LANG> options are not +sufficient to generate the tags for a particular language. Some of the common +reasons for this are:

+
    +
  • To ignore commented lines or sections for the language file, so that +tags aren’t generated for symbols that are within the comments.

  • +
  • To enter and exit scope, and use it for tagging based on contextual +state or with end-scope markers that are difficult to match to their +associated scope entry point.

  • +
  • To support nested scopes.

  • +
  • To change the pattern searched for, or the resultant tag for the same +pattern, based on scoping or contextual location.

  • +
  • To break up an overly complicated --mline-regex-<LANG> pattern into +separate regex patterns, for performance or readability reasons.

  • +
+

To help handle such things, Universal Ctags has been enhanced with multi-table +regex matching. The feature is inspired by lex, the fast lexical analyzer +generator, which is a popular tool on Unix environments for writing parsers, and +RegexLexer of Pygments. +Knowledge about them will help you understand the new options.

+

The new options are:

+
+
--_tabledef-<LANG>

Declares a new regex matching table of a given name for the language, +as described in “Declaring a new regex table”.

+
+
--_mtable-regex-<LANG>

Adds a regex pattern and associated tag generation information and flags, to +the given table, as described in “Adding a regex to a regex table”.

+
+
--_mtable-extend-<LANG>

Includes a previously-defined regex table to the named one.

+
+
+

The above will be discussed in more detail shortly.

+

First, let’s explain the feature with an example. Consider an +imaginary language X has a similar syntax as JavaScript: var is +used as defining variable(s), and “/* ... */” is used for block +comments.

+

Here is our input, input.x:

+
/* BLOCK COMMENT
+var dont_capture_me;
+*/
+var a /* ANOTHER BLOCK COMMENT */, b;
+
+
+

We want ctags to capture a and b - but it is difficult to write a parser +that will ignore dont_capture_me in the comment with a classical regex +parser defined with --regex-<LANG> or --mline-regex-<LANG>, because of +the block comments.

+

The --regex-<LANG> option only works on one line at a time, so can not know +dont_capture_me is within comments. The --mline-regex-<LANG> could +do it in theory, but due to the greedy nature of the regex engine it is +impractical and potentially inefficient to do so, given that there could be +multiple block comments in the file, with ‘*’ inside them, etc.

+

A parser written with multi-table regex, on the other hand, can capture only +a and b safely. But it is more complicated to understand.

+

Here is the 1st version of X.ctags:

+
--langdef=X
+--map-X=.x
+--kinddef-X=v,var,variables
+
+
+

Not so interesting. It doesn’t really do anything yet. It just creates a new +language named X, for files ending with a .x suffix, and defines a +new tag for variable kinds.

+

When writing a multi-table parser, you have to think about the necessary states +of parsing. For the parser of language X, we need the following states:

+
    +
  • toplevel (initial state)

  • +
  • comment (inside comment)

  • +
  • vars (var statements)

  • +
+
+

Declaring a new regex table

+

Before adding regular expressions, you have to declare tables for each state +with the --_tabledef-<LANG>=<TABLE> option.

+

Here is the 2nd version of X.ctags doing so:

+
--langdef=X
+--map-X=.x
+--kinddef-X=v,var,variables
+
+--_tabledef-X=toplevel
+--_tabledef-X=comment
+--_tabledef-X=vars
+
+
+

For table names, only characters in the range [0-9a-zA-Z_] are acceptable.

+

For a given language, for each file’s input the ctags multi-table parser begins +with the first declared table. For X.ctags, toplevel is the one. +The other tables are only ever entered/checked if another table specified to do +so, starting with the first table. In other words, if the first declared table +does not find a match for the current input, and does not specify to go to +another table, the other tables for that language won’t be used. The flags to go +to another table are {tenter}, {tleave}, and {tjump}, as described +later.

+
+
+

Adding a regex to a regex table

+

The new option to add a regex to a declared table is --_mtable-regex-<LANG>, +and it follows this form:

+
--_mtable-regex-<LANG>=<TABLE>/<PATTERN>/<NAME>/[<KIND>]/LONGFLAGS
+
+
+

The parameters for --_mtable-regex-<LANG> look complicated. However, +<PATTERN>, <NAME>, and <KIND> are the same as the parameters of the +--regex-<LANG> and --mline-regex-<LANG> options. <TABLE> is simply +the name of a table previously declared with the --_tabledef-<LANG> option.

+

A regex pattern added to a parser with --_mtable-regex-<LANG> is matched +against the input at the current byte position, not line. Even if you do not +specify the ‘^’ anchor at the start of the pattern, ctags adds ‘^’ to +the pattern automatically. Unlike the --regex-<LANG> and +--mline-regex-<LANG> options, a ‘^’ anchor does not mean “beginning of +line” in --_mtable-regex-<LANG>; instead it means the beginning of the +input string (i.e., the current byte position).

+

The LONGFLAGS include the already discussed flags for --regex-<LANG> and +--mline-regex-<LANG>: {scope=...}, {mgroup=N}, {_advanceTo=N}, +{basic}, {extend}, and {icase}. The {exclusive} flag does not +make sense for multi-table regex.

+

In addition, several new flags are introduced exclusively for multi-table +regex use:

+
+
{tenter}

Push the current table on the stack, and enter another table.

+
+
{tleave}

Leave the current table, pop the stack, and go to the table that was +just popped from the stack.

+
+
{tjump}

Jump to another table, without affecting the stack.

+
+
{treset}

Clear the stack, and go to another table.

+
+
{tquit}

Clear the stack, and stop processing the current input file for this +language.

+
+
+

To explain the above new flags, we’ll continue using our example in the +next section.

+
+
+

Skipping block comments

+

Let’s continue with our example. Here is the 3rd version of X.ctags:

+
 1--langdef=X
+ 2--map-X=.x
+ 3--kinddef-X=v,var,variables
+ 4
+ 5--_tabledef-X=toplevel
+ 6--_tabledef-X=comment
+ 7--_tabledef-X=vars
+ 8
+ 9--_mtable-regex-X=toplevel/\/\*//{tenter=comment}
+10--_mtable-regex-X=toplevel/.//
+11
+12--_mtable-regex-X=comment/\*\///{tleave}
+13--_mtable-regex-X=comment/.//
+
+
+

Four --_mtable-regex-X lines are added for skipping the block comments. Let’s +discuss them one by one.

+

For each new file it scans, ctags always chooses the first pattern of the +first table of the parser. Even if it’s an empty table, ctags will only try +the first declared table. (in such a case it would immediately fail to match +anything, and thus stop processing the input file and effectively do nothing)

+

The first declared table (toplevel) has the following regex added to +it first:

+
9--_mtable-regex-X=toplevel/\/\*//{tenter=comment}
+
+
+

A pattern of \/\* is added to the toplevel table, to match the +beginning of a block comment. A backslash character is used in front of the +leading ‘/’ to escape the separation character ‘/’ that separates the fields +of --_mtable-regex-<LANG>. Another backslash inside the pattern is used +before the asterisk ‘*’, to make it a literal asterisk character in regex.

+

The last // means ctags should not tag something matching this pattern. +In --regex-<LANG> you never use // because it would be pointless to +match something and not tag it using and single-line --regex-<LANG>; in +multi-line --mline-regex-<LANG> you rarely see it, because it would rarely +be useful. But in multi-table regex it’s quite common, since you frequently +want to transition from one state to another (i.e., tenter or tjump +from one table to another).

+

The long flag added to our first regex of our first table is tenter, which +is a long flag for switching the table and pushing on the stack. {tenter=comment} +means “switch the table from toplevel to comment”.

+

So given the input file input.x shown earlier, ctags will begin at +the toplevel table and try to match the first regex. It will succeed, and +thus push on the stack and go to the comment table.

+

It will begin at the top of the comment table (it always begins at the top +of a given table), and try each regex line in sequence until it finds a match. +If it fails to find a match, it will pop the stack and go to the table that was +just popped from the stack, and begin trying to match at the top of that table. +If it continues failing to find a match, and ultimately reaches the end of the +stack, it will stop processing for this file. For the next input file, it will +begin again from the top of the first declared table.

+

Getting back to our example, the top of the comment table has this regex:

+
12--_mtable-regex-X=comment/\*\///{tleave}
+
+
+

Similar to the previous toplevel table pattern, this one for \*\/ uses +a backslash to escape the separator ‘/’, as well as one before the ‘*’ to +make it a literal asterisk in regex. So what it’s looking for, from a simple +string perspective, is the sequence */. Note that this means even though +you see three backslashes /// at the end, the first one is escaped and used +for the pattern itself, and the --_mtable-regex-X only has // to +separate the regex pattern from the long flags, instead of the usual ///. +Thus it’s using the shorthand form of the --_mtable-regex-X option. +It could instead have been:

+
--_mtable-regex-X=comment/\*\////{tleave}
+
+
+

The above would have worked exactly the same.

+

Getting back to our example, remember we’re looking at the input.x +file, currently using the comment table, and trying to match the first +regex of that table, shown above, at the following location:

+
   ,ctags is trying to match starting here
+  v
+/* BLOCK COMMENT
+var dont_capture_me;
+*/
+var a /* ANOTHER BLOCK COMMENT */, b;
+
+
+

The pattern doesn’t match for the position just after /*, because that +position is a space character. So ctags tries the next pattern in the same +table:

+
13--_mtable-regex-X=comment/.//
+
+
+

This pattern matches any any one character including newline; the current +position moves one character forward. Now the character at the current position is +‘B’. The first pattern of the table */ still does not match with the input. So +ctags uses next pattern again. When the current position moves to the */ +of the 3rd line of input.x, it will finally match this:

+
12--_mtable-regex-X=comment/\*\///{tleave}
+
+
+

In this pattern, the long flag {tleave} is specified. This triggers table +switching again. {tleave} makes ctags switch the table back to the last +table used before doing {tenter}. In this case, toplevel is the table. +ctags manages a stack where references to tables are put. {tenter} pushes +the current table to the stack. {tleave} pops the table at the top of the +stack and chooses it.

+

So now ctags is back to the toplevel table, and tries the first regex +of that table, which was this:

+
9--_mtable-regex-X=toplevel/\/\*//{tenter=comment}
+
+
+

It tries to match that against its current position, which is now the +newline on line 3, between the */ and the word var:

+
/* BLOCK COMMENT
+var dont_capture_me;
+*/ <--- ctags is now at this newline (/n) character
+var a /* ANOTHER BLOCK COMMENT */, b;
+
+
+

The first regex of the toplevel table does not match a newline, so it tries +the second regex:

+
13--_mtable-regex-X=toplevel/.//
+
+
+

This matches a newline successfully, but has no actions to perform. So ctags +moves one character forward (the newline it just matched), and goes back to the +top of the toplevel table, and tries the first regex again. Eventually we’ll +reach the beginning of the second block comment, and do the same things as before.

+

When ctags finally reaches the end of the file (the position after b;), +it will not be able to match either the first or second regex of the +toplevel table, and quit processing the input file.

+

So far, we’ve successfully skipped over block comments for our new X +language, but haven’t generated any tags. The point of ctags is to generate +tags, not just keep your computer warm. So now let’s move onto actually tagging +variables…

+
+
+

Capturing variables in a sequence

+

Here is the 4th version of X.ctags:

+
 1--langdef=X
+ 2--map-X=.x
+ 3--kinddef-X=v,var,variables
+ 4
+ 5--_tabledef-X=toplevel
+ 6--_tabledef-X=comment
+ 7--_tabledef-X=vars
+ 8
+ 9--_mtable-regex-X=toplevel/\/\*//{tenter=comment}
+10--_mtable-regex-X=toplevel/var[ \n\t]//{tenter=vars}
+11--_mtable-regex-X=toplevel/.//
+12
+13--_mtable-regex-X=comment/\*\///{tleave}
+14--_mtable-regex-X=comment/.//
+15
+16--_mtable-regex-X=vars/;//{tleave}
+17--_mtable-regex-X=vars/\/\*//{tenter=comment}
+18--_mtable-regex-X=vars/([a-zA-Z][a-zA-Z0-9]*)/\1/v/
+19--_mtable-regex-X=vars/.//
+
+
+

One pattern in toplevel was added, and a new table vars with four +patterns was also added.

+

The new regex in toplevel is this:

+
10--_mtable-regex-X=toplevel/var[ \n\t]//{tenter=vars}
+
+
+

The purpose of this being in toplevel is to switch to the vars table when +the keyword var is found in the input stream. We need to switch states +(i.e., tables) because we can’t simply capture the variables a and b +with a single regex pattern in the toplevel table, because there might be +block comments inside the var statement (as there are in our +input.x), and we also need to create two tags: one for a and one +for b, even though the word var only appears once. In other words, we +need to “remember” that we saw the keyword var, when we later encounter the +names a and b, so that we know to tag each of them; and saving that +“in-variable-statement” state is accomplished by switching tables to the +vars table.

+

The first regex in our new vars table is:

+
16--_mtable-regex-X=vars/;//{tleave}
+
+
+

This pattern is used to match a single semi-colon ‘;’, and if it matches +pop back to the toplevel table using the {tleave} long flag. We +didn’t have to make this the first regex pattern, because it doesn’t overlap +with any of the other ones other than the /.// last one (which must be +last for this example to work).

+

The second regex in our vars table is:

+
17--_mtable-regex-X=vars/\/\*//{tenter=comment}
+
+
+

We need this because block comments can be in variable definitions:

+
var a /* ANOTHER BLOCK COMMENT */, b;
+
+
+

So to skip block comments in such a position, the pattern \/\* is used just +like it was used in the toplevel table: to find the literal /* beginning +of the block comment and enter the comment table. Because we’re using +{tenter} and {tleave} to push/pop from a stack of tables, we can +use the same comment table for both toplevel and vars to go to, +because ctags will remember the previous table and {tleave} will +pop back to the right one.

+

The third regex in our vars table is:

+
18--_mtable-regex-X=vars/([a-zA-Z][a-zA-Z0-9]*)/\1/v/
+
+
+

This is nothing special, but is the one that actually tags something: it +captures the variable name and uses it for generating a variable (shorthand +v) tag kind.

+

The last regex in the vars table we’ve seen before:

+
19--_mtable-regex-X=vars/.//
+
+
+

This makes ctags ignore any other characters, such as whitespace or the +comma ‘,’.

+
+
+

Running our example

+
$ cat input.x
+/* BLOCK COMMENT
+var dont_capture_me;
+*/
+var a /* ANOTHER BLOCK COMMENT */, b;
+
+$ u-ctags -o - --fields=+n --options=X.ctags input.x
+u-ctags -o - --fields=+n --options=X.ctags input.x
+a       input.x /^var a \/* ANOTHER BLOCK COMMENT *\/, b;$/;"   v       line:4
+b       input.x /^var a \/* ANOTHER BLOCK COMMENT *\/, b;$/;"   v       line:4
+
+
+

It works!

+

You can find additional examples of multi-table regex in our github repo, under +the optlib directory. For example puppetManifest.ctags is a serious +example. It is the primary parser for testing multi-table regex parsers, and +used in the actual ctags program for parsing puppet manifest files.

+
+
+
+

Scheduling a guest parser with _guest regex flag

+

With _guest regex flag, you can run a parser (a guest parser) on an +area of the current input file. +See “Guest parser: Applying a parser to specified areas of input file” about the concept of the guest parser.

+

The _guest regex flag specifies a guest spec, and attaches it to +the associated regex pattern.

+

A guest spec has three fields: <PARSER>, <START> of area, and <END> of area. +The _guest regex flag has following forms:

+
{_guest=<PARSER>,<START>,<END>}
+
+
+

ctags maintains a data called guest request during parsing. A +guest request also has three fields: parser, start of area, and +end of area.

+

You, a parser developer, have to fill the fields of guest specs. +ctags inquiries the guest spec when matching the regex pattern +associated with it, tries to fill the fields of the guest request, +and runs a guest parser when all the fields of the guest request are +filled.

+

If you use Multi-line pattern match to define a host parser, +you must specify all the fields of guest request.

+

On the other hand if you don’t use Multi-line pattern match to define a host parser, +ctags can fill fields of guest request incrementally; more than +one guest specs are used to fill the fields. In other words, you can +make some of the fields of a guest spec empty.

+
+

The <PARSER> field of _guest regex flag

+

For <PARSER>, you can specify one of the following items:

+

a name of a parser

+
+

If you know the guest parser you want to run before parsing +the input file, specify the name of the parser.

+

An example of running C parser as a guest parser:

+
{_guest=C,...
+
+
+
+

the group number of a regex pattern started from ‘\’ (backslash)

+
+

If a parser name appears in an input file, write a regex pattern +to capture the name. Specify the group number where the name is +stored to the parser. In such case, use ‘\’ as the prefix for +the number.

+

Let’s see an example. Git Flavor Markdown (GFM) is a language for +documentation. It provides a notation for quoting a snippet of +program code; the language treats the area started from ~~~ to +~~~ as a snippet. You can specify a programming language of +the snippet with starting the area with +~~~<THE_NAME_OF_LANGUAGE>, like ~~~C or ~~~Java.

+

To run a guest parser on the area, you have to capture the +<THE_NAME_OF_LANGUAGE> with a regex pattern:

+
--_mtable-regex-Markdown=main/~~~([a-zA-Z0-9][-#+a-zA-Z0-9]*)[\n]//{_guest=\1,0end,}
+
+
+

The pattern captures the language name in the input file with the +regex group 1, and specify it to <PARSER>:

+
{guest=\1,...
+
+
+
+

the group number of a regex pattern started from ‘*’ (asterisk)

+
+

If a file name implying a programming language appears in an input +file, capture the file name with the regex pattern where the guest +spec attaches to. ctags tries to find a proper parser for the +file name by inquiring the langmap.

+

Use ‘*’ as the prefix to the number for specifying the group of +the regex pattern that captures the file name.

+

Let’s see an example. Consider you have a shell script that emits +a program code instantiated from one of the templates. Here documents +are used to represent the templates like:

+
i=...
+cat > foo.c <<EOF
+        int main (void) { return $i; }
+EOF
+
+cat > foo.el <<EOF
+        (defun foo () (1+ $i))
+EOF
+
+
+

To run guest parsers for the here document areas, the shell +script parser of ctags must choose the parsers from the file +names (foo.c and foo.el):

+
--regex-sh=/cat > ([a-z.]+) <<EOF//{_guest=*1,0end,}
+
+
+

The pattern captures the file name in the input file with the +regex group 1, and specify it to <PARSER>:

+
{_guest=*1,...
+
+
+
+
+
+

The <START> and <END> fields of _guest regex flag

+

The <START> and <END> fields specify the area the <PARSER> parses. <START> +specifies the start of the area. <END> specifies the end of the area.

+

The forms of the two fields are the same: a regex group number +followed by start or end. e.g. 3start, 0end. The suffixes, +start and end, represents one of two boundaries of the group.

+

Let’s see an example:

+
{_guest=C,2end,3start}
+
+
+

This guest regex flag means running C parser on the area between +2end and 3start. 2end means the area starts from the end of +matching of the 2nd regex group associated with the flag. 3start +means the area ends at the beginning of matching of the 3rd regex +group associated with the flag.

+

Let’s more realistic example. +Here is an optlib file for an imaginary language single:

+
--langdef=single
+--map-single=.single
+--regex-single=/^(BEGIN_C<).*(>END_C)$//{_guest=C,1end,2start}
+
+
+

This parser can run C parser and extract main function from the +following input file:

+
BEGIN_C<int main (int argc, char **argv) { return 0; }>END_C
+        ^                                             ^
+         `- "1end" points here.                       |
+                               "2start" points here. -+
+
+
+
+
+
+

Defining a subparser

+
+

Basic

+

About the concept of subparser, see “Subparser: Tagging definitions of higher (upper) level language”.

+

--langdef=<LANG> option is extended as +--langdef=<LANG>[{base=<LANG>}[{shared|dedicated|bidirectional}]][{_autoFQTag}] to define +a subparser for a specified base parser. Combining with --kinddef-<LANG> +and --regex-<KIND> options, you can extend an existing parser +without risk of kind confliction.

+

Let’s see an example.

+

input.c

+
static int set_one_prio(struct task_struct *p, int niceval, int error)
+{
+}
+
+SYSCALL_DEFINE3(setpriority, int, which, int, who, int, niceval)
+{
+        ...;
+}
+
+
+
$ ctags  -x --_xformat="%20N %10K %10l"  -o - input.c
+        set_one_prio   function          C
+     SYSCALL_DEFINE3   function          C
+
+
+

C parser doesn’t understand that SYSCALL_DEFINE3 is a macro for defining an +entry point for a system.

+

Let’s define linux subparser which using C parser as a base parser (linux.ctags):

+
--langdef=linux{base=C}
+--kinddef-linux=s,syscall,system calls
+--regex-linux=/SYSCALL_DEFINE[0-9]\(([^, )]+)[\),]*/\1/s/
+
+
+

The output is change as follows with linux parser:

+
$ ctags --options=./linux.ctags -x --_xformat="%20N %10K %10l"  -o - input.c
+         setpriority    syscall      linux
+        set_one_prio   function          C
+     SYSCALL_DEFINE3   function          C
+
+
+

setpriority is recognized as a syscall of linux.

+

Using only --regex-C=... you can capture setpriority. +However, there were concerns about kind confliction; when introducing +a new kind with --regex-C=..., you cannot use a letter and name already +used in C parser and --regex-C=... options specified in the other places.

+

You can use a newly defined subparser as a new namespace of kinds. +In addition you can enable/disable with the subparser usable +--languages=[+|-] option:

+
+
+

Direction flags

+

As explained in “Direction flags” in +“Running multiple parsers on an input file”, you can choose direction(s) how a base parser and a +guest parser work together with direction flags.

+

The following examples are taken from #1409 submitted by @sgraham on +github Universal Ctags repository.

+

input.cc and input.mojom are input files, and have the same +contents:

+
ABC();
+int main(void)
+{
+}
+
+
+

C++ parser can capture main as a function. Mojom subparser defined in the +later runs on C++ parser and is for capturing ABC.

+
+

shared combination

+

{shared} is specified, for input.cc, both tags capture by C++ parser +and mojom parser are recorded to tags file. For input.mojom, only +tags captured by mojom parser are recorded to tags file.

+

mojom-shared.ctags:

+
--langdef=mojom{base=C++}{shared}
+--map-mojom=+.mojom
+--kinddef-mojom=f,function,functions
+--regex-mojom=/^[ ]+([a-zA-Z]+)\(/\1/f/
+
+
+
$ ctags --options=mojom-shared.ctags --fields=+l -o - input.cc
+ABC     input.cc        /^ ABC();$/;"   f       language:mojom
+main    input.cc        /^int main(void)$/;"    f       language:C++    typeref:typename:int
+
+
+
$ ctags --options=mojom-shared.ctags --fields=+l -o - input.mojom
+ABC     input.mojom     /^ ABC();$/;"   f       language:mojom
+
+
+

Mojom parser uses C++ parser internally but tags captured by C++ parser are +dropped in the output.

+
+
+

dedicated combination

+

{dedicated} is specified, for input.cc, only tags capture by C++ +parser are recorded to tags file. For input.mojom, both tags capture +by C++ parser and mojom parser are recorded to tags file.

+

mojom-dedicated.ctags:

+
--langdef=mojom{base=C++}{dedicated}
+--map-mojom=+.mojom
+--kinddef-mojom=f,function,functions
+--regex-mojom=/^[ ]+([a-zA-Z]+)\(/\1/f/
+
+
+
$ ctags --options=mojom-dedicated.ctags --fields=+l -o - input.cc
+main    input.cc        /^int main(void)$/;"    f       language:C++    typeref:typename:int
+
+
+
$ ctags --options=mojom-dedicated.ctags --fields=+l -o - input.mojom
+ABC     input.mojom     /^ ABC();$/;"   f       language:mojom
+main    input.mojom     /^int main(void)$/;"    f       language:C++    typeref:typename:int
+
+
+

Mojom parser works only when .mojom file is given as input.

+
+
+

bidirectional combination

+

{bidirectional} is specified, both tags capture by C++ parser and +mojom parser are recorded to tags file for either input input.cc and +input.mojom.

+

mojom-bidirectional.ctags:

+
--langdef=mojom{base=C++}{bidirectional}
+--map-mojom=+.mojom
+--kinddef-mojom=f,function,functions
+--regex-mojom=/^[ ]+([a-zA-Z]+)\(/\1/f/
+
+
+
$ ctags --options=mojom-bidirectional.ctags --fields=+l -o - input.cc
+ABC     input.cc        /^ ABC();$/;"   f       language:mojom
+main    input.cc        /^int main(void)$/;"    f       language:C++    typeref:typename:int
+
+
+
$ ctags --options=mojom-bidirectional.ctags --fields=+l -o - input.mojom
+ABC     input.cc        /^ ABC();$/;"   f       language:mojom
+main    input.cc        /^int main(void)$/;"    f       language:C++    typeref:typename:int
+
+
+
+
+
+
+

Translating an option file into C source code (optlib2c)

+

Universal Ctags has an optlib2c script that translates an option file into C +source code. Your optlib parser can thus easily become a built-in parser.

+

To add your optlib file, foo.ctags, into ctags do the following steps;

+
    +
  • copy foo.ctags file on optlib/ directory

  • +
  • add foo.ctags on OPTLIB2C_INPUT variable in makefiles/optlib2c_input.mak

  • +
  • add fooParser on PARSER_LIST macro variable in main/parser_p.h

  • +
+

You are encouraged to submit your .ctags file to our repository on +github through a pull request. See “Contributions” for more details.

+
+
+ + +
+
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/ctags/docs/optscript.html b/ctags/docs/optscript.html new file mode 100644 index 0000000..158f633 --- /dev/null +++ b/ctags/docs/optscript.html @@ -0,0 +1,425 @@ + + + + + + + + + Optscript, a programming language for extending optlib parsers — Universal Ctags 0.3.0 documentation + + + + + + + + + + + + + + + +
+
+
+
+ +
+

Optscript, a programming language for extending optlib parsers

+ +
+

Preparation for learning

+

Optscript is an implementation of PostScript(tm) alike stack +oriented general purpose programming language. Developers of optlib +parsers can utilize the language for extending their parsers.

+

You may not be familiar with a stack oriented programming language. +Though there are some differences, the syntax and core non-graphical +operators of Optscript and PostScript are the same. You can get the +basic knowledge for using Optscript from the materials for learning +PostScript.

+

“PostScript Language Tutorial & Cookbook” published by Adobe Systems +Inc. The book is known as “blue book”. This is the best place to +start. PostScript is a language for controlling printers. So it has +many graphical operators. Optscript is for tagging, and doesn’t have +such graphical operators. So you can skip the sections about graphics +(but you may want to read them because the book is written well).

+

Ghostscript (gs or gsnd) is an interpreter for the PostScript +language and PDF files. Unlike Optscript, it implements the full-set of +PostScript features including graphical operators. It is available +under either the GNU GPL Affero license. You can Ghostscript while +reading the blue book. Do web searching to know about Ghostscript.

+

optscript is an command that source files are included in +Universal Ctags source tree. You can use it as the replacement of +gs. However, I recommend you to have gs at hand because +optscript may have bugs. gs is much mature than optscript. +Having two interpreters helps you to know correct behavior.

+

Though gs has much higher qualities than optscript, eventually +you may have to build the optscript command to learn Optscript +specific operators. You can built the command with “make +optscript”.

+
    +
  • red book

    +

    TBW

    +
  • +
+
+
+

Syntax extension

+

? is a prefix for representing a character literal.

+

For an example, ?x represents 120. This is a short cut for (x) 0 +get.

+

Some characters has special notation using \.

+

?\t

+
+

tab

+
+

?\n

+
+

newline

+
+

?\_

+
+

space

+
+
+
+

The optscript command

+

You can run optscript with no argument:

+
$ ./optsript
+OPT>
+
+
+

OPT> is the prompt of the interpreter. +You can stop it with quit operator:

+
$ ./optsript
+OPT> quit
+$
+
+
+

Let’s see some example sessions. To help you understand the session +easily, Python sessions doing the same as Optscript are also written.

+
    +
  • hello world

    +

    Optscript:

    +
    OPT> (hello, world) =
    +hello, world
    +
    +
    +

    Python:

    +
    >>> print ('hello, world')
    +hello, world
    +
    +
    +
  • +
  • Adding

    +

    Optscript:

    +
    OPT> 2 3 add =
    +5
    +
    +
    +

    Python:

    +
    >>> print (2 + 3)
    +5
    +
    +
    +
  • +
  • Variables

    +

    Optscript:

    +
    OPT> /x 2 def
    +OPT> /y 3 def
    +OPT> x y add =
    +5
    +
    +
    +

    Python:

    +
    >>> x = 2
    +>>> y = 3
    +>>> print (x + y)
    +5
    +
    +
    +
  • +
  • Procedures

    +

    Optscript:

    +
    OPT> /add5_and_print { 5 add = } def
    +OPT> 4 add5_and_print
    +9
    +
    +
    +

    Python:

    +
    >>> def add5_and_print(x):
    +...    print(x + 5);
    +>>> add5_and_print(4)
    +9
    +
    +
    +
  • +
  • string manipulation

    +

    TBW

    +
  • +
  • array manipulation

    +

    TBW

    +
  • +
  • dict manipulation

    +

    TBW

    +
  • +
  • control flow

    +

    TBW

    +
  • +
  • operators for printing

    +

    TBW

    +
  • +
  • reading script from file

    +

    TBW

    +
  • +
+
+
+

Optscript in ctags

+ +
+

Operators

+

. -> - . corkIndex:int

+
+

Push the cork index for the tag

+
+

\n -> - \n matchedString:string

+
+

n is an integer (0…9) representing a group in a pattern. +Push the matched string for the group.

+
+

_matchloc

+
+

TBW

+
+

:field (See the output of --_list-operators)

+
+
+
Get the value for the specified field from a tag

and put it.

+
+
+
+

field: (See the output of --_list-operators)

+
+

Set a value at the stack to the specified field of a tag.

+
+

_tag

+
+

TBW

+
+

_COMMIT

+
+

TBW

+
+

_traced

+
+

TBW

+
+
+
+

Data types

+

MATCHLOC

+
+

TBW

+
+

index:int

+
+

TBW

+
+

TAG

+
+

TBW

+
+
+
+
+

Recipes

+

TBW

+
+
+

Difference between Optscript and PostScript

+
    +
  • Memory management

  • +
  • Dynamically extendable data type

    +
      +
    • string

    • +
    • array

    • +
    +
  • +
+
+
+ + +
+
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/ctags/docs/osx.html b/ctags/docs/osx.html new file mode 100644 index 0000000..fb89401 --- /dev/null +++ b/ctags/docs/osx.html @@ -0,0 +1,165 @@ + + + + + + + + + Building on Mac OS — Universal Ctags 0.3.0 documentation + + + + + + + + + + + + + + + +
+
+
+
+ +
+

Building on Mac OS

+
+
Maintainer
+

Cameron Eagans <me@cweagans.net>

+
+
+
+

This part of the documentation is written by Cameron Eagans, a co-maintainer of Universal Ctags and the maintainer of +the OSX packaging of this project.

+
+

Build Prerequisites

+

Building ctags on OSX should be no different than building on GNU/Linux. The same toolchains are used, and the Mac OS +packaging scripts use autotools and make (as you’d expect).

+

You may need to install the xcode command line tools. You can install the entire xcode distribution from the App Store, +or for a lighter install, you can simply run xcode-select --install to only install the compilers and such. See +https://stackoverflow.com/a/9329325 for more information. Once your build toolchain is installed, proceed to the next +section.

+

At this point, if you’d like to build from an IDE, you’ll have to figure it out. Building ctags is a pretty straightforward +process that matches many other projects and most decent IDEs should be able to handle it.

+
+

Building Manually (i.e. for development)

+

You can simply run the build instructions in README.md.

+
+
+

Building with Homebrew

+

Homebrew (https://brew.sh/) is the preferred method for installing Universal Ctags for end users. Currently, the process +for installing with Homebrew looks like this:

+
brew tap universal-ctags/universal-ctags
+brew install --HEAD universal-ctags
+
+
+

Eventually, we hope to move the Universal-ctags formula to the main Homebrew repository, but since we don’t have any +tagged releases at this point, it’s a head-only formula and wouldn’t be accepted. When we have a tagged release, we’ll +submit a PR to Homebrew.

+

If you’d like to help with the Homebrew formula, you can find the repository here: +https://github.com/universal-ctags/homebrew-universal-ctags

+
+
+
+

Differences between OSX and GNU/Linux

+

There other things where building ctags on OSX differs from building on GNU/Linux.

+
    +
  • Filenames on HFS+ (the Mac OS filesystem) are case-preserving, but not case-sensitive in 99% of configurations. If a +user manually formats their disk with a case sensitive version of HFS+, then the filesystem will behave like normal +GNU/Linux systems. Depending on users doing this is not a good thing.

  • +
+
+
+

Contributing

+

This documentation is very much a work in progress. If you’d like to contribute, submit a PR and mention @cweagans for +review.

+
+
+ + +
+
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/ctags/docs/other-projects.html b/ctags/docs/other-projects.html new file mode 100644 index 0000000..1eda28e --- /dev/null +++ b/ctags/docs/other-projects.html @@ -0,0 +1,811 @@ + + + + + + + + + Relationship between other projects — Universal Ctags 0.3.0 documentation + + + + + + + + + + + + + + + +
+
+
+
+ +
+

Relationship between other projects

+ +
+

Other tagging engines

+
+

Exuberant Ctags

+

The origin of Universal Ctags.

+
+
+

Geany

+

Geany is a small and lightweight IDE. +Geany maintains their own tagging engine derived from ctags. +We are looking for the way to merge or share the source code each +other.

+

Repo

+
+
+

Geany has created a library out of ctags

+
+
+

Their language parsers have many improvements to various parsers. +Changes known by devs worth backporting:

+
    +
  • Various fixes for D parser (c.c), but currently the code diverges +from ours to some extent.

  • +
+

They have these additional language parsers:

+ +
+
+
+

Software using ctags

+
+

Pygments

+
+

Pygments is a generic syntax highlighter.

+

It can utilize tags file +as input for making hyperlinks. However, Pygments just looks +at names and lines in tags file. scopes and kinds are not +used. See here for +details.

+

As far as I (Masatake YAMATO) tried, using Pygments from ctags +is not so useful. There are critical gap between ctags and Pygments. +ctags focuses on identifiers. Pygments focuses on keywords.

+
+
+
+

GNU global

+
+

GNU global is a source code tagging system.

+

I (Masatake YAMATO) don’t inspect this much but GNU global uses +ctags internally.

+

A person at GNU global project proposed an extension for the tags file +format: See this ticket for details.

+

See also ‘Source code reading’ related sites.

+
+
+
+

GNU Source-highlight

+
+

GNU Source-highlight produces a document with syntax highlighting.

+

It can utilize tags file +as input for making hyperlinks. +See Generating References +section for details.

+

I (Masatake YAMATO) have not tried the feature yet.

+
+
+
+

OpenGrok

+
+

OpenGrok is a fast and usable source +code search and cross reference engine.

+

I (Masatake YAMATO) don’t inspect this much but OpenGrok uses +ctags internally.

+
+
+
+

Linux kernel

+
+

See linux/scripts/tags.sh +of Linux kernel source tree. +It utilizes c parser to the utmost limit.

+
+
+
+
+

Other interesting ctags repositories

+

There are several interesting repo’s with ctags around. These are +interesting to integrate in the future.

+
+

VIM-Japan

+

VIM-Japan have some interesting things, especially regarding encoding.

+
+
+

Anjuta

+

Anjuta DevStudio is a versatile Integrated Development Environment (IDE) +on GNOME Desktop Environment and features a number of advanced +programming facilities.

+

They did not fork Exuberant Ctags, but they did +natively include it in Anjuta. +They have made several additions to +their version of it including fairly extensive Vala language support.

+
+
+

Tagbar

+

Tagbar is a Vim plugin that provides an easy way to browse the tags of the +current file and get an overview of its structure.

+

This is a gold mine of optlibs.

+
+
orphan
+

+
+
+
+
+

Tracking other projects

+

This is working note for tracking activities other projects, +especially activity at Exuberant Ctags.

+

I(Masatake YAMATO) consider tracking activities as the first class +fruits of this project.

+
+

Exuberant Ctags

+
+

subversion

+
    +
  • status

    +

    Revisions up to <r815> are merged except:

    +
    +

    NOTHING HERE NOW

    +
    +

    (Mon Sep 22 12:41:32 2014 by yamato)

    +
  • +
  • howto

    +
    <svn>
    +=> <git: local Universal Ctags repo>
    +=> <git: local Universal Ctags repo>
    +
    +
    +
      +
    1. prepare your own Universal Ctags repo: a local git repo cloned from github. +You may know how to do it :)

      +
      $ git clone https://github.com/universal-ctags/ctags.git
      +
      +
      +
    2. +
    3. prepare Exuberant Ctags SVN repo: a local git repo clone from Exuberant Ctags svn tree.

    4. +
    +
    +

    The original clone is already part of Exuberant Ctags tree.

    +

    To initialize your git repository with the required subversion information do

    +
    $ git svn init https://svn.code.sf.net/p/ctags/code/trunk
    +$ git update-ref refs/remotes/git-svn refs/remotes/origin/sourceforge
    +
    +
    +

    and then

    +
    $ git svn fetch
    +$ git svn rebase
    +
    +
    +

    to get the latest changes and reflect it to the local copy.

    +
    +
      +
    1. merge

    2. +
    +
    +

    TODO

    +
    +
      +
    1. cherry-pick

      +

      4.1. Make a branch at local Universal Ctags repo and switch to it.

      +

      4.2. Do cherry-pick like:

      +
      $ git cherry-pick -s -x c81a8ce
      +
      +
      +

      You can find commit id on the another terminal +<git: local Universal Ctags repo>:

      +
      $ git log
      +
      +
      +

      or

      +
      $ git log --oneline
      +
      +
      +

      If conflicts are occurred in cherry-picking, you can +abort/reset cherry-picking with:

      +
      $ git reset --hard
      +
      +
      +
      +
      <git: local Universal Ctags repo>

      at the branch for picking.

      +
      +
      +
    2. +
    +
  • +
+
+
+

bugs

+
+

<367> C++11 override makes a C++ member function declaration ignored

+
+
    +
  • fixed in:

    +
    d4fcbdd
    +#413
    +#405
    +
    +
    +
  • +
+
+

<366> --options=.ctags doesn’t work under Windows

+
+
    +
  • fixed in:

    +
    15cedc6c94e95110cc319b5cdad7807caf3db1f4
    +
    +
    +
  • +
+
+

<365> Selecting Python kinds is broken

+
+
    +
  • fixed in:

    +
    4a95e4a55f67230fc4eee91ffb31c18c422df6d3
    +
    +
    +
  • +
  • discussed at #324.

  • +
+
+

<364> Ruby method on self is missing the trailing ? in the generated tag name

+
+
    +
  • fixed in:

    +
    d9ba5df9f4d54ddaa511bd5440a1a3decaa2dc28
    +
    +
    +
  • +
+
+

<363> Invalid C input file causes invalid read / heap overflow

+
+
    +
  • it is not reproduced.

  • +
  • the test case is imported as parser-c.r/c-heapoverflow-sh-bug-363.d:

    +
    $ make units UNITS=c-heapoverflow-sh-bug-363 VG=1
    +
    +
    +
  • +
+
+

<361> Invalid C input file causes invalid read / heap overflow

+
+
    +
  • it is not reproduced.

  • +
+
+

<360> Fails to parse annotation’s fields with default value

+
+
    +
  • fixed in:

    +
    682a7f3b180c27c1196f8a1ae662d6e8ad142939
    +
    +
    +
  • +
+
+

<358> Vim parser: Segmentation fault when reading empty vim file

+
+
    +
  • directly contributed by the original author of bug report and patch:

    +
    e0f854f0100e7a3cb8b959a23d6036e43f6b6c85
    +
    +
    +
  • +
  • it is fixed in sf, too:

    +
    5d774f6022a1af71fa5866994699aafce0253085
    +
    +
    +
  • +
+
+

<356> [python] mistakes module level attribute for class level attribute in module level if

+
+
    +
  • fixed in:

    +
    ab91e6e1ae84b80870a1e8712fc7f3133e4b5542
    +
    +
    +
  • +
+
+

<355> Error when parsing empty file (OCaml)

+
+
    +
  • fixed in:

    +
    02ec2066b5be6b129eba49685bd0b17fef4acfa
    +
    +
    +
  • +
+
+

<341> Lua: “function f ()” whitespace

+
+
    +
  • fixed in:

    +
    8590bbef5fcf70f6747d509808c29bf84342cd0d
    +
    +
    +
  • +
+
+

<341> Introducing ctags.conf.d

+
+
    +
  • merged the improved version:

    +
    216880c5287e0421d9c49898d983144db61c83aa
    +
    +
    +
  • +
+
+

<271> regex callback is broken; <320> [PATCH] fix regex callback match count

+
+
    +
  • merged patch (with updated bug number):

    +
    a12b3a24b62d6535a968e076675f68bac9ad32ba
    +
    +
    +
  • +
+
+

<177> Lua: “function” results in function tag (includes patch)

+
+
    +
  • fixed in:

    +
    5606f3f711afeac74587a249650a5f7b416f19be
    +
    +
    +
  • +
+
+
+
+
+
+

patches

+

Tracking the tickets in patch tracker is quite fruitful. +Patches are always there. So it is easy to evaluate the value:)

+
+

[(<]TICKET#[>)] TITLE

+
+
    +
  • STATUS

    +
      +
    • MORE STATUS

    • +
    +
  • +
+
+

<TICKET#>

+
+

means the ticket is closed from the view of Exuberant Ctags tree +developers. We don’t have to take time for this ticket.

+
+

(TICKET#)

+
+

means the ticket is still opened from the view of Exuberant Ctags +tree developers. We don’t have to take time for this ticket.

+
+
+
+
+

<85> Add --encoding option to make utf-8 encoded tags file

+
+
    +
  • contributed by the original author:

    +
    b3f670c7c4a3c3570b8d2d82756735586aafc0cb
    +
    +
    +
  • +
+
+

<84> C++11 new using semantics

+
+
    +
  • solved by another implementation:

    +
    c93e3bfa05b70d7fbc2539454c957eb2169e16b3
    +502355489b1ba748b1a235641bbd512ba6da315e
    +
    +
    +
  • +
+
+

<83> New full non-regex PHP parser

+
+
    +
  • contributed by the original author

  • +
+
+

<82> Support for comments in .ctags files

+
+
    +
  • contributed by the original author:

    +
    cab4735e4f99ce23c52b78dc879bc06af66796fd
    +
    +
    +
  • +
+
+

<81> ocaml parser segfaults on invalid files

+
+
    +
  • the bug is not reproduced

  • +
+
+

<80> Add support for falcon pl

+
+
    +
  • contributed by the original author

  • +
+
+

<74> protobuf parser

+
+
    +
  • Merged after getting approval from the original author

  • +
+
+

<67> Objective C language parser

+
+
    +
  • This is the implementation we have in Universal Ctags tree.

  • +
+
+

<65> absoluteFilename uses strcpy on overlapping strings

+
+
    +
  • Fixed in Universal Ctags tree, however the ticket is still open:

    +
    d2bdf505abb7569deae2b50305ea1edce6208557
    +
    +
    +
  • +
+
+

<64> Fix strcpy() misuse

+
+
    +
  • Fixed in Universal Ctags tree, however the ticket is still open:

    +
    d2bdf505abb7569deae2b50305ea1edce6208557
    +
    +
    +
  • +
+
+

<55> TTCN-3 support

+
+
    +
  • contributed by the original author

  • +
+
+

<51> Ada support

+
+
    +
  • Ada support is now available in Universal Ctags tree:

    +
    4b6b4a72f3d2d4ef969d7c650de1829d79f0ea7c
    +
    +
    +
  • +
+
+

<38> Ada support

+
+
    +
  • Ada support is now available in Universal Ctags tree:

    +
    4b6b4a72f3d2d4ef969d7c650de1829d79f0ea7c
    +
    +
    +
  • +
+
+

<33> Add basic ObjC support

+
+
    +
  • This one is written in regexp.

  • +
  • we have better objc parser.

  • +
+
+

(1) bibtex parser

+
+
    +
  • Reject because…

    +
      +
    • the owner of the ticket is anonymous.

    • +
    • the name of patch author is not written explicitly at +the header of patch.

    • +
    +
  • +
  • Alternative

    +

    https://gist.github.com/ptrv/4576213

    +
  • +
+
+
+
+
+

devel mailing list (ctags-devel@sourceforge)

+
+

<[Ctags] Shebang with python3 instead of python> +From: Martin Ueding <dev@ma…> - 2013-01-26 18:36:32

+
+

Added python, python2 and python3 as extensions of +python parser:

+
bb81485205c67617f1b34f61341e60b9e8030502
+
+
+
+

<[Ctags-devel] Lack of fnmatch(3) in Windows> +From: Frank Fesevur <ffes@us…> - 2013-08-24 20:25:47

+
+

There is no fnmatch() in the Windows C library. Therefore +a string comparison is done in fileNameMatched() in +strlist.c and patterns are not recognized:

+
698bf2f3db692946d2358892d228a864014abc4b
+
+
+
+

<Re: [Ctags-devel] WindRes parser> +From: Frank Fesevur <ffes@unns…> - 2013-08-30 21:23:50

+
+

A parser for Windows Resource files. +https://en.wikipedia.org/wiki/Resource_%28Windows%29

+
95b4806ba6c006e4b7e72a006700e33c720ab9e7
+
+
+
+

([Ctags-devel] Skip repeat PATH_SEPARATORs in relativeFilename()) +From: Seth Dickson <whefxlr@gm…> - 2013-12-24 04:51:01

+
+

Looks interesting.

+
+
+
+
+

Fedora

+

Some patches are maintained in ctags package of Fedora. +Inventory of patches are +http://pkgs.fedoraproject.org/cgit/ctags.git/tree/ctags.spec

+

<ctags-5.7-destdir.patch>

+
+

This patch was merged in Universal Ctags git tree:

+
d4b5972427a46cbdcbfb050a944cf62b300676be
+
+
+
+

<ctags-5.7-segment-fault.patch>

+
+

This patch was merged in Universal Ctags git tree:

+
8cc2b482f6c7257c5151893a6d02b8c79851fedd
+
+
+
+

(ctags-5.8-cssparse.patch)

+
+

Not in Universal Ctags tree.

+

The reproducer is attached to the following page: +https://bugzilla.redhat.com/show_bug.cgi?id=852101

+

However, Universal Ctags doesn’t reproduce with it.

+

I, Masatake YAMATO, read the patch. However, I don’t +understand the patch.

+
+

<ctags-5.8-css.patch>

+
+

This patch was merged in Universal Ctags git tree:

+
80c1522a36df3ba52b8b7cd7f5c79d5c30437a63
+
+
+
+

<ctags-5.8-memmove.patch>

+
+

This patch was merged in Exuberant Ctags svn tree. +As the result this patch is in Universal Ctags tree:

+
d2bdf505abb7569deae2b50305ea1edce6208557
+
+
+
+

<ctags-5.8-ocaml-crash.patch>

+
+

This patch was merged in Exuberant Ctags svn tree. +As the result this patch is in Universal Ctags tree:

+
ddb29762b37d60a875252dcc401de0b7479527b1
+
+
+
+

<ctags-5.8-format-security.patch>

+
+

This patch was merged in Exuberant Ctags svn tree. +As the result this patch is in Universal Ctags tree:

+
2f7a78ce21e4156ec3e63c821827cf1d5680ace8
+
+
+
+
+
+

Debian

+

Some patches are maintained in ctags package of Debian. +Inventory of patches are +http://anonscm.debian.org/cgit/users/cjwatson/exuberant-ctags.git/tree/debian/patches/series

+

<python-disable-imports.patch>

+
+

Universal Ctags tags Y in import X as Y and Z in from X import Y as Z +as definition tags. They are turned on by default. +The others are tagged as reference tags. reference tags are recorded only +when “r” extra tags are enabled. e.g. --extras=+r.

+
+

<vim-command-loop.patch>

+
+

This patch was merged as an alternative for +7fb36a2f4690374526e9e7ef4f1e24800b6914ec

+

Discussed on https://github.com/fishman/ctags/issues/74

+
e59325a576e38bc63b91abb05a5a22d2cef25ab7
+
+
+
+
+
+
+ + +
+
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/ctags/docs/output-format.html b/ctags/docs/output-format.html new file mode 100644 index 0000000..9a81a2e --- /dev/null +++ b/ctags/docs/output-format.html @@ -0,0 +1,144 @@ + + + + + + + + + Output formats — Universal Ctags 0.3.0 documentation + + + + + + + + + + + + + + + +
+
+
+
+ +
+

Output formats

+

This section deals with individual output-format topics.

+

The command line option --output-format=format chooses an output format. +Supported format are u-ctags, e-ctags, etags, xref, and json.

+
+
u-ctags, e-ctags

u-ctags is the default output format extending the Exuberant Ctags +output format (e-ctags).

+

--format=1 and --format=2 are same as --output-format=e-ctags +and --output-format=u-ctags respectively.

+

See man page tags (5) for details. The difference between +u-ctags and e-ctags are marked as “EXCEPTION”. +Additional changes in Universal Ctags are described in +Changes to the tags file format.

+
+
etags

Output format for Emacs etags. +--output-format=etags can be abbreviated as -e.

+

See emacs git for +details.

+
+
xref

A tabular, human-readable cross reference (xref) format. +--output-format=xref can be abbreviated as -x.

+

See section Xref output for details.

+
+
json

JSON format.

+

See section JSON output for details.

+
+
+
+ +
+ + +
+
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/ctags/docs/output-json.html b/ctags/docs/output-json.html new file mode 100644 index 0000000..6f349a1 --- /dev/null +++ b/ctags/docs/output-json.html @@ -0,0 +1,101 @@ + + + + + + + + + JSON output — Universal Ctags 0.3.0 documentation + + + + + + + + + + + + + + + +
+
+
+
+ +
+

JSON output

+

See ctags-client-tools(7).

+
+ + +
+
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/ctags/docs/output-tags.html b/ctags/docs/output-tags.html new file mode 100644 index 0000000..7b58d4d --- /dev/null +++ b/ctags/docs/output-tags.html @@ -0,0 +1,551 @@ + + + + + + + + + Changes to the tags file format — Universal Ctags 0.3.0 documentation + + + + + + + + + + + + + + + +
+
+
+
+ +
+

Changes to the tags file format

+
+

F kind usage

+

You cannot use F (file) kind in your .ctags because Universal Ctags +reserves it. See ctags-incompatibilities(7).

+
+
+

Reference tags

+

Traditionally ctags collects the information for locating where a +language object is DEFINED.

+

In addition Universal Ctags supports reference tags. If the extra-tag +r is enabled, Universal Ctags also collects the information for +locating where a language object is REFERENCED. This feature was +proposed by @shigio in #569 for GNU GLOBAL.

+

Here are some examples. Here is the target input file named reftag.c.

+
#include <stdio.h>
+#include "foo.h"
+#define TYPE point
+struct TYPE { int x, y; };
+TYPE p;
+#undef TYPE
+
+
+

Traditional output:

+
$ ctags -o - reftag.c
+TYPE        reftag.c        /^#define TYPE /;"      d       file:
+TYPE        reftag.c        /^struct TYPE { int x, y; };$/;"        s       file:
+p   reftag.c        /^TYPE p;$/;"   v       typeref:typename:TYPE
+x   reftag.c        /^struct TYPE { int x, y; };$/;"        m       struct:TYPE     typeref:typename:int    file:
+y   reftag.c        /^struct TYPE { int x, y; };$/;"        m       struct:TYPE     typeref:typename:int    file:
+
+
+

Output with the extra-tag r enabled:

+
$ ctags --list-extras | grep ^r
+r   Include reference tags  off
+$ ctags -o - --extras=+r reftag.c
+TYPE        reftag.c        /^#define TYPE /;"      d       file:
+TYPE        reftag.c        /^#undef TYPE$/;"       d       file:
+TYPE        reftag.c        /^struct TYPE { int x, y; };$/;"        s       file:
+foo.h       reftag.c        /^#include "foo.h"/;"   h
+p   reftag.c        /^TYPE p;$/;"   v       typeref:typename:TYPE
+stdio.h     reftag.c        /^#include <stdio.h>/;" h
+x   reftag.c        /^struct TYPE { int x, y; };$/;"        m       struct:TYPE     typeref:typename:int    file:
+y   reftag.c        /^struct TYPE { int x, y; };$/;"        m       struct:TYPE     typeref:typename:int    file:
+
+
+

#undef X and two #include are newly collected.

+

“roles” is a newly introduced field in Universal Ctags. The field +named is for recording how a tag is referenced. If a tag is definition +tag, the roles field has “def” as its value.

+

Universal Ctags prints the role information when the r +field is enabled with --fields=+r.

+
$ ctags -o - --extras=+r --fields=+r reftag.c
+TYPE        reftag.c        /^#define TYPE /;"      d       file:
+TYPE        reftag.c        /^#undef TYPE$/;"       d       file:   roles:undef
+TYPE        reftag.c        /^struct TYPE { int x, y; };$/;"        s       file:   roles:def
+foo.h       reftag.c        /^#include "foo.h"/;"   h       roles:local
+p   reftag.c        /^TYPE p;$/;"   v       typeref:typename:TYPE   roles:def
+stdio.h     reftag.c        /^#include <stdio.h>/;" h       roles:system
+x   reftag.c        /^struct TYPE { int x, y; };$/;"        m       struct:TYPE     typeref:typename:int    file:   roles:def
+y   reftag.c        /^struct TYPE { int x, y; };$/;"        m       struct:TYPE     typeref:typename:int    file:   roles:def
+
+
+

The Reference tag marker field, R, is a specialized GNU global +requirement; D is used for the traditional definition tags, and R is +used for the new reference tags. The field can be used only with +--_xformat.

+
$ ctags -x --_xformat="%R %-16N %4n %-16F %C" --extras=+r reftag.c
+D TYPE                3 reftag.c         #define TYPE point
+D TYPE                4 reftag.c         struct TYPE { int x, y; };
+D p                   5 reftag.c         TYPE p;
+D x                   4 reftag.c         struct TYPE { int x, y; };
+D y                   4 reftag.c         struct TYPE { int x, y; };
+R TYPE                6 reftag.c         #undef TYPE
+R foo.h               2 reftag.c         #include "foo.h"
+R stdio.h             1 reftag.c         #include <stdio.h>
+
+
+

See Customizing xref output for more details about +--_xformat.

+

Although the facility for collecting reference tags is implemented, +only a few parsers currently utilize it. All available roles can be +listed with --list-roles:

+
$ ctags --list-roles
+#LANGUAGE      KIND(L/N)         NAME                ENABLED DESCRIPTION
+SystemdUnit    u/unit            Requires            on      referred in Requires key
+SystemdUnit    u/unit            Wants               on      referred in Wants key
+SystemdUnit    u/unit            After               on      referred in After key
+SystemdUnit    u/unit            Before              on      referred in Before key
+SystemdUnit    u/unit            RequiredBy          on      referred in RequiredBy key
+SystemdUnit    u/unit            WantedBy            on      referred in WantedBy key
+Yaml           a/anchor          alias               on      alias
+DTD            e/element         attOwner            on      attributes owner
+Automake       c/condition       branched            on      used for branching
+Cobol          S/sourcefile      copied              on      copied in source file
+Maven2         g/groupId         dependency          on      dependency
+DTD            p/parameterEntity elementName         on      element names
+DTD            p/parameterEntity condition           on      conditions
+LdScript       s/symbol          entrypoint          on      entry points
+LdScript       i/inputSection    discarded           on      discarded when linking
+...
+
+
+

The first column shows the name of the parser. +The second column shows the letter/name of the kind. +The third column shows the name of the role. +The fourth column shows whether the role is enabled or not. +The fifth column shows the description of the role.

+

You can define a role in an optlib parser for capturing reference +tags. See Capturing reference tags for more +details.

+

--roles-<LANG>.<KIND> is the option for enabling/disabling +specified roles.

+
+
+

Pseudo-tags

+

See ctags-client-tools(7) about the +concept of the pseudo-tags.

+
+

TAG_KIND_DESCRIPTION

+

This is a newly introduced pseudo-tag. It is not emitted by default. +It is emitted only when --pseudo-tags=+TAG_KIND_DESCRIPTION is +given.

+

This is for describing kinds; their letter, name, and description are +enumerated in the tag.

+

ctags emits TAG_KIND_DESCRIPTION with following format:

+
!_TAG_KIND_SEPARATOR!{parser}   {letter},{name} /{description}/
+
+
+

A backslash and a slash in {description} is escaped with a backslash.

+
+
+

TAG_KIND_SEPARATOR

+

This is a newly introduced pseudo-tag. It is not emitted by default. +It is emitted only when --pseudo-tags=+TAG_KIND_SEPARATOR is +given.

+

This is for describing separators placed between two kinds in a +language.

+

Tag entries including the separators are emitted when --extras=+q +is given; fully qualified tags contain the separators. The separators +are used in scope information, too.

+

ctags emits TAG_KIND_SEPARATOR with following format:

+
!_TAG_KIND_SEPARATOR!{parser}   {sep}   /{upper}{lower}/
+
+
+

or

+
!_TAG_KIND_SEPARATOR!{parser}   {sep}   /{lower}/
+
+
+

Here {parser} is the name of language. e.g. PHP. +{lower} is the letter representing the kind of the lower item. +{upper} is the letter representing the kind of the upper item. +{sep} is the separator placed between the upper item and the lower +item.

+

The format without {upper} is for representing a root separator. The +root separator is used as prefix for an item which has no upper scope.

+

* given as {upper} is a fallback wild card; if it is given, the +{sep} is used in combination with any upper item and the item +specified with {lower}.

+

Each backslash character used in {sep} is escaped with an extra +backslash character.

+

Example output:

+
$ ctags -o - --extras=+p --pseudo-tags=  --pseudo-tags=+TAG_KIND_SEPARATOR input.php
+!_TAG_KIND_SEPARATOR!PHP    ::      /*c/
+...
+!_TAG_KIND_SEPARATOR!PHP    \\      /c/
+...
+!_TAG_KIND_SEPARATOR!PHP    \\      /nc/
+...
+
+
+

The first line means :: is used when combining something with an +item of the class kind.

+

The second line means \\ is used when a class item is at the top +level; no upper item is specified.

+

The third line means \\ is used when for combining a namespace item +(upper) and a class item (lower).

+

Of course, ctags uses the more specific line when choosing a +separator; the third line has higher priority than the first.

+
+
+

TAG_OUTPUT_FILESEP

+

This pseudo-tag represents the separator used in file name: slash or +backslash. This is always ‘slash’ on Unix-like environments. +This is also ‘slash’ by default on Windows, however when +--output-format=e-tags or --use-slash-as-filename-separator=no +is specified, it becomes ‘backslash’.

+
+
+

TAG_OUTPUT_MODE

+

This pseudo-tag represents output mode: u-ctags or e-ctags. +This is controlled by --output-format option.

+

See also Compatible output and weakness.

+
+
+
+

Truncating the pattern for long input lines

+

See --pattern-length-limit=N option in ctags(1).

+
+
+

Parser specific fields

+

A tag has a name, an input file name, and a pattern as basic +information. Some fields like language:, signature:, etc are +attached to the tag as optional information.

+

In Exuberant Ctags, fields are common to all languages. +Universal Ctags extends the concept of fields; a parser can define +its specific field. This extension was proposed by @pragmaware in +#857.

+

For implementing the parser specific fields, the options for listing and +enabling/disabling fields are also extended.

+

In the output of --list-fields, the owner of the field is printed +in the LANGUAGE column:

+
$ ctags --list-fields
+#LETTER NAME            ENABLED LANGUAGE         XFMT  DESCRIPTION
+...
+-       end             off     C                TRUE   end lines of various constructs
+-       properties      off     C                TRUE   properties (static, inline, mutable,...)
+-       end             off     C++              TRUE   end lines of various constructs
+-       template        off     C++              TRUE   template parameters
+-       captures        off     C++              TRUE   lambda capture list
+-       properties      off     C++              TRUE   properties (static, virtual, inline, mutable,...)
+-       sectionMarker   off     reStructuredText TRUE   character used for declaring section
+-       version         off     Maven2           TRUE   version of artifact
+
+
+

e.g. reStructuredText is the owner of the sectionMarker field and +both C and C++ own the end field.

+

--list-fields takes one optional argument, LANGUAGE. If it is +given, --list-fields prints only the fields for that parser:

+
$ ctags --list-fields=Maven2
+#LETTER NAME            ENABLED LANGUAGE        XFMT  DESCRIPTION
+-       version         off     Maven2          TRUE  version of artifact
+
+
+

A parser specific field only has a long name, no letter. For +enabling/disabling such fields, the name must be passed to +--fields-<LANG>.

+

e.g. for enabling the sectionMarker field owned by the +reStructuredText parser, use the following command line:

+
$ ctags --fields-reStructuredText=+{sectionMarker} ...
+
+
+

The wild card notation can be used for enabling/disabling parser specific +fields, too. The following example enables all fields owned by the +C++ parser.

+
$ ctags --fields-C++='*' ...
+
+
+

* can also be used for specifying languages.

+

The next example is for enabling end fields for all languages which +have such a field.

+
$ ctags --fields-'*'=+'{end}' ...
+...
+
+
+

In this case, using wild card notation to specify the language, not +only fields owned by parsers but also common fields having the name +specified (end in this example) are enabled/disabled.

+

Using the wild card notation to specify the language is helpful to +avoid incompatibilities between versions of Universal Ctags itself +(SELF INCOMPATIBLY).

+

In Universal Ctags development, a parser developer may add a new +parser specific field for a certain language. Sometimes other developers +then recognize it is meaningful not only for the original language +but also other languages. In this case the field may be promoted to a +common field. Such a promotion will break the command line +compatibility for --fields-<LANG> usage. The wild card for +<LANG> will help in avoiding this unwanted effect of the promotion.

+

With respect to the tags file format, nothing is changed when +introducing parser specific fields; <fieldname>:<value> is used as +before and the name of field owner is never prefixed. The language: +field of the tag identifies the owner.

+
+
+

Parser specific extras

+

As man page of Exuberant Ctags says, --extras option specifies +whether to include extra tag entries for certain kinds of information. +This option is available in Universal Ctags, too.

+

In Universal Ctags it is extended; a parser can define its specific +extra flags. They can be controlled with --extras-<LANG>=[+|-]{...}.

+

See some examples:

+
$ ctags --list-extras
+#LETTER NAME                   ENABLED LANGUAGE         DESCRIPTION
+F       fileScope              TRUE    NONE             Include tags ...
+f       inputFile              FALSE   NONE             Include an entry ...
+p       pseudo                 FALSE   NONE             Include pseudo tags
+q       qualified              FALSE   NONE             Include an extra ...
+r       reference              FALSE   NONE             Include reference tags
+g       guest                  FALSE   NONE             Include tags ...
+-       whitespaceSwapped      TRUE    Robot            Include tags swapping ...
+
+
+

See the LANGUAGE column. NONE means the extra flags are language +independent (common). They can be enabled or disabled with --extras= as before.

+

Look at whitespaceSwapped. Its language is Robot. This flag is enabled +by default but can be disabled with --extras-Robot=-{whitespaceSwapped}.

+
$ cat input.robot
+*** Keywords ***
+it's ok to be correct
+    Python_keyword_2
+
+$ ctags -o - input.robot
+it's ok to be correct       input.robot     /^it's ok to be correct$/;"     k
+it's_ok_to_be_correct       input.robot     /^it's ok to be correct$/;"     k
+
+$ ctags -o - --extras-Robot=-'{whitespaceSwapped}' input.robot
+it's ok to be correct       input.robot     /^it's ok to be correct$/;"     k
+
+
+

When disabled the name it’s_ok_to_be_correct is not included in the +tags output. In other words, the name it’s_ok_to_be_correct is +derived from the name it’s ok to be correct when the extra flag is +enabled.

+
+

Discussion

+

(This subsection should move to somewhere for developers.)

+

The question is what are extra tag entries. As far as I know none has +answered explicitly. I have two ideas in Universal Ctags. I +write “ideas”, not “definitions” here because existing parsers don’t +follow the ideas. They are kept as is in variety reasons but the +ideas may be good guide for people who wants to write a new parser +or extend an exiting parser.

+

The first idea is that a tag entry whose name is appeared in the input +file as is, the entry is NOT an extra. (If you want to control the +inclusion of such entries, the classical --kind-<LANG>=[+|-]... is +what you want.)

+

Qualified tags, whose inclusion is controlled by --extras=+q, is +explained well with this idea. +Let’s see an example:

+
$ cat input.py
+class Foo:
+    def func (self):
+        pass
+
+$ ctags -o - --extras=+q --fields=+E input.py
+Foo input.py        /^class Foo:$/;"        c
+Foo.func    input.py        /^    def func (self):$/;"      m       class:Foo       extra:qualified
+func        input.py        /^    def func (self):$/;"      m       class:Foo
+
+
+

Foo and func are in input.py. So they are no extra tags. In +other hand, Foo.func is not in input.py as is. The name is +generated by ctags as a qualified extra tag entry. +whitespaceSwapped extra flag of Robot parser is also aligned well +on the idea.

+

I don’t say all parsers follows this idea.

+
$ cat input.cc
+class A
+{
+  A operator+ (int);
+};
+
+$ ctags --kinds-all='*' --fields= -o - input.cc
+A   input.cc        /^class A$/
+operator +  input.cc        /^  A operator+ (int);$/
+
+
+

In this example operator+ is in input.cc. +In other hand, operator + is in the ctags output as non extra tag entry. +See a whitespace between the keyword operator and + operator. +This is an exception of the first idea.

+

The second idea is that if the inclusion of a tag cannot be +controlled well with --kind-<LANG>=[+|-]..., the tag may be an +extra.

+
$ cat input.c
+static int foo (void)
+{
+        return 0;
+}
+int bar (void)
+{
+        return 1;
+}
+
+$ ctags --sort=no -o - --extras=+F input.c
+foo input.c /^static int foo (void)$/;"     f       typeref:typename:int    file:
+bar input.c /^int bar (void)$/;"    f       typeref:typename:int
+
+$ ctags -o - --extras=-F input.c
+foo input.c /^static int foo (void)$/;"     f       typeref:typename:int    file:
+
+$
+
+
+

Function foo of C language is included only when F extra flag +is enabled. Both foo and bar are functions. Their inclusions +can be controlled with f kind of C language: --kind-C=[+|-]f.

+

The difference between static modifier or implicit extern modifier in +a function definition is handled by F extra flag.

+

Basically the concept kind is for handling the kinds of language +objects: functions, variables, macros, types, etc. The concept extra +can handle the other aspects like scope (static or extern).

+

However, a parser developer can take another approach instead of +introducing parser specific extra; one can prepare staticFunction and +exportedFunction as kinds of one’s parser. The second idea is a +just guide; the parser developer must decide suitable approach for the +target language.

+

Anyway, in the second idea, --extras is for controlling inclusion +of tags. If what you want is not about inclusion, --param-<LANG> +can be used as the last resort.

+
+
+
+

Parser specific parameter

+

To control the detail of a parser, --param-<LANG> option is introduced. +--kinds-<LANG>, --fields-<LANG>, --extras-<LANG> +can be used for customizing the behavior of a parser specified with <LANG>.

+

--param-<LANG> should be used for aspects of the parser that +the options(kinds, fields, extras) cannot handle well.

+

A parser defines a set of parameters. Each parameter has name and +takes an argument. A user can set a parameter with following notation

+
--param-<LANG>:name=arg
+
+
+

An example of specifying a parameter

+
--param-CPreProcessor:if0=true
+
+
+

Here if0 is a name of parameter of CPreProcessor parser and +true is the value of it.

+

All available parameters can be listed with --list-params option.

+
$ ctags --list-params
+#PARSER         NAME     DESCRIPTION
+CPreProcessor   if0      examine code within "#if 0" branch (true or [false])
+CPreProcessor   ignore   a token to be specially handled
+
+
+

(At this time only CPreProcessor parser has parameters.)

+
+
+ + +
+
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/ctags/docs/output-xref.html b/ctags/docs/output-xref.html new file mode 100644 index 0000000..4f9c67d --- /dev/null +++ b/ctags/docs/output-xref.html @@ -0,0 +1,236 @@ + + + + + + + + + Xref output — Universal Ctags 0.3.0 documentation + + + + + + + + + + + + + + + +
+
+
+
+ +
+

Xref output

+

Xref output is a tabular, human-readable cross reference (xref) format.

+

The default information contained in the output includes:

+
    +
  • the tag name

  • +
  • the kind of tag

  • +
  • the line number

  • +
  • file name

  • +
  • source line (with extra white space condensed) of the file

  • +
+

--_xformat option allows a user to customize the output information. See +Customizing xref output for more details.

+

Xref output goes to standard output by default.

+

Notes:

+
+
    +
  • Printing z`{kind} field in xref format doesn’t include `kind: prefix.

  • +
  • Printing Z`{scope} field in xref format doesn’t include `scope: prefix.

  • +
+
+
+

Customizing xref output

+

--_xformat option allows a user to customize the cross reference +(xref) output enabled with -x.

+
--_xformat=FORMAT
+
+
+

The notation for FORMAT is similar to that employed by printf(3) in +the C language; % represents a slot which is substituted with a +field value when printing. You can specify multiple slots in FORMAT. +Here field means an item listed with --list-fields option.

+

The notation of a slot:

+
%[-][.][WIDTH-AND-ADJUSTMENT]FIELD-SPECIFIER
+
+
+

FIELD-SPECIFIER specifies a field whose value is printed. +Short notation and long notation are available. They can be mixed +in a FORMAT. Specifying a field with either notation, one or more +fields are activated internally.

+

The short notation is just a letter listed in the LETTER column of +the --list-fields output.

+

The long notation is a name string surrounded by braces({ and +}). The name string is listed in the NAME column of the output of +the same option. To specify a field owned by a parser, prepend +the parser name to the name string with . as a separator.

+

Wild card (*) can be used where a parser name is specified. In this +case both common and parser specific fields are activated and printed. +If a common field and a parser specific field have the same name, +the common field has higher priority.

+

WIDTH-AND-ADJUSTMENT is a positive number. +The value of the number is used as the width of +the column where a field is printed. The printing is +right adjusted by default, and left +adjusted when - is given as prefix. +The output is not truncated by default even if its field width is +specified and smaller than width of output value. For truncating +the output to the specified width, use . as prefix.

+

An example of specifying common fields:

+
$  ctags -x --_xformat="%-20N %4n %-16{input}|" main/main.c | head
+CLOCKS_PER_SEC        360 main/main.c     |
+CLOCKS_PER_SEC        364 main/main.c     |
+CLOCK_AVAILABLE       358 main/main.c     |
+CLOCK_AVAILABLE       363 main/main.c     |
+Totals                 87 main/main.c     |
+__anonae81ef0f0108     87 main/main.c     |
+addTotals             100 main/main.c     |
+batchMakeTags         436 main/main.c     |
+bytes                  87 main/main.c     |
+clock                 365 main/main.c     |
+
+
+

Here %-20N %4n %-16{input}| is a format string. Let’s look at the +elements of the format.

+

%-20N

+
+

The short notation is used here. +The element means filling the slot with the name of the tag. +The width of the column is 20 characters and left adjusted.

+
+

%4n

+
+

The short notation is used here. +The element means filling the slot with the line number of +the tag. The width of the column is 4 characters and right +adjusted.

+
+

%-16{input}

+
+

The long notation is used here. +The element means filling the slot with the input file name +where the tag is defined. The width of column is 16 +characters and left adjusted.

+
+

|

+
+

Printed as is.

+
+

Another example of specifying parser specific fields:

+
$  ctags -x --_xformat="%-20N [%10{C.properties}]" main/main.c
+CLOCKS_PER_SEC       [          ]
+CLOCK_AVAILABLE      [          ]
+Totals               [          ]
+__anonae81ef0f0108   [          ]
+addTotals            [    extern]
+batchMakeTags        [    static]
+bytes                [          ]
+clock                [          ]
+clock                [    static]
+...
+
+
+

Here “%-20N [%10{C.properties}]” is a format string. Let’s look at +the elements of the format.

+

%-20N

+
+

Already explained in the first example.

+
+

[ and ]

+
+

Printed as is.

+
+

%10{C.properties}

+
+

The long notation is used here. +The element means filling the slot with the value +of the properties field of the C parser. +The width of the column is 10 characters and right adjusted.

+
+
+
+ + +
+
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/ctags/docs/parser-asm.html b/ctags/docs/parser-asm.html new file mode 100644 index 0000000..3e6d7f5 --- /dev/null +++ b/ctags/docs/parser-asm.html @@ -0,0 +1,119 @@ + + + + + + + + + Asm parser — Universal Ctags 0.3.0 documentation + + + + + + + + + + + + + + + +
+
+
+
+ +
+

Asm parser

+
+
Maintainer
+

Masatake YAMATO <yamato@redhat.com>

+
+
+

The original (Exuberant Ctags) parser handles #define C preprocessor directive and C +style comments by itself. In Universal Ctags Asm parser utilizes CPreProcessor meta +parser for handling them. So a language object defined with #define is tagged as +“defines” of CPreProcessor language, not Asm language.

+
$ cat input.S
+#define S 1
+
+$ e-ctags --fields=+l  -o - input.S
+S    input.S /^#define S 1$/;"       d       language:Asm
+
+$ u-ctags --fields=+l  -o - input.S
+S    input.S /^#define S /;" d       language:CPreProcessor  file:
+
+
+
+ + +
+
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/ctags/docs/parser-cmake.html b/ctags/docs/parser-cmake.html new file mode 100644 index 0000000..b8158b4 --- /dev/null +++ b/ctags/docs/parser-cmake.html @@ -0,0 +1,128 @@ + + + + + + + + + CMake parser — Universal Ctags 0.3.0 documentation + + + + + + + + + + + + + + + +
+
+
+
+ +
+

CMake parser

+

The CMake parser is used for .cmake and CMakeLists.txt files. +It generates tags for the following items:

+
    +
  • User-defined functions

  • +
  • User-defined macros

  • +
  • User-defined options created by option()

  • +
  • Variables defined by set()

  • +
  • Targets created by add_custom_target(), add_executable() and add_library()

  • +
+

The parser uses the experimental multi-table regex ctags options to +perform the parsing and tag generation.

+

Caveats:

+
+

Names that are ${} references to variables are not tagged.

+

For example, given the following:

+
set(PROJECT_NAME_STR ${PROJECT_NAME})
+add_executable( ${PROJECT_NAME_STR} ... )
+add_custom_target( ${PROJECT_NAME_STR}_tests ... )
+add_library( sharedlib ... )
+
+
+

…the variable PROJECT_NAME_STR and target sharedlib will both be tagged, +but the other targets will not be.

+
+

References:

+
+
+
+ + +
+
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/ctags/docs/parser-cxx.html b/ctags/docs/parser-cxx.html new file mode 100644 index 0000000..5aa52b5 --- /dev/null +++ b/ctags/docs/parser-cxx.html @@ -0,0 +1,396 @@ + + + + + + + + + The new C/C++ parser — Universal Ctags 0.3.0 documentation + + + + + + + + + + + + + + + +
+
+
+
+ +
+

The new C/C++ parser

+
+
Maintainer
+

Szymon Tomasz Stefanek <s.stefanek@gmail.com>

+
+
+
+

Introduction

+

The C++ language has strongly evolved since the old C/C++ parser was +written. The old parser was struggling with some of the new features +of the language and has shown signs of reaching its limits. For this +reason in February/March 2016 the C/C++ parser was rewritten from +scratch.

+

In the first release several outstanding bugs were fixed and some new +features were added. Among them:

+
    +
  • Tagging of “using namespace” declarations

  • +
  • Tagging of function parameters

  • +
  • Extraction of function parameter types

  • +
  • Tagging of anonymous structures/unions/classes/enums

  • +
  • Support for C++11 lambdas (as anonymous functions)

  • +
  • Support for function-level scopes (for local variables and parameters)

  • +
  • Extraction of local variables which include calls to constructors

  • +
  • Extraction of local variables from within the for(), while(), if() +and switch() parentheses.

  • +
  • Support for function prototypes/declarations with trailing return type

  • +
+

At the time of writing (March 2016) more features are planned.

+
+
+

Notable New Features

+

Some of the notable new features are described below.

+
+

Properties

+

Several properties of functions and variables can be extracted +and placed in a new field called properties. +The syntax to enable it is:

+
$ ctags ... --fields-c++=+{properties} ...
+
+
+

At the time of writing the following properties are reported:

+
    +
  • virtual: a function is marked as virtual

  • +
  • static: a function/variable is marked as static

  • +
  • inline: a function implementation is marked as inline

  • +
  • explicit: a function is marked as explicit

  • +
  • extern: a function/variable is marked as extern

  • +
  • const: a function is marked as const

  • +
  • pure: a virtual function is pure (i.e = 0)

  • +
  • override: a function is marked as override

  • +
  • default: a function is marked as default

  • +
  • final: a function is marked as final

  • +
  • delete: a function is marked as delete

  • +
  • mutable: a variable is marked as mutable

  • +
  • volatile: a function is marked as volatile

  • +
  • specialization: a function is a template specialization

  • +
  • scopespecialization: template specialization of scope a<x>::b()

  • +
  • deprecated: a function is marked as deprecated via __attribute__

  • +
  • scopedenum: a scoped enumeration (C++11)

  • +
+
+
+

Preprocessor macros

+
+

Defining a macro from command line

+

The new parser supports the definition of real preprocessor macros +via the -D option. All types of macros are supported, +including the ones with parameters and variable arguments. +Stringification, token pasting and recursive macro expansion are also supported.

+

Option -I is now simply a backward-compatible syntax to define a +macro with no replacement.

+

The syntax is similar to the corresponding gcc -D option.

+

Some examples follow.

+
$ ctags ... -D IGNORE_THIS ...
+
+
+

With this commandline the following C/C++ input

+
int IGNORE_THIS a;
+
+
+

will be processed as if it was

+
int a;
+
+
+

Defining a macro with parameters uses the following syntax:

+
$ ctags ... -D "foreach(arg)=for(arg;;)" ...
+
+
+

This example defines for(arg;;) as the replacement foreach(arg). +So the following C/C++ input

+
foreach(char * p,pointers)
+{
+
+}
+
+
+

is processed in new C/C++ parser as:

+
for(char * p;;)
+{
+
+}
+
+
+

and the p local variable can be extracted.

+

The previous commandline includes quotes since the macros generally contain +characters that are treated specially by the shells. You may need some escaping.

+

Token pasting is performed by the ## operator, just like in the normal +C preprocessor.

+
$ ctags ... -D "DECLARE_FUNCTION(prefix)=int prefix ## Call();"
+
+
+

So the following code

+
DECLARE_FUNCTION(a)
+DECLARE_FUNCTION(b)
+
+
+

will be processed as

+
int aCall();
+int bCall();
+
+
+

Macros with variable arguments use the gcc __VA_ARGS__ syntax.

+
$ ctags ... -D "DECLARE_FUNCTION(name,...)=int name(__VA_ARGS__);"
+
+
+

So the following code

+
DECLARE_FUNCTION(x,int a,int b)
+
+
+

will be processed as

+
int x(int a,int b);
+
+
+
+
+

Automatically expanding macros defined in the same input file (HIGHLY EXPERIMENTAL)

+

If a CPreProcessor macro defined in a C/C++/CUDA file, the macro invocation in the +SAME file can be expanded with following options:

+
--param-CPreProcessor:_expand=1
+--fields-C=+{macrodef}
+--fields-C++=+{macrodef}
+--fields-CUDA=+{macrodef}
+--fields=+{signature}
+
+
+

Let’s see an example.

+

input.c: +.. code-block:: C

+
+

#define DEFUN(NAME) int NAME (int x, int y) +#define BEGIN { +#define END }

+
+
DEFUN(myfunc)

BEGIN +return -1 +END

+
+
+
+

The output without options: +.. code-block:

+
$ ctags -o - input.c
+BEGIN        input.c /^#define BEGIN /;"     d       language:C      file:
+DEFUN        input.c /^#define DEFUN(/;"     d       language:C      file:
+END  input.c /^#define END /;"       d       language:C      file:
+
+
+

The output with options: +.. code-block:

+
$ ctags --param-CPreProcessor:_expand=1 --fields-C=+'{macrodef}' --fields=+'{signature}' -o - input.c
+BEGIN        input.c /^#define BEGIN /;"     d       language:C      file:   macrodef:{
+DEFUN        input.c /^#define DEFUN(/;"     d       language:C      file:   signature:(NAME)        macrodef:int NAME (int x, int y)
+END  input.c /^#define END /;"       d       language:C      file:   macrodef:}
+myfunc       input.c /^DEFUN(myfunc)$/;"     f       language:C      typeref:typename:int    signature:(int x,int y)
+
+
+

myfunc coded by DEFUN macro is captured well.

+

This feature is highly experimental. At least three limitations are known.

+
    +
  • This feature doesn’t understand #undef yet. +Once a macro is defined, its invocation is always expanded even +after the parser sees #undef for the macro in the same input +file.

  • +
  • Macros are expanded incorrectly if the result of macro expansion +includes the macro invocation again.

  • +
  • Currently, ctags can expand a macro invocation only if its +definitions are in the same input file. ctags cannot expand a macro +defined in the header file included from the current input file.

  • +
+

Enabling this macro expansion feature makes the parsing speed about +two times slower.

+
+
+
+
+

Incompatible Changes

+

The parser is mostly compatible with the old one. There are some minor +incompatible changes which are described below.

+
+

Anonymous structure names

+

The old parser produced structure names in the form __anonN where N +was a number starting at 1 in each file and increasing at each new +structure. This caused collisions in symbol names when ctags was run +on multiple files.

+

In the new parser the anonymous structure names depend on the file name +being processed and on the type of the structure itself. Collisions are +far less likely (though not impossible as hash functions are unavoidably +imperfect).

+

Pitfall: the file name used for hashing includes the path as passed to the +ctags executable. So the same file “seen” from different paths will produce +different structure names. This is unavoidable and is up to the user to +ensure that multiple ctags runs are started from a common directory root.

+
+
+

File scope

+

The file scope information is not 100% reliable. It never was. +There are several cases in that compiler, linker or even source code +tricks can “unhide” file scope symbols (for instance *.c files can be +included into each other) and several other cases in that the limitation +of the scope of a symbol to a single file simply cannot be determined +with a single pass or without looking at a program as a whole.

+

The new parser defines a simple policy for file scope association +that tries to be as compatible as possible with the old parser and +should reflect the most common usages. The policy is the following:

+
    +
  • Namespaces are in file scope if declared inside a .c or .cpp file

  • +
  • Function prototypes are in file scope if declared inside a .c or .cpp file

  • +
  • K&R style function definitions are in file scope if declared static +inside a .c file.

  • +
  • Function definitions appearing inside a namespace are in file scope only +if declared static inside a .c or .cpp file. +Note that this rule includes both global functions (global namespace) +and class/struct/union members defined outside of the class/struct/union +declaration.

  • +
  • Function definitions appearing inside a class/struct/union declaration +are in file scope only if declared static inside a .cpp file

  • +
  • Function parameters are always in file scope

  • +
  • Local variables are always in file scope

  • +
  • Variables appearing inside a namespace are in file scope only if +they are declared static inside a .c or .cpp file

  • +
  • Variables that are members of a class/struct/union are in file scope +only if declared in a .c or .cpp file

  • +
  • Typedefs are in file scope if appearing inside a .c or .cpp file

  • +
+

Most of these rules are debatable in one way or the other. Just keep in mind +that this is not 100% reliable.

+
+
+

Inheritance information

+

The new parser does not strip template names from base classes. +For a declaration like

+
template<typename A> class B : public C<A>
+
+
+

the old parser reported C as base class while the new one reports +C<A>.

+
+
+

Typeref

+

The syntax of the typeref field (typeref:A:B) was designed with only +struct/class/union/enum types in mind. Generic types don’t have A +information and the keywords became entirely optional in C++: +you just can’t tell. Furthermore, struct/class/union/enum types +share the same namespace and their names can’t collide, so the A +information is redundant for most purposes.

+

To accommodate generic types and preserve some degree of backward +compatibility the new parser uses struct/class/union/enum in place +of A where such keyword can be inferred. Where the information is +not available it uses the ‘typename’ keyword.

+

Generally, you should ignore the information in field A and use +only information in field B.

+
+
+
+ + +
+
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/ctags/docs/parser-html.html b/ctags/docs/parser-html.html new file mode 100644 index 0000000..0e7f6f5 --- /dev/null +++ b/ctags/docs/parser-html.html @@ -0,0 +1,135 @@ + + + + + + + + + The new HTML parser — Universal Ctags 0.3.0 documentation + + + + + + + + + + + + + + + +
+
+
+
+ +
+

The new HTML parser

+
+
Maintainer
+

Jiri Techet <techet@gmail.com>

+
+
+
+

Introduction

+

The old HTML parser was line-oriented based on regular expression matching. This +brought several limitations like the inability of the parser to deal with tags +spanning multiple lines and not respecting HTML comments. In addition, the speed +of the parser depended on the number of regular expressions - the more tag types +were extracted, the more regular expressions were needed and the slower the +parser became. Finally, parsing of embedded JavaScript was very limited, based +on regular expressions and detecting only function declarations.

+

The new parser is hand-written, using separated lexical analysis (dividing +the input into tokens) and syntax analysis. The parser has been profiled and +optimized for speed so it is one of the fastest parsers in Universal Ctags. +It handles HTML comments correctly and in addition to existing tags it extracts +also <h1>, <h2> and <h3> headings. It should be reasonably simple to add new +tag types.

+

Finally, the parser uses the new functionality of Universal Ctags to use another +parser for parsing other languages within a host language. This is used for +parsing JavaScript within <script> tags and CSS within <style> tags. This +simplifies the parser and generates much better results than having a simplified +JavaScript or CSS parser within the HTML parser. To run JavaScript and CSS parsers +from HTML parser, use --extras=+g option.

+
+
+ + +
+
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/ctags/docs/parser-in-c.html b/ctags/docs/parser-in-c.html new file mode 100644 index 0000000..a9dcbde --- /dev/null +++ b/ctags/docs/parser-in-c.html @@ -0,0 +1,199 @@ + + + + + + + + + Writing a parser in C — Universal Ctags 0.3.0 documentation + + + + + + + + + + + + + + + +
+
+
+
+ +
+

Writing a parser in C

+

The section is based on the section “Integrating a new language parser” in “How +to Add Support for a New Language to Exuberant Ctags (EXTENDING)” of Exuberant Ctags documents.

+

Now suppose that I want to truly integrate compiled-in support for Swine into +ctags.

+
+

Registering a parser

+

First, I create a new module, swine.c, and add one externally visible function +to it, extern parserDefinition *SwineParser(void), and add its name to the +table in parsers.h. The job of this parser definition function is to create +an instance of the parserDefinition structure (using parserNew()) and +populate it with information defining how files of this language are recognized, +what kinds of tags it can locate, and the function used to invoke the parser on +the currently open file.

+

The structure parserDefinition allows assignment of the following fields:

+
struct sParserDefinition {
+        /* defined by parser */
+        char* name;                    /* name of language */
+        kindDefinition* kindTable;         /* tag kinds handled by parser */
+        unsigned int kindCount;        /* size of 'kinds' list */
+        const char *const *extensions; /* list of default extensions */
+        const char *const *patterns;   /* list of default file name patterns */
+        const char *const *aliases;    /* list of default aliases (alternative names) */
+        parserInitialize initialize;   /* initialization routine, if needed */
+        parserFinalize finalize;       /* finalize routine, if needed */
+        simpleParser parser;           /* simple parser (common case) */
+        rescanParser parser2;          /* rescanning parser (unusual case) */
+        selectLanguage* selectLanguage; /* may be used to resolve conflicts */
+        unsigned int method;           /* See METHOD_ definitions above */
+        unsigned int useCork;              /* bit fields of corkUsage */
+        ...
+};
+
+
+

The name field must be set to a non-empty string. Also either parser or +parser2 must set to point to a parsing routine which will generate the tag +entries. All other fields are optional.

+
+
+

Reading input file stream

+

Now all that is left is to implement the parser. In order to do its job, the +parser should read the file stream using using one of the two I/O interfaces: +either the character-oriented getcFromInputFile(), or the line-oriented +readLineFromInputFile().

+

See “Input text stream” for more details.

+
+
+

Parsing

+

How our Swine parser actually parses the contents of the file is entirely up to +the writer of the parser--it can be as crude or elegant as desired. You will +note a variety of examples from the most complex (parsers/cxx/*.[hc]) to the +simplest (parsers/make.[ch]).

+
+
+

Adding a tag to the tag file

+

When the Swine parser identifies an interesting token for which it wants to add +a tag to the tag file, it should create a tagEntryInfo structure and +initialize it by calling initTagEntry(), which initializes defaults and +fills information about the current line number and the file position of the +beginning of the line. After filling in information defining the current entry +(and possibly overriding the file position or other defaults), the parser passes +this structure to makeTagEntry().

+

See “Output tag stream” for more details.

+
+
+

Adding the parser to ctags

+

Lastly, be sure to add your the name of the file containing your parser (e.g. +parsers/swine.c) to the macro PARSER_SRCS in the file source.mak, so +that your new module will be compiled into the program.

+
+
+

Misc.

+

This is all there is to it. All other details are specific to the parser and how +it wants to do its job.

+

There are some support functions which can take care of some commonly needed +parsing tasks, such as keyword table lookups (see main/keyword.c), which you +can make use of if desired (examples of its use can be found in parsers/c.c, +parsers/eiffel.c, and parsers/fortran.c).

+

Support functions can be found in main/*.h excluding main/*_p.h.

+

Almost everything is already taken care of automatically for you by the +infrastructure. Writing the actual parsing algorithm is the hardest part, but is +not constrained by any need to conform to anything in ctags other than that +mentioned above.

+

There are several different approaches used in the parsers inside Universal +Ctags and you can browse through these as examples of how to go about creating +your own.

+
+
+ + +
+
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/ctags/docs/parser-puppetManifest.html b/ctags/docs/parser-puppetManifest.html new file mode 100644 index 0000000..a6529f2 --- /dev/null +++ b/ctags/docs/parser-puppetManifest.html @@ -0,0 +1,116 @@ + + + + + + + + + puppetManifest parser — Universal Ctags 0.3.0 documentation + + + + + + + + + + + + + + + +
+
+
+
+ +
+

puppetManifest parser

+
+
Maintainer
+

Masatake YAMATO <yamato@redhat.com>

+
+
+

puppetManifest is an experimental parser for testing multi tables +regex meta parser defined with --_mtable-<LANG> option.

+

The parser has some bugs derived from the limit of the multi tables +regex meta parser.

+

Here document

+
+

The parser cannot ignore the contents inside the area of +here document. The end marker of here document is defined +in the source code. Currently, ctags has no way to add a +regex pattern for detecting the end maker.

+
+
+ + +
+
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/ctags/docs/parser-python.html b/ctags/docs/parser-python.html new file mode 100644 index 0000000..d09b433 --- /dev/null +++ b/ctags/docs/parser-python.html @@ -0,0 +1,142 @@ + + + + + + + + + The new Python parser — Universal Ctags 0.3.0 documentation + + + + + + + + + + + + + + + +
+
+
+
+ +
+

The new Python parser

+
+
Maintainer
+

Colomban Wendling <ban@herbesfolles.org>

+
+
+
+

Introduction

+

The old Python parser was a line-oriented parser that grew way beyond +its capabilities, and ended up riddled with hacks and easily fooled by +perfectly valid input. By design, it especially had problems dealing +with constructs spanning multiple lines, like triple-quoted strings +or implicitly continued lines; but several less tricky constructs were +also mishandled, and handling of lexical constructs was duplicated and +each clone evolved in its own direction, supporting different features +and having different bugs depending on the location.

+

All this made it very hard to fix some existing bugs, or add new +features. To fix this regrettable state of things, the parser has been +rewritten from scratch separating lexical analysis (generating tokens) +from syntactical analysis (understanding what the lexemes mean). +This moves understanding lexemes to a single location, making it +consistent and easier to extend with new lexemes, and lightens the +burden on the parsing code making it more concise, robust and clear.

+

This rewrite allowed to quite easily fix all known bugs of the old +parser, and add many new features, including:

+
    +
  • Tagging function parameters

  • +
  • Extraction of decorators

  • +
  • Proper handling of semicolons

  • +
  • Extracting multiple variables in a combined declaration

  • +
  • More accurate support of mixed indentation

  • +
  • Tagging local variables

  • +
+

The parser should be compatible with the old one.

+
+
+ + +
+
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/ctags/docs/parser-tcl.html b/ctags/docs/parser-tcl.html new file mode 100644 index 0000000..a8a6c0e --- /dev/null +++ b/ctags/docs/parser-tcl.html @@ -0,0 +1,153 @@ + + + + + + + + + The new Tcl parser — Universal Ctags 0.3.0 documentation + + + + + + + + + + + + + + + +
+
+
+
+ +
+

The new Tcl parser

+
+
Maintainer
+

Masatake YAMATO <yamato@redhat.com>

+
+
+

Tcl parser is rewritten as a token oriented parser to support +namespace. It was line oriented parser. Some incompatibility between +Exuberant Ctags is introduced in the rewriting.

+

The line oriented parser captures class, public|protected|private +method. They are definitions in ITcl and TclOO. The new token oriented Tcl +parser ignores them. Instead ITcl and TclOO subparser running on Tcl base +parser capture them.

+
+

Known bugs

+
+

Full qualified tags

+

The separator used in full qualified tags should be :: but . is +used.

+

A ITcl or TclOO class C can be defined in a Tcl namespace N:

+
namespace eval N {
+    oo::class create C {
+    }
+}
+
+
+

When --extras=+q is given, currently ctags reports:

+
N.C ...
+
+
+

This should be:

+
N::C ...
+
+
+

Much work is needed to fix this.

+
+
+

Nested procs

+

proc defined in a proc cannot be captured well. +This is a regression.

+
+
+
+ + +
+
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/ctags/docs/parser-vim.html b/ctags/docs/parser-vim.html new file mode 100644 index 0000000..a41f490 --- /dev/null +++ b/ctags/docs/parser-vim.html @@ -0,0 +1,122 @@ + + + + + + + + + The Vim parser — Universal Ctags 0.3.0 documentation + + + + + + + + + + + + + + + +
+
+
+
+ +
+

The Vim parser

+
+

Incompatible change

+

Quoted from :help script-variable in the Vim documentation:

+
                        *script-variable* *s:var*
+In a Vim script variables starting with "s:" can be used. They
+cannot be accessed from outside of the scripts, thus are local to
+the script.
+
+
+

Exuberant Ctags records the prefix s: as part of a script-local +variable’s name. However, it is omitted from function names. As +requested in issue #852 on GitHub, Universal Ctags now also includes +the prefix in script-local function names.

+
+
+ + +
+
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/ctags/docs/parser-xslt.html b/ctags/docs/parser-xslt.html new file mode 100644 index 0000000..29adb79 --- /dev/null +++ b/ctags/docs/parser-xslt.html @@ -0,0 +1,117 @@ + + + + + + + + + XSLT parser — Universal Ctags 0.3.0 documentation + + + + + + + + + + + + + + + +
+
+
+
+ +
+

XSLT parser

+
+
Maintainer
+

Masatake YAMATO <yamato@redhat.com>

+
+
+

This parser only supports XSLT 1.0. +If a newer version (2.0 and 3.0) is specified in an input file, ctags +just skips the input. With --verbose, ctags prints the detected +version of the input file.

+

Scope information generated by the XSLT parser is a bit broken. +Currently a period (.) is used as the separator in nested scopes. +This is the default separator value in ctags.

+

When the XSLT parser captures a node <xsl:template match=”…”> the +value of the match attribute is tagged with kind matchedTemplate. +When a matchedTemplate name is stored as part of the scope information, +client tools may be confused because . is used both as the scope separator +and in the XPath match expression.

+
+ + +
+
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/ctags/docs/parsers.html b/ctags/docs/parsers.html new file mode 100644 index 0000000..33a64ca --- /dev/null +++ b/ctags/docs/parsers.html @@ -0,0 +1,129 @@ + + + + + + + + + Parsers — Universal Ctags 0.3.0 documentation + + + + + + + + + + + + + + + +
+ + +
+
+ + + + \ No newline at end of file diff --git a/ctags/docs/reporting.html b/ctags/docs/reporting.html new file mode 100644 index 0000000..94b5475 --- /dev/null +++ b/ctags/docs/reporting.html @@ -0,0 +1,302 @@ + + + + + + + + + Request for extending a parser (or Reporting a bug of parser) — Universal Ctags 0.3.0 documentation + + + + + + + + + + + + + + + +
+
+
+
+ +
+

Request for extending a parser (or Reporting a bug of parser)

+
+
Maintainer
+

Masatake YAMATO <yamato@redhat.com>

+
+
+ +
+

Sometimes you will find u-ctags doesn’t make a tag for a language +object unexpectedly. Writing a patch for making the tag is +appreciate. However, you may not have time to do so. In that case, you +can open an issue on the GitHub page of u-ctags.

+

This section tells you how to drive u-ctags developers effectively.

+
+

Before reporting

+

U-Ctags just captures the definitions of language objects. U-ctags +has an infrastructure for capturing references for language objects. +However, we implement reference tagging limited area. We will not +work on writing new code for capturing references for your favorite +language. About requests for capturing reference tags, we will say +“patches are welcome.”.

+

What kind of language objects u-ctags captures is controlled by +--kind-<LANG> option. Some kinds are disabled by default because we +assume people don’t want too large tags file. When you cannot find a +language object you want in a tags file, it is worth for checking the +status of kinds. --list-kinds=<LANG> or (--list-kinds-full=<LANG>) +option lists the status of the given language.

+

Let’s see an example.

+

Consider following input (foo.h):

+
struct point {
+  int x, y;
+};
+
+struct point *make_point(int x0, int y0);
+
+
+

tags output generated with u-ctags -o - /tmp/foo.h is as following.

+
point    foo.h    /^struct point {$/;"    s
+x    foo.h    /^  int x, y;$/;"    m    struct:point    typeref:typename:int
+y    foo.h    /^  int x, y;$/;"    m    struct:point    typeref:typename:int
+
+
+

Though point, x and y are tagged, the declaration make_point +is not tagged because prototype kind of C++ is disabled by default. +You can know it from the output of ctags --list-kinds-full=C++.

+
#LETTER NAME       ENABLED REFONLY NROLES MASTER DESCRIPTION
+A       alias      no      no      0      NONE   namespace aliases
+L       label      no      no      0      C      goto labels
+N       name       no      no      0      NONE   names imported via using scope::symbol
+...
+p       prototype  no      no      0      C      function prototypes
+
+
+

By turning on the kind with --kinds-C++=+p, u-ctags tags +make_point:

+
make_point    foo.h    /^struct point *make_point(int x0, int y0);$/;"    p    typeref:struct:point *
+point    foo.h    /^struct point {$/;"    s
+x    foo.h    /^  int x, y;$/;"    m    struct:point    typeref:typename:int
+y    foo.h    /^  int x, y;$/;"    m    struct:point    typeref:typename:int
+
+
+

Wildcard * is for enabling all kinds of a language at once. +--kinds-C++=* option enables all kinds of C++ parser. If you specify all +as the name of <LANG>, you can enable all kinds of all languages at once.

+
+
+

The content of report

+

Don’t assume following three things.

+

U-ctags developers know vi.

+
+

If you explain the expectation about how tags related functions of vi +and its plugins, U-ctags developers don’t understand it. +The answer from them can be “it can be a bug of vi.”

+
+

U-ctags developers know the programming language that you are talking.

+
+

U-ctags developers need your help to understand the meaning of +language object you asked tagging especially about kind. A person +extending a parser have to decide a kind of newly tagging language +object: reusing an existing kind or introducing a new kind. +U-ctags developers expect a report know the concept kind, field, +and extra. ctags.1 man page of u-ctags explains them.

+
+

English is the native language of the head maintainer.

+
+

I don’t want to write this but I have to write this. +Following are my private request for reporters.

+

Instead of long explanation, showing code or output +examples make me understand what you want.

+

Don’t omit sentences. Please, write your sentence +in full.

+

Use pronounce fewer.

+
+

U-ctags can generate something meaningful from a broken input.

+
+

From garbage, u-ctags generates garbage. +For a syntactically broken input source file, U-ctags +does not work well. U-ctags developers will not work +on improving u-ctags for handing such input. +The exception is that macro related input. Well known +one is C and C++.

+
+

Following a tuple with three items helps us to understand what you want.

+
    +
  1. Input file

    +
    +

    A shorter input file is better. However, it must be syntactically +valid. Show the URL (or something) where you get the input +file. It is needed to incorporate the input file to the u-ctags +source tree as a test case.

    +
    +
  2. +
  3. Command line running u-ctags

  4. +
  5. Expected output

  6. +
+

These three items should be rendered preformatted form on an issue +page of GitHub. Use triple backquotes notation of GitHub’s +markdown notation. I will close an issue with a bad notation +like this issue.

+
+
+

An example of good report

+

For the following input file(input.f90), u-ctags reports incomplete pattern +for function f at the line 23.

+
! input.f90, taken from https://github.com/universal-ctags/ctags/issues/1616
+module example_mod
+
+ ! This module contains two interfaces:
+ !   1. f_interface, which is an interface to the local f function
+ !   2. g, which is implemented in the example_smod submodule
+
+    interface f_interface
+       ! The function `f` is defined below, within the `contains` statement
+        module function f(x) result(y)
+           integer :: x, y
+        end function f
+     end interface f_interface
+
+    interface
+       ! The function `g` is implemented in example_smod.f90
+        module function g(x) result(y)
+           integer :: x,y
+        end function g
+    end interface
+
+    contains
+     function f(x) result(y)
+        integer :: x, y
+
+        y = x * 2
+     end function f
+end module example_mod
+
+
+

I run ctags with following command line:

+
u-ctags --fields=+n -o - /tmp/input.f90
+
+
+

What I got:

+
example_mod     /tmp/input.f90  /^module example_mod$/;"        m       line:2
+f       /tmp/input.f90  /^     fu/;"    f       line:23
+f_interface     /tmp/input.f90  /^    interface f_interface$/;" i       line:8  module:example_mod
+
+
+

I think this should be:

+
example_mod     /tmp/input.f90  /^module example_mod$/;"        m       line:2
+f       /tmp/input.f90  /^     function f/;"    f       line:23
+f_interface     /tmp/input.f90  /^    interface f_interface$/;" i       line:8  module:example_mod
+
+
+

or:

+
example_mod     /tmp/input.f90  /^module example_mod$/;"        m       line:2
+f       /tmp/input.f90  /^     function f(x) result(y)/;"       f       line:23
+f_interface     /tmp/input.f90  /^    interface f_interface$/;" i       line:8  module:example_mod
+
+
+

Either way, /^ fu/ is too short as a pattern.

+

The version of u-ctags is 83b0d1f6:

+
$ u-ctags --version
+Universal Ctags 0.0.0(83b0d1f6), Copyright (C) 2015 Universal Ctags Team
+Universal Ctags is derived from Exuberant Ctags.
+Exuberant Ctags 5.8, Copyright (C) 1996-2009 Darren Hiebert
+  Compiled: Dec 15 2017, 08:07:36
+  URL: https://ctags.io/
+  Optional compiled features: +wildcards, +regex, +multibyte, +debug, +option-directory, +xpath, +json, +interactive, +sandbox, +yaml
+
+
+
+
+ + +
+
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/ctags/docs/running-multi-parsers.html b/ctags/docs/running-multi-parsers.html new file mode 100644 index 0000000..7e1d620 --- /dev/null +++ b/ctags/docs/running-multi-parsers.html @@ -0,0 +1,548 @@ + + + + + + + + + Running multiple parsers on an input file — Universal Ctags 0.3.0 documentation + + + + + + + + + + + + + + + +
+
+
+
+ +
+

Running multiple parsers on an input file

+

Universal Ctags provides parser developers two ways, guest parser (guest/host) +and subparser (sub/base), to run multiple parsers for an input file.

+

This section shows concepts behind the running multiple parsers and real +examples.

+
+

Guest parser: Applying a parser to specified areas of input file

+

Guest parser (guest/host) considers the case that an input file has areas +written in languages different from the language for the input file.

+

A host parser parses the input file and detects the areas. +The host parser schedules guest parsers parsing the areas. +The guest parsers parse the areas.

+
+_images/area-and-parsers.svg +
+
+

Command line interface

+

Running guest parser can be controlled with guest (g) extras flag. +By default it is disabled. To turning on the feature running +guest parser, specify --extras=+g.

+

If --fields=+E is given, all tags generated by a guest parser is marked +guest in their extras: fields.

+
+
+

Examples of guest parser

+
+

{CSS,JavaScript}/HTML parser combination

+

For an HTML file, you may want to run HTML parser, of course. The +HTML file may have CSS areas and JavaScript areas. In other hand +Universal Ctags has both CSS and JavaScript parsers. Don’t you +think it is useful if you can apply these parsers to the areas?

+

In this case, HTML has responsible to detect the CSS and +JavaScript areas and record the positions of the areas. +The HTML parser schedules delayed invocations of CSS and +JavaScript parsers on the area with promise API.

+

Here HTML parser is a host parser. CSS and JavaScript parsers +are guest parsers.

+

See “The new HTML parser” and “parsers/html.c”.

+
+
+

C/Yacc parser combination

+

A yacc file has some areas written in C. Universal Ctags has both YACC +and C parsers. You may want to run C parser for the areas from YACC +parser.

+

Here YACC parser is a host parser. C parser is a guest parser. +See “parsers/yacc.c”.

+
+
+

Pod/Perl parser combination

+

Pod (Plain Old Documentation) is a language for documentation. The language +can be used not only in a stand alone file but also it can be +used inside a Perl script.

+

Universal Ctags has both parsers for Perl and Pod. +The Perl parser recognizes the area where Pod document is +embedded in a Perl script and schedules applying pod parser +as a guest parser on the area.

+
+
+
+
+

Subparser: Tagging definitions of higher (upper) level language

+
+

Background

+

Consider an application written in language X. The application has +its domain own concepts. Developers of the application may try to +express the concepts in the syntax of language X.

+

In language X level, the developer can define functions, variables, types, and +so on. Further more, if the syntax of X allows, the developers want to +define higher level (= application level) things for implementing the +domain own concepts.

+

Let me show the part of source code of SPY-WARS, an imaginary game application. +It is written in scheme language, a dialect of lisp. +(Here gauche is considered +as the implementation of scheme interpreter).

+
(define agent-tables (make-hash-table))
+(define-class <agent> ()
+  ((rights :init-keyword :rights)
+   (responsibilities :init-keyword :responsibilities)))
+
+(define-macro (define-agent name rights responsibilities)
+  `(hash-table-put! agent-tables ',name
+                    (make <agent>
+                      :rights ',rights
+                      :responsibilities ',responsibilities)))
+
+(define-agent Bond (kill ...) ...)
+(define-agent Bourne ...)
+
+...
+
+
+

define, define-class, and define-macro are keywords of scheme +for defining a variable, class and macro. Therefore scheme parser of +ctags should make tags for agent-tables with variable kind, +<agent> with class kind, and define-agent with macro kind. +There is no discussion here.

+
+

NOTE: To be exactly define-class and define-macro are not the part +of scheme language. They are part of gauche. That means three parsers +are stacked: scheme, gosh, and SPY-WARS.

+
+

The interesting things here are Bond and Bourne.

+
(define-agent Bond (kill ...) ...)
+(define-agent Bourne ...)
+
+
+

In scheme parser level, the two expressions define nothing; the two +expressions are just macro (define-agent) expansions.

+

However, in the application level, they define agents as the +macro name shown. In this level Universal Ctags should capture +Bond and Bourne. The question is which parser should +capture them? scheme parser should not; define-agent is not part of +scheme language. Newly defined SPY-WARS parser is the answer.

+

Though define-agent is just a macro in scheme parser level, +it is keyword in SPY-WARS parser. SPY-WARS parser makes a +tag for a token next to define-agent.

+

The above example illustrates levels of language in an input +file. scheme is used as the base language. With the base language we +can assume an imaginary higher level language named SPY-WARS is used +to write the application. To parse the source code of the application +written in two stacked language, ctags uses the two stacked parsers.

+

Making higher level language is very popular technique in the +languages of lisp family (see “On Lisp” for more details). +However, it is not special to lisp.

+

Following code is taken from linux kernel written in C:

+
DEFINE_EVENT(mac80211_msg_event, mac80211_info,
+        TP_PROTO(struct va_format *vaf),
+        TP_ARGS(vaf)
+);
+
+
+

There is no concept EVENT in C language, however it make sense in the +source tree of linux kernel. So we can consider linux parser, based on +C parser, which tags mac80211_msg_event as event kind.

+
+
+

Terms

+
+

Base parser and subparser

+

In the context of the SPY-WARS example, scheme parser is called a base +parser. The SPY-WARS is called a subparser. A base parser tags +definitions found in lower level view. A subparser on the base parser tags +definitions found in higher level view. This relationship can be nested. +A subparser can be a base parser for another subparser.

+
+_images/stack-and-parsers.svg +
+

At a glance the relationship between two parsers are similar to the +relationship guest parser and host parser description in +“Guest parser: Applying a parser to specified areas of input file”. +However, they are different. Though a guest +parser can run stand-alone, a subparser cannot; a subparser needs help +from base parser to work.

+
+
+

Top down parser choice and bottom up parser choice

+

There are two ways to run a subparser: top down or bottom up parser +choices.

+

Universal Ctags can chose a subparser automatically. +Matching file name patterns and extensions are the typical ways for +choosing. A user can choose a subparser with --language-force= option. +Choosing a parser in these deterministic way is called top down. +When a parser is chosen as a subparser in the top down way, the +subparser must call its base parser. The base parser may call methods +defined in the subparser.

+

Universal Ctags uses bottom up choice when the top down way +doesn’t work; a given file name doesn’t match any patterns and +extensions of subparsers and the user doesn’t specify +--language-force= explicitly. In choosing a subparser bottom up way +it is assumed that a base parser for the subparser can be chosen +by top down way. During a base parser running, the base parser tries +to detect use of higher level languages in the input file. As shown +later in this section, the base parser utilizes methods defined in its +subparsers for the detection. If the base parser detects the use of a +higher level language, a subparser for the higher level language is +chosen. Choosing a parser in this non-deterministic way (dynamic way) +is called bottom up.

+ ++++ + + + + + + + + + + + + + +

input file

subparser choices

<SUB_LANG> (input.sub)

top down

<BASE_LANG> (input.base)

bottom up

+

Here is an example. Universal Ctags has both m4 parser and Autoconf +parser. The m4 parser is a base parser. The Autoconf parser is a +subparser based on the m4 parser. If configure.ac is given as an +input file, Autoconf parser is chosen automatically because the +Autoconf parser has configure.ac in its patterns list. Based on the +pattern matching, Universal Ctags chooses the Autoconf parser +automatically (top down choice).

+

If input.m4 is given as an input file, the Autoconf parser is +not chosen. Instead the m4 parser is chosen automatically because +the m4 parser has .m4 in its extension list. The m4 parser passes +every token finding in the input file to the +Autoconf parser. The Autoconf parser gets the chance to probe +whether the Autoconf parser itself can handle the input or not; if +a token name is started with AC_, the Autoconf parser +reports “this is Autoconf input though its file extension +is .m4” to the m4 parser. As the result the Autoconf parser is +chosen (bottom up choice).

+

Some subparsers can be chosen both top down and bottom up ways. Some +subparser can be chosen only top down way or bottom up ways.

+
+
+

Direction flags

+

Direction flags specify how a base parser and a subparser work together. You +can choose directions by putting a long flag after +--langdef=<SUB_LANG>{base=<BASE_LANG>}.

+

The following three direction flags are available;

+
+
shared (default):

For an input file of <BASE_LANG> (ex. input.base), tags captured by +both <BASE_LANG> and <SUB_LANG> parser are recorded to tags file.

+

For an input file of <SUB_LANG> (ex. input.sub), tags captured by only +<SUB_LANG> parser are recorded to tags file.

+ +++++ + + + + + + + + + + + + + + + + +

input file

tags of <BASE_LANG>

tags of <SUB_LANG>

input.base

recorded

recorded

input.sub

---

recorded

+
+
dedicated:

For an input file of <BASE_LANG> (ex. input.base), tags captured by +only <BASE_LANG> parser are recorded to tags file.

+

For an input file of <SUB_LANG> (ex. input.sub), tags captured by both +<BASE_LANG> and <SUB_LANG> parser are recorded to tags file.

+ +++++ + + + + + + + + + + + + + + + + +

input file

tags of <BASE_LANG>

tags of <SUB_LANG>

input.base

recorded

---

input.sub

recorded

recorded

+
+
bidirectional:

For an input file of both <BASE_LANG> (ex. input.base) and +<SUB_LANG> (ex. input.sub), tags captured by both <BASE_LANG> and +<SUB_LANG> parser are recorded to tags file.

+ +++++ + + + + + + + + + + + + + + + + +

input file

tags of <BASE_LANG>

tags of <SUB_LANG>

input.base

recorded

recorded

input.sub

recorded

recorded

+
+
+

If no direction flag is specified, it implies {shared}.

+

See “Direction flags” in “Extending ctags with Regex parser (optlib)” for examples of using the +direction flags.

+
+
+
+

Listing subparsers

+

Subparsers can be listed with --list-subparser:

+
$ ctags --options=./linux.ctags --list-subparsers=C
+#NAME                          BASEPARSER           DIRECTION
+linux                          C                    base => sub {shared}
+
+
+
+
+

Command line interface

+

Running subparser can be controlled with subparser (s) extras flag. +By default it is enabled. To turning off the feature running +subparser, specify --extras=-s.

+
+
+

Examples of subparser

+
+

Automake/Make parser combination

+

Simply to say the syntax of Automake is the subset of Make. However, +the Automake parser has interests in Make macros having special +suffixes: _PROGRAMS, _LTLIBRARIES, and _SCRIPTS so on.

+

Here is an example of input for Automake:

+
bin_PROGRAMS = ctags
+ctags_CPPFLAGS =    \
+        -I.         \
+        -I$(srcdir) \
+        -I$(srcdir)/main
+
+
+

From the point of the view of the Make parser, bin_PROGRAMS is a just +a macro; the Make parser tags bin_PROGRAMS as a macro. The Make parser +doesn’t tag ctags being right side of ‘=’ because it is not a new +name: just a value assigned to bin_PROGRAMS. However, for the Automake +parser ctags is a new name; the Automake parser tags ctags with +kind Program. The Automake parser can tag it with getting help from +the Make parser.

+

The Automake parser is an exclusive subparser. It is chosen in top +down way; an input file name Makefile.am gives enough information for +choosing the Automake parser.

+

To give chances to the Automake parser to capture Automake own +definitions, The Make parser provides following interface in +parsers/make.h:

+
struct sMakeSubparser {
+        subparser subparser;
+
+        void (* valueNotify) (makeSubparser *s, char* name);
+        void (* directiveNotify) (makeSubparser *s, char* name);
+        void (* newMacroNotify) (makeSubparser *s,
+                                 char* name,
+                                 bool withDefineDirective,
+                                 bool appending);
+};
+
+
+

The Automake parser defines methods for tagging Automake own definitions +in a struct sMakeSubparser type variable, and runs the Make parser by +calling scheduleRunningBaseparser function.

+

The Make parser tags Make own definitions in an input file. In +addition Make parser calls the methods during parsing the input file.

+
$ ctags --fields=+lK  --extras=+r -o - Makefile.am
+bin  Makefile.am     /^bin_PROGRAMS = ctags$/;"      directory       language:Automake
+bin_PROGRAMS Makefile.am     /^bin_PROGRAMS = ctags$/;"      macro   language:Make
+ctags        Makefile.am     /^bin_PROGRAMS = ctags$/;"      program language:Automake       directory:bin
+ctags_CPPFLAGS       Makefile.am     /^ctags_CPPFLAGS =    \\$/;"    macro   language:Make
+
+
+

bin_PROGRAMS and ctags_CPPFLAGS are tagged as macros of Make. +In addition bin is tagged as directory, and ctags as program of Automake.

+

bin is tagged in a callback function assigned to newMacroFound method. +ctags is tagged in a callback function assigned to valuesFound method.

+

--extras=+r is used in the example. Reference (r) extra is needed to +tag bin. bin is not defined in the line, bin_PROGRAMS =. +bin is referenced as a name of directory where programs are +stored. Therefore r is needed.

+

For tagging ctags, the Automake parser must recognize +bin in bin_PROGRAMS first. ctags is tagged +because it is specified as a value for bin_PROGRAMS. +As the result r is also needed to tag ctags.

+

Only Automake related tags are emitted if Make parser is +disabled.

+
$ ctags --languages=-Make --fields=+lKr --extras=+r -o - Makefile.am
+bin     Makefile.am     /^bin_PROGRAMS = ctags$/;"      directory       language:Automake       roles:program
+ctags   Makefile.am     /^bin_PROGRAMS = ctags$/;"      program language:Automake       directory:bin
+
+
+
+
+

Autoconf/M4 parser combination

+

Universal Ctags uses m4 parser as a base parser and Autoconf parse as +a subparser for configure.ac input file.

+
AC_DEFUN([PRETTY_VAR_EXPAND],
+          [$(eval "$as_echo_n" $(eval "$as_echo_n" "${$1}"))])
+
+
+

The m4 parser finds no definition here. However, Autoconf parser finds +PRETTY_VAR_EXPAND as a macro definition. Syntax like (...) is part +of M4 language. So Autoconf parser is implemented as a subparser of +m4 parser. The most parts of tokens in input files are handled by +M4. Autoconf parser gives hints for parsing configure.ac and +registers callback functions to +Autoconf parser.

+
+
+
+
+ + +
+
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/ctags/docs/search.html b/ctags/docs/search.html new file mode 100644 index 0000000..c2d1a7a --- /dev/null +++ b/ctags/docs/search.html @@ -0,0 +1,98 @@ + + + + + + + + Search — Universal Ctags 0.3.0 documentation + + + + + + + + + + + + + + + + + + + +
+
+
+
+ +

Search

+ +
+ +

+ Please activate JavaScript to enable the search + functionality. +

+
+ + +

+ Searching for multiple words only shows matches that contain + all words. +

+ + +
+ + + +
+ + + +
+ +
+ + +
+
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/ctags/docs/searchindex.js b/ctags/docs/searchindex.js new file mode 100644 index 0000000..d9745c2 --- /dev/null +++ b/ctags/docs/searchindex.js @@ -0,0 +1 @@ +Search.setIndex({docnames:["autotools","building","contributions","developers","extending","index","interactive-mode","internal","man-pages","man/ctags-client-tools.7","man/ctags-faq.7","man/ctags-incompatibilities.7","man/ctags-lang-iPythonCell.7","man/ctags-lang-inko.7","man/ctags-lang-julia.7","man/ctags-lang-python.7","man/ctags-lang-r.7","man/ctags-lang-sql.7","man/ctags-lang-verilog.7","man/ctags-optlib.7","man/ctags.1","man/readtags.1","man/tags.5","news","option-file","optlib","optscript","osx","other-projects","output-format","output-json","output-tags","output-xref","parser-asm","parser-cmake","parser-cxx","parser-html","parser-in-c","parser-puppetManifest","parser-python","parser-tcl","parser-vim","parser-xslt","parsers","reporting","running-multi-parsers","testing","tips","tracking","windows"],envversion:{"sphinx.domains.c":2,"sphinx.domains.changeset":1,"sphinx.domains.citation":1,"sphinx.domains.cpp":3,"sphinx.domains.index":1,"sphinx.domains.javascript":2,"sphinx.domains.math":2,"sphinx.domains.python":3,"sphinx.domains.rst":2,"sphinx.domains.std":2,sphinx:56},filenames:["autotools.rst","building.rst","contributions.rst","developers.rst","extending.rst","index.rst","interactive-mode.rst","internal.rst","man-pages.rst","man/ctags-client-tools.7.rst","man/ctags-faq.7.rst","man/ctags-incompatibilities.7.rst","man/ctags-lang-iPythonCell.7.rst","man/ctags-lang-inko.7.rst","man/ctags-lang-julia.7.rst","man/ctags-lang-python.7.rst","man/ctags-lang-r.7.rst","man/ctags-lang-sql.7.rst","man/ctags-lang-verilog.7.rst","man/ctags-optlib.7.rst","man/ctags.1.rst","man/readtags.1.rst","man/tags.5.rst","news.rst","option-file.rst","optlib.rst","optscript.rst","osx.rst","other-projects.rst","output-format.rst","output-json.rst","output-tags.rst","output-xref.rst","parser-asm.rst","parser-cmake.rst","parser-cxx.rst","parser-html.rst","parser-in-c.rst","parser-puppetManifest.rst","parser-python.rst","parser-tcl.rst","parser-vim.rst","parser-xslt.rst","parsers.rst","reporting.rst","running-multi-parsers.rst","testing.rst","tips.rst","tracking.rst","windows.rst"],objects:{},objnames:{},objtypes:{},terms:{"0":[2,6,7,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,25,26,31,35,42,44,46],"000":17,"01":[28,48],"02":2,"02ec2066b5be6b129eba49685bd0b17fef4acfa":[28,48],"04":[28,48],"06":22,"07":44,"08":[28,44,48],"0900":2,"0alpha":17,"0end":25,"0th":7,"0x01":22,"0x07":22,"0x08":22,"0x0b":22,"0x0c":22,"0x1f":22,"0x20":22,"0x21":22,"0x7f":22,"1":[2,5,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,25,28,29,31,33,35,42,44,45,46,47,48,49],"10":[2,3,9,10,25,32],"100":[22,32,35],"10k":25,"10l":25,"11":[28,35,48],"116":46,"12":[2,28,48],"120":26,"133":46,"1364":18,"1409":25,"15":[22,44],"154":46,"15cedc6c94e95110cc319b5cdad7807caf3db1f4":[28,48],"16":32,"1616":44,"1620780":18,"16f":31,"16n":31,"17":6,"170":46,"177":[28,48],"1795612":46,"18":[28,48],"1800":18,"1850914":46,"187":46,"1878155":46,"1880687":46,"19":2,"1903":10,"1996":44,"1998":22,"1end":25,"1st":25,"1start":25,"2":[2,7,9,10,11,16,17,19,20,21,22,25,26,28,29,31,42,44,46,47,48],"20":[28,32,48],"2005":18,"2008":3,"2009":[2,44],"2013":[28,48,49],"2014":[28,48],"2015":[3,44],"2016":[2,35],"2017":[18,44],"2019":2,"2023624":46,"20n":[25,32],"21":[28,48],"216880c5287e0421d9c49898d983144db61c83aa":[28,48],"219":25,"22":[28,48],"23":[28,44,48],"230":46,"24":[28,48],"25":[17,28,48],"255":7,"26":[28,48],"2674":18,"271":[28,48],"28window":[28,48],"29":[28,48],"2end":25,"2f7a78ce21e4156ec3e63c821827cf1d5680ace8":[28,48],"2nd":[9,10,25],"2start":25,"3":[2,7,10,16,19,20,21,23,24,25,26,28,31,32,42,46,47,48,49],"30":[28,48,49],"3000":20,"3006":17,"317":25,"3184782":46,"32":[28,48,49],"320":[28,48],"324":[28,48],"33":[28,48],"341":[28,48],"347":46,"355":[28,48],"356":[28,48],"358":[28,32,48],"36":[28,44,48],"360":[28,32,48],"361":[28,48],"363":[28,32,48],"364":[28,32,48],"365":[28,32,48],"366":[28,48],"367":[28,48],"37":2,"38":[28,48],"383":47,"389":22,"39":17,"393":2,"3rd":[7,9,25],"3start":25,"4":[7,10,16,19,20,25,26,28,31,32,46,48,49],"405":[28,48],"41":[28,48],"413":[28,48],"436":32,"45":9,"4576213":[28,48],"47":[28,48],"49":9,"4a95e4a55f67230fc4eee91ffb31c18c422df6d3":[28,48],"4b6b4a72f3d2d4ef969d7c650de1829d79f0ea7c":[28,48],"4n":[31,32],"4th":25,"5":[5,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,26,28,29,31,44,46,48,49],"50":[9,28,48],"502355489b1ba748b1a235641bbd512ba6da315":[28,48],"51":[28,46,48],"512":22,"55":[28,48],"5606f3f711afeac74587a249650a5f7b416f19b":[28,48],"569":31,"5d774f6022a1af71fa5866994699aafce0253085":[28,48],"5th":7,"6":[20,25,31],"63":28,"64":[17,28,48,49],"64a05963c108af4b7832a2215006ff5cafcaaebb":2,"65":[28,48],"67":[28,48],"682a7f3b180c27c1196f8a1ae662d6e8ad142939":[28,48],"698bf2f3db692946d2358892d228a864014abc4b":[28,48],"7":[2,4,5,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,28,30,31,34,46,48],"74":[28,48],"75":46,"77":[3,47],"7fb36a2f4690374526e9e7ef4f1e24800b6914ec":[28,48],"8":[19,20,22,28,44,48,49],"80":[28,48],"80c1522a36df3ba52b8b7cd7f5c79d5c30437a63":[28,48],"81":[28,48],"82":[28,48],"8299595":18,"83":[28,48],"83b0d1f6":44,"84":[28,48],"85":[28,48],"852":41,"852101":[28,48],"857":31,"8590bbef5fcf70f6747d509808c29bf84342cd0d":[28,48],"87":32,"89":22,"8cc2b482f6c7257c5151893a6d02b8c79851fedd":[28,48],"9":[9,10,11,12,13,14,15,16,17,18,19,20,21,25,26,46],"906459647":3,"93":46,"9329325":27,"95b4806ba6c006e4b7e72a006700e33c720ab9e7":[28,48],"96":[11,20],"99":27,"9_":19,"9a":25,"abstract":[11,20],"boolean":[9,20,21],"break":[2,7,22,25,26,31],"byte":[6,7,11,20,23,25,32],"case":[7,9,10,19,20,21,22,23,25,27,28,31,32,35,37,44,45,47,48,49],"char":[7,20,22,25,35,37,45],"class":[2,6,8,9,11,15,18,19,20,21,22,23,25,28,31,35,40,45,48],"const":[7,35,37],"default":[0,7,9,10,11,12,18,19,20,21,22,23,24,25,28,29,31,32,35,37,42,44,45,46,47,48,49],"do":[0,2,7,8,9,12,15,19,20,21,22,23,25,26,27,28,37,44,46,47,48,49],"enum":[7,18,22,35],"export":14,"final":[9,10,24,25,26,35,36,37],"function":[2,4,8,9,11,14,15,16,17,18,20,21,22,23,25,28,31,34,35,36,37,39,41,44,45,46,47,48],"goto":44,"import":[2,5,8,19,20,25,26,28,44,48],"int":[7,9,15,20,22,25,26,31,35,37,44],"long":[2,3,7,8,9,19,20,25,26,29,32,44,45,46],"new":[3,5,7,9,15,19,20,22,24,28,31,37,43,44,45,46,47,48],"null":7,"public":[2,7,20,25,35,40],"return":[2,7,9,15,16,17,20,21,23,25,31,35,46],"short":[9,20,22,24,25,26,32,44],"static":[0,2,7,10,20,22,24,25,31,32,35,47,49],"switch":[7,25,28,35,48],"throw":22,"true":[7,9,10,20,21,25,31],"try":[2,20,25,45,46],"var":[7,9,17,25,41,47],"void":[7,9,11,20,25,31,37,45],"while":[6,7,10,14,19,20,21,26,35,46,49],A:[2,7,9,10,14,15,18,19,20,21,22,23,25,28,29,31,35,40,44,45,46,47,48,49],AND:[8,21,32],AS:17,And:[10,24,25],As:[5,10,19,20,22,23,25,28,31,41,45,46,48,49],At:[2,24,25,27,31,35,45,46,47,49],Be:[19,22],But:[5,9,22,25,49],By:[7,9,10,20,21,23,24,25,39,44,45],FOR:[8,25,46],For:[2,6,7,9,10,11,14,15,17,19,20,21,22,23,24,25,26,31,32,34,35,44,45,46,49],IN:23,If:[0,2,3,6,7,9,10,12,15,16,18,19,20,21,24,25,26,27,28,31,32,35,42,44,45,46,47,48,49],In:[0,2,6,7,9,10,11,17,19,20,21,22,23,25,26,31,32,33,35,36,37,41,44,45,46,47,49],It:[0,7,9,10,12,14,19,20,21,22,23,24,25,26,28,31,34,35,36,40,44,45,46,47,49],Its:[7,20,31],NOT:[22,23,31],No:[9,11,20],Not:[25,28,48,49],OF:2,OR:17,Of:[7,10,31],On:[0,10,18,19,20,22,23,25,45],One:[7,10,20,25,49],Or:10,Such:[20,31,46,47],TO:8,That:[9,45],The:[0,2,3,4,5,6,9,10,12,13,14,15,17,18,19,20,21,22,23,24,27,28,29,31,32,33,34,37,38,43,45,46,47,48,49],Their:[28,31,49],Then:[7,9,10,21,49],There:[2,10,15,22,23,25,27,28,35,37,45,48,49],These:[2,7,9,10,20,21,22,23,24,25,28,44,46],To:[0,2,6,7,11,15,19,20,21,22,23,24,25,26,28,31,32,35,36,39,45,47,48],WITH:8,Will:25,With:[2,3,7,19,23,25,31,35,42,45,46],_:[9,19,26,46],__anon9f26d2460108:20,__anonae81ef0f0108:32,__anonn:35,__arg:20,__attribute__:35,__declspec:20,__main__:25,__name__:25,__va_args__:35,_advanceto:25,_anonym:25,_autofqtag:25,_commit:26,_echo:[2,19,20,24],_expand:35,_extra:25,_extradef:[23,25],_field:25,_fielddef:25,_forc:[19,24],_guest:5,_interact:[6,23],_list:26,_ltlibrari:45,_matchloc:26,_mtabl:[25,26,38],_p:37,_prelud:26,_program:45,_role:25,_roledef:25,_scopesep:25,_script:45,_sequel:26,_tabledef:25,_tag:26,_tag_:22,_tag_extra_descript:9,_tag_field_descript:9,_tag_file_format:[20,22],_tag_file_sort:[20,22],_tag_kind_descript:9,_tag_kind_separ:31,_tag_proc_cwd:9,_tag_program_author:22,_tag_program_nam:[9,22],_tag_program_url:22,_tag_program_vers:22,_tag_role_descript:9,_test:34,_trace:26,_type:[6,9],_xformat:[20,25,31,32],a12b3a24b62d6535a968e076675f68bac9ad32ba:[28,48],aaa:24,aarch64:0,ab91e6e1ae84b80870a1e8712fc7f3133e4b5542:[28,48],abaqu:23,abbrevi:[5,29],abc2:17,abc:[17,23,25],abil:[5,10,23],abl:[3,20,22,25,27,46],abort:[10,23,28,48],about:[0,2,7,8,10,14,15,16,18,19,20,21,22,23,25,26,31,35,37,44,46,49],abov:[0,2,7,9,10,11,17,20,21,22,24,25,37,45,46],absenc:[3,20],absolut:[9,10,20,24],absolutefilenam:[28,48],abstractclass:11,ac:[2,7,45,46],ac_:[7,45],ac_config_fil:2,ac_defun:45,acal:35,accept:[19,20,22,23,25,27],access:[3,7,15,20,21,23,25,26,41],accesson:22,accessor:23,accommod:35,accomplish:[10,25],accord:9,account:[2,10,49],accur:39,achiev:[3,6],act:47,action:[8,20,25],activ:[5,6,7,19,28,32,46,48],actual:[7,9,19,20,21,22,25,37,46],ad:[2,4,9,10,18,19,20,22,23,24,26,28,35,46,48,49],ada:[23,28,46,48],add5_and_print:26,add:[0,3,4,10,18,20,21,22,24,25,26,28,31,36,37,38,39,46,48],add_custom_target:34,add_execut:34,add_librari:34,addit:[0,5,7,9,10,11,19,20,22,23,24,25,26,28,29,31,36,45],address:[20,22],addtot:32,adjust:[2,7,20,22,32],adob:26,advanc:[2,5,28,49],advantag:[10,20],affect:[0,20,25,49],affero:26,after:[0,2,6,7,9,11,17,20,21,22,24,25,28,31,35,37,45,46,47,48,49],again:[25,35],against:[3,20,23,25],agent:45,ah_:7,ah_verbatim:7,ahead:25,aim:[22,46],akefil:20,algorithm:[20,37],alia:[17,20,21,31,44],alias:[9,20,37,44],align:[2,20,23,31],alik:26,all:[2,3,7,8,9,11,14,19,20,21,22,23,24,25,26,31,35,37,39,44,45,46,47,49],allow:[2,6,7,10,17,20,21,22,23,25,32,37,39,45,49],almost:[3,37,49],alnum:25,alon:45,alongsid:0,alpha:25,alphabet:[3,19,20,21,22,24],alphanumer:19,alreadi:[0,7,10,20,25,28,32,37,48,49],also:[0,2,3,4,5,6,7,8,23,24,25,26,28,31,35,36,37,39,41,45,46,47,49],alter:[10,20],altern:[2,20,28,37,48],although:[20,22,31],alwai:[9,10,20,22,25,28,31,35,46,48,49],am:[2,3,45],am_:7,ambigu:20,among:35,amount:22,an:[0,2,3,5,6,7,8,10,11,12,15,16,17,18,19,20,21,22,26,27,28,29,31,32,35,37,38,42,48,49],analysi:[7,36,39,47],analyz:[7,15,25,46],ancestor:[5,19],anchor:[25,31],andreicristianpetcu:25,android:0,androideabi21:0,androideabi:0,ani:[2,3,7,9,10,11,19,20,22,24,25,27,31,37,45,46,49],annot:[25,28,48],announc:6,anonfunc84011d2c0101:15,anonfuncn:15,anonscm:[28,48],anonym:[9,15,20,25,28,48],anoth:[0,7,9,10,14,15,20,22,25,28,31,32,36,45,46,48,49],ansibleplaybook:23,answer:[2,31,44,45],ant:[11,23],anti:49,antun:3,anymor:49,anynam:10,anyth:[25,37],anywai:[7,9,31],api:[4,5,45,49],app:27,appar:46,appear:[6,7,9,10,16,20,21,22,24,25,31,35,49],append:[8,9,20,45,46],appl:2,appli:[2,5,7,9,11,19,20,22,25],applic:[2,3,7,20,45,49],appreci:44,approach:[7,10,31,37,46],appropri:[20,23],approv:[19,28,48],appveyor:[2,3],apt:0,ar:[0,2,5,6,7,8,9,11,13,14,17,18,19,20,21,22,23,24,25,26,27,28,29,31,32,34,35,37,40,41,44,45,46,47,48,49],arbitrari:22,archiv:49,area:[2,5,7,20,25,38,44,47],aren:25,arg:[22,31,35,46,47],argc:[20,22,25],argdecl4:20,argument:[0,5,6,7,9,10,19,20,21,22,24,26,31,35,46,47],argv:[20,22,25],arihiro:7,aris:20,arithi:7,arithmet:10,ariti:22,arm:0,armeabi:0,armv7a:0,around:[9,10,20,22,28],arrai:[7,26],arrang:8,array_s:7,array_spec:46,artifact:31,as_:7,as_echo_n:45,ascii:19,asciidoc:23,asdf:22,ask:[7,10,22,44],asm:[5,43],aspect:[2,24,31,47],assembl:9,assert:18,assign:[7,15,20,23,25,37,45],associ:[9,16,20,23,25,35],assum:[7,9,10,18,20,23,44,45,47],assumpt:[11,20],asterisk:25,atom:25,attach:[9,15,16,19,20,25,28,31,48],attempt:[10,23],attown:31,attribut:[11,13,28,31,42,48],au:22,author:[2,5,8,22,28,48],auto:[18,20],autoconf:[0,7,23,46,49],autoconfpars:7,autoconfsubpars:7,autogen:[0,49],autoit:23,autoload:20,automak:[0,23,31],automat:[2,4,5,10,20,24,37,45,46],autoreconf:0,autotool:[0,27,49],avail:[2,7,9,10,20,23,26,28,31,32,35,45,46,47,48,49],avid:3,avoid:[8,9,12,19,20,21,22,31],awai:22,awar:[20,49],awk:2,b3f670c7c4a3c3570b8d2d82756735586aafc0cb:[28,48],b4n:7,b:[9,10,11,14,16,18,19,20,21,22,25,35,46],back:[19,20,25],backend:[7,46],background:[3,4,20],backport:[2,28],backquot:44,backslash:[9,10,19,20,22,25,31,46,49],backtrack:25,backward:[8,9,10,20,35],bad:[2,44],badinput:3,bagl:17,baha:20,ban:39,bar:[20,22,23,25,31],bare:[9,10],base:[0,2,3,4,10,20,21,23,25,35,36,37,40,46,49],base_lang:45,baselang:20,basemethodt:7,basenam:46,basepars:45,bash:[2,46,47,49],basi:[10,20],basic:[5,19,20,21,26,28,31,48],batch:[3,7],batchmaketag:32,baz:[20,25],bb81485205c67617f1b34f61341e60b9e8030502:[28,48],bcall:35,becam:[35,36],becaus:[0,2,3,6,7,10,11,12,14,15,18,19,20,22,23,24,25,26,28,31,42,44,45,48],becom:[2,20,21,23,24,25,31],been:[3,6,9,10,19,20,22,23,25,36,39,49],beer:49,befor:[0,4,5,7,9,11,17,19,20,21,22,23,24,25,31,46,47],begin0:21,begin:[6,7,8,9,17,18,20,21,24,25,26,35,37],begin_c:25,behalf:7,behav:[10,20,22,27],behavior:[2,8,10,20,22,25,26,31,47],behaviour:23,behind:[7,25,45],being:[0,7,9,10,20,22,23,25,35,45],bel:22,bell:7,belong:20,below:[9,10,20,21,22,35,44,46,49],benefit:20,besid:[17,46],best:[9,10,20,22,26],better:[5,9,19,20,28,36,44,48],between:[1,2,5,7,8,11,15,20,22,23,25,29,31,40,45],beyond:39,bibtex:[23,28,48],bidirect:[7,45],big:10,biggest:20,bin:[0,10,20,45,46,49],bin_program:45,binari:[0,10,20,21,22,23,46,49],bisect:2,bit:[0,7,8,9,15,37,42,49],blank:25,blob:[12,17],block:[2,9,18,20,35,46],blue:26,bond:45,book:26,bool:[7,45],bore:2,borrow:49,bostic:22,both:[2,7,9,10,19,20,21,22,23,25,31,32,34,35,42,45,46,49],bottleneck:5,bottom:[7,19],boundari:25,bourn:45,bpf:6,brace:[9,19,20,23,32],bracket:25,bram:[20,22],branch:[20,28,31,48],breakag:2,brew:27,brief:20,briefli:20,broken:[9,28,42,44,46,48],brought:[14,36],brows:[28,37],bs:22,bsd:0,bsdi:22,buffer:[2,6],bug1856363:46,bug:[2,5,8,26,35,38,39,43],bugfix:2,bugzilla:[28,48],build:[5,6,7,8,10,11,21,23,25,26,47],builddir:47,built:[6,9,10,19,20,24,25,26,46,49],bunch:21,bundl:0,burden:39,bust:20,bypass:4,c11:49,c81a8c:[28,48],c93e3bfa05b70d7fbc2539454c957eb2169e16b3:[28,48],c99:49,c:[0,3,5,7,8,9,10,11,12,16,17,18,19,21,22,23,24,28,31,32,33,40,43,44,46,47,48,49],c_end:7,ca:22,cab4735e4f99ce23c52b78dc879bc06af66796fd:[28,48],call:[4,5,6,9,10,20,21,22,24,25,35,37,45,46,47],callabl:[15,20],callback:[7,28,45,48],caller:2,cameron:[3,27],can:[0,2,3,4,5,6,7,8,9,11,12,15,17,18,19,20,21,22,23,24,25,26,27,28,29,31,32,35,37,40,41,44,45,46,47,48,49],candid:[17,25],cannot:[2,7,9,10,11,14,15,18,20,22,23,25,31,35,38,40,41,44,45,46,47,49],capabl:[3,10,20,22,39],capit:19,captur:[2,19,31,35,40,42,44,45,47],card:[31,32],care:[3,37],cat:[9,25,31,33,46],catchev:25,categor:20,caus:[8,9,20,22,28,35,46,48],caveat:[8,10,34],cc:[0,2,22,25,31,47,49],cc_for_build:0,cd:[0,2,10],cell:12,centric:23,certain:[0,9,20,21,22,25,31],cfg:2,cfgentrylist:7,cfgfile:7,cflag:0,cflags_for_build:0,cflow:10,cgcc:47,cgcc_cflag:47,cgi:[28,48],cgit:[28,48],ch:[2,10,37],chain:21,chanc:[7,19,45],chang:[1,5,7,9,10,11,20,22,25,28,29,43,46,47,48],chapter:[4,17,19,25],charact:[2,7,9,19,20,21,22,23,24,25,26,31,32,35,37,46],check:[2,5,7,9,20,22,24,25,44,46],checker:18,cherri:[28,48],child:25,choic:[7,10],choos:[7,10,11,17,19,25,29,31,45],chooseexclusivesubpars:7,chop:[2,5],chose:45,chosen:[7,22,23,45],ci:[2,46],circl:0,circumst:10,cite:10,cjwatson:[28,48],clang:0,clark:22,class_method:19,classic:[9,10,25,31],classnam:20,clean:[46,47,49],cleanup:2,clear:[2,19,20,24,25,39],client:[5,8,10,12,13,14,15,17,18,20,21,22,23,30,31,42],clock:[18,32],clock_avail:32,clocks_per_sec:32,clojur:[7,23],clojurekind:7,clojurepars:7,clone:[0,20,28,39,48],close:[7,9,20,28,44,48],clumsi:22,cmake:[5,23,43],cmakelist:34,cmd:49,cmdline:46,cnf:24,co:[22,27,49],cobol:[11,31],code:[0,2,3,5,6,7,9,10,13,14,15,16,17,18,20,21,22,23,24,26,28,31,35,38,39,44,45,46,47,48],codeblock:49,coexist:7,collect:[2,20,31,49],collid:35,collis:35,colomban:[3,7,39],colon:[20,22,25],column:[9,20,22,23,26,31,32],com:[0,2,3,5,7,12,17,18,19,20,21,22,23,25,27,28,33,35,36,38,40,42,44,46,47,48,49],combin:[2,3,9,19,20,22,23,31,39],combinev2:9,come:[2,17,19,20,46,49],comma:[2,20,21,25,46],command:[1,3,5,6,7,8,9,10,12,19,21,22,24,25,27,28,29,31,44,47,48],commandlin:35,comment:[2,10,17,19,20,22,23,24,28,33,36,46,48],commit:[5,7,28,48],common:[2,5,9,10,20,21,25,26,31,32,35,37],commonli:[20,37],commun:[6,49],compar:[20,21,24,46,47],comparison:[20,28,48],compat:[8,10,19,20,23,31,35,39],compdef:20,compil:[1,4,5,18,20,24,25,27,35,37,44,47],complet:[0,2,3,6,10,11,20,49],complex:[2,20,23,37],compli:22,compliant:22,complic:[0,15,20,25,46],compon:[10,19,20],compos:20,comprehens:3,comput:[6,25],concaten:[20,22],concept:[7,19,20,23,25,31,44,45],conceptu:10,concern:[20,25],concis:39,concret:20,condens:[20,32],condit:[10,20,23,31,46],conduct:20,conf:[20,24,28,48],config:[0,20,23,24,49],configur:[1,2,5,7,10,19,20,23,27,45,47,49],conflict:[11,19,20,25,28,37,48],conform:37,confus:[2,17,19,20,42,49],connect:7,consensu:21,consid:[2,4,7,15,20,21,23,25,28,44,45,46,48],consist:[2,19,20,22,23,39],constant:[13,14,18],constrain:[25,37],constraint:18,construct:[10,20,31,39],constructor:[16,35],consult:[5,10],contain:[2,9,10,19,20,21,22,24,31,32,35,37,44,46,49],content:[5,6,8,19,22,37,38],context:[7,9,16,22,25,45],contextu:25,continu:[5,23,25,39,46,49],contrari:[21,24],contribut:[1,3,5,25,28,48],contributor:[2,3,46],control:[2,6,8,19,20,23,26,31,44,45],convei:22,convent:[11,19,20,46],convers:[20,22],convert:[7,9,20,22,23,25,46,49],cookbook:26,copi:[22,25,28,31,48,49],copyright:[2,44],core:[2,21,26],cork:[4,26],cork_nil:7,cork_queu:7,corkindex:26,corkusag:37,correct:[9,20,26,31,46],correctli:[9,36],correspond:[6,20,23,35],cosmet:2,cost:46,could:[3,9,10,20,21,22,25,49],count:[7,22,28,48],counter:[7,46],coupl:49,cours:[2,7,20,31,45],cover:[18,47],coverag:5,covergroup:18,cp932:23,cp:49,cpp:[0,35],cppcheck:5,cppflag:0,cppflags_for_build:0,cpreprocessor:[31,33,35],cpu:19,cr:[10,22],crash:[2,7,28,48],creat:[0,2,5,7,15,17,20,25,28,34,37,40,49],credit:8,crisp:22,criteria:2,critic:[20,23,28],crlf:49,cron:10,cross:[1,10,20,28,29,32,46,49],crude:37,cs:[20,22],csc:3,cscope:10,css:[23,28,36,46,48],csspars:[28,48],cstart:7,ct:21,ctag:[0,2,3,6,7,8,21,27,29,30,31,32,33,34,35,36,38,40,41,42,44,45,46],ctagd:12,ctags_attr_unus:7,ctags_cppflag:45,ctags_vs2013:[2,49],ctagswrit:7,ctrl:20,cuda:[23,35],cumul:[10,20],current:[2,3,6,7,9,10,14,16,19,20,22,23,25,27,28,31,35,37,38,40,42],cursor:[20,22,23],custom:[8,10,19,20,24,29,31],cut:[20,26],cweagan:[3,27],cxx:37,cycl:7,cygwin1:49,cygwin:[3,10,49],d2bdf505abb7569deae2b50305ea1edce6208557:[28,48],d4b5972427a46cbdcbfb050a944cf62b300676b:[28,48],d4fcbdd:[28,48],d9ba5df9f4d54ddaa511bd5440a1a3decaa2dc28:[28,48],d:[7,10,12,16,20,21,22,24,25,27,28,31,33,35,46,47,48],dai:[2,49],damag:6,darren:[5,10,19,20,21,22,44],darrenhiebert:[19,20,21],darwin:0,dash:[20,25],data:[7,8,10,16,18,20,22,23,25,46],datafram:16,date:[2,10,22],dbusintrospect:23,ddb29762b37d60a875252dcc401de0b7479527b1:[28,48],deal:[2,7,10,11,20,21,23,29,36,39,43],debat:35,debian:[0,23],debug:[19,20,21,22,23,24,26,44,46,49],debugg:[2,49],dec:44,decent:[27,49],decid:[2,5,9,21,25,31,44],decim:22,declar:[2,7,11,17,18,19,20,28,31,35,36,39,44,48],declare_funct:35,decor:39,dedic:[5,7,45],deem:10,deeper:[15,19],def:[6,7,9,12,15,19,20,25,26,31],defici:49,defin:[5,7,8,10,12,14,15,17,18,20,22,24,26,31,32,33,34,37,38,40,44,45,46],define_ev:45,definit:[2,5,7,8,9,15,20,23,24,25,28,31,35,37,40,44,48],defun:[25,35],degre:35,delai:[10,45],delet:[35,46],delimit:[9,20],demon:22,demonstr:[16,20],deni:9,depend:[0,7,10,14,16,20,21,22,23,27,31,35,36,39,46,49],dependencycount:7,deploi:3,deprec:35,depth:20,deptype_subpars:7,deriv:[9,17,19,20,21,28,31,38,44,46],descend:[10,20,22],describ:[2,4,9,11,13,18,20,21,22,23,24,25,29,31,35,46],descript:[2,7,8,23,25,31,44,45],design:[2,4,9,18,19,20,25,35,39],desir:[10,20,22,37],desktop:[28,49],despit:20,destdir:[28,48],detail:[2,4,7,8,11,19,21,22,23,24,25,28,29,31,32,37,45,47],detect:[2,20,21,23,36,38,42,45,46],determin:[8,19,22,23,35],determinist:45,dev:[0,23,28,48],devel:[0,10,49],develop:[3,5,7,9,20,25,26,28,31,44,45,46,47,48,49],developd:21,devot:20,devstudio:28,dfseeko:0,dftello:0,dhiebert:[19,20,21,22],dialect:[17,45],dickei:22,dickson:[28,48],dict:26,did:28,didn:25,diff:[2,23,46,49],differ:[1,5,7,8,9,11,14,15,20,22,23,25,29,31,35,37,39,45,46],difficult:[20,25,46],dilemma:20,dir:[2,19,20,24],direct:[3,7,9,20,33,39],directivenotifi:45,directli:[3,7,9,20,28,48],directori:[2,7,8,9,11,19,20,22,25,35,44,45,47,49],dirtag:10,disabl:[0,7,9,12,18,19,20,22,24,25,28,31,44,45,46,47,48,49],disadvantag:10,disallow:19,discard:31,discuss:[9,21,25,28,45,48],disk:27,dispatch:3,displai:[20,23],distinguish:[9,20,22],distract:10,distribut:[1,2,22,27,49],diverg:28,divid:36,dll:49,dllexport:20,dnf:0,do_someth:25,doc:[2,17,20],docbook:28,document:[5,11,17,18,19,20,22,25,27,28,37,38,41,45,49],docutil:0,doe:[7,8,11,15,19,20,23,24,25,35,44,46,47],doeslinecommentstart:7,doesn:[2,7,9,10,11,15,16,17,19,20,21,23,24,25,26,28,32,35,44,45,46,48],doesstringliteralstart:7,dollar:17,domain:45,don:[2,3,7,9,15,19,20,22,24,25,27,28,31,35,44,45,46,48],done:[7,10,21,22,25,28,48,49],dont_capture_m:25,dot:25,doubl:[10,20,22],doublequot:22,doublesharp:12,down:[7,49],downcas:21,download:49,draft:[5,22],drawback:[20,49],drive:[20,44,49],drop:[20,25],dt:[7,23],dtd:[2,23,31],dtsi:7,dtsparser:7,due:[9,20,25,49],duplic:[10,20,22,39],durat:46,dure:[0,7,9,20,24,25,45,46,49],dynam:[26,45],e0f854f0100e7a3cb8b959a23d6036e43f6b6c85:[28,48],e59325a576e38bc63b91abb05a5a22d2cef25ab7:[28,48],e:[0,2,5,7,9,10,11,14,16,18,19,20,21,22,24,25,26,28,29,31,33,35,37,45,46,48,49],each:[2,6,7,9,10,19,20,21,22,23,24,25,28,31,35,39,46],eagan:[3,27],eagerli:20,earli:9,earlier:[9,25],easi:[5,7,9,23,28,48,49],easier:[2,7,19,20,22,23,24,39],easili:[10,20,24,25,26,39],echo:[6,46],ecosystem:49,ed:15,edel:22,edit:[6,20,22,49],editor:[2,3,5,10,18,20,22],editorconfig:2,edu:[20,22],edv:3,effect:[7,9,19,20,25,31,44,46],effici:10,effort:20,eg:19,egrep:19,eiffel:[10,20,37],either:[9,10,19,20,25,26,32,37,44],ek:19,ekr:20,el:[2,25],eleg:37,element:[7,19,31,32],elementnam:31,elimin:20,elisp:[3,9],elixir:23,elm:23,els:[20,22],elsewher:22,elvi:[20,22],emac:[3,5,8,29],emacslisp:9,email:22,embed:[7,20,22,36,45],emerg:49,emit:[6,7,9,15,19,20,25,31,45],emphas:7,emphasi:25,emploi:32,empti:[2,19,20,22,24,25,28,37,48],emul:[20,23],en:[28,48],enabeld:12,enabl:[0,7,9,12,14,15,17,18,19,20,22,25,28,31,32,35,44,45,46,47,48,49],enclos:[20,22],encod:[10,20,22,28,48],encount:[10,20,25],encourag:25,end:[2,3,6,7,8,9,17,19,20,21,22,26,27,31,35,38,39,44,46,49],end_c:25,end_of_fil:7,endif:20,endmodul:18,energi:20,engin:[2,5,11],english:44,enhanc:25,enjoi:46,enough:[2,7,21,22,45,46,47,49],ensur:[21,22,35],enter:[2,6,25,46],enter_c_prologu:7,entersubpars:7,entir:[10,20,25,27,35,37],entitl:20,entri:[2,7,8,9,10,19,21,22,25,31,37],entrypoint:31,enumer:[18,20,22,23,31,35,46],env:20,environ:[3,8,10,24,25,28,31,49],eof:[20,25,46],eq:[9,21],equal:[7,20,21],equival:[20,21,25],er:25,error:[2,7,8,9,19,20,21,23,25,28,46,47,48,49],escap:[9,10,17,19,20,21,22,25,31,35],esoter:20,especi:[2,23,28,39,44,46,48,49],essenti:[7,20],esubparserrundirect:7,etag:[0,9,11,19,20,29,46],etagswrit:7,etc:[5,10,14,20,22,24,25,31,47],eval:[25,40,45],evalu:[2,19,21,23,26,28,46,48],even:[2,9,10,11,20,21,22,25,32,35,46,49],event:[18,25,45],eventu:[25,26,27],ever:[10,24,25],everi:[8,20,45],everyth:37,evolv:[35,39],ex:[0,9,10,20,22,45,49],ex_cmd:20,exactli:[20,21,22,24,25,45],examin:[10,20,31],exampl:[0,5,6,7,8,9,10,11,12,16,20,22,23,24,26,31,32,34,35,37,47],example_mod:44,example_smod:44,exce:11,except:[2,3,8,9,11,19,20,25,28,29,31,44,46,48],excess:20,excit:[20,25],exclud:[10,20,21,24,37],exclus:[7,10,19,20,23,45],exclusivesubparserchosencallback:7,exclusivesubparserchosennotifi:7,excmd:[9,10,20,23],exctag:0,exec:10,execut:[1,9,10,19,20,22,23,35,46],exercis:20,exert:20,exhibit:20,exist:[2,7,10,20,23,24,25,31,36,39,44,46,47,49],exit:[19,20,25,26,31,46,47],exp:21,expand:[19,20],expans:[20,22,35,45],expect:[2,7,9,10,13,20,23,24,26,27,44,46,47],expens:[10,20],experiment:[2,5,10,19,20,34,38],explain:[2,12,19,20,22,24,25,31,32,44,46],explan:[2,44],explicit:35,explicitli:[7,19,20,25,28,31,45,47,48],exploit:6,exportedfunct:31,expr:21,express:[2,4,5,8,19,20,22,23,36,42,45,49],ext:[20,46],extend:[2,5,8,9,19,20,21,24,29,31,37,39,45],extens:[2,4,5,7,8,10,18,19,21,22,23,25,28,31,37,45,48],extension_field:20,extensionfield:7,extent:28,extern:[7,18,20,31,32,35,37,49],extra:[0,7,8,9,10,11,14,15,17,19,21,22,28,29,32,36,40,44,45,46,48],extract:[9,12,17,25,35,36,39,49],extrem:10,exuber:[2,5,7,8,9,11,19,20,22,25,29,31,33,37,40,41,44,46],f90:[44,46],f:[2,9,12,16,17,18,19,20,21,22,23,25,28,29,35,44,48,49],f_interfac:44,facil:[2,3,5,10,28,31],fact:[20,25],factor:10,fail:[2,10,20,25,26,28,46,48],failur:[20,46],fairli:[20,28],falcon:[23,28,48],fall:20,fallback:[25,31],fals:[7,9,20,21,31],famili:45,familiar:[26,46],faq:[2,5,8],far:[2,10,25,28,31,35,49],fast:[10,20,25,28],faster:21,fastest:36,fatal:[19,23],fault:[28,48],favor:10,favorit:[8,12,20,44],featur:[2,5,6,10,19,20,22,23,24,25,26,28,31,39,43,44,45,46,49],feb:22,februari:35,fedora:[0,3,23],fedoraproject:[28,48],feel:49,ferit:28,fesevur:[3,28,48,49],fetch:[28,48],few:[2,3,9,10,20,31],fewer:[20,44],ff:22,ffe:[3,28,48,49],fget:22,field:[3,4,6,8,10,11,14,15,16,19,21,22,26,28,29,32,33,35,37,44,45,46,48],fieldnam:[25,26,31],fifth:31,figur:27,file:[2,4,5,6,7,8,13,14,15,16,18,21,26,28,29,32,33,34,42,44,47,48,49],file_nam:20,filedesc:11,fileencod:23,filenam:[6,20,22,27,31,49],filenamematch:[28,48],filescop:[9,11,20,31],filesystem:[6,27],filetyp:20,fill:[7,15,19,20,25,32,37],filter:[2,6,8,20,22,46,49],find:[2,5,7,9,10,17,19,20,21,23,25,27,28,44,45,48],findautoconftag:7,fine:[20,25,47,49],finer:23,finish:[7,20],first:[2,5,7,9,10,16,19,20,21,22,24,25,28,31,32,35,37,45,46,48],fishman:[20,28,48],fit:[10,20],fix:[2,3,7,9,18,20,28,35,39,40,46,48],flag:[5,7,8,9,10,20,31],flavor:[25,49],flex:2,flexibl:7,flip:21,flow:[2,26],flush:7,fnmatch:[28,48,49],focu:[19,25],focus:[19,28],fold:[9,20,21],foldcas:[9,20,21],follow:[0,2,6,7,8,9,11,15,18,19,20,22,23,24,25,28,31,34,35,37,44,45,46,47,48,49],foo:[0,2,7,9,10,11,20,22,23,25,26,31,44],foo_for_build:0,foo_t:22,foobar:[6,25],foobaz:6,fool:[20,39],foopars:[2,25],forc:[2,7,9,13,14,15,16,20,45],foreach:35,foreachsubpars:7,forget:[2,25],fork:[2,5,10,11,18,28,49],form:[2,10,11,19,20,25,35,44,46],formal:20,format:[2,3,5,6,8,10,19,21,23,25,27,28,32,46,48],former:11,formula:27,forth:20,fortran:[3,9,20,37],forward:[9,20,25,49],found:[0,5,7,8,9,19,20,23,25,37,45,46,49],four:[7,20,25],fourth:31,fox:22,fp:7,fprintf:7,fq:7,fragment:26,frame:16,framework:[7,25],frank:[3,28,48,49],free:[2,7,49],freed:7,freedom:22,frequent:[2,10,25],fri:22,friendli:11,from:[1,2,3,4,5,8,9,10,11,15,16,17,19,20,21,26,27,28,31,36,37,38,39,41,44,45,47,48],front:25,frrrwww:46,fruit:[7,28,48],fseek:0,ft:20,fte:22,ftell:0,ftp:10,fu:44,full:[4,18,19,20,23,25,26,28,44,48,49],fulli:[5,6,31],fun1:17,fun2:17,func1:22,func2:22,func3:22,func:[25,31],functionparamet:23,functionvar:16,further:[20,21,45],furthermor:[20,35],fussi:5,futur:[2,3,9,11,19,20,22,23,28],fuzz:[2,5],fyi:2,g:[2,7,9,16,19,20,21,22,25,26,28,31,36,37,44,45,48,49],game:45,gap:28,gar:25,garbag:[20,44],gather:[2,9,14,15,16,20,23],gauch:45,gawk:49,gaz:25,gcc:[0,20,23,35,47],gcda:47,gcno:47,gcov:47,gdb:[25,49],gdbinit:[23,25],geani:[2,3,20],gear:49,gener:[0,2,3,4,5,9,10,11,12,13,19,20,21,22,23,26,28,31,34,35,36,37,39,42,44,45,46,47,48,49],get:[2,3,7,9,16,25,26,28,44,45,48,49],getcfrominputfil:[7,37],getflag:22,getinputlanguag:7,getinputlinenumb:7,getinputlineoffset:7,getsourcelinenumb:7,gfm:25,gh3006:17,ghost:[4,5],ghostscript:26,gigo:20,gist:[28,48],git:[0,2,21,23,25,28,29,48],github:[0,2,5,7,12,17,18,21,25,27,28,41,44,48],gitreadi:2,give:[7,9,10,19,20,21,22,25,45,46,49],given:[7,9,11,19,20,23,25,31,32,34,40,44,45,46,47],glade:23,glanc:45,glibc:[25,49],glob:10,global:[2,10,20,23,25,31,35],globalvar:16,glsl:28,gm:[28,48],gmail:[3,5,35,36,46],gnome:28,gnu:[1,5,8,10,19,23,25,26,31],go:[0,9,10,23,25,37,47,49],goal:[3,5,8],goe:[7,9,21,25,32],gold:28,goo:25,good:[2,3,5,9,10,23,25,27,31,46,49],gosh:45,got:44,gperftool:47,gpl:[26,49],grab:[20,25],graft:7,grain:[20,25],grammar:[7,20],granular:23,graph:19,graphic:26,great:3,greedi:25,grep:[6,20,23,31,49],grew:[5,39],group:[4,9,10,11,12,13,14,15,16,17,18,19,20,21,22,25,26],groupid:31,grow:10,gs:26,gsnd:26,guarante:20,guess:[4,5],guest:[4,5,17,31],gui:49,guid:[2,3,31],guidelin:2,h1:[9,36],h2:36,h3:36,h:[2,7,9,10,18,20,21,22,25,31,37,44,45,46],ha:[3,5,6,7,9,10,15,17,19,20,21,22,23,24,25,26,28,31,32,35,36,38,39,44,45,46,49],hack:[1,2,3,39],had:[23,24,39],hand:[7,19,20,22,23,25,26,31,36,44,45],handl:[3,6,7,9,10,11,20,22,25,27,31,33,36,37,39,45],handler:23,hanschen:12,happen:[19,20],happi:2,har:[2,46],hard:[9,28,39,48],harder:2,hardest:37,hardwar:18,hash:[20,35,45],haskel:[3,23],hat:2,have:[0,2,3,7,8,9,11,14,15,17,19,20,21,22,23,24,25,26,27,28,31,32,35,36,39,44,45,46,48,49],haven:25,hax:23,hc:37,hda:3,hdr:10,he:[3,46],head1:[19,25],head2:19,head3:19,head4:19,head:[2,23,27,32,36,44,46],header:[2,20,23,28,35,48],heading1:11,heading2:11,heading3:11,heap:[28,48],heapoverflow:[28,48],heart:20,heaviest:3,hello:[20,26],help:[2,3,9,11,19,20,21,22,23,25,26,27,31,34,41,44,45,46,49],helper:2,henc:3,herbesfol:39,here:[0,2,3,7,9,10,12,14,15,16,20,21,23,25,27,28,31,32,38,45,46,47,48,49],hereinaft:20,hexadecim:22,hf:27,hh:20,hi:[9,20,22],hidden:20,hiebert:[5,10,19,20,21,22,44],hierarchi:8,higher:[5,7,20,25,26,31,32],highest:20,highli:25,highlight:20,himself:22,hint:[8,9,45],histori:[2,9],hit:10,hoc:19,hold:[7,20,22,23],home:[3,10,20,24],homedr:[20,24],homepath:[20,24],honest:25,hook:2,hope:[22,27],hors:22,host:[0,7,10,20,25,36,45,49],how:[0,4,8,9,12,19,21,23,25,28,31,37,44,45,48,49],howev:[2,7,9,10,11,15,17,19,20,22,23,25,26,28,31,41,44,45,46,47,48],howto:[28,48],hpp:20,html:[2,5,9,10,11,17,19,23,34,43],http:[0,2,5,7,10,12,17,18,19,20,21,27,28,34,44,48,49],human:[20,21,29,32,47],hxx:20,hyperlink:28,i686:49,i:[0,2,3,7,8,9,11,14,17,18,19,20,21,22,23,24,25,26,28,31,35,37,44,45,46,47,48,49],ibiblio:10,icas:[19,21,25],iconv:[23,49],iconv_dir:49,iconvlib:49,id:[1,2,3,6,10,15,18,22,27,28,48],id_t:15,idea:[2,4,9,23,24,31,46,49],ident:[9,20],identifi:[10,20,22,23,25,28,31,37,46],idutil:10,ieee:18,ieeexplor:18,if0:[20,31],ifclass:18,ifdef:20,ignor:[10,11,13,19,20,23,24,25,28,31,35,38,40,46,48],ignore_thi:35,ignorecas:20,illustr:[20,45],imagin:10,imaginari:[25,45],imbal:20,immedi:[19,20,24,25],immut:17,impact:[2,7,10],imperfect:35,impl:21,implement:[2,4,5,7,10,20,22,25,26,28,31,35,37,44,45,48],impli:[2,7,10,19,20,25,45],implicit:31,implicitli:[20,39],impos:20,imposs:[2,26,35],impract:25,improperli:20,improv:[2,3,5,22,28,44,46,48],in_source_fil:2,inabl:36,inappropri:20,inc:[20,22,26],includ:[1,2,5,6,7,9,11,17,19,20,21,22,24,25,26,28,31,32,35,39,41,48,49],inclus:31,incompat:[2,5,8,9,10,20,22,31,40,43],incomplet:44,inconsist:20,inconveni:[0,10],incorpor:44,incorrect:20,incorrectli:[20,35],increas:[10,22,35],increment:[25,46],inde:[20,25],indent:[2,24,39],independ:[2,20,22,31],index:[5,7,20,26],indic:[9,20,21,24,25],indirectlyimport:15,individu:[9,20,29,43],ineffici:25,infer:[20,35],infinit:[2,46],influenc:10,info:[19,20],inform:[5,7,9,10,18,19,20,22,23,27,28,31,32,37,42,45,48],infrastructur:[37,44],inherit:[20,21],inhibit:20,iniconf:7,init:[28,45,48],initi:[5,7,10,11,15,22,25,28,37,48],inittagentri:[7,37],inject:9,inko:[5,8,23],inlin:[6,22,31,35],inner:25,input:[2,3,4,5,8,12,13,14,15,16,17,18,19,21,25,28,29,32,33,36,39,42,44,47,48],inputend:7,inputfil:[4,11,20,31],inputfileinfo:7,inputsect:31,inputstart:7,inquir:[20,25],inquiri:25,insensit:[19,20,21,25],insert:[2,46],insid:[9,22,25,35,37,38,45],insight:3,insist:10,inspect:[8,20,28,46],inspir:[20,23,25],instal:[0,2,5,6,23,27,49],instanc:[18,20,35,37,49],instanti:[18,25],instead:[2,8,11,15,20,23,24,25,26,28,31,40,44,45,46,48],instruct:[20,27],integ:[7,9,17,21,26,44],integr:[7,28,37,49],intellig:10,intend:[19,25,49],intent:[2,7,20,24,46],interact:[3,5,20,21,44,46],interest:[3,5,7,20,25,37,45,47,48],interfac:[8,18,37,44],intern:[0,3,4,19,20,25,28,32,49],interpret:[10,19,20,23,26,45],interpretconfig:7,interrupt:46,introduc:[2,3,7,9,11,15,19,20,22,23,24,25,28,31,40,44,46,47,48],introduct:[8,43],invalid:[20,25,28,46,48],inventori:[28,48],invert:46,investig:49,invit:2,invoc:[10,20,35,45],invok:[6,10,20,37,46],io:[2,5,10,19,20,21,44],ipython:12,ipythoncel:[5,8,15,23],irrespect:20,is_runn:46,isn:15,iso:49,isol:10,issu:[3,8,10,17,20,23,25,28,41,44,46,48],itcl:[23,40],item:[5,9,20,21,22,25,31,32,34,44],iter:[7,25],its:[2,4,6,9,10,11,15,17,19,20,21,22,23,25,28,31,32,35,37,39,44,45,46],itself:[2,7,9,12,15,19,25,31,33,35,45],iuliano:22,j:20,jai:22,jame:22,jansson:[0,49],java:[10,20,25],javaproperti:23,javascript:[2,9,17,20,22,25,36,46],javaspr:25,jelveh:[5,20],jiri:36,jl:14,job:[3,7,10,37,49],join:2,jp:3,jq:46,js:46,json:[5,6,8,17,20,23,29,44,46],json_output_vers:9,jsonwrit:7,jstype:[9,18,20],julia:[5,8,23,46],jump:[2,8,9,20,25],jumppanen:22,jussi:22,jussij:22,just:[2,7,9,19,20,21,23,25,28,31,32,35,42,44,45,46],k:[2,18,19,20,31,35],k_namespac:7,karol:3,kconfig:23,keep:[2,3,9,10,19,20,21,22,25,35,46,47],kei:[9,10,17,20,31],keith:22,ken:3,kentkt:3,kept:[20,31,46],ker:20,kernel:[45,47],keystrok:10,keyword:[2,7,17,18,20,25,28,31,35,37,45],keyword_init:7,keyword_non:7,kill:45,kind:[4,5,6,8,14,15,19,21,22,26,28,29,32,37,42,44,45,46,48],kindcount:37,kinddef:[19,20,25],kinddefinit:37,kindlett:25,kindspec:20,kindtabl:37,kindx:20,kirkenda:[20,22],kirkendal:[20,22],klass:9,know:[2,7,9,14,15,19,20,21,23,25,26,28,31,44,46,48,49],knowledg:[25,26],known:[2,7,8,9,16,20,22,25,26,28,35,39,43,44,49],kotlin:23,ks:15,ksh:10,kz:16,l1:18,l2:18,l3:18,l4:18,l5:18,l6:18,l7:18,l:[0,9,10,16,18,20,21,23,25,31,33,44],label:[20,23,44],lack:[28,48],lambda:[2,8,9,20,25,31,35],lang1:46,lang2:46,lang:[2,5,8,9,10,20,24,25,26,31,38,44,46],langdef:[19,20,23,24,25,45],langmap:[18,20,23,25],languag:[0,3,5,7,8,12,13,14,15,16,17,19,21,22,23,24,25,28,31,32,33,34,35,36,37,44,48],larg:[2,3,10,11,20,44],last:[3,7,9,20,21,22,25,31],lastli:37,later:[2,9,10,19,20,22,25,45,49],latest:[20,28,34,48],latin1:23,launch:23,layer:49,layout:47,lazi:25,ldflag:0,ldflags_for_build:0,ldscript:[23,31],le4679d360100:25,lead:[20,22,25,46],leaf:10,leak:[3,22],learn:[5,20,46],least:[2,35,49],leav:[20,25],leave_c_prologu:7,leavesubpars:7,left:[2,7,20,32,37],legaci:[9,20,23],leleliu008:0,lemmi:22,length:[11,17,20,22,31],less:[2,10,23,35,39],let:[7,9,10,15,19,21,23,25,26,31,32,35,44,45,46],letter:[5,8,9,18,19,22,23,31,32,44,49],level:[5,7,8,16,19,20,23,24,25,28,31,35,48],lex:25,lexem:39,lexic:[25,36,39],lf:22,lgtm:2,lib:[0,10,19],liber:22,libiconv:[0,23,49],libjansson:[0,6,9,20,49],librari:[0,3,20,21,23,28,48,49],libreadtag:21,libseccomp:[0,6],libxml2:[0,23,49],libxml:23,libyaml:[0,23,49],licens:[20,26,49],life:7,lighten:39,lighter:27,lightweight:[3,28],like:[0,2,3,7,9,10,11,15,20,21,22,23,24,25,27,28,31,35,36,39,44,45,46,47,48,49],limit:[6,9,11,20,22,28,31,35,36,38,44,46],line:[1,5,6,7,8,9,12,19,21,22,24,26,27,28,29,32,36,37,39,40,44,46,47],line_pattern:[19,20],linefe:22,linenum:7,link:[20,23,31,49],linker:[23,35],linux:[1,2,5,6,10,25,45,47],lisp:[3,9,21,45],list:[2,3,6,7,8,10,11,16,18,19,21,22,25,26,31,32,37,44,46],liter:[7,9,13,17,25,26],lj:22,lk:45,lkr:45,ll:[9,25,27],llvm:0,ln:25,load:[2,5,7,8,14,19,20,23],loader:26,local:[0,2,10,20,22,24,28,31,35,39,41,44,46,48],localparam:18,locat:[5,8,9,19,20,22,25,31,37,39],log:[23,28,48],logic:[2,7,21,22],longer:[10,20],longflag:[25,26],look:[2,9,10,17,20,21,22,24,25,27,28,31,32,35,46,48],lookup:[10,37],lookupkeyword:7,loop:[2,6,28,46,48],lot:[22,25],love:46,lower:[20,22,31,45],lowercas:19,lrm:18,ls:[0,20],ltx:22,lua:[28,48],lvalu:25,m4:[7,23,25],m4_:7,m4_defin:25,m4found:7,m4subpars:7,m4tmp:7,m:[3,9,16,18,19,20,22,25,31,44,46],ma:[28,48],mac80211_info:45,mac80211_msg_ev:45,mac:[1,5],macek:22,machin:[0,20,21,23],macintosh:22,maco:10,macro:[2,7,9,10,14,20,25,31,34,37,44,45,46],macrodef:[9,35],made:[7,22,28,39],magic:[20,22],mai:[0,2,3,7,9,10,11,15,17,19,20,21,22,23,25,26,27,28,31,35,37,42,44,45,46,47,48,49],main:[2,5,7,9,11,20,22,25,27,32,37,45,46],mainli:[3,7,23],maintain:[2,3,5,7,19,21,23,25,27,28,33,35,36,38,39,40,42,44,46,47,48,49],mainten:[2,24],major:[5,11,20,49],mak:[2,20,23,25,37,49],make:[0,2,3,4,5,8,10,11,16,17,19,20,21,22,23,24,25,26,27,28,35,37,39,44,46,47,48,49],make_point:44,makeautoconftag:7,makefil:[2,20,25,45,49],makepromis:7,maker:38,makesubpars:45,maketagentri:[7,37],man:[5,9,10,11,12,13,14,15,16,17,18,19,20,23,24,25,29,31,44],man_man:2,manag:[4,5,20,25,26],mani:[2,7,8,20,21,22,23,25,26,27,28,39,46,49],manifest:25,manipul:[19,23,26],manner:[10,19,20,23],manual:[9,10,11,12,13,14,15,16,17,18,19,20,21,22,25,34],map:[8,9,10,11,13,14,15,16,18,19,25],mar:2,march:35,mark:[20,21,22,23,25,29,35,45,46],markdown:[23,25,44],marker:[2,7,20,22,24,25,26,31,38],marko:22,martin:[28,48],masatak:[2,3,7,23,25,28,33,38,40,42,44,46,47,48],master:[12,18,20,28,44],match:[5,7,8,9,19,20,21,23,26,27,28,36,42,45,48],matchedstr:26,matchedtempl:42,matchloc:26,materi:26,matlab:20,matter:[9,22],matur:26,maven2:[23,31],maxdepth:20,maxim:46,mayb:[3,19,20,46],mayswitchlanguag:7,mb:10,mbyte:22,md:[12,27],me:[2,3,27,44,45],mean:[0,2,7,9,10,20,21,22,25,28,31,32,39,44,45,46,48],meaning:[31,44],measur:47,meet:[20,46],member:[2,7,8,9,18,20,22,28,35,48],memmov:[28,48],memori:[2,3,7,26,46],mention:[22,27,37,49],menu:49,mere:[9,20],merg:[2,28,46,48],meson:[2,23],mesonbuild:23,mesonopt:23,messag:[2,19,20,46],met:46,meta:[9,19,20,23,33,38],method:[4,6,9,10,13,19,21,22,25,27,28,37,40,45,46,48],method_:37,methoda:19,methodb:19,mgroup:25,microsoft:1,middl:20,might:[2,6,10,22,25],mind:[25,35],mine:28,mingw32:[23,49],mingw:[23,49],minifi:20,minim:10,minimum:10,minor:[2,35],minu:[7,9,20],mio:7,misc:[2,4,7,46,47],misccomp:10,miscellan:[8,23],mishandl:39,mislead:10,miss:[9,20,21,22,28,48],mistak:[28,48],mistakenli:20,misus:[28,48],mix:[2,20,32,39],mk_mingw:[23,49],mk_mvc:49,mkdir:0,mkstemp:[20,49],mline:[19,20,25,26],mm:20,mode:[2,5,10,20,24,31],modelin:20,modern:[10,25],modif:[2,7],modifi:[2,19,20,25,31],modport:18,modul:[2,14,15,18,20,25,28,37,44,46,48],module_vers:20,mojom:25,moment:[3,49],mon:[28,48],moolenaar:[20,22],moos:23,more:[2,3,5,7,10,11,18,19,20,21,22,23,24,25,27,28,31,32,35,36,37,39,45,46,47,48,49],most:[0,2,3,4,9,10,11,19,20,22,23,25,27,35,37,45,46,49],mostli:[3,22,25,35],motiv:[2,8],move:[2,5,23,25,27,31,39],ms:[1,5,20,22],msbuild:49,msdo:24,msg:[19,20,24],mswindow:24,msy:49,msys2:[10,23,49],much:[7,20,21,23,24,25,26,27,28,36,40,49],multi:[5,8,19,20,34,38],multibyt:[20,44],multilanguag:3,multilin:20,multipl:[2,3,4,5,8,10,19,20,21,22,23,24,32,35,36,39,46],must:[2,7,11,19,20,22,23,25,26,31,37,44,45,46,47,49],mutabl:[31,35],mv:49,my:[2,3,7,8,21,44],my_ctag:0,myemacs_tag:0,myfunc:[21,35],mymethod:21,myrddin:23,mystruct:20,myvar:21,n:[2,7,11,12,14,15,16,18,20,21,22,25,26,31,35,40,44,46],naiv:20,name:[1,2,3,6,7,8,9,14,15,17,18,19,22,25,26,28,31,32,34,37,41,42,44,45,46,48,49],name_pattern:[19,20],nameattr:16,nameref:15,namespac:[14,15,20,25,31,35,40,44],narrow:7,nativ:[0,23,28,44,49],natur:[20,25],navig:2,nbyte:20,nc:31,ndk:0,ne:21,nearer:9,nearest:9,necessari:[5,22,25],necessarili:10,neck:20,nedit:[8,22],need:[0,6,7,9,10,14,19,20,21,22,23,25,27,35,36,37,40,44,45,46,47,49],neither:20,nest:[7,21,22,25,42,45,46],net:[3,10,18,19,20,21,22,27,28,48,49],nettyp:18,never:[7,10,20,25,31,35,46],new_field:22,newer:[42,46],newli:[2,9,19,20,23,24,25,31,44,45],newlin:[6,20,25,26,46],newmacrocallback:7,newmacrofound:45,newmacronotifi:[7,45],next:[7,9,10,20,22,24,25,27,31,45,46],nice:10,nicev:25,nil:9,nix:[1,5],nl:22,nmake:49,nmap:10,no_nomatch:10,no_parameter_port_list:18,node:[10,42],nois:5,non:[2,9,10,19,20,22,23,25,26,28,31,37,45,46,48],none:[9,12,14,15,16,17,18,20,24,31,44,46],nonomatch:10,nor:[20,25],normal:[9,20,22,27,35,49],notabl:[8,10,43],notat:[9,19,20,25,26,31,32,44],note:[8,9,10,12,14,15,16,18,19,21,22,23,24,25,28,32,35,37,45,48,49],notepad:3,noth:[7,19,20,23,25,28,31,45,46,48],notic:[2,9,14,15,21],notifi:[10,23],notori:25,now:[0,3,7,9,10,11,21,22,25,28,35,37,41,48],nowadai:23,nrole:[18,20,44],nsi:23,num:[19,24],number:[5,6,7,9,10,19,20,21,22,25,28,32,35,36,37,48],numer:[20,22],nvi:22,o:[2,9,11,12,14,15,16,17,18,19,20,25,31,33,35,37,44,45,46,47],obei:15,objc:[28,48],object:[2,5,6,7,9,13,15,17,20,25,28,31,33,44,48],objection:10,objectivec:[20,23],observ:20,obsolet:[8,24],obtain:[7,46],obviou:[2,22,25],obvious:49,ocaml:[28,48],occasion:[3,19],occur:[9,20,22,23,28,48],occurr:20,odd:25,off:[20,23,31,45],offer:21,offici:[10,19,20,21],offset:7,often:[10,20,22,25],ok:[31,46],old:[9,22,35,36,39,45,46,49],older:[10,20,25,46,49],omit:[19,20,22,25,41,44],omni:3,onc:[2,6,10,19,20,22,24,25,27,35,44,46],one:[0,2,3,6,7,8,9,11,16,17,19,20,21,22,23,24,25,28,31,32,35,36,37,39,44,46,48],onelin:[28,48],ones:[9,11,18,20,21,25,35],onli:[2,6,7,9,10,11,12,19,20,21,22,23,24,25,27,28,31,35,36,42,45,46,48,49],onto:25,oo:40,op:[20,26],opaqu:7,open:[6,9,11,20,28,37,44,48],oper:[2,8,9,10,21,25,31,35],opposit:9,opt:[0,19,26],optim:[22,36],option:[5,6,7,8,12,14,15,16,17,18,22,28,29,31,32,34,35,36,37,38,44,45,46,47,48,49],optlib2c:[2,5,24],optlib2c_input:[2,25],optlib:[2,3,4,5,7,8,11,23,28,31,45],optscript:[5,20],optsript:26,order:[3,5,10,20,21,37],ordinari:24,org:[3,10,17,18,19,20,22,28,34,39,48,49],orient:[0,20,26,36,37,39,40],origin:[7,9,10,20,22,23,28,31,33,47,48,49],orphan:[20,28],os:[1,5],osx:1,other:[1,2,3,5,7,9,10,14,15,17,19,20,21,22,24,25,27,31,34,35,36,37,45,46,47],otherwis:[9,13,20,24],our:[2,28,37],out:[0,2,3,20,22,23,27,28,46],outer:25,outlin:4,output:[2,4,5,6,8,11,12,13,14,15,16,17,19,24,26,31,35,37,44,46,47],outsid:[20,35,41],outstand:35,over:[6,20,22,25],overcom:20,overflow:[6,28,48],overhaul:7,overlap:[25,28,48],overli:[11,25],overload:20,overrid:[5,20,21,23,24,28,35,37,48],overridden:[18,46],overview:[8,28],overwrit:20,overwritten:20,own:[3,7,9,10,20,22,23,25,28,31,32,37,39,45,46,48],owner:[20,28,31,48],p1:18,p2:18,p3:18,p:[9,10,18,20,21,22,23,25,28,31,35,44,48,49],pacemak:49,packag:[0,10,18,20,27,28,48,49],package_kind:7,packcc:[0,4,5,23],page:[5,9,10,11,12,13,14,15,16,17,18,19,20,23,24,25,28,29,31,44,48],pai:25,pair:[7,19,20,21,23,46],parallel:10,param:[20,31,35],paramet:[2,7,9,19,20,24,25,29,35,39,46],parameter:11,parameterent:31,parent:[7,25],parenthes:[20,35],parenthesi:[20,21],pars:[2,4,7,8,11,19,20,22,23,25,26,28,34,35,36,39,45,48],parser2:37,parser:[3,5,8,9,11,12,13,16,17,18,21,22,24,28,29,32,47,48,49],parser_list:[2,25],parser_p:[2,25],parser_src:[2,37],parserdefinit:[7,37],parserdepend:7,parserfin:37,parseriniti:37,parsernew:[7,37],part:[0,2,5,7,9,10,22,23,25,27,28,37,41,42,45,46,48,49],partial:[19,20],particip:5,particular:[10,20,25],particularli:10,partit:20,partli:10,pascal:22,pass:[2,6,7,9,10,12,20,23,24,25,31,35,37,45,46,47],passwd:[23,25],past:[20,35],pat:9,patch:[2,44,46],path:[6,9,10,11,20,21,22,35,47,49],path_separ:[28,48],pathnam:[5,19,20],pattern:[5,6,7,8,10,12,19,20,21,22,26,28,29,37,38,44,45,46,48],paul:22,pdb:49,pdf:26,pdx:[20,22],peg:[7,23],peopl:[2,5,9,19,22,23,31,44],per:[6,7,20],perfect:20,perfectli:39,perform:[2,5,10,21,25,34,35,49],perhap:10,period:[10,20,42,49],perl6:23,perl:[8,20,23],perldoc:19,perlpod:19,permit:20,person:[2,3,5,19,20,24,28,44],perspect:25,php:[3,20,23,28,31,46,48],pick:[28,48],pipe:20,pipebuf:22,pitfal:[9,35],pkg:[0,28,48,49],pkg_config_libdir:0,pkg_config_path:0,pkgconfig:0,pl:[17,28,48],place:[20,25,26,31,35],placehold:[19,20,25],placement:25,plain:45,plan:35,platform:[2,3,10,20,23],pleas:[0,2,3,20,44,49],plist:23,pll:20,plpgsql:17,plpythonu:17,plu:[7,9,20],plug:3,plugin:[2,3,18,28,44],plural:23,plv8:17,pod:[8,23,25],point:[7,20,25,27,31,37,44,45,46],pointer:35,pointless:25,polici:[25,35],poor:49,pop:[19,20,25],popul:37,popular:[0,2,24,25,45],port:[18,49],portabl:22,portion:20,posit:[9,20,22,25,32,37,45,46],posix:[11,19,20,21,22,25,49],possess:25,possibl:[2,19,20,22,23,24,25,35,37,47],post:[21,25],postgresql:17,postscript:5,potenti:[2,10,20,22,25],power:[24,25,49],powershel:23,pp:25,pr0:25,pr1:25,pr:27,pragmawar:31,prebuilt:0,preced:[9,20],predic:21,prefer:[20,25,27],prefix:[0,2,7,9,19,20,21,22,25,26,31,32,35,41,46],preformat:44,preload:[8,19,20,24],prepar:[2,5,7,28,31,48],prepend:[20,32],preprocessor:[20,23,33],prerequisit:1,presenc:[10,20],present:[6,9,10,20,22,49],preserv:[27,35,49],press:20,pretti:27,pretty_var_expand:45,prevent:[9,11,20],previou:[8,20,25,35],previous:[20,24,25],primari:[2,3,5,25],primarili:[5,10],prin1:9,print:[10,19,20,21,25,26,31,32,42,47],printabl:19,printer:26,printf:32,prioriti:[31,32],privat:[7,19,20,25,40,44],privileg:0,probabl:9,probe:[7,45],probelanguag:7,problem:[3,9,10,20,21,22,39,49],proc:25,proce:27,procedur:[17,25,26],process:[2,6,7,9,10,19,20,23,24,25,27,35,46,49],processor:21,produc:[9,20,21,22,24,25,28,35,49],profession:49,profil:[36,47],program:[0,3,5,6,7,18,19,20,21,22,25,28,35,37,44,45,47,49],programm:24,programmat:[6,23],progress:[2,27,49],project:[0,2,3,5,9,10,19,20,21,22,23,24,27,49],project_nam:34,project_name_str:34,promis:[4,45],promot:31,prompt:[20,26,49],pronounc:44,proof:3,proofread:5,proper:[9,17,19,20,25,39,49],properli:[20,25,49],properti:[2,18,31,32],propertylist:[2,23],propos:[8,9,28,31],protect:[20,25,40,46],protobuf:[23,28,48],prototyp:[2,4,7,18,20,22,35,44],provid:[0,2,3,5,7,9,10,19,20,22,23,24,25,26,28,45,49],prune:10,pseudo:[8,20,21,22,29],pstack:26,ptag:9,pthon:23,ptr:20,ptrv:[28,48],pub:10,publish:26,pull:[5,25],puppet:[25,46],puppetmanifest:[5,23,25,43,46],purchas:49,pure:[18,20,35],purpos:[2,7,9,20,22,23,25,26,35,46],pursu:20,push:[2,19,25,26],put:[2,7,10,12,19,20,21,22,24,25,26,45,46],pwd:[0,10],px:20,py:[9,12,15,25,31,46],pygment:25,python2:[28,48],python3:[0,28,48],python:[5,8,9,12,16,17,20,21,23,25,26,28,43,46,48,49],python_keyword_2:31,pythonloggingconfig:23,q:[7,10,18,20,21,23,25,31,40],qemuhx:23,qingm:3,qq:3,qtmoc:23,qualifi:[4,5,10,20,31],qualiti:[3,26],quantifi:25,queri:[2,21],question:[10,31,45],queue:7,quick:[2,10,21],quickli:[10,19,20],quiet:[19,20,24,25],quirk:25,quit:[10,19,20,22,24,25,26,28,39,46,48],qunus:0,quot:[2,7,9,10,17,20,22,23,24,25,35,39,41],r3:17,r6class:23,r815:[28,48],r:[2,5,8,10,14,15,18,20,22,23,25,26,28,31,35,45,46,48],race:20,rais:[9,21],random:[2,14,15,16,46],randomli:2,rang:[22,25],ranlib:0,rare:[20,22,24,25],raspbian:3,rather:20,raw:4,rb:6,rc:20,re:[9,25,28,48],reach:[19,25,35],read:[2,4,6,7,8,9,10,11,19,20,22,23,24,25,26,28,46,48],readabl:[20,21,22,25,29,32,47],readcmd:47,reader:19,readi:[2,46,47],readili:3,readlinefrombypass:7,readlinefrombypassslow:7,readlinefrominputfil:[7,37],readlineraw:7,readlinerawwithnoseek:7,readm:[12,27],readtag:[0,5,8,20,22,47],real:[7,20,22,24,35,45],realist:25,realli:[10,20,22,25],rearrang:46,reason:[2,9,10,15,20,23,25,31,35,36,46,47],rebas:[2,28,48],rebuild:10,receiv:[2,6,7,20],recent:49,recip:5,recogn:[7,9,19,20,22,23,25,28,31,37,45,46,48,49],recognit:46,recommend:[10,19,22,23,26,49],record:[2,7,14,15,20,25,28,31,41,45,46,48],recov:[20,25],recurs:[10,20,35],red:[2,26],redhat:[2,3,23,25,28,33,38,40,42,44,46,47,48],reduc:[2,19,20,22],redund:[8,19,35],ref:[19,25,28,48],refactor:2,refect:23,refer:[7,8,9,14,15,18,19,20,21,23,28,29,32,34,44,45,46,48],referenc:[2,20,31,45],refin:[2,19,20],reflect:[28,35,48],refonli:[18,20,44],reftag:31,refus:20,reg_newlin:25,regard:[20,22,23,28],regardless:16,regener:10,regex:[2,4,5,8,9,11,12,20,23,24,26,28,34,38,44,45,48,49],regexlex:25,regexmatch:7,regexp:[9,19,21,28,48],regist:[4,18,23,45],registr:7,regress:[3,40,46],regrett:39,regular:[4,5,9,19,20,21,22,36],reject:[9,11,28,48],rel:[9,10,20,22,24,25],relat:[5,15,20,25,28,44,45],relationship:[5,15,45],relativefilenam:[28,48],relaxng:23,releas:[2,3,20,27,35,49],relev:25,reli:[9,20],reliabl:[35,47],remain:[9,10,20,49],remark:[8,22],rememb:[0,7,10,21,25,46],remot:[10,28,48],remov:[2,9,19,20,23,46,47],renam:[0,2,11,20,23],render:[20,44],repeat:[28,48],repeatedli:12,repl:[6,23],replac:[9,10,11,17,19,20,22,23,26,35],repo:[25,28,48],report:[2,5,19,20,28,35,40,45,46,48],repositori:[2,5,7,20,21,22,25,27,48,49],repres:[2,6,7,9,10,15,19,20,21,23,25,26,31,32,46],represent:[10,19,20],reproduc:[28,46,48],request:[5,6,7,25,41],requestautomaticfqtag:7,requir:[0,2,6,7,9,11,20,22,23,25,28,31,46,48,49],requiredbi:31,requisit:46,rescan:37,rescanpars:37,resembl:9,reserv:[11,19,22,31],reset:[20,28,48],resist:[10,20],resolv:[20,37],resort:31,resourc:[20,28,46,48],resource_:[28,48],respect:[20,25,29,31,36],respons:[2,6,45],rest:[7,9,11,19,20,25],restor:20,restrict:[9,11,18,22],restructuredtext:[22,23,31],result:[0,3,5,9,10,11,20,21,23,25,28,35,36,44,45,47,48],ret:20,retain:20,retri:20,reus:[7,11,44],review:[5,23,27],revis:[20,28,48],reviv:46,rewrit:[39,40],rewritten:[23,35,39,40],reza:[5,20],rge:23,rget:23,rich:10,riddl:39,right:[3,7,20,22,25,32,45],risk:[25,49],rm:49,robot:[23,31],robust:[3,39],role:[9,14,15,19,25,31,45,46],roledesc:25,root:[10,24,25,31,35,46],rough:2,roughli:19,routin:[10,20,37],rpmspec:23,rspec:23,rst:[2,46],rubi:[11,19,28,48],rule:[5,11,15,19,20,22,25,26,35,46],run:[0,2,3,4,5,6,9,10,17,20,21,22,23,24,26,27,35,36,40,44,49],runnabl:46,runtim:[20,49],rust:23,rzk:[14,15,46],rzkz:[14,15],s4class:23,s:[1,3,6,7,8,9,10,11,14,17,18,19,20,21,22,23,25,26,27,28,31,32,33,35,41,44,45,46,48,49],s_ok_to_be_correct:31,safe:[21,25],sai:[9,10,31,44,45],said:24,samborski:3,same:[0,2,7,8,9,19,20,21,22,25,26,27,29,32,46,49],sampl:[7,46],sandbox:[5,44],sap:22,satisfi:[10,21],save:[20,25],saw:25,scan:[7,10,20,25],scandir:49,scanfil:7,scanstr:7,schedul:[2,4,5,45],schedulerunningbasepars:[7,45],schedulerunningbasepas:7,scheme:[3,9,21,45],scope:[5,6,7,8,9,10,14,15,16,18,20,22,23,28,31,32,42,44],scopedenum:35,scopeindex:7,scopekind:[6,9,20],scopespeci:35,scratch:[35,39],script:[7,9,10,20,21,23,24,25,26,27,28,36,41,45],scss:23,sdk:0,search:[5,9,10,19,20,21,22,23,25,26,28],sec:10,seccomp:[0,6],second:[7,10,20,22,25,31,46],secondari:[2,3],section:[2,7,9,10,11,12,13,14,15,16,17,18,19,20,21,22,24,25,26,27,28,29,31,37,43,44,45],sectionmark:31,secur:[6,8,28,48],sed:[19,49],see:[0,2,4,7,8,23,24,25,26,27,28,29,30,31,32,35,37,44,45,46,47,49],seem:[9,20],seen:[20,22,25,35],segfault:[28,48],segment:[28,48],select:[8,10,22,23,27,28,46,48],selectlanguag:37,self:[2,9,10,28,31,48],semant:[2,28,47,48],semi:[5,22,25],semicolon:[9,10,20,22,39],send:[6,10,46],sens:[20,25,45],sensit:[19,27,49],sent:20,sentenc:44,sep:[25,28,31,48],separ:[2,9,10,19,20,21,22,23,24,31,32,36,39,40,42,46,49],sequenc:[2,9,17,18,20,22,23],seri:[28,48],seriou:25,server:10,servic:20,session:26,set:[0,2,3,7,8,9,19,20,22,23,24,25,26,31,34,37,46,49],set_one_prio:25,seth:[28,48],setm4quot:7,setopt:10,setprior:25,setuid:20,setup:49,sever:[10,22,25,28,35,36,37,39],sf:[2,28,48],sgraham:25,sh:[0,10,11,20,25,27,28,46,47,48,49],shamelessli:20,share:[7,28,35,45],sharedlib:34,shebang:[28,48],shell:[9,10,11,19,20,23,24,25,35,46,49],shift:[2,9],shigio:31,shortcut:49,shorten:25,shorter:[21,44],shortest:46,shorthand:25,shortli:25,should:[0,5,7,8,9,11,15,19,20,21,22,25,26,27,31,35,36,37,39,40,44,45,46,49],show:[0,2,9,20,21,23,31,44,45,46],show_bug:[28,48],shown:[0,7,19,20,24,25,35,45,47],shrink:46,shrunk:46,si:22,side:[7,9,19,45],sign:[20,35],signal:6,signatur:[15,20,25,31,35],signifi:20,signific:[10,20,24],significantli:[20,49],silent:20,similar:[2,10,15,19,25,32,35,45],simpl:[2,7,10,20,25,35,36,37,46],simplepars:37,simpler:[0,9],simplest:[6,37],simpli:[2,9,20,25,27,35,45],simplifi:[7,21,36],sinc:[9,10,14,19,20,21,22,24,25,27,35],singl:[6,9,10,19,20,22,24,25,35,39,49],singlequot:46,singletonmethod:11,site:[2,10,19,20,21,24,28,49],situat:[11,20,21],size:[6,10,11,20,22,37],sketch:2,skill:3,skip:[2,19,20,22,26,28,42,46,47,48],slap:5,slash:[20,25,31,49],slightli:25,sln:49,slot:32,slow:[25,49],slower:[22,35,36],sm4subpars:7,smakesubpars:45,small:[2,19,28,46],smaller:[21,32],smart:[20,22],snet:22,snippet:[2,25],so:[0,2,3,4,7,8,9,11,15,17,19,20,21,22,23,24,25,26,28,31,33,35,36,37,44,45,46,47,48,49],softwar:[5,10,20,49],sole:[9,22],solid:7,solut:[10,49],solv:[9,22,28,48],some:[0,2,3,5,7,9,10,11,19,20,22,23,25,26,28,31,35,37,38,39,40,44,45,46,48,49],someev:25,someon:10,someth:[19,20,22,25,31,44,47],sometim:[2,10,21,23,31,44,49],somewhat:0,somewher:[2,31],soon:[46,49],sort:[8,9,10,12,15,16,17,20,22,31,49],sorter:[8,21],sought:20,sourc:[0,2,3,5,7,9,10,11,13,14,15,16,17,18,19,20,22,23,24,26,31,32,35,37,38,44,45,46,47,49],source_fil:[11,20],sourcefil:31,sourceforg:[2,3,10,19,20,21,22,49],space:[5,19,20,21,22,24,25,26,32,49],span:[20,36,39],spars:47,sparserdefinit:37,speak:9,spec:[11,19,20,23,25,28,48],special:[19,20,22,25,26,31,35,45,46,49],specif:[2,5,7,8,9,11,12,21,22,25,26,29,32,37,49],specifi:[2,5,6,7,8,9,11,12,15,19,20,21,22,23,25,26,31,32,42,44,46,47,49],specparam:18,speech:49,speed:[3,35,36],split:9,spot:46,spring:25,spy:45,sql:[2,5,8,11,46],srb:19,src:10,srcdir:45,ssubpars:7,stabl:[2,19],stack:[12,19,25,26,45],stackoverflow:27,stage:[0,9,20,23],stall:[5,49],stand:[7,22,45],standard:[3,8,9,10,11,18,19,20,32,47],stare:12,start:[4,5,6,7,8,9,17,19,20,21,22,23,24,26,35,41,45,46,47,49],startup:20,state:[25,26,39],statement:[8,18,20,25,44],staticfunct:31,station:20,statist:20,statu:[19,28,44,46,47,48],std:18,stderr:[7,47],stdin:[6,46],stdio:[6,20,31],stdout:[6,46,47],steadili:3,stefanek:[3,35],step:[2,9,10,19,25,49],steve:[20,22],steveno:2,still:[7,9,10,11,22,23,25,28,46,47,48,49],stolen:20,stop:[25,26,46],store:[7,8,9,23,25,27,42,45],straightforward:27,strang:8,strategi:23,strcmp:[21,24],strcpy:[28,48],stream:[4,5,19,25],strict:17,stricter:19,strictli:9,string:[7,9,13,17,19,20,21,23,25,26,28,32,37,39,48],stringif:[20,35],stringifi:17,strip:[20,35],strlist:[28,48],strncmp:7,strongli:35,struct:[7,9,18,20,22,25,31,35,37,44,45],structur:[7,20,22,23,28,37],struggl:35,stubbornli:20,studi:7,style:[2,5,9,19,20,21,33,35,36],sub:[7,19,22,45,46],sub_lang:45,subdirectori:[46,49],subject:20,submit:[5,17,25,27],submod:5,submodul:44,subpars:[4,5,9,12,20,23,40],subparser_base_runs_sub:7,subparser_bi_direct:7,subparser_sub_runs_bas:7,subparserrundirect:7,subrubi:19,subscrib:25,subscript:25,subsect:[2,9,19,20,31],subsequ:[25,46],subset:[19,20,45],subshel:47,substitut:[19,32],substr:[21,23,25],subsubsect:19,subtl:[25,46],subvers:22,succe:25,successfulli:[25,26],sudo:0,suffer:22,suffici:25,suffix:[9,20,21,23,25,45,46],suggest:[9,46],suitabl:[2,4,20,22,23,25,26,31],summar:[2,10],summari:[8,20,22,46,49],supplement:49,suppli:[10,20],supplier:10,support:[2,3,5,6,8,9,12,17,19,20,22,23,25,28,29,31,35,37,39,40,42,46,48],suppos:37,suppress:[23,25],sure:[2,20,21,37,49],surround:[9,19,20,23,25,26,32],sv:18,svalu:22,svg:23,svh:18,svi:18,svn:[28,48],svr4:20,swap:[20,31],swine:37,swinepars:37,symbol:[2,7,14,20,23,25,31,35,44],synchron:20,synonym:[18,20],synopsi:8,syntact:[20,39,44],syntax:[5,7,20,25,28,35,36,45,46,49],syscal:25,syscall_defin:25,syscall_define3:25,sysint:10,sysroot:0,system:[0,6,9,10,20,22,25,26,27,28,31,46,49],systemd:7,systemdunit:[7,23,31],systemtap:23,systemverilog:[18,23],szymon:[3,35],t:[2,3,7,8,9,11,12,15,16,17,18,19,20,21,22,23,24,25,26,27,28,31,32,35,44,45,46,48],ta:[20,23],tab:[9,19,20,21,22,23,26],tabl:[5,20,34,37,38,45],tabular:[20,29,32],tag:[4,5,8,12,13,16,17,19,26,27,29,32,33,34,35,36,39,42,44,46,47,48,49],tag_extra_descript:9,tag_field_descript:9,tag_file_encod:[9,20,23],tag_file_format:9,tag_file_sort:9,tag_kind_descript:9,tag_kind_separ:9,tag_nam:20,tag_output_excmd:9,tag_output_filesep:9,tag_output_mod:[9,22],tag_pattern_length_limit:9,tag_proc_cwd:9,tag_program_author:9,tag_program_nam:9,tag_role_descript:9,tagaddress:22,tagbar:3,tagentryinfo:[7,37],tagfield:22,tagfil:[20,21,22],tagmanag:20,tagnam:22,tagrel:10,tail:[20,46],tailor:20,takata:3,take:[2,3,6,7,9,10,19,20,23,26,28,31,37,46,48],taken:[7,20,25,37,44,45,46,49],talk:44,tap:27,target:[2,19,20,23,31,34,46,47,49],task:[2,3,18,37,49],task_struct:25,tbw:[2,4,5,9,26],tcl:[5,23,25,43],tcloo:[23,40],tdm:49,tdragon:49,team:[2,44],techet:36,technic:25,techniqu:[21,45],tell:[21,22,35,44],templat:[2,20,25,31,35,42],temporari:[7,20],temporarili:49,tend:[10,20],tenter:25,term:[2,9,23],termin:[6,9,20,28,48,49],test1_var1:17,test1_var2:17,test1_var3:17,test2_var1:17,test2_var2:17,test2_var3:17,test:[3,5,6,7,10,11,17,19,20,23,25,28,38,44,48,49],test_var3:17,tex:22,text:[3,4,5,8,17,20,22,25,37],textual:20,th:25,than:[2,7,9,19,20,21,22,23,24,25,26,27,31,32,36,37,46,49],the_name_of_languag:25,thei:[2,3,7,9,10,14,18,19,20,21,22,25,28,31,32,35,40,41,45,46,48,49],them:[2,7,9,10,17,19,20,21,22,23,24,25,26,33,35,40,44,45,46,47,49],themselv:14,theoret:7,theori:25,therefor:[3,7,19,20,22,24,25,28,45,48,49],thi:[2,4,5,6,7,9,10,11,13,14,15,16,18,19,20,21,22,23,24,25,26,27,28,29,31,32,35,36,37,39,40,42,43,44,45,46,47,48,49],thing:[2,9,24,25,27,28,39,44,45,49],think:[2,7,15,19,20,25,44,45,46],third:[10,25,31],those:[3,10,20,21,24],though:[7,10,11,19,20,23,25,26,35,44,45],thoughtfulli:2,thousand:22,three:[10,19,20,23,25,35,44,45,49],through:[3,19,20,24,25,37],thu:[10,20,24,25,41],ticket:[28,48],till:[2,7],time:[2,3,6,7,8,16,19,20,22,24,25,26,28,31,35,44,46,47,48],tinst:[2,5,24],tip:[5,8,21,23],titl:[7,9,28,48],tjump:25,tleav:25,tm:26,tmain:[2,5,23,24,46],tmain_compar:47,tmain_run:47,tmp:[7,9,25,44,46],tmpdir:20,to_char:17,toctre:2,todai:25,todo:[7,23,28,48],togeth:[5,14,20,25,45,49],token:[7,17,20,31,35,36,37,39,40,45],tokeninfo:[4,5],toler:9,tom:22,tomasz:[3,35],too:[0,2,7,9,12,20,28,31,44,46,48,49],tool:[0,2,5,7,8,12,13,14,15,17,18,20,21,22,23,25,27,30,31,42,47,49],toolchain:[0,27,49],top:[2,7,12,16,19,20,23,25,31],topic:[2,9,20,29,43],toplevel:25,total:[20,32],touch:7,toward:49,tp_arg:45,tp_proto:45,tquit:25,track:[2,5,7,19,23,46],tracker:[2,28,48],tradit:[5,22,31,49],tradition:[22,31],trail:[20,22,28,35,48],trait:13,transform:[0,2],transit:25,translat:[2,5,7,9,21,24],travi:46,treat:[9,19,20,22,24,25,35],tree:[0,2,7,10,20,26,28,44,45,46,48],treset:25,tri:[20,23,24,25,28,35,45,46],trial:49,trick:[35,49],tricki:39,trigger:[25,46],trim:[9,17],tripl:[39,44],trivial:10,trojan:22,troubl:20,truli:37,truncat:[20,29,32,46],trunk:[28,48],ttcn:[2,23,28,48],tue:2,tupl:44,turn:[9,20,21,23,28,44,45,48],tutori:26,tweak:21,twice:[11,22],two:[0,2,6,7,9,10,19,20,21,22,23,24,25,26,31,35,37,44,45,46,49],two_altern:20,txt2tag:23,txt:[34,47],type:[2,4,8,10,18,19,20,22,25,31,35,36,45,46],typedef:[7,9,18,20,22,35],typenam:[9,11,15,20,25,31,35,44],typeref:[9,11,15,20,25,31,44],typescript:[2,3,23],typic:[2,10,20,25,45],u:[2,5,11,17,20,22,25,29,31,33,44],ubuntu:[0,3],uctag:20,uctagsend:20,ued:[28,48],uganda:20,ugli:20,uk:22,ultim:25,ultra:25,unabl:[20,46],unavail:46,unavoid:35,unbalanc:20,uncertain:21,unconstrain:20,uncov:10,uncrustifi:2,undef:[20,31,35],undefin:[13,20,22,25],under:[2,10,20,24,25,26,28,47,48,49],underscor:[2,20],understand:[2,19,20,23,25,26,28,35,39,44,48,49],understood:20,unescap:9,unexpect:46,unexpectedli:44,unfair:46,unfortun:[5,22],unhid:35,uni:22,unicod:8,unifi:[5,18,24],unintend:9,unintuit:25,union:[9,18,20,22,35],uniqu:[11,19,20,22],unit:[2,3,5,7,18,24,28,31,47,48,49],univers:[0,2,3,4,6,7,8,9,11,12,13,14,15,16,17,18,19,20,21,23,24,25,26,27,28,29,31,33,36,37,41,44,45,48,49],unix:[10,20,22,25,31,49],unknown:[7,14,15,20,25],unless:[19,20],unlik:[15,20,25,26],unmap:20,unmatch:10,unn:[28,48],unnam:19,unnecessari:2,unoffici:10,unpredict:22,unrecogn:9,unsav:6,unset:7,unsign:[7,37],unsort:[9,20,21,22],until:[20,21,25],unus:2,unusu:37,unwant:[12,31],uo:[18,20],up:[3,7,8,19,20,24,25,28,35,37,39,46,48],upcas:21,updat:[2,7,9,28,48],upon:[10,20],upper:[5,7,20,22,23,25,31],url:[2,22,44],us:[0,1,2,3,4,5,6,8,10,15,18,21,22,23,25,26,27,31,32,34,35,36,37,40,41,42,44,45,46,47,48],usabl:[22,25,28],usag:[4,16,20,22,23,25,29,35,46],usecork:[7,37],useless:20,user:[0,3,5,6,10,11,17,19,20,21,22,23,25,27,28,31,32,34,35,45,48,49],usr:[0,20,24],usual:[7,19,20,25,46],utf:[20,28,48],util:[2,7,8,10,19,20,21,26,28,31,33,45,49],utmost:28,v1:23,v7a:0,v8:17,v:[0,9,12,16,17,18,20,22,23,25,31],va_format:45,vaf:45,val:17,vala:28,valgrind:[2,47],valid:[5,9,13,20,21,39,44],valink:7,valu:[7,9,15,16,18,19,20,21,22,23,25,26,28,31,32,42,45,46,48],valuenotifi:45,valuesfound:45,var0:15,var1:15,varchar:17,variabl:[0,2,7,8,9,15,16,18,21,22,24,26,31,34,35,39,41,45,46],variant:46,variat:46,varieti:[3,20,23,31,37,46],variou:[2,3,9,17,20,28,31],varlink:23,vberthoux:10,vcxproj:[2,49],ve:[2,3,25],vector:16,vendor:49,verbos:[20,23,42],veri:[7,19,20,24,25,27,36,39,45,46,49],verif:18,verifi:[11,47],verilog:[3,5,8,23,46],versa:24,versatil:28,version:[2,3,5,6,7,9,10,11,12,13,14,15,16,17,18,19,20,21,22,24,25,27,28,31,42,44,46,48,49],vfm:9,vg:[2,28,46,48],vhd:46,vi:[8,10,44],via:[7,15,23,35,44,46],vice:24,view:[28,45,48],vile:22,vim:[3,5,10,12,20,22,23,43,46,48],violat:[19,22],virtual:[20,31,35],viru:49,visibl:[20,37],visit:[19,20,24],visual:10,visualstudio:49,vitor:3,volatil:35,vs2012:49,vs2013:49,vs:20,vstring:7,vstringlength:7,vstringvalu:7,vt:22,w64:49,w:[16,18,20,26],wa:[5,6,7,10,20,22,23,24,25,28,31,35,36,39,40,46,47,48,49],wai:[0,2,6,7,9,10,15,19,20,22,23,24,25,28,35,38,39,44,45,46,49],wait:2,wall:47,want:[0,2,6,8,11,15,18,19,20,21,25,26,31,37,44,45,46,49],wantedbi:31,war:45,warm:25,warn:[11,19,22,23,25,47],warning_cflag:47,we:[0,2,5,7,9,10,14,15,19,21,22,23,24,25,27,28,44,45,46,48],weak:[8,20,31],wealth:20,web:[2,5,10,19,20,21,26],websit:3,welcom:[2,5,44],well:[2,3,7,16,25,26,31,35,40,44,46,47,49],wendl:[3,7,39],were:[7,20,23,24,25,35,36,39,46],wextra:47,what:[7,8,9,19,20,21,22,24,25,31,37,39,44,46,49],whefxlr:[28,48],when:[0,2,3,6,7,8,9,11,12,19,20,21,22,23,24,25,26,27,28,31,32,35,37,40,42,44,45,46,47,48,49],where:[0,2,3,5,6,7,9,10,19,20,21,22,25,27,31,32,35,44,45,47,49],wherea:20,wherev:19,whether:[2,7,9,10,14,15,16,20,21,23,25,31,45,46],which:[0,3,5,6,7,8,9,11,18,19,20,21,22,23,24,25,31,32,35,37,44,45,46,49],whichev:19,white:[19,20,22,32],whitespac:[2,11,24,25,28,31,48],whitespaceswap:31,who:[0,2,5,9,19,20,21,25,31,46],whole:[10,19,21,25,35],whose:[10,18,20,31,32],why:[7,8,14,15],wide:[20,23,25],width:32,wiki:[28,48],wikipedia:[28,48],wild:[31,32],wildcard:[20,25,44],win32:[2,3,20,49],window:[1,3,5,10,20,23,24,28,31,48],windr:[3,23,28,48],wip:2,wireshark:23,wish:10,with_empty_parameter_port_list:18,with_iconv:[23,49],with_parameter_port_list:18,withdefinedirect:45,within:[10,19,20,25,31,35,36,44,46,49],without:[2,7,9,10,19,20,22,23,25,31,35,46,49],won:[9,25],wonder:19,word:[9,19,20,25,31],work:[2,3,5,7,9,10,11,12,20,21,22,23,24,25,27,28,40,44,45,46,47,48,49],workaround:[10,20],world:26,wors:20,worship:20,worth:[28,44],would:[2,10,20,21,22,24,25,49],wouldn:27,wrap:[9,21],write:[3,4,5,7,9,10,19,20,21,22,23,25,26,31,35,44,45,47],writeentri:7,writer:[7,37],writert:7,writerwritetag:7,writetagentri:7,written:[0,5,7,9,17,20,22,24,25,26,27,28,35,36,45,46,48,49],wrong:[8,20,25,46],wrote:[2,3],wspars:47,www:[2,10,17,20,49],x0:[14,15,44,46],x1:[14,15],x20:22,x21:22,x2:[14,15],x3:[14,15],x4:15,x64:49,x86_64:[0,49],x:[9,12,14,15,19,20,22,25,26,28,29,31,32,35,44,45,46,47,48],xbb:23,xbf:23,xcode:27,xdg_config_hom:[20,24],xef:23,xfmt:31,xml:[11,49],xname:25,xpath:[42,44],xplang:17,xref:[5,20,29,31],xrefwrit:7,xsl:42,xslt:[5,23,43],xxx:22,xyz2:17,xyz:[17,22],xz:49,y0:44,y1:15,y3:15,y4:15,y:[7,14,15,20,25,26,28,31,35,44,48],yacc:[7,23],yamato:[2,3,7,23,25,28,33,38,40,42,44,46,47,48],yaml:[23,31,44],ye:[9,10,11,18,20,23,49],year:3,yet:[3,20,25,28,35],yml:0,yoshida:7,you:[0,3,4,5,7,9,10,11,12,15,18,19,20,21,23,24,25,26,27,28,31,32,35,37,44,45,46,47,48,49],young:2,your:[3,7,9,10,12,19,20,21,23,24,25,26,27,28,31,37,44,48,49],yumrepo:[7,23],yyerror:7,z0:[19,25],z4:15,z:[10,11,15,19,20,23,25,28,32,48],z_0:25,z_:25,za:[19,25],zephir:23,zero:46,zeu:22,zip:49,zk:20,zsh:[2,8,20],zshrc:10,zzz:24},titles:["Building with configure (*nix including GNU/Linux)","Building ctags","Contributions","Who we are","Extending ctags with a parser written in C","Universal Ctags Hacking Guide","Interactive mode","Input text stream","Man pages","ctags-client-tools","ctags-faq","ctags-incompatibilities","ctags-lang-iPythonCell","ctags-lang-inko","ctags-lang-julia","ctags-lang-python","ctags-lang-r","ctags-lang-sql","ctags-lang-verilog","ctags-optlib","ctags","readtags","tags","Other changes","Option files","Extending ctags with Regex parser (optlib)","Optscript, a programming language for extending optlib parsers","Building on Mac OS","Relationship between other projects","Output formats","JSON output","Changes to the tags file format","Xref output","Asm parser","CMake parser","The new C/C++ parser","The new HTML parser","Writing a parser in C","puppetManifest parser","The new Python parser","The new Tcl parser","The Vim parser","XSLT parser","Parsers","Request for extending a parser (or Reporting a bug of parser)","Running multiple parsers on an input file","Testing a parser","Testing ctags","Tracking other projects","Building/hacking/using on MS-Windows"],titleterms:{"8":23,"case":[2,46],"class":10,"do":10,"function":[7,10],"import":[14,15,23,46],"long":[10,11,23,31],"new":[2,23,25,35,36,39,40],A:11,AND:[14,15],FOR:[9,19],No:24,TO:20,The:[7,11,25,26,35,36,39,40,41,44],WITH:20,_guest:25,about:9,accept:11,acknowledg:46,action:21,ad:[25,37],add:2,advanc:25,all:10,alphabet:11,also:[9,10,11,12,13,14,15,16,17,18,19,20,21,22],alwai:23,an:[9,23,24,25,44,45,46],anjuta:28,anonym:35,api:7,append:10,appli:45,applic:11,ar:[3,10],area:45,argument:[23,25],arrang:11,asm:33,author:[10,19,20],autoconf:45,automak:45,automat:[7,23,25,35],avoid:[10,24],background:[7,45],backward:22,bad:46,base:[7,45],basic:[2,25],befor:[2,44],begin:10,behavior:21,between:[10,26,27,28,49],bidirect:25,bit:10,block:[25,49],bom:23,bottleneck:47,bottom:45,bug:[17,20,28,40,44,46,48],build:[0,1,2,9,27,49],bypass:7,c:[2,4,20,25,35,37,45],call:7,can:10,captur:25,categori:46,caus:10,caveat:20,chang:[0,2,23,31,35,41],charact:11,check:47,choic:45,chop:46,client:9,cmake:34,code:[25,49],codebas:2,combin:[11,25,45],command:[2,11,20,23,26,35,45,46,49],comment:25,commit:2,compat:[2,22],compil:[0,7,49],complement:23,condit:25,configur:[0,24],content:[2,10,20,23,25,26,28,44,46,47],contribut:[2,27],control:[21,25],cork:7,coverag:47,cppcheck:47,cpreprocessor:23,credit:[20,21],cross:0,css:45,ctag:[1,4,5,9,10,11,12,13,14,15,16,17,18,19,20,22,23,24,25,26,28,37,47,48,49],custom:[12,25,32],d:23,data:[9,26],debian:[28,48],declar:25,dedic:25,defin:[2,11,19,23,25,35],definit:[11,19,45],descript:[9,10,11,12,13,14,15,16,17,18,19,20,21,22],design:7,detail:20,determin:20,devel:[28,48],develop:[2,27],differ:[10,24,26,27,49],direct:[25,45],directori:[10,24,46],disabl:23,disallow:11,discuss:31,distribut:0,document:2,doe:10,down:45,e:27,emac:[2,20],enabl:23,encod:23,end:[10,25],engin:[25,28],entri:[20,23],environ:[11,20],error:10,everi:10,exampl:[2,14,15,17,19,21,25,44,45,46],except:[22,23],exclud:23,exclus:25,execut:0,expand:[23,35],experiment:[23,25,35],express:[7,9,14,15,21,25],extend:[4,7,22,23,25,26,44],extens:[11,20,24,26],extra:[12,20,23,25,31],exuber:[10,23,24,28,48],f:[11,31],facil:[46,47],faq:10,favorit:10,featur:35,fedora:[28,48],field:[7,9,18,20,23,25,31],file:[9,10,11,19,20,22,23,24,25,31,35,37,45,46],filter:[9,21,23],find:[46,47],flag:[19,25,45],follow:10,format:[9,11,20,22,29,31],found:10,from:[7,22,23,24,25,35,46,49],full:[2,7,40],fulli:[23,25],fussi:47,fuzz:46,g:23,gather:46,gcc:49,geani:28,gener:[6,7,25],ghost:7,global:28,gnu:[0,2,20,27,28,49],goal:22,good:44,group:7,guess:[7,20,23],guest:[7,25,45],guid:5,hack:[5,49],have:10,heurist:20,hierarchi:10,higher:45,highli:[23,35],highlight:28,hint:15,homebrew:27,how:[2,7,10,20,46],html:[36,45],i:[10,27],id:49,idea:7,improv:23,includ:[0,23],incompat:[11,23,24,35,41],inform:[2,25,35],inherit:35,inko:13,input:[7,9,11,20,23,31,35,37,45,46],inputfil:7,inspect:[21,23],instal:47,instead:10,interact:[6,23],interest:28,interfac:[11,20,45],intern:[7,23],introduct:[22,35,36,39],ipythoncel:12,issu:[18,24],its:7,japan:28,javascript:45,json:[9,30],julia:14,jump:10,kernel:28,kind:[2,7,9,11,12,16,18,20,23,25,31],known:[17,18,40,46],lambda:15,lang:[11,12,13,14,15,16,17,18,19,23],langdef:11,langmap:11,languag:[2,9,11,18,20,26,45,46],learn:26,letter:[11,20,25],level:[10,45],licens:2,line:[2,10,11,20,23,25,31,35,45,49],linux:[0,27,28,49],list:[9,20,23,24,28,45,48],load:[11,24],locat:10,log:2,m4:45,mac:27,macro:[23,35],mail:[28,48],main:47,make:[7,9,45],man:[2,8,46],manag:[7,24],mani:10,manual:27,map:[20,23],match:[10,25],maxdepth:23,member:10,messag:23,method:7,microsoft:49,minim:46,misc:37,miscellan:20,mode:[6,23],motiv:20,ms:49,multi:[10,25],multilin:25,multipl:[7,9,25,45],my:10,n:23,name:[0,10,11,20,21,23,35],nedit:20,nest:40,never:23,nix:0,nois:46,notabl:[9,35],note:[2,20,46],notic:23,number:23,numer:11,obsolet:[11,20],one:10,opengrok:28,oper:[20,26],option:[2,9,10,11,19,20,21,23,24,25,26],optlib2c:25,optlib:[19,20,24,25,26],optscript:26,order:[11,24],orient:24,origin:2,os:27,osx:27,other:[11,23,28,48,49],our:25,outlin:7,output:[7,9,20,21,22,23,25,29,30,32],overrid:25,overview:19,packcc:7,page:[2,8,46],paramet:[18,31],pars:[9,37],parser:[2,4,7,19,20,23,25,26,31,33,34,35,36,37,38,39,40,41,42,43,44,45,46],part:[11,47],patch:[28,48],path:24,pathnam:24,pattern:[9,11,23,25,31],perform:47,perl:[19,45],pod:[19,45],postscript:26,prefix:23,preload:11,prepar:26,preprocessor:35,prerequisit:27,previou:9,print:23,proc:40,program:26,project:[28,48],promis:7,properti:35,propos:22,pseudo:[9,23,31],pull:2,puppetmanifest:38,put:23,pygment:28,python:[15,39],qualifi:[2,7,25,40],quiet:23,r:16,raw:7,read:[21,37],readtag:[9,21,23],realist:2,recip:26,redund:9,refer:[2,10,17,25,31],regex:[7,19,25],regist:[7,37],regular:[7,25],rel:23,relat:[23,26],relationship:28,remark:9,remov:11,report:44,repositori:28,request:[2,44],result:46,review:[2,46],role:[2,20],rule:2,run:[7,25,45,46,47],s:[0,12],same:[10,23,35],sandbox:6,schedul:[7,25],scope:[2,11,19,25,35],script:2,secur:22,see:[9,10,11,12,13,14,15,16,17,18,19,20,21,22],select:20,semi:46,separ:25,sequenc:25,session:46,set:10,share:25,should:[2,10],skip:[23,25],slap:46,so:10,softwar:28,sort:[21,23],sorter:9,sourc:[25,28],sourceforg:[28,48],specif:[10,18,20,23,31,46],specifi:[10,24,45],sql:17,squash:2,standard:22,start:[2,11,25],statement:15,store:19,strang:10,stream:[7,37],structur:35,studio:49,submit:2,submod:6,subpars:[7,25,45],subvers:[28,48],summari:[14,15],support:[10,18],synchron:23,synopsi:[9,11,12,13,14,15,16,17,18,19,20,21],syntax:[26,47],system:24,t:10,tabl:[2,23,25,26,28,44,46,47],tag:[2,6,7,9,10,11,14,15,20,21,22,23,25,28,31,37,40,45],tag_kind_descript:31,tag_kind_separ:31,tag_output_filesep:31,tag_output_mod:31,tagbar:28,tagfield:11,tbw:7,tcl:40,term:45,test:[2,46,47],text:[7,10],than:11,time:[10,11],timeout:46,tinst:47,tip:[18,24],titl:2,tmain:47,todo:47,tokeninfo:7,tool:9,top:45,track:[25,28,48],translat:25,truncat:[11,31],type:[7,9,15,26],typeref:35,under:46,unicod:10,unit:46,univers:[5,10,22],up:[10,11,45],upper:45,us:[7,9,11,14,19,20,24,28,49],usag:[7,31],user:2,utf:23,util:9,valgrind:46,valid:46,variabl:[10,11,20,25],verilog:18,vi:[20,22],vim:[28,41],visual:49,want:10,we:3,weak:22,what:[2,10],when:10,which:10,who:3,why:10,wide:24,wildcard:23,window:49,write:[2,24,37,46],written:4,wrong:10,xref:32,xslt:42,yacc:45,you:2,your:2,zsh:10}}) \ No newline at end of file diff --git a/ctags/docs/testing.html b/ctags/docs/testing.html new file mode 100644 index 0000000..83b5d5f --- /dev/null +++ b/ctags/docs/testing.html @@ -0,0 +1,754 @@ + + + + + + + + + Testing a parser — Universal Ctags 0.3.0 documentation + + + + + + + + + + + + + + + +
+
+
+
+ +
+

Testing a parser

+ +

It is difficult for us to know syntax of all languages supported in ctags. Test +facility and test cases are quite important for maintaining ctags with limited +resources.

+
+

Units test facility

+
+
Maintainer
+

Masatake YAMATO <yamato@redhat.com>

+
+
+
+

Test facility

+

Exuberant Ctags has a test facility. The test case were Test +directory. So Here I call it Test.

+

Main aim of the facility is detecting regression. All files under Test +directory are given as input for old and new version of ctags +commands. The output tags files of both versions are compared. If any +difference is found the check fails. Test expects the older ctags +binary to be correct.

+

This expectation is not always met. Consider that a parser for a new +language is added. You may want to add a sample source code for that +language to Test. An older ctags version is unable to generate a +tags file for that sample code, but the newer ctags version does. At +this point a difference is found and Test reports failure.

+

Units facility

+

The units test facility (Units) I describe here takes a different +approach. An input file and an expected output file are given by a +contributor of a language parser. The units test facility runs ctags +command with the input file and compares its output and the expected +output file. The expected output doesn’t depend on ctags.

+

If a contributor sends a patch which may improve a language parser, +and if a reviewer is not familiar with that language, s/he cannot +evaluate it.

+

Unit test files, the pair of input file and expected output file may +be able to explain the intent of patch well; and may help the +reviewer.

+
+

How to write a test case

+

The test facility recognizes an input file and an expected +output file by patterns of file name. Each test case should +have its own directory under Units directory.

+

Units/TEST/input.* requisite

+
+

Input file name must have a input as basename. TEST +part should explain the test case well.

+
+

Units/TEST/input[-_][0-9].* Units/TEST/input[-_][0-9][-_]*.* optional

+
+

Optional input file names. They are put next to input.* in +testing command line.

+
+

Units/TEST/expected.tags optional

+
+

Expected output file must have a name expected.tags. It +should be the same directory of the input file.

+

If this file is not given, the exit status of ctags process +is just checked; the output is ignored.

+

If you want to test etags output (specified with -e ), +Use .tags-e as suffix instead of .tags. +In such a case you don’t have to write -e to args.ctags. +The test facility sets -e automatically.

+

If you want to test cross reference output (specified with -x ), +Use .tags-x as suffix instead of .tags. +In such a case you don’t have to write -x to args.ctags. +The test facility sets -x automatically.

+

If you want to test json output (specified with --output-format=json ), +Use .tags-json as suffix instead of .tags. +In such a case you don’t have to write --output-format=json to args.ctags, +and add json to features as described below. +The test facility sets the option and the feature automatically.

+
+

Units/TEST/args.ctags optional

+
+

-o - is used as default optional argument when running a +unit test ctags. If you want to add more options, enumerate +options in args.ctags file.

+

Remember you have to put one option in one line; don’t +put multiple options to one line. Multiple options in +one line doesn’t work.

+
+

Units/TEST/filter optional

+
+

You can rearrange the output of ctags with this command +before comparing with executed.tags. +This command is invoked with no argument. The output +ctags is given via stdin. Rearrange data should be +written to stdout.

+
+

Units/TEST/features optional

+
+

If a unit test case requires special features of ctags, +enumerate them in this file line by line. If a target ctags +doesn’t have one of the features, the test is skipped.

+

If a file line is started with !, the effect is inverted; +if a target ctags has the feature specified with !, the +test is skipped.

+

All features built-in can be listed with passing +--list-features to ctags.

+
+

Units/TEST/languages optional

+
+

If a unit test case requires that language parsers are enabled/available, +enumerate them in this file line by line. If one of them is +disabled/unavailable, the test is skipped.

+

language parsers enabled/available can be checked with passing +--list-languages to ctags.

+
+
+
+

Note for importing a test case from Test directory

+

I think all test cases under Test directory should be converted to +Units.

+

If you convert use following TEST name convention.

+
    +
  • use .t instead of .d as suffix for the name

  • +
+

Here is an example:

+
Test/simple.sh
+
+
+

This should be:

+
Units/simple.sh.t
+
+
+

With this name convention we can track which test case is converted or +not.

+
+
+

Example of files

+

See Units/parser-c.r/c-sample.d.

+
+
+

How to run unit tests

+

test make target:

+
$ make units
+
+
+

The result of unit tests is reported by lines. You can specify +test cases with UNITS=.

+

An example to run vim-command.d only:

+
$ make units UNITS=vim-command
+
+
+

Another example to run vim-command.d and parser-python.r/bug1856363.py.d:

+
$ make units UNITS=vim-command,bug1856363.py
+
+
+

During testing OUTPUT.tmp, EXPECTED.tmp and DIFF.tmp files are +generated for each test case directory. These are removed when the +unit test is passed. If the result is FAILED, it is kept for +debugging. Following command line can clean up these generated files +at once:

+
$ make clean-units
+
+
+

Other than FAILED and passed two types of result are +defined.

+

skipped

+
+

means running the test case is skipped in some reason.

+
+

failed (KNOWN bug)

+
+

means the result was failed but the failure is expected. +See “Gathering test cases for known bugs”.

+
+
+
+

Example of running

+
$ make units
+Category: ROOT
+-------------------------------------------------------------------------
+Testing 1795612.js as JavaScript                            passed
+Testing 1850914.js as JavaScript                            passed
+Testing 1878155.js as JavaScript                            passed
+Testing 1880687.js as JavaScript                            passed
+Testing 2023624.js as JavaScript                            passed
+Testing 3184782.sql as SQL                                  passed
+...
+
+
+
+
+

Running unit tests for specific languages

+

You can run only the tests for specific languages by setting +LANGUAGES to parsers as reported by +ctags --list-languages:

+
make units LANGUAGES=PHP,C
+
+
+

Multiple languages can be selected using a comma separated list.

+
+
+

Gathering test cases for known bugs

+

When we meet a bug, it is an important development activity to make a small test +case that triggers the bug. +Even the bug cannot be fixed in soon, +the test case is an important result of work. Such result should +be merged to the source tree. However, we don’t love FAILED +message, too. What we should do?

+

In such a case, merge as usually but use .b as suffix for +the directory of test case instead of .d.

+

parser-autoconf.r/nested-block.ac.b/ is an example +of .b``* suffix usage.

+

When you run test.units target, you will see:

+
Testing c-sample as C                                 passed
+Testing css-singlequote-in-comment as CSS             failed (KNOWN bug)
+Testing ctags-simple as ctags                         passed
+
+
+

Suffix .i is a variant of .b. .i is for merging/gathering input +which lets ctags process enter an infinite loop. Different from .b, +test cases marked as .i are never executed. They are just skipped +but reported the skips:

+
Testing ada-ads as Ada                                passed
+Testing ada-function as Ada                           skipped (may cause an infinite loop)
+Testing ada-protected as Ada                          passed
+...
+
+Summary (see CMDLINE.tmp to reproduce without test harness)
+------------------------------------------------------------
+  #passed:                                347
+  #FIXED:                                 0
+  #FAILED (unexpected-exit-status):       0
+  #FAILED (unexpected-output):            0
+  #skipped (features):                    0
+  #skipped (languages):                   0
+  #skipped (infinite-loop):               1
+    ada-protected
+  ...
+
+
+
+
+

Running under valgrind and timeout

+

If VG=1 is given, each test cases are run under valgrind. +If valgrind detects an error, it is reported as:

+
$ make units VG=1
+Testing css-singlequote-in-comment as CSS             failed (valgrind-error)
+...
+Summary (see CMDLINE.tmp to reproduce without test harness)
+------------------------------------------------------------
+...
+#valgrind-error:                        1
+  css-singlequote-in-comment
+...
+
+
+

In this case the report of valgrind is recorded to +Units/css-singlequote-in-comment/VALGRIND-CSS.tmp.

+

NOTE: /bin/bash is needed to report the result. You can specify a shell +running test with SHELL macro like:

+
$ make units VG=1 SHELL=/bin/bash
+
+
+

If TIMEOUT=N is given, each test cases are run under timeout +command. If ctags doesn’t stop in N second, it is stopped +by timeout command and reported as:

+
$ make units TIMEOUT=1
+Testing css-singlequote-in-comment as CSS             failed (TIMED OUT)
+...
+Summary (see CMDLINE.tmp to reproduce without test harness)
+------------------------------------------------------------
+...
+#TIMED-OUT:                             1
+  css-singlequote-in-comment
+...
+
+
+

If TIMEOUT=N is given, .i test cases are run. They will be +reported as TIMED-OUT.

+
+
+

Categories

+

With .r suffix, you can put test cases under a sub directory +of Units. Units/parser-ada.r is an example. If misc/units +test harness, the sub directory is called a category. parser-ada.r +is the name category in the above example.

+

CATEGORIES macro of make is for running units in specified categories. +Following command line is for running units in +Units/parser-sh.r and Units/parser-ada.r:

+
$ make units CATEGORIES='parser-sh,parser-ada'
+
+
+
+
+

Finding minimal bad input

+

When a test case is failed, the input causing FAILED result is +passed to misc/units shrink. misc/units shrink tries to make the +shortest input which makes ctags exits with non-zero status. The +result is reported to Units/\*/SHRINK-${language}.tmp. Maybe +useful to debug.

+
+
+

Acknowledgments

+

The file name rule is suggested by Maxime Coste <frrrwww@gmail.com>.

+
+
+
+

Reviewing the result of Units test

+

Try misc/review.

+
$ misc/review --help
+Usage:
+        misc/review          help|--help|-h                 show this message
+        misc/review          [list] [-b]                    list failed Units and Tmain
+                             -b                             list .b (known bug) marked cases
+        misc/review          inspect [-b]                   inspect difference interactively
+                             -b                             inspect .b (known bug) marked cases
+$
+
+
+
+
+

Semi-fuzz(Fuzz) testing

+

Unexpected input can lead ctags to enter an infinite loop. The fuzz +target tries to identify these conditions by passing +semi-random (semi-broken) input to ctags.

+
$ make fuzz LANGUAGES=LANG1[,LANG2,...]
+
+
+

With this command line, ctags is run for random variations of all test +inputs under Units/*/input.* of languages defined by LANGUAGES +macro variable. In this target, the output of ctags is ignored and +only the exit status is analyzed. The ctags binary is also run under +timeout command, such that if an infinite loop is found it will exit +with a non-zero status. The timeout will be reported as following:

+
[timeout C]                Units/test.vhd.t/input.vhd
+
+
+

This means that if C parser doesn’t stop within N seconds when +Units/test.vhd.t/input.vhd is given as an input, timeout will +interrupt ctags. The default duration can be changed using +TIMEOUT=N argument in make command. If there is no timeout but +the exit status is non-zero, the target reports it as following:

+
[unexpected-status(N) C]                Units/test.vhd.t/input.vhd
+
+
+

The list of parsers which can be used as a value for LANGUAGES can +be obtained with following command line

+
$ ctags --list-languages
+
+
+

Besides LANGUAGES and TIMEOUT, fuzz target also takes the +following parameters:

+
+

VG=1

+
+

Run ctags under valgrind. If valgrind finds a memory +error it is reported as:

+
[valgrind-error Verilog]                Units/array_spec.f90.t/input.f90
+
+
+

The valgrind report is recorded at +Units/\*/VALGRIND-${language}.tmp.

+
+
+

As the same as units target, this semi-fuzz test target also calls +misc/units shrink when a test case is failed. See “Units test facility” +about the shrunk result.

+
+
+

Noise testing

+

After enjoying developing Semi-fuzz testing, I’m looking for a more unfair +approach. Run

+
$ make noise LANGUAGES=LANG1[,LANG2,...]
+
+
+

The noise target generates test cases by inserting or deleting one +character to the test cases of Units.

+

It takes a long time, even without VG=1, so this cannot be run +under Travis CI. However, it is a good idea to run it locally.

+
+
+

Chop and slap testing

+

After reviving many bug reports, we recognized some of them spot +unexpected EOF. The chop target was developed based on this recognition.

+

The chop target generates many input files from an existing input file +under Units by truncating the existing input file at variety file +positions.

+
$ make chop  LANGUAGES=LANG1[,LANG2,...]
+
+
+

It takes a long time, especially with VG=1, so this cannot be run +under Travis CI. However, it is a good idea to run it locally.

+

slap target is derived from chop target. While chop target truncates +the existing input files from tail, the slap target does the same +from head.

+
+
+

Input validation for Units

+

We have to maintain parsers for languages that we don’t know well. We +don’t have enough time to learn the languages.

+

Units test cases help us not introduce wrong changes to a parser.

+

However, there is still an issue; a developer who doesn’t know a +target language well may write a broken test input file for the +language. Here comes “Input validation.”

+
+

How to run an example session of input validation

+

You can validate the test input files of Units with validate-input +make target if a validator or a language is defined.

+

Here is an example validating an input file for JSON.

+
$ make validate-input VALIDATORS=jq
+...
+Category: ROOT
+------------------------------------------------------------
+simple-json.d/input.json with jq                                 valid
+
+Summary
+------------------------------------------------------------
+  #valid:                                 1
+  #invalid:                               0
+  #skipped (known invalidation)           0
+  #skipped (validator unavailable)        0
+
+
+

This example shows validating simple-json.d/input.json as an input +file with jq validator. With VALIDATORS variable passed via +command-line, you can specify validators to run. Multiple validators +can be specified using a comma-separated list. If you don’t give +VALIDATORS, the make target tries to use all available validators.

+

The meanings of “valid” and “invalid” in “Summary” are apparent. In +two cases, the target skips validating input files:

+

#skipped (known invalidation)

+
+

A test case specifies KNOWN-INVALIDATION in its validator file.

+
+

#skipped (validator unavailable)

+
+

A command for a validator is not available.

+
+
+
+

validator file

+

validator file in a Units test directory specifies which +validator the make target should use.

+
$ cat Units/simple-json.d/validator
+jq
+
+
+

If you put validator file to a category directory (a directory +having .r suffix), the make target uses the validator specified in +the file as default. The default validator can be overridden with a +validator file in a subdirectory.

+
$ cat Units/parser-puppetManifest.r/validator
+puppet
+# cat Units/parser-puppetManifest.r/puppet-append.d/validator
+KNOWN-INVALIDATION
+
+
+

In the example, the make target uses puppet validator for validating +the most of all input files under Units/parser-puppetManifest.r +directory. An exception is an input file under +Units/parser-puppetManifest.r/puppet-append.d directory. The +directory has its specific validator file.

+

If a Unit test case doesn’t have expected.tags file, the make +target doesn’t run the validator on the file even if a default +validator is given in its category directory.

+

If a Unit test case specifies KNOWN-INVALIDATION in its validator +file, the make target just increments “#skipped (known invalidation)” +counter. The target reports the counter at the end of execution.

+
+
+

validator command

+

A validator specified in a validator file is a command file put +under misc/validators directory. The command must have “validator-” +as prefix in its file name. For an example, +misc/validators/validator-jq is the command for “jq”.

+

The command file must be an executable. validate-input make target +runs the command in two ways.

+

is_runnable method

+
+

Before running the command as a validator, the target runs +the command with “is_runnable” as the first argument. +A validator command can let the target know whether the +validator command is runnable or not with exit status. +0 means ready to run. Non-zero means not ready to run.

+

The make target never runs the validator command for +validation purpose if the exit status is non-zero.

+

For an example, misc/validators/validator-jq command uses jq +command as its backend. If jq command is not available on a +system, validator-jq can do nothing. If such case, +is_runnable method of validator-jq command should exit with +non-zero value.

+
+

validate method

+
+

The make target runs the command with “validate* and an input +file name for validating the input file. The command exits +non-zero if the input file contains invalid syntax. This method +will never run if is_runnable method of the command exits with +non-zero.

+
+
+
+
+

Testing examples in language specific man pages

+
+
Maintainer
+

Masatake YAMATO <yamato@redhat.com>

+
+
+
+

man-test is a target for testing the examples in the language +specific man pages (man/ctags-lang-<LANG>.7.rst.in). The command +line for running the target is:

+
$ make man-test
+
+
+

An example for testing must have following form:

+
"input.<EXT>"
+
+.. code-block:: <LANG>
+
+  <INPUT LINES>
+
+"output.tags"
+with "<OPTIONS FOR CTAGS>"
+
+.. code-block:: tags
+
+  <TAGS OUTPUT LINES>
+
+
+

The man-test target recognizes the form and does the same as +the following shell code for each example in the man page:

+
$ echo <INPUT LINES> > input.<EXT>
+$ echo <TAGS OUTPUT LINES> > output.tags
+$ ctags <OPTIONS FOR CTAGS> > actual.tags
+$ diff output.tags actual.tags
+
+
+

A backslash character at the end of <INPUT LINES> or +<TAGS OUTPUT LINES> represents the continuation of lines; +a subsequent newline is ignored.

+
.. code-block:: tags
+
+   very long\
+        line
+
+
+

is read as:

+
.. code-block:: tags
+
+   very long     line
+
+
+

Here is an example of a test case taken from +ctags-lang-python.7.rst.in:

+
"input.py"
+
+.. code-block:: Python
+
+   import X0
+
+"output.tags"
+with "--options=NONE -o - --extras=+r --fields=+rzK input.py"
+
+.. code-block:: tags
+
+        X0      input.py        /^import X0$/;" kind:module     roles:imported
+
+
+

make man-test returns 0 if the all test cases in the all language +specific man pages are passed.

+

Here is an example output of the man-test target.

+
$ make man-test
+  RUN      man-test
+# Run test cases in ./man/ctags-lang-julia.7.rst.in
+```
+./man/ctags-lang-julia.7.rst.in[0]:75...passed
+./man/ctags-lang-julia.7.rst.in[1]:93...passed
+```
+# Run test cases in ./man/ctags-lang-python.7.rst.in
+```
+./man/ctags-lang-python.7.rst.in[0]:116...passed
+./man/ctags-lang-python.7.rst.in[1]:133...passed
+./man/ctags-lang-python.7.rst.in[2]:154...passed
+./man/ctags-lang-python.7.rst.in[3]:170...passed
+./man/ctags-lang-python.7.rst.in[4]:187...passed
+./man/ctags-lang-python.7.rst.in[5]:230...passed
+```
+# Run test cases in ./man/ctags-lang-verilog.7.rst.in
+```
+./man/ctags-lang-verilog.7.rst.in[0]:51...passed
+```
+OK
+
+
+

NOTE: keep examples in the man pages simple. If you want to test ctags +complicated (and or subtle) input, use the units target. The main +purpose of the examples is for explaining the parser.

+
+
+ + +
+
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/ctags/docs/tips.html b/ctags/docs/tips.html new file mode 100644 index 0000000..f394313 --- /dev/null +++ b/ctags/docs/tips.html @@ -0,0 +1,247 @@ + + + + + + + + + Testing ctags — Universal Ctags 0.3.0 documentation + + + + + + + + + + + + + + + +
+
+
+
+ +
+

Testing ctags

+ +
+

Tmain: a facility for testing main part

+
+
Maintainer
+

Masatake YAMATO <yamato@redhat.com>

+
+
+
+

Tmain is introduced to test the area where Units +does not cover well.

+

Units works fine for testing parsers. However, it +assumes something input is given to ctags command, +and a tags file is generated from ctags command.

+

Other aspects cannot be tested. Such areas are files +and directories layout after installation, standard +error output, exit status, etc.

+

You can run test cases with following command line:

+
$ make tmain
+
+
+

Tmain is still under development so I will not write +the details here.

+

To write a test case, see files under Tmain/tmain-example.d. +In the example, Tmain does:

+
    +
  1. runs new subshell and change the working directory to Tmain/tmain-example.d,

  2. +
  3. runs run.sh with bash,

  4. +
  5. captures stdout, stderr and exit status, and

  6. +
  7. compares them with stdout-expected.txt, stderr-expected.txt, +and exit-expected.txt.

  8. +
  9. compares it with tags-expected.txt if run.sh generates tags file.

  10. +
+

run.sh is run with following 3 arguments:

+
    +
  1. the path for the target ctags

  2. +
  3. the path for builddir directory

  4. +
  5. the path for the target readtags

  6. +
+

The path for readtags is not reliable; readtags command is not +available if --disable-readcmd was given in configure time. A case, +testing the behavior of readtags, must verify the command existence +with test -x $3 before going into the main part of the test.

+

When comparing tags file with tags-expected.txt, you +must specify the path of tags explicitly with -o option +in ctags command line like:

+
CTAGS=$1
+BUILDDIR=$2
+${CTAGS} ... -o $BUILDDIR/tags ...
+
+
+

This makes it possible to keep the original source directory clean.

+

See also tmain_run and tmain_compare functions in misc/units.

+

If run.sh exits with code 77, the test case is skipped. +The output to stdout is captured and printed as the reason +of skipping.

+
+

TODO

+
    +
  • Run under valgrind

  • +
+
+
+
+

Tinst: installation test

+
+
Maintainer
+

Masatake YAMATO <yamato@redhat.com>

+
+
+
+

tinst target is for testing the result of make install.

+
$ make tinst
+
+
+
+
+

Fussy syntax checking

+

If -Wall of gcc is not enough, you may be interested in this.

+

You can change C compiler warning options with ‘WARNING_CFLAGS’ +configure arg-var option.

+
$ ./configure WARNING_CFLAGS='-Wall -Wextra'
+
+
+

If configure option ‘--with-sparse-cgcc’ is specified, +cgcc is used as CC. cgcc is part of Sparse, Semantic Parser for C. +It is used in development of Linux kernel for finding programming error. +cgcc acts as a c compiler but more fussy. ‘-Wsparse-all’ is used as +default option passed to cgcc but you can change with ‘CGCC_CFLAGS’ +configure arg-var option.

+
$ ./configure --with-sparse-cgcc [CGCC_CFLAGS='-Wsparse-all']
+
+
+
+
+

Finding performance bottleneck

+

See Profiling with gperftools and #383.

+
+
+

Checking coverage

+

Before starting coverage measuring, you need to specify +‘--enable-coverage-gcov’ configure option.

+
$ ./configure --enable-coverage-gcov
+
+
+

After doing make clean, you can build coverage measuring ready +ctags by make. At this time *.gcno files are generated +by the compiler. *.gcno files can be removed with make clean.

+

After building ctags, you can run run-gcov target. When running +*.gcda files. The target runs ctags with all input files under +Units/**/input.*; and call gcov. Human readable result is +printed. The detail can be shown in *.gcov. files. *.gcda files +and *.gcov files can be removed with make clean-gcov.

+
+
+

Running cppcheck

+

cppcheck is a tool for static C/C++ code +analysis.

+

To run it do as following after install cppcheck:

+
$ make cppcheck
+
+
+
+
+ + +
+
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/ctags/docs/tracking.html b/ctags/docs/tracking.html new file mode 100644 index 0000000..6dcd884 --- /dev/null +++ b/ctags/docs/tracking.html @@ -0,0 +1,605 @@ + + + + + + + + + Tracking other projects — Universal Ctags 0.3.0 documentation + + + + + + + + + + + + + +
+
+
+
+ +
+

Tracking other projects

+

This is working note for tracking activities other projects, +especially activity at Exuberant Ctags.

+

I(Masatake YAMATO) consider tracking activities as the first class +fruits of this project.

+
+

Exuberant Ctags

+
+

subversion

+
    +
  • status

    +

    Revisions up to <r815> are merged except:

    +
    +

    NOTHING HERE NOW

    +
    +

    (Mon Sep 22 12:41:32 2014 by yamato)

    +
  • +
  • howto

    +
    <svn>
    +=> <git: local Universal Ctags repo>
    +=> <git: local Universal Ctags repo>
    +
    +
    +
      +
    1. prepare your own Universal Ctags repo: a local git repo cloned from github. +You may know how to do it :)

      +
      $ git clone https://github.com/universal-ctags/ctags.git
      +
      +
      +
    2. +
    3. prepare Exuberant Ctags SVN repo: a local git repo clone from Exuberant Ctags svn tree.

    4. +
    +
    +

    The original clone is already part of Exuberant Ctags tree.

    +

    To initialize your git repository with the required subversion information do

    +
    $ git svn init https://svn.code.sf.net/p/ctags/code/trunk
    +$ git update-ref refs/remotes/git-svn refs/remotes/origin/sourceforge
    +
    +
    +

    and then

    +
    $ git svn fetch
    +$ git svn rebase
    +
    +
    +

    to get the latest changes and reflect it to the local copy.

    +
    +
      +
    1. merge

    2. +
    +
    +

    TODO

    +
    +
      +
    1. cherry-pick

      +

      4.1. Make a branch at local Universal Ctags repo and switch to it.

      +

      4.2. Do cherry-pick like:

      +
      $ git cherry-pick -s -x c81a8ce
      +
      +
      +

      You can find commit id on the another terminal +<git: local Universal Ctags repo>:

      +
      $ git log
      +
      +
      +

      or

      +
      $ git log --oneline
      +
      +
      +

      If conflicts are occurred in cherry-picking, you can +abort/reset cherry-picking with:

      +
      $ git reset --hard
      +
      +
      +
      +
      <git: local Universal Ctags repo>

      at the branch for picking.

      +
      +
      +
    2. +
    +
  • +
+
+
+

bugs

+
+

<367> C++11 override makes a C++ member function declaration ignored

+
+
    +
  • fixed in:

    +
    d4fcbdd
    +#413
    +#405
    +
    +
    +
  • +
+
+

<366> --options=.ctags doesn’t work under Windows

+
+
    +
  • fixed in:

    +
    15cedc6c94e95110cc319b5cdad7807caf3db1f4
    +
    +
    +
  • +
+
+

<365> Selecting Python kinds is broken

+
+
    +
  • fixed in:

    +
    4a95e4a55f67230fc4eee91ffb31c18c422df6d3
    +
    +
    +
  • +
  • discussed at #324.

  • +
+
+

<364> Ruby method on self is missing the trailing ? in the generated tag name

+
+
    +
  • fixed in:

    +
    d9ba5df9f4d54ddaa511bd5440a1a3decaa2dc28
    +
    +
    +
  • +
+
+

<363> Invalid C input file causes invalid read / heap overflow

+
+
    +
  • it is not reproduced.

  • +
  • the test case is imported as parser-c.r/c-heapoverflow-sh-bug-363.d:

    +
    $ make units UNITS=c-heapoverflow-sh-bug-363 VG=1
    +
    +
    +
  • +
+
+

<361> Invalid C input file causes invalid read / heap overflow

+
+
    +
  • it is not reproduced.

  • +
+
+

<360> Fails to parse annotation’s fields with default value

+
+
    +
  • fixed in:

    +
    682a7f3b180c27c1196f8a1ae662d6e8ad142939
    +
    +
    +
  • +
+
+

<358> Vim parser: Segmentation fault when reading empty vim file

+
+
    +
  • directly contributed by the original author of bug report and patch:

    +
    e0f854f0100e7a3cb8b959a23d6036e43f6b6c85
    +
    +
    +
  • +
  • it is fixed in sf, too:

    +
    5d774f6022a1af71fa5866994699aafce0253085
    +
    +
    +
  • +
+
+

<356> [python] mistakes module level attribute for class level attribute in module level if

+
+
    +
  • fixed in:

    +
    ab91e6e1ae84b80870a1e8712fc7f3133e4b5542
    +
    +
    +
  • +
+
+

<355> Error when parsing empty file (OCaml)

+
+
    +
  • fixed in:

    +
    02ec2066b5be6b129eba49685bd0b17fef4acfa
    +
    +
    +
  • +
+
+

<341> Lua: “function f ()” whitespace

+
+
    +
  • fixed in:

    +
    8590bbef5fcf70f6747d509808c29bf84342cd0d
    +
    +
    +
  • +
+
+

<341> Introducing ctags.conf.d

+
+
    +
  • merged the improved version:

    +
    216880c5287e0421d9c49898d983144db61c83aa
    +
    +
    +
  • +
+
+

<271> regex callback is broken; <320> [PATCH] fix regex callback match count

+
+
    +
  • merged patch (with updated bug number):

    +
    a12b3a24b62d6535a968e076675f68bac9ad32ba
    +
    +
    +
  • +
+
+

<177> Lua: “function” results in function tag (includes patch)

+
+
    +
  • fixed in:

    +
    5606f3f711afeac74587a249650a5f7b416f19be
    +
    +
    +
  • +
+
+
+
+
+
+

patches

+

Tracking the tickets in patch tracker is quite fruitful. +Patches are always there. So it is easy to evaluate the value:)

+
+

[(<]TICKET#[>)] TITLE

+
+
    +
  • STATUS

    +
      +
    • MORE STATUS

    • +
    +
  • +
+
+

<TICKET#>

+
+

means the ticket is closed from the view of Exuberant Ctags tree +developers. We don’t have to take time for this ticket.

+
+

(TICKET#)

+
+

means the ticket is still opened from the view of Exuberant Ctags +tree developers. We don’t have to take time for this ticket.

+
+
+
+
+

<85> Add --encoding option to make utf-8 encoded tags file

+
+
    +
  • contributed by the original author:

    +
    b3f670c7c4a3c3570b8d2d82756735586aafc0cb
    +
    +
    +
  • +
+
+

<84> C++11 new using semantics

+
+
    +
  • solved by another implementation:

    +
    c93e3bfa05b70d7fbc2539454c957eb2169e16b3
    +502355489b1ba748b1a235641bbd512ba6da315e
    +
    +
    +
  • +
+
+

<83> New full non-regex PHP parser

+
+
    +
  • contributed by the original author

  • +
+
+

<82> Support for comments in .ctags files

+
+
    +
  • contributed by the original author:

    +
    cab4735e4f99ce23c52b78dc879bc06af66796fd
    +
    +
    +
  • +
+
+

<81> ocaml parser segfaults on invalid files

+
+
    +
  • the bug is not reproduced

  • +
+
+

<80> Add support for falcon pl

+
+
    +
  • contributed by the original author

  • +
+
+

<74> protobuf parser

+
+
    +
  • Merged after getting approval from the original author

  • +
+
+

<67> Objective C language parser

+
+
    +
  • This is the implementation we have in Universal Ctags tree.

  • +
+
+

<65> absoluteFilename uses strcpy on overlapping strings

+
+
    +
  • Fixed in Universal Ctags tree, however the ticket is still open:

    +
    d2bdf505abb7569deae2b50305ea1edce6208557
    +
    +
    +
  • +
+
+

<64> Fix strcpy() misuse

+
+
    +
  • Fixed in Universal Ctags tree, however the ticket is still open:

    +
    d2bdf505abb7569deae2b50305ea1edce6208557
    +
    +
    +
  • +
+
+

<55> TTCN-3 support

+
+
    +
  • contributed by the original author

  • +
+
+

<51> Ada support

+
+
    +
  • Ada support is now available in Universal Ctags tree:

    +
    4b6b4a72f3d2d4ef969d7c650de1829d79f0ea7c
    +
    +
    +
  • +
+
+

<38> Ada support

+
+
    +
  • Ada support is now available in Universal Ctags tree:

    +
    4b6b4a72f3d2d4ef969d7c650de1829d79f0ea7c
    +
    +
    +
  • +
+
+

<33> Add basic ObjC support

+
+
    +
  • This one is written in regexp.

  • +
  • we have better objc parser.

  • +
+
+

(1) bibtex parser

+
+
    +
  • Reject because…

    +
      +
    • the owner of the ticket is anonymous.

    • +
    • the name of patch author is not written explicitly at +the header of patch.

    • +
    +
  • +
  • Alternative

    +

    https://gist.github.com/ptrv/4576213

    +
  • +
+
+
+
+
+

devel mailing list (ctags-devel@sourceforge)

+
+

<[Ctags] Shebang with python3 instead of python> +From: Martin Ueding <dev@ma…> - 2013-01-26 18:36:32

+
+

Added python, python2 and python3 as extensions of +python parser:

+
bb81485205c67617f1b34f61341e60b9e8030502
+
+
+
+

<[Ctags-devel] Lack of fnmatch(3) in Windows> +From: Frank Fesevur <ffes@us…> - 2013-08-24 20:25:47

+
+

There is no fnmatch() in the Windows C library. Therefore +a string comparison is done in fileNameMatched() in +strlist.c and patterns are not recognized:

+
698bf2f3db692946d2358892d228a864014abc4b
+
+
+
+

<Re: [Ctags-devel] WindRes parser> +From: Frank Fesevur <ffes@unns…> - 2013-08-30 21:23:50

+
+

A parser for Windows Resource files. +https://en.wikipedia.org/wiki/Resource_%28Windows%29

+
95b4806ba6c006e4b7e72a006700e33c720ab9e7
+
+
+
+

([Ctags-devel] Skip repeat PATH_SEPARATORs in relativeFilename()) +From: Seth Dickson <whefxlr@gm…> - 2013-12-24 04:51:01

+
+

Looks interesting.

+
+
+
+
+

Fedora

+

Some patches are maintained in ctags package of Fedora. +Inventory of patches are +http://pkgs.fedoraproject.org/cgit/ctags.git/tree/ctags.spec

+

<ctags-5.7-destdir.patch>

+
+

This patch was merged in Universal Ctags git tree:

+
d4b5972427a46cbdcbfb050a944cf62b300676be
+
+
+
+

<ctags-5.7-segment-fault.patch>

+
+

This patch was merged in Universal Ctags git tree:

+
8cc2b482f6c7257c5151893a6d02b8c79851fedd
+
+
+
+

(ctags-5.8-cssparse.patch)

+
+

Not in Universal Ctags tree.

+

The reproducer is attached to the following page: +https://bugzilla.redhat.com/show_bug.cgi?id=852101

+

However, Universal Ctags doesn’t reproduce with it.

+

I, Masatake YAMATO, read the patch. However, I don’t +understand the patch.

+
+

<ctags-5.8-css.patch>

+
+

This patch was merged in Universal Ctags git tree:

+
80c1522a36df3ba52b8b7cd7f5c79d5c30437a63
+
+
+
+

<ctags-5.8-memmove.patch>

+
+

This patch was merged in Exuberant Ctags svn tree. +As the result this patch is in Universal Ctags tree:

+
d2bdf505abb7569deae2b50305ea1edce6208557
+
+
+
+

<ctags-5.8-ocaml-crash.patch>

+
+

This patch was merged in Exuberant Ctags svn tree. +As the result this patch is in Universal Ctags tree:

+
ddb29762b37d60a875252dcc401de0b7479527b1
+
+
+
+

<ctags-5.8-format-security.patch>

+
+

This patch was merged in Exuberant Ctags svn tree. +As the result this patch is in Universal Ctags tree:

+
2f7a78ce21e4156ec3e63c821827cf1d5680ace8
+
+
+
+
+
+

Debian

+

Some patches are maintained in ctags package of Debian. +Inventory of patches are +http://anonscm.debian.org/cgit/users/cjwatson/exuberant-ctags.git/tree/debian/patches/series

+

<python-disable-imports.patch>

+
+

Universal Ctags tags Y in import X as Y and Z in from X import Y as Z +as definition tags. They are turned on by default. +The others are tagged as reference tags. reference tags are recorded only +when “r” extra tags are enabled. e.g. --extras=+r.

+
+

<vim-command-loop.patch>

+
+

This patch was merged as an alternative for +7fb36a2f4690374526e9e7ef4f1e24800b6914ec

+

Discussed on https://github.com/fishman/ctags/issues/74

+
e59325a576e38bc63b91abb05a5a22d2cef25ab7
+
+
+
+
+
+ + +
+
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/ctags/docs/windows.html b/ctags/docs/windows.html new file mode 100644 index 0000000..e68cb2d --- /dev/null +++ b/ctags/docs/windows.html @@ -0,0 +1,257 @@ + + + + + + + + + Building/hacking/using on MS-Windows — Universal Ctags 0.3.0 documentation + + + + + + + + + + + + + + + +
+
+
+
+ +
+

Building/hacking/using on MS-Windows

+
+
Maintainer
+

Frank Fesevur <ffes@users.sourceforge.net>

+
+
+
+

This part of the documentation is written by Frank Fesevur, co-maintainer of Universal Ctags and the maintainer of the Windows port of this project. It is still very much a work in progress. Things still need to be written down, tested or even investigated. When building for Windows you should be aware that there are many compilers and build environments available. This is a summary of available options and things that have been tested so far.

+
+

Compilers

+

There are many compilers for Windows. Compilers not mentioned here may work but are not tested.

+
+

Microsoft Visual Studio

+

https://www.visualstudio.com/

+

Obviously there is Microsoft Visual Studio 2013. Many professional developers targeting Windows use Visual Studio. Visual Studio comes in a couple of different editions. Their Express and Community editions are free to use, but a Microsoft-account is required to download the .iso and when you want to continue using it after a 30-days trial period. Other editions of Visual Studio must be purchased.

+

Installing Visual Studio will give you the IDE, the command line compilers and the MS-version of make named nmake.

+

Note that ctags cannot be built with Visual Studio older than 2013 anymore. There is C99 (or C11) coding used that generates syntax errors with VS2012 and older. This could affect compilers from other vendors as well.

+
+
+

GCC

+

There are three flavors of GCC for Windows:

+ +

MinGW started it all, but development stalled for a while and no x64 was available. Then the MinGW-w64 fork emerged. It started as a 64-bit compiler, but soon they included both a 32-bit and a 64-bit compiler. But the name remained, a bit confusing. Another fork of MinGW is TDM-GCC. It also provides both 32-bit and 64-bit compilers. All have at least GCC 4.8. MinGW-w64 appears to be the most used flavor of MinGW at this moment. Many well known programs that originate from GNU/Linux use MinGW-w64 to compile their Windows port.

+
+
+
+

Building ctags from the command line

+
+

Microsoft Visual Studio

+

Most users of Visual Studio will use the IDE and not the command line to compile a project. But by default a shortcut to the command prompt that sets the proper path is installed in the Start Menu. When this command prompt is used nmake -f mk_mvc.mak will compile ctags. You can also go into the win32 subdirectory and run msbuild ctags_vs2013.sln for the default build. Use msbuild ctags_vs2013.sln /p:Configuration=Release to specifically build a release build. MSBuild is what the IDE uses internally and therefore will produce the same files as the IDE.

+

If you want to build an iconv enabled version, you must specify WITH_ICONV=yes and ICONV_DIR like below:

+
nmake -f mk_mvc.mak WITH_ICONV=yes ICONV_DIR=path/to/iconvlib
+
+
+

If you want to build a debug version using mk_mvc.mak, you must specify DEBUG=1 like below:

+
nmake -f mk_mvc.mak DEBUG=1
+
+
+

If you want to create PDB files for debugging even for a release version, you must specify PDB=1 like below:

+
nmake -f mk_mvc.mak PDB=1
+
+
+
+
+

GCC

+

General

+

All the GCC’s come with installers or with zipped archives. Install or extract them in a directory without spaces.

+

GNU Make builds for Win32 are available as well, and sometimes are included with the compilers. Make sure it is in your path, for instance by copying the make.exe in the bin directory of your compiler.

+

Native win32 versions of the GNU/Linux commands cp, rm and mv can be useful. rm is almost always used in by the clean target of a makefile.

+

CMD

+

Any Windows includes a command prompt. Not the most advanced, but it is enough to do the build tasks. Make sure the path is set properly and make -f mk_mingw.mak should do the trick.

+

If you want to build an iconv enabled version, you must specify WITH_ICONV=yes like below:

+
make -f mk_mingw.mak WITH_ICONV=yes
+
+
+

If you want to build a debug version, you must specify DEBUG=1 like below:

+
make -f mk_mingw.mak DEBUG=1
+
+
+

MSYS / MSYS2

+

From their site: MSYS is a collection of GNU utilities such as bash, make, gawk and grep to allow building of applications and programs which depend on traditional UNIX tools to be present. It is intended to supplement MinGW and the deficiencies of the cmd shell.

+

MSYS comes in two flavors; the original from MinGW and MSYS2. +See https://www.msys2.org/ about MSYS2.

+

MSYS is old but still works. You can build ctags with it using make -f mk_mingw.mak. The Autotools are too old on MSYS so you cannot use them.

+

MSYS2 is a more maintained version of MSYS, but specially geared towards MinGW-w64. You can also use Autotools to build ctags. +If you use Autotools you can enable parsers which require jansson, libxml2 or libyaml, and can also do the Units testing with make units.

+

The following packages are needed to build a full-featured version:

+
    +
  • base-devel (make, autoconf)

  • +
  • mingw-w64-{i686,x86_64}-toolchain (mingw-w64-{i686,x86_64}-gcc, mingw-w64-{i686,x86_64}-pkg-config)

  • +
  • mingw-w64-{i686,x86_64}-jansson

  • +
  • mingw-w64-{i686,x86_64}-libxml2

  • +
  • mingw-w64-{i686,x86_64}-libyaml

  • +
  • mingw-w64-{i686,x86_64}-xz

  • +
+

If you want to build a single static-linked binary, you can use the following command:

+
./autogen.sh
+./configure --disable-external-sort --enable-static
+make
+
+
+

--disable-external-sort is a recommended option for Windows builds.

+

Cygwin

+

Cygwin provides ports of many GNU/Linux tools and a POSIX API layer. This is the most complete way to get the GNU/Linux terminal feel under Windows. Cygwin has a setup that helps you install all the tools you need. One drawback of Cygwin is that it has poor performance.

+

It is easy to build a Cygwin version of ctags using the normal GNU/Linux build steps. This ctags.exe will depend on cygwin1.dll and should only be used within the Cygwin ecosystem.

+

The following packages are needed to build a full-featured version:

+
    +
  • libiconv-devel

  • +
  • libjansson-devel

  • +
  • libxml2-devel

  • +
  • libyaml-devel

  • +
+

Cygwin has packages with a recent version of MinGW-w64 as well. This way it is easy to cross-compile a native Windows application with make -f mk_mingw.mak  CC=i686-w64-mingw32-gcc.

+

You can also build a native Windows version using Autotools.

+
./autogen.sh
+./configure --host=i686-w64-mingw32 --disable-external-sort
+make
+
+
+

If you use Autotools you can also do the Units testing with make units.

+

Some anti-virus software slows down the build and test process significantly, especially when ./configure is running and during the Units tests. In that case it could help to temporarily disable them. But be aware of the risks when you disable your anti-virus software.

+

Cross-compile from GNU/Linux

+

All major distributions have both MinGW and MinGW-w64 packages. Cross-compiling works the same way as with Cygwin. You cannot do the Windows based Units tests on GNU/Linux.

+
+
+
+

Building ctags with IDEs

+

I have no idea how things work for most GNU/Linux developers, but most Windows developers are used to IDEs. Not many use a command prompt and running the debugger from the command line is not a thing a Windows developers would normally do. Many IDEs exist for Windows, I use the two below.

+
+

Microsoft Visual Studio

+

As already mentioned Microsoft Visual Studio 2013 has the free Express and Community editions. For ctags the Windows Desktop Express Edition is enough to get the job done. The IDE has a proper debugger. Project files for VS2013 can be found in the win32 directory.

+

Please know that when files are added to the sources.mak, these files need to be added to the .vcxproj and .vcxproj.filters files as well. The XML of these files should not be a problem.

+
+
+

Code::Blocks

+

http://www.codeblocks.org/

+

Code::Blocks is a decent GPL-licensed IDE that has good gcc and gdb integration. The TDM-GCC that can be installed together with Code::Blocks works fine and I can provide a project file. This is an easy way to have a free - free as in beer as well as in speech - solution and to have the debugger within the GUI as well.

+
+
+
+

Other differences between Microsoft Windows and GNU/Linux

+

There other things where building ctags on Microsoft Windows differs from building on GNU/Linux.

+
    +
  • Filenames on Windows file systems are case-preserving, but not case-sensitive.

  • +
  • Windows file systems use backslashes "\" as path separators, but paths with forward slashes "/" are no problem for a Windows program to recognize, even when a full path (include drive letter) is used.

  • +
  • The default line-ending on Windows is CRLF. A tags file generated by the Windows build of ctags will contain CRLF.

  • +
  • The tools used to build ctags do understand Unix-line endings without problems. There is no need to convert the line-ending of existing files in the repository.

  • +
  • Due to the differences between the GNU/Linux and Windows C runtime library there are some things that need to be added to ctags to make the program as powerful as it is on GNU/Linux. At this moment regex and fnmatch are borrowed from glibc. mkstemp() is taken from MinGW-w64’s runtime library. scandir() is taken from Pacemaker.

  • +
  • Units testing needs a decent bash shell, some unix-like tools (e.g. diff, sed) and Python 3.5 or later. It is only tested using Cygwin or MSYS2.

  • +
+
+
+ + +
+
+
+
+ +
+
+ + + + \ No newline at end of file -- cgit v1.2.3