3434import java .nio .charset .StandardCharsets ;
3535import java .time .Duration ;
3636import java .util .ArrayList ;
37+ import java .util .Collections ;
3738import java .util .List ;
3839import java .util .concurrent .ExecutionException ;
3940import java .util .concurrent .ExecutorService ;
@@ -58,20 +59,25 @@ public class Ctags implements Resettable {
5859
5960 private static final Logger LOGGER = LoggerFactory .getLogger (Ctags .class );
6061
62+ private final RuntimeEnvironment env ;
6163 private volatile boolean closing ;
6264 private final LangTreeMap defaultLangMap = new LangTreeMap ();
6365 private LangMap langMap ;
66+ private List <String > command ;
6467 private Process ctags ;
6568 private OutputStreamWriter ctagsIn ;
6669 private BufferedReader ctagsOut ;
6770 private static final String CTAGS_FILTER_TERMINATOR = "__ctags_done_with_file__" ;
68- private String binary ;
6971 private String CTagsExtraOptionsFile = null ;
7072 private int tabSize ;
7173 private Duration timeout = Duration .ofSeconds (10 );
7274
7375 private boolean junit_testing = false ;
7476
77+ public Ctags () {
78+ env = RuntimeEnvironment .getInstance ();
79+ }
80+
7581 /**
7682 * Gets a value indicating if a subprocess of ctags was started and it is
7783 * not alive.
@@ -82,14 +88,6 @@ public boolean isClosed() {
8288 return ctags != null && !ctags .isAlive ();
8389 }
8490
85- public String getBinary () {
86- return binary ;
87- }
88-
89- public void setBinary (String binary ) {
90- this .binary = binary ;
91- }
92-
9391 public void setLangMap (LangMap langMap ) {
9492 this .langMap = langMap ;
9593 }
@@ -136,22 +134,31 @@ public void close() {
136134 }
137135 }
138136
139- private void initialize () throws IOException {
140- ProcessBuilder processBuilder ;
141- List <String > command = new ArrayList <>();
137+ /**
138+ * Gets the command-line arguments used to run ctags.
139+ * @return a defined (immutable) list
140+ */
141+ public List <String > getArgv () {
142+ initialize ();
143+ return Collections .unmodifiableList (command );
144+ }
145+
146+ private void initialize () {
147+ env .validateUniversalCtags ();
142148
143- command .add (binary );
144- command .add ("--c-kinds=+l" );
149+ command = new ArrayList <>();
150+ command .add (env .getCtags ());
151+ command .add ("--kinds-c=+l" );
145152
146153 // Workaround for bug #14924: Don't get local variables in Java
147154 // code since that creates many false positives.
148155 // CtagsTest : bug14924 "too many methods" guards for this
149156 // universal ctags are however safe, so enabling for them
150- command .add ("--java- kinds=+l" );
157+ command .add ("--kinds-java =+l" );
151158
152- command .add ("--sql- kinds=+l" );
153- command .add ("--Fortran- kinds=+L" );
154- command .add ("--C++-kinds =+l" );
159+ command .add ("--kinds-sql =+l" );
160+ command .add ("--kinds-Fortran =+L" );
161+ command .add ("--kinds- C++=+l" );
155162 command .add ("--file-scope=yes" );
156163 command .add ("-u" );
157164 command .add ("--filter=yes" );
@@ -201,18 +208,20 @@ private void initialize() throws IOException {
201208
202209 /* Add extra command line options for ctags. */
203210 if (CTagsExtraOptionsFile != null ) {
204- LOGGER .log (Level .INFO , "Adding extra options to ctags" );
211+ LOGGER .log (Level .FINER , "Adding extra options to ctags" );
205212 command .add ("--options=" + CTagsExtraOptionsFile );
206213 }
214+ }
207215
216+ private void run () throws IOException {
208217 StringBuilder sb = new StringBuilder ();
209218 for (String s : command ) {
210219 sb .append (s ).append (" " );
211220 }
212221 String commandStr = sb .toString ();
213222 LOGGER .log (Level .FINE , "Executing ctags command [{0}]" , commandStr );
214223
215- processBuilder = new ProcessBuilder (command );
224+ ProcessBuilder processBuilder = new ProcessBuilder (command );
216225
217226 ctags = processBuilder .start ();
218227 ctagsIn = new OutputStreamWriter (
@@ -242,7 +251,9 @@ private void initialize() throws IOException {
242251 }
243252
244253 private void addRustSupport (List <String > command ) {
245- command .add ("--langdef=rust" );
254+ if (!env .getCtagsLanguages ().contains ("Rust" )) { // Built-in would be capitalized.
255+ command .add ("--langdef=rust" ); // Lower-case if user-defined.
256+ }
246257 defaultLangMap .add (".RS" , "rust" ); // Upper-case file spec
247258
248259 // The following are not supported yet in Universal Ctags b13cb551
@@ -256,9 +267,12 @@ private void addRustSupport(List<String> command) {
256267 }
257268
258269 private void addPowerShellSupport (List <String > command ) {
259- command .add ("--langdef=powershell" );
270+ if (!env .getCtagsLanguages ().contains ("PowerShell" )) { // Built-in would be capitalized.
271+ command .add ("--langdef=powershell" ); // Lower-case if user-defined.
272+ }
260273 defaultLangMap .add (".PS1" , "powershell" ); // Upper-case file spec
261274 defaultLangMap .add (".PSM1" , "powershell" ); // Upper-case file spec
275+
262276 command .add ("--regex-powershell=/\\ $(\\ {[^}]+\\ })/\\ 1/v,variable/" );
263277 command .add ("--regex-powershell=/\\ $([[:alnum:]_]+([:.][[:alnum:]_]+)*)/\\ 1/v,variable/" );
264278 command .add ("--regex-powershell=/^[[:space:]]*(:[^[:space:]]+)/\\ 1/l,label/" );
@@ -275,8 +289,11 @@ private void addPowerShellSupport(List<String> command) {
275289 }
276290
277291 private void addPascalSupport (List <String > command ) {
278- command .add ("--langdef=pascal" );
292+ if (!env .getCtagsLanguages ().contains ("Pascal" )) { // Built-in would be capitalized.
293+ command .add ("--langdef=pascal" ); // Lower-case if user-defined.
294+ }
279295 defaultLangMap .add (".PAS" , "pascal" ); // Upper-case file spec
296+
280297 command .add ("--regex-pascal=/([[:alnum:]_]+)[[:space:]]*=[[:space:]]*\\ ([[:space:]]*[[:alnum:]_][[:space:]]*\\ )/\\ 1/t,Type/" );
281298 command .add ("--regex-pascal=/([[:alnum:]_]+)[[:space:]]*=[[:space:]]*class[[:space:]]*[^;]*$/\\ 1/c,Class/" );
282299 command .add ("--regex-pascal=/([[:alnum:]_]+)[[:space:]]*=[[:space:]]*interface[[:space:]]*[^;]*$/\\ 1/i,interface/" );
@@ -290,7 +307,9 @@ private void addPascalSupport(List<String> command) {
290307 }
291308
292309 private void addSwiftSupport (List <String > command ) {
293- command .add ("--langdef=swift" );
310+ if (!env .getCtagsLanguages ().contains ("Swift" )) { // Built-in would be capitalized.
311+ command .add ("--langdef=swift" ); // Lower-case if user-defined.
312+ }
294313 defaultLangMap .add (".SWIFT" , "swift" ); // Upper-case file spec
295314 command .add ("--regex-swift=/enum[[:space:]]+([^\\ {\\ }]+).*$/\\ 1/n,enum,enums/" );
296315 command .add ("--regex-swift=/typealias[[:space:]]+([^:=]+).*$/\\ 1/t,typealias,typealiases/" );
@@ -303,9 +322,12 @@ private void addSwiftSupport(List<String> command) {
303322 }
304323
305324 private void addKotlinSupport (List <String > command ) {
306- command .add ("--langdef=kotlin" );
325+ if (!env .getCtagsLanguages ().contains ("Kotlin" )) { // Built-in would be capitalized.
326+ command .add ("--langdef=kotlin" ); // Lower-case if user-defined.
327+ }
307328 defaultLangMap .add (".KT" , "kotlin" ); // Upper-case file spec
308329 defaultLangMap .add (".KTS" , "kotlin" ); // Upper-case file spec
330+
309331 command .add ("--regex-kotlin=/^[[:space:]]*((abstract|final|sealed|implicit|lazy)[[:space:]]*)*" +
310332 "(private[^ ]*|protected)?[[:space:]]*class[[:space:]]+([[:alnum:]_:]+)/\\ 4/c,classes/" );
311333 command .add ("--regex-kotlin=/^[[:space:]]*((abstract|final|sealed|implicit|lazy)[[:space:]]*)*" +
@@ -326,8 +348,13 @@ private void addKotlinSupport(List<String> command) {
326348 command .add ("--regex-kotlin=/^[[:space:]]*import[[:space:]]+([[:alnum:]_.:]+)/\\ 1/I,imports/" );
327349 }
328350
351+ /**
352+ * Override Clojure support with patterns from https://gist.github.com/kul/8704283.
353+ */
329354 private void addClojureSupport (List <String > command ) {
330- command .add ("--langdef=clojure" ); // clojure support (patterns are from https://gist.github.com/kul/8704283)
355+ if (!env .getCtagsLanguages ().contains ("Clojure" )) { // Built-in would be capitalized.
356+ command .add ("--langdef=clojure" ); // Lower-case if user-defined.
357+ }
331358 defaultLangMap .add (".CLJ" , "clojure" ); // Upper-case file spec
332359 defaultLangMap .add (".CLJS" , "clojure" ); // Upper-case file spec
333360 defaultLangMap .add (".CLJX" , "clojure" ); // Upper-case file spec
@@ -345,9 +372,12 @@ private void addClojureSupport(List<String> command) {
345372 }
346373
347374 private void addHaskellSupport (List <String > command ) {
348- command .add ("--langdef=haskell" ); // below was added with #912
375+ if (!env .getCtagsLanguages ().contains ("Haskell" )) { // Built-in would be capitalized.
376+ command .add ("--langdef=haskell" ); // below added with #912. Lowercase if user-defined.
377+ }
349378 defaultLangMap .add (".HS" , "haskell" ); // Upper-case file spec
350379 defaultLangMap .add (".HSC" , "haskell" ); // Upper-case file spec
380+
351381 command .add ("--regex-haskell=/^[[:space:]]*class[[:space:]]+([a-zA-Z0-9_]+)/\\ 1/c,classes/" );
352382 command .add ("--regex-haskell=/^[[:space:]]*data[[:space:]]+([a-zA-Z0-9_]+)/\\ 1/t,types/" );
353383 command .add ("--regex-haskell=/^[[:space:]]*newtype[[:space:]]+([a-zA-Z0-9_]+)/\\ 1/t,types/" );
@@ -359,8 +389,11 @@ private void addHaskellSupport(List<String> command) {
359389 }
360390
361391 private void addScalaSupport (List <String > command ) {
362- command .add ("--langdef=scala" ); // below is bug 61 to get full scala support
392+ if (!env .getCtagsLanguages ().contains ("Scala" )) { // Built-in would be capitalized.
393+ command .add ("--langdef=scala" ); // below is bug 61 to get full scala support. Lower-case
394+ }
363395 defaultLangMap .add (".SCALA" , "scala" ); // Upper-case file spec
396+
364397 command .add ("--regex-scala=/^[[:space:]]*((abstract|final|sealed|implicit|lazy)[[:space:]]*)*" +
365398 "(private|protected)?[[:space:]]*class[[:space:]]+([a-zA-Z0-9_]+)/\\ 4/c,classes/" );
366399 command .add ("--regex-scala=/^[[:space:]]*((abstract|final|sealed|implicit|lazy)[[:space:]]*)*" +
@@ -408,6 +441,7 @@ public Definitions doCtags(String file) throws IOException,
408441 }
409442 } else {
410443 initialize ();
444+ run ();
411445 }
412446
413447 CtagsReader rdr = new CtagsReader ();
@@ -429,7 +463,7 @@ public Definitions doCtags(String file) throws IOException,
429463 * the ctags process completes so that the indexer can
430464 * make progress instead of hanging the whole operation.
431465 */
432- IndexerParallelizer parallelizer = RuntimeEnvironment . getInstance () .getIndexerParallelizer ();
466+ IndexerParallelizer parallelizer = env .getIndexerParallelizer ();
433467 ExecutorService executor = parallelizer .getCtagsWatcherExecutor ();
434468 Future <Definitions > future = executor .submit (() -> {
435469 readTags (rdr );
0 commit comments