The purpose of this project is to modernize and augment the many custom JavaScript Patterns for Exuberant Ctags that have been floating the web for years.
We want to make sure Exuberant Ctags doesn't miss a single named symbol in our whole code base and do so without unnecessary duplication:
- Tags,
- Array literals,
- Object literals,
- Object properties,
- Generator functions,
- Free-form functions,
- Constructors and classes,
- Methods,
- Variables,
- Named imports,
- Named exports
This is done by disabling the default "kinds", creating new ones, and crafting as many patterns as necessary.
These patterns are only usable with Exuberant Ctags. Universal Ctags is not currently supported.
Note about disabling the default "kinds".
The option --javascript-kinds=-c-f-m-p-v
in .ctags will disable the default kinds, c
(classes), f
(functions), m
(methods), p
(properties), and v
(global variables), for javascript files.
This means your ctags program's builtin regex patterns or any user defined patterns registered against these kinds will no longer function and the patterns defined in .ctags will be the only patterns active for the javascript language.
This is done to have a single source of patterns and avoid duplicated tags.
$ make tags
-
Copy
.ctags
to your$HOME
directory. -
Use this command to generate a
tags
file at the root of your JavaScript project:$ ctags -R .
-
Append the content of
.ctags
to~/.ctags
. -
Use this command to generate a
tags
file at the root of your JavaScript project:$ ctags -R .
--regex-javascript=/\/\/[ \t]*\(FIXME\)[ \t]*:*\(.*\)/\1/T,Tag,Tags/b
--regex-javascript=/\/\/[ \t]*\(TODO\)[ \t]*:*\(.*\)/\1/T,Tag,Tags/b
--regex-javascript=/\/\/[ \t]*\(BUG\)[ \t]*:*\(.*\)/\1/T,Tag,Tags/b
--regex-javascript=/\/\/[ \t]*\(NOBUG\)[ \t]*:*\(.*\)/\1/T,Tag,Tags/b
--regex-javascript=/\/\/[ \t]*\(???\)[ \t]*:*\(.*\)/\1/T,Tag,Tags/b
--regex-javascript=/\/\/[ \t]*\(!!!\)[ \t]*:*\(.*\)/\1/T,Tag,Tags/b
--regex-javascript=/\/\/[ \t]*\(HACK\)[ \t]*:*\(.*\)/\1/T,Tag,Tags/b
--regex-javascript=/\/\/[ \t]*\(XXX\)[ \t]*:*\(.*\)/\1/T,Tag,Tags/b
CODE | TAG | KIND
----------------------------------------------------|---------------------|-----
// FIXME: fix non-working Patterns | FIXME | T
// TODO: better ES6+ support | TODO | T
// BUG: there's really something fishy about this | BUG | T
// ???: what the flying fuck? | ??? | T
// !!!: dear god! | !!! | T
// HACK: deployment is in 15 minutes | HACK | T
// XXX: I. Must. Finish. That. Mess. Quickly. | XXX | T
--regex-javascript=/^[ \t]*var[ \t]\{1,\}\([A-Za-z0-9_$]\{1,\}\)[ \t]*=[ \t]*\[/\1/A,Array,Arrays/b
--regex-javascript=/^[ \t]*let[ \t]\{1,\}\([A-Za-z0-9_$]\{1,\}\)[ \t]*=[ \t]*\[/\1/A,Array,Arrays/b
--regex-javascript=/^[ \t]*const[ \t]\{1,\}\([A-Za-z0-9_$]\{1,\}\)[ \t]*=[ \t]*\[/\1/A,Array,Arrays/b
CODE | TAG | KIND
----------------------------------------------------|---------------------|-----
let array_name = [... | array_name | A
var array_name = [... | array_name | A
const array_name = [... | array_name | A
--regex-javascript=/^[ \t]*var[ \t]\{1,\}\([A-Za-z0-9_$]\{1,\}\)[ \t]*=[ \t]*[{]/\1/O,Object,Objects/b
--regex-javascript=/^[ \t]*let[ \t]\{1,\}\([A-Za-z0-9_$]\{1,\}\)[ \t]*=[ \t]*[{]/\1/O,Object,Objects/b
--regex-javascript=/^[ \t]*const[ \t]\{1,\}\([A-Za-z0-9_$]\{1,\}\)[ \t]*=[ \t]*[{]/\1/O,Object,Objects/b
CODE | TAG | KIND
----------------------------------------------------|---------------------|-----
let object_name = {... | object_name | O
var object_name = {... | object_name | O
const object_name = {... | object_name | O
--regex-javascript=/^[ \t]*\(this\.\)*\([A-Za-z0-9_$]\{1,\}\)[ \t]*[:=].*[,;]*[^{]$/\2/P,Property,Properties/b
CODE | TAG | KIND
----------------------------------------------------|---------------------|-----
foo: 123, | foo | P
foo: 123 | foo | P
bar : "eee", | bar | P
bar : "eee" | bar | P
baz : /regexp/, | baz | P
baz : /regexp/ | baz | P
TODO:
var obj_lit_inline = { prop_qux: 1 };
--regex-javascript=/^[ \t]*function[ \t]*\*[ \t]*\([A-Za-z0-9_$]\{1,\}\)/\1/G,Generator,Generators/b
--regex-javascript=/^[ \t]*var[ \t]\{1,\}\([a-z][A-Za-z0-9_$]\{1,\}\)[ \t]*=[ \t]*function\([ \t]*\*\)/\1/G,Generator,Generators/b
--regex-javascript=/^[ \t]*let[ \t]\{1,\}\([a-z][A-Za-z0-9_$]\{1,\}\)[ \t]*=[ \t]*function\([ \t]*\*\)/\1/G,Generator,Generators/b
--regex-javascript=/^[ \t]*const[ \t]\{1,\}\([a-z][A-Za-z0-9_$]\{1,\}\)[ \t]*=[ \t]*function\([ \t]*\*\)/\1/G,Generator,Generators/b
--regex-javascript=/^[ \t]*\(\*[ \t]\)\([A-Za-z0-9_$]\{1,\}\)[ \t]*(.*)[ \t]*[{]/\2/G,Generator,Generators/b
CODE | TAG | KIND
----------------------------------------------------|---------------------|-----
function* generator_name() {... | generator_name | G
function *generator_name() {... | generator_name | G
function * generator_name() {... | generator_name | G
function*generator_name() {... | generator_name | G
const generator_name = function* () {... | generator_name | G
const generator_name = function * () {... | generator_name | G
* generator_name() {... | generator_name | G
--regex-javascript=/^[ \t]*function[ \t]*\([A-Za-z0-9_$]\{1,\}\)[ \t(]/\1/F,Function,Functions/b
--regex-javascript=/^[ \t]*[(]function[ \t]*\([A-Za-z0-9_$]\{1,\}\)[ \t(]/\1/F,Function,Functions/b
--regex-javascript=/^[ \t]*var[ \t]\{1,\}\([a-z][A-Za-z0-9_$]\{1,\}\)[ \t]*=[ \t]*function[^\*][^\*]/\1/F,Function,Functions/b
--regex-javascript=/^[ \t]*let[ \t]\{1,\}\([a-z][A-Za-z0-9_$]\{1,\}\)[ \t]*=[ \t]*function[^\*][^\*]/\1/F,Function,Functions/b
--regex-javascript=/^[ \t]*const[ \t]\{1,\}\([a-z][A-Za-z0-9_$]\{1,\}\)[ \t]*=[ \t]*function[^\*][^\*]/\1/F,Function,Functions/b
--regex-javascript=/^[ \t]*var[ \t]\{1,\}\([a-z][A-Za-z0-9_$]\{1,\}\)[ \t]*=[ \t]*([^\*]/\1/F,Function,Functions/b
--regex-javascript=/^[ \t]*let[ \t]\{1,\}\([a-z][A-Za-z0-9_$]\{1,\}\)[ \t]*=[ \t]*([^\*]/\1/F,Function,Functions/b
--regex-javascript=/^[ \t]*const[ \t]\{1,\}\([a-z][A-Za-z0-9_$]\{1,\}\)[ \t]*=[ \t]*([^\*]/\1/F,Function,Functions/b
CODE | TAG | KIND
----------------------------------------------------|---------------------|-----
function func_name() {... | func_name | F
(function func_name() {... | func_name | F
var func_name = function() {... | func_name | F
let func_name = function() {... | func_name | F
const func_name = function() {... | func_name | F
--regex-javascript=/^[ \t]*var[ \t]\{1,\}\([A-Z][A-Za-z0-9_$]\{1,\}\)[ \t]*=[ \t]*function/\1/C,Class,Classes/b
--regex-javascript=/^[ \t]*let[ \t]\{1,\}\([A-Z][A-Za-z0-9_$]\{1,\}\)[ \t]*=[ \t]*function/\1/C,Class,Classes/b
--regex-javascript=/^[ \t]*const[ \t]\{1,\}\([A-Z][A-Za-z0-9_$]\{1,\}\)[ \t]*=[ \t]*function/\1/C,Class,Classes/b
--regex-javascript=/^[ \t]*class[ \t]\{1,\}\([A-Za-z0-9_$]\{1,\}\)/\1/C,Class,Classes/b
CODE | TAG | KIND
----------------------------------------------------|---------------------|-----
class ClassName {... | ClassName | C
var Constructor = function() {... | Constructor | C
--regex-javascript=/^[ \t]*this\.\([A-Za-z0-9_$]\{1,\}\)[ \t]*=.*[{]$/\1/M,Method,Methods/b
--regex-javascript=/^[ \t]*\([A-Za-z0-9_$]\{1,\}\)[ \t]*[:=][ \t]*[(]*function[ \t]*(/\1/M,Method,Methods/b
--regex-javascript=/^[ \t]*static[ \t]\{1,\}\([A-Za-z0-9_$]\{1,\}\)[ \t]*(/\1/M,Method,Methods/b
--regex-javascript=/^[ \t]*\([A-Za-z0-9_$]\{1,\}\)(.*)[ \t]*[{]/\1/M,Method,Methods/b
CODE | TAG | KIND
----------------------------------------------------|---------------------|-----
this.method_name = function() {... | method_name | M
method_name : function() {... | method_name | M
static method_name() {... | method_name | M
method_name() {... | method_name | M
--regex-javascript=/^[ \t]*var[ \t]\{1,\}\([A-Za-z0-9_$]\{1,\}\)[ \t]*=[ \t]*[0-9\"'\/]/\1/V,Variable,Variables/b
--regex-javascript=/^[ \t]*let[ \t]\{1,\}\([A-Za-z0-9_$]\{1,\}\)[ \t]*=[ \t]*[0-9\"'\/]/\1/V,Variable,Variables/b
--regex-javascript=/^[ \t]*const[ \t]\{1,\}\([A-Za-z0-9_$]\{1,\}\)[ \t]*=[ \t]*[0-9\"'\/]/\1/V,Variable,Variables/b
--regex-javascript=/^[ \t]*var[ \t]\{1,\}\([A-Za-z0-9_$]\{1,\}\)[ \t]*=[ \t]*new/\1/V,Variable,Variables/b
--regex-javascript=/^[ \t]*let[ \t]\{1,\}\([A-Za-z0-9_$]\{1,\}\)[ \t]*=[ \t]*new/\1/V,Variable,Variables/b
--regex-javascript=/^[ \t]*const[ \t]\{1,\}\([A-Za-z0-9_$]\{1,\}\)[ \t]*=[ \t]*new/\1/V,Variable,Variables/b
CODE | TAG | KIND
----------------------------------------------------|---------------------|-----
const var_name = 1; | var_name | V
var var_name = /regexp/; | var_name | V
let var_name = 'foo'; | var_name | V
let var_name = "bar"; | var_name | V
let var_name = new ClassName(); | var_name | V
TODO:
var foo, bar, baz;
- Special kinds for special types (RegExp, Math, Map, etc.)?
Tagging direct imports would be redundant so we only tag named imports.
--regex-javascript=/^[ \t]*import[ \t]\{1,\}\([{][ \t]*\)*\([A-Za-z0-9_\*]*[ \t]as[ \t]\)\([A-Za-z0-9_]\{1,\}\)/\3/I,Import,Imports/b
--regex-javascript=/^[ \t]*import[ \t]\{1,\}\([{][ \t]*\)*\([A-Za-z0-9_\*]*[ \t]as[ \t]\)*\([A-Za-z0-9_]\{1,\}\),[ \t]*\([A-Za-z0-9_\*]*[ \t]as[ \t]\)\([A-Za-z0-9_]\{1,\}\)/\5/I,Import,Imports/b
--regex-javascript=/^[ \t]*import[ \t]\{1,\}\([{][ \t]*\)*\([A-Za-z0-9_\*]*[ \t]as[ \t]\)*\([A-Za-z0-9_]\{1,\}\),[ \t]*\([A-Za-z0-9_\*]*[ \t]as[ \t]\)*\([A-Za-z0-9_]\{1,\}\),[ \t]*\([A-Za-z0-9_\*]*[ \t]as[ \t]\)\([A-Za-z0-9_]\{1,\}\)/\7/I,Import,Imports/b
CODE | TAG | KIND
----------------------------------------------------|---------------------|-----
import { * as imp1 } | imp1 | I
import { foo as imp2 } | imp2 | I
import { imp3, * as imp4 } | imp4 | I
import { imp5, bar as imp6 } | imp6 | I
import { imp7, imp8, * as imp9 } | imp9 | I
import { imp10, imp11, baz as imp12 } | imp12 | I
import { * as imp13, * as imp14, * as imp15 } | imp13, imp14, imp15 | I
import { foo as imp16, bar as imp17, baz as imp18 } | imp16, imp17, imp18 | I
import * as imp19 | imp19 | I
import foo as imp20 | imp20 | I
import imp21, * as imp22 | imp22 | I
import imp23, bar as imp24 | imp24 | I
import imp25, imp26, * as imp27 | imp27 | I
import imp28, imp29, baz as imp30 | imp30 | I
import * as imp31, * as imp32, * as imp33 | imp31, imp32, imp33 | I
import foo as imp34, bar as imp35, baz as imp36 | imp34, imp35, imp36 | I
Same story as imports, tagging direct exports would be redundant so we only tag named exports.
--regex-javascript=/^[ \t]*export[ \t]\{1,\}\({[ \t]*\)*\([A-Za-z0-9_\*]*[ \t]as[ \t]\)\([A-Za-z0-9_]\{1,\}\)/\3/E,Export,Exports/b
--regex-javascript=/^[ \t]*export[ \t]\{1,\}\({[ \t]*\)*\([A-Za-z0-9_\*]*[ \t]as[ \t]\)*\([A-Za-z0-9_]\{1,\}\),[ \t]*\([A-Za-z0-9_\*]*[ \t]as[ \t]\)\([A-Za-z0-9_]\{1,\}\)/\5/E,export,Exports/b
--regex-javascript=/^[ \t]*export[ \t]\{1,\}\({[ \t]*\)*\([A-Za-z0-9_\*]*[ \t]as[ \t]\)*\([A-Za-z0-9_]\{1,\}\),[ \t]*\([A-Za-z0-9_\*]*[ \t]as[ \t]\)*\([A-Za-z0-9_]\{1,\}\),[ \t]*\([A-Za-z0-9_\*]*[ \t]as[ \t]\)\([A-Za-z0-9_]\{1,\}\)/\7/E,Export,Exports/b
--regex-javascript=/^[ \t]*export[ \t]\{1,\}var[ \t]\{1,\}\([A_Za-z0-9_$]\{1,\}\)/\1/E,Export,Exports/b
--regex-javascript=/^[ \t]*export[ \t]\{1,\}let[ \t]\{1,\}\([A_Za-z0-9_$]\{1,\}\)/\1/E,Export,Exports/b
--regex-javascript=/^[ \t]*export[ \t]\{1,\}const[ \t]\{1,\}\([A_Za-z0-9_$]\{1,\}\)/\1/E,Export,Exports/b
--regex-javascript=/^[ \t]*export[ \t]\{1,\}var[ \t]\{1,\}\([A_Za-z0-9_$]\{1,\}\)[ \t]*[^,]\{1,\},[ \t]*\([A_Za-z0-9_$]\{1,\}\)/\2/E,Export,Exports/b
--regex-javascript=/^[ \t]*export[ \t]\{1,\}let[ \t]\{1,\}\([A_Za-z0-9_$]\{1,\}\)[ \t]*[^,]\{1,\},[ \t]*\([A_Za-z0-9_$]\{1,\}\)/\2/E,Export,Exports/b
--regex-javascript=/^[ \t]*export[ \t]\{1,\}const[ \t]\{1,\}\([A_Za-z0-9_$]\{1,\}\)[ \t]*[^,]\{1,\},[ \t]*\([A_Za-z0-9_$]\{1,\}\)/\2/E,Export,Exports/b
--regex-javascript=/^[ \t]*export[ \t]\{1,\}var[ \t]\{1,\}\([A_Za-z0-9_$]\{1,\}\)[ \t]*[^,]\{1,\},[ \t]*\([A_Za-z0-9_$]\{1,\}\)[ \t]*,[ \t]*\([A_Za-z0-9_$]\{1,\}\)/\3/E,Export,Exports/b
--regex-javascript=/^[ \t]*export[ \t]\{1,\}let[ \t]\{1,\}\([A_Za-z0-9_$]\{1,\}\)[ \t]*[^,]\{1,\},[ \t]*\([A_Za-z0-9_$]\{1,\}\)[ \t]*,[ \t]*\([A_Za-z0-9_$]\{1,\}\)/\3/E,Export,Exports/b
--regex-javascript=/^[ \t]*export[ \t]\{1,\}const[ \t]\{1,\}\([A_Za-z0-9_$]\{1,\}\)[ \t]*[^,]\{1,\},[ \t]*\([A_Za-z0-9_$]\{1,\}\)[ \t]*,[ \t]*\([A_Za-z0-9_$]\{1,\}\)/\3/E,Export,Exports/b
CODE | TAG | KIND
----------------------------------------------------|---------------------|-----
export { var1 as exp04, var2 as exp05 }; | exp04, exp05 | E
export let exp06, exp07; | exp06, exp07 | E
export var exp08, exp09, exp09b; | exp08, exp09 | E
export let exp10 = 1, exp11 = 2; | exp10, exp11 | E
export const exp12 = 1, exp13 = 2; | exp12, exp13 | E
export var exp14 = 1, exp15 = 2; | exp14, exp15 | E