Skip to content

Commit a2acfbd

Browse files
authored
Merge pull request #2963 from idodeclare/feature/ctags_opts
Feature/ctags opts
2 parents 4f28d1c + 6de4f5a commit a2acfbd

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+1117
-89
lines changed

opengrok-indexer/src/main/java/org/opengrok/indexer/analysis/AbstractAnalyzer.java

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
/*
2121
* Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
2222
* Use is subject to license terms.
23-
* Portions Copyright (c) 2017-2018, Chris Fraire <[email protected]>.
23+
* Portions Copyright (c) 2017-2019, Chris Fraire <[email protected]>.
2424
*/
2525
package org.opengrok.indexer.analysis;
2626

@@ -34,7 +34,6 @@
3434
import org.opengrok.indexer.configuration.Project;
3535

3636
/**
37-
*
3837
* @author Chandan
3938
*/
4039
public abstract class AbstractAnalyzer extends Analyzer {
@@ -52,16 +51,25 @@ public AbstractAnalyzer(ReuseStrategy reuseStrategy) {
5251
super(reuseStrategy);
5352
}
5453

54+
/**
55+
* Subclasses should override to return the case-insensitive name aligning
56+
* with either a built-in Universal Ctags language name or an OpenGrok
57+
* custom language name.
58+
* @return a defined instance or {@code null} if the analyzer has no aligned
59+
* Universal Ctags language
60+
*/
61+
public abstract String getCtagsLang();
62+
5563
public abstract long getVersionNo();
5664

5765
/**
5866
* Subclasses should override to produce a value relevant for the evolution
5967
* of their analysis in each release.
6068
*
61-
* @return 0
69+
* @return 0 since {@link AbstractAnalyzer} is not specialized
6270
*/
6371
protected int getSpecializedVersionNo() {
64-
return 0; // FileAnalyzer is not specialized.
72+
return 0;
6573
}
6674

6775
public void setCtags(Ctags ctags) {

opengrok-indexer/src/main/java/org/opengrok/indexer/analysis/AnalyzerGuru.java

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,8 @@ public class AnalyzerGuru {
240240
*/
241241
private static final Map<String, Long> ANALYZER_VERSIONS = new HashMap<>();
242242

243+
private static final LangTreeMap langMap = new LangTreeMap();
244+
243245
/*
244246
* If you write your own analyzer please register it here. The order is
245247
* important for any factory that uses a FileAnalyzerFactory.Matcher
@@ -431,8 +433,10 @@ public static void addPrefix(String prefix, AnalyzerFactory factory) {
431433
AnalyzerFactory oldFactory;
432434
if (factory == null) {
433435
oldFactory = pre.remove(prefix);
436+
langMap.exclude(prefix);
434437
} else {
435438
oldFactory = pre.put(prefix, factory);
439+
langMap.add(prefix, factory.getAnalyzer().getCtagsLang());
436440
}
437441

438442
if (factoriesDifferent(factory, oldFactory)) {
@@ -448,21 +452,39 @@ public static void addPrefix(String prefix, AnalyzerFactory factory) {
448452
* @param factory a factory which creates the analyzer to use for the given
449453
* extension (if you pass null as the analyzer, you will disable the
450454
* analyzer used for that extension)
455+
* @throws IllegalArgumentException if {@code extension} contains a period
451456
*/
452-
public static void addExtension(String extension,
453-
AnalyzerFactory factory) {
457+
public static void addExtension(String extension, AnalyzerFactory factory) {
458+
if (extension.contains(".")) {
459+
throw new IllegalArgumentException("extension contains a '.'");
460+
}
461+
462+
// LangMap fileSpec requires a leading period to indicate an extension.
463+
String langMapExtension = "." + extension;
464+
454465
AnalyzerFactory oldFactory;
455466
if (factory == null) {
456467
oldFactory = ext.remove(extension);
468+
langMap.exclude(langMapExtension);
457469
} else {
458470
oldFactory = ext.put(extension, factory);
471+
langMap.add(langMapExtension, factory.getAnalyzer().getCtagsLang());
459472
}
460473

461474
if (factoriesDifferent(factory, oldFactory)) {
462475
addCustomizationKey("e:" + extension);
463476
}
464477
}
465478

479+
/**
480+
* Gets an unmodifiable view of the language mappings resulting from
481+
* {@link #addExtension(String, AnalyzerFactory)} and
482+
* {@link #addPrefix(String, AnalyzerFactory)}.
483+
*/
484+
public static LangMap getLangMap() {
485+
return langMap.unmodifiable();
486+
}
487+
466488
/**
467489
* Get the default Analyzer.
468490
*

opengrok-indexer/src/main/java/org/opengrok/indexer/analysis/Ctags.java

Lines changed: 46 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ public class Ctags implements Resettable {
5959
private static final Logger LOGGER = LoggerFactory.getLogger(Ctags.class);
6060

6161
private volatile boolean closing;
62+
private final LangTreeMap defaultLangMap = new LangTreeMap();
63+
private LangMap langMap;
6264
private Process ctags;
6365
private OutputStreamWriter ctagsIn;
6466
private BufferedReader ctagsOut;
@@ -88,6 +90,10 @@ public void setBinary(String binary) {
8890
this.binary = binary;
8991
}
9092

93+
public void setLangMap(LangMap langMap) {
94+
this.langMap = langMap;
95+
}
96+
9197
public int getTabSize() {
9298
return tabSize;
9399
}
@@ -152,13 +158,15 @@ private void initialize() throws IOException {
152158
command.add("--filter-terminator=" + CTAGS_FILTER_TERMINATOR + "\n");
153159
command.add("--fields=-anf+iKnS");
154160
command.add("--excmd=pattern");
155-
command.add("--langmap=sh:+.kshlib"); // RFE #17849
156-
command.add("--langmap=sql:+.plb"); // RFE #19208
157-
command.add("--langmap=sql:+.pls"); // RFE #19208
158-
command.add("--langmap=sql:+.pld"); // RFE #19208
159-
command.add("--langmap=sql:+.pks"); // RFE #19208 ?
160-
command.add("--langmap=sql:+.pkb"); // # 1763
161-
command.add("--langmap=sql:+.pck"); // # 1763
161+
162+
defaultLangMap.clear();
163+
defaultLangMap.add(".KSHLIB", "sh"); // RFE #17849. Upper-case file spec
164+
defaultLangMap.add(".PLB", "sql"); // RFE #19208. Upper-case file spec
165+
defaultLangMap.add(".PLS", "sql"); // RFE #19208. Upper-case file spec
166+
defaultLangMap.add(".PLD", "sql"); // RFE #19208. Upper-case file spec
167+
defaultLangMap.add(".PKS", "sql"); // RFE #19208 ? Upper-case file spec
168+
defaultLangMap.add(".PKB", "sql"); // # 1763. Upper-case file spec
169+
defaultLangMap.add(".PCK", "sql"); // # 1763. Upper-case file spec
162170

163171
//Ideally all below should be in ctags, or in outside config file,
164172
//we might run out of command line SOON
@@ -185,6 +193,12 @@ private void initialize() throws IOException {
185193

186194
//PLEASE add new languages ONLY with POSIX syntax (see above wiki link)
187195

196+
if (langMap != null) {
197+
command.addAll(langMap.mergeSecondary(defaultLangMap).getCtagsArgs());
198+
} else {
199+
command.addAll(defaultLangMap.getCtagsArgs());
200+
}
201+
188202
/* Add extra command line options for ctags. */
189203
if (CTagsExtraOptionsFile != null) {
190204
LOGGER.log(Level.INFO, "Adding extra options to ctags");
@@ -229,7 +243,7 @@ private void initialize() throws IOException {
229243

230244
private void addRustSupport(List<String> command) {
231245
command.add("--langdef=rust");
232-
command.add("--langmap=rust:+.rs");
246+
defaultLangMap.add(".RS", "rust"); // Upper-case file spec
233247

234248
// The following are not supported yet in Universal Ctags b13cb551
235249
command.add("--regex-rust=/^[[:space:]]*(pub[[:space:]]+)?(static|const)[[:space:]]+(mut[[:space:]]+)?" +
@@ -242,26 +256,27 @@ private void addRustSupport(List<String> command) {
242256
}
243257

244258
private void addPowerShellSupport(List<String> command) {
245-
command.add("--langdef=Posh");
246-
command.add("--langmap=Posh:+.ps1,Posh:+.psm1");
247-
command.add("--regex-Posh=/\\$(\\{[^}]+\\})/\\1/v,variable/");
248-
command.add("--regex-Posh=/\\$([[:alnum:]_]+([:.][[:alnum:]_]+)*)/\\1/v,variable/");
249-
command.add("--regex-Posh=/^[[:space:]]*(:[^[:space:]]+)/\\1/l,label/");
250-
251-
command.add("--_fielddef-Posh=signature,signatures");
252-
command.add("--fields-Posh=+{signature}");
259+
command.add("--langdef=powershell");
260+
defaultLangMap.add(".PS1", "powershell"); // Upper-case file spec
261+
defaultLangMap.add(".PSM1", "powershell"); // Upper-case file spec
262+
command.add("--regex-powershell=/\\$(\\{[^}]+\\})/\\1/v,variable/");
263+
command.add("--regex-powershell=/\\$([[:alnum:]_]+([:.][[:alnum:]_]+)*)/\\1/v,variable/");
264+
command.add("--regex-powershell=/^[[:space:]]*(:[^[:space:]]+)/\\1/l,label/");
265+
266+
command.add("--_fielddef-powershell=signature,signatures");
267+
command.add("--fields-powershell=+{signature}");
253268
// escaped variable markers
254-
command.add("--regex-Posh=/`\\$([[:alnum:]_]+([:.][[:alnum:]_]+)*)/\\1//{exclusive}");
255-
command.add("--regex-Posh=/`\\$(\\{[^}]+\\})/\\1//{exclusive}");
256-
command.add("--regex-Posh=/#.*\\$([[:alnum:]_]+([:.][[:alnum:]_]+)*)/\\1//{exclusive}");
257-
command.add("--regex-Posh=/#.*\\$(\\{[^}]+\\})/\\1//{exclusive}");
258-
command.add("--regex-Posh=/^[[:space:]]*(function|filter)[[:space:]]+([^({[:space:]]+)[[:space:]]*" +
269+
command.add("--regex-powershell=/`\\$([[:alnum:]_]+([:.][[:alnum:]_]+)*)/\\1//{exclusive}");
270+
command.add("--regex-powershell=/`\\$(\\{[^}]+\\})/\\1//{exclusive}");
271+
command.add("--regex-powershell=/#.*\\$([[:alnum:]_]+([:.][[:alnum:]_]+)*)/\\1//{exclusive}");
272+
command.add("--regex-powershell=/#.*\\$(\\{[^}]+\\})/\\1//{exclusive}");
273+
command.add("--regex-powershell=/^[[:space:]]*(function|filter)[[:space:]]+([^({[:space:]]+)[[:space:]]*" +
259274
"(\\(([^)]+)\\))?/\\2/f,function,functions/{icase}{exclusive}{_field=signature:(\\4)}");
260275
}
261276

262277
private void addPascalSupport(List<String> command) {
263278
command.add("--langdef=pascal");
264-
command.add("--langmap=pascal:+.pas");
279+
defaultLangMap.add(".PAS", "pascal"); // Upper-case file spec
265280
command.add("--regex-pascal=/([[:alnum:]_]+)[[:space:]]*=[[:space:]]*\\([[:space:]]*[[:alnum:]_][[:space:]]*\\)/\\1/t,Type/");
266281
command.add("--regex-pascal=/([[:alnum:]_]+)[[:space:]]*=[[:space:]]*class[[:space:]]*[^;]*$/\\1/c,Class/");
267282
command.add("--regex-pascal=/([[:alnum:]_]+)[[:space:]]*=[[:space:]]*interface[[:space:]]*[^;]*$/\\1/i,interface/");
@@ -276,7 +291,7 @@ private void addPascalSupport(List<String> command) {
276291

277292
private void addSwiftSupport(List<String> command) {
278293
command.add("--langdef=swift");
279-
command.add("--langmap=swift:+.swift");
294+
defaultLangMap.add(".SWIFT", "swift"); // Upper-case file spec
280295
command.add("--regex-swift=/enum[[:space:]]+([^\\{\\}]+).*$/\\1/n,enum,enums/");
281296
command.add("--regex-swift=/typealias[[:space:]]+([^:=]+).*$/\\1/t,typealias,typealiases/");
282297
command.add("--regex-swift=/protocol[[:space:]]+([^:\\{]+).*$/\\1/p,protocol,protocols/");
@@ -289,8 +304,8 @@ private void addSwiftSupport(List<String> command) {
289304

290305
private void addKotlinSupport(List<String> command) {
291306
command.add("--langdef=kotlin");
292-
command.add("--langmap=kotlin:+.kt");
293-
command.add("--langmap=kotlin:+.kts");
307+
defaultLangMap.add(".KT", "kotlin"); // Upper-case file spec
308+
defaultLangMap.add(".KTS", "kotlin"); // Upper-case file spec
294309
command.add("--regex-kotlin=/^[[:space:]]*((abstract|final|sealed|implicit|lazy)[[:space:]]*)*" +
295310
"(private[^ ]*|protected)?[[:space:]]*class[[:space:]]+([[:alnum:]_:]+)/\\4/c,classes/");
296311
command.add("--regex-kotlin=/^[[:space:]]*((abstract|final|sealed|implicit|lazy)[[:space:]]*)*" +
@@ -313,9 +328,9 @@ private void addKotlinSupport(List<String> command) {
313328

314329
private void addClojureSupport(List<String> command) {
315330
command.add("--langdef=clojure"); // clojure support (patterns are from https://gist.github.com/kul/8704283)
316-
command.add("--langmap=clojure:+.clj");
317-
command.add("--langmap=clojure:+.cljs");
318-
command.add("--langmap=clojure:+.cljx");
331+
defaultLangMap.add(".CLJ", "clojure"); // Upper-case file spec
332+
defaultLangMap.add(".CLJS", "clojure"); // Upper-case file spec
333+
defaultLangMap.add(".CLJX", "clojure"); // Upper-case file spec
319334

320335
command.add("--regex-clojure=/\\([[:space:]]*create-ns[[:space:]]+([-[:alnum:]*+!_:\\/.?]+)/\\1/n,namespace/");
321336
command.add("--regex-clojure=/\\([[:space:]]*def[[:space:]]+([-[:alnum:]*+!_:\\/.?]+)/\\1/d,definition/");
@@ -331,8 +346,8 @@ private void addClojureSupport(List<String> command) {
331346

332347
private void addHaskellSupport(List<String> command) {
333348
command.add("--langdef=haskell"); // below was added with #912
334-
command.add("--langmap=haskell:+.hs");
335-
command.add("--langmap=haskell:+.hsc");
349+
defaultLangMap.add(".HS", "haskell"); // Upper-case file spec
350+
defaultLangMap.add(".HSC", "haskell"); // Upper-case file spec
336351
command.add("--regex-haskell=/^[[:space:]]*class[[:space:]]+([a-zA-Z0-9_]+)/\\1/c,classes/");
337352
command.add("--regex-haskell=/^[[:space:]]*data[[:space:]]+([a-zA-Z0-9_]+)/\\1/t,types/");
338353
command.add("--regex-haskell=/^[[:space:]]*newtype[[:space:]]+([a-zA-Z0-9_]+)/\\1/t,types/");
@@ -345,7 +360,7 @@ private void addHaskellSupport(List<String> command) {
345360

346361
private void addScalaSupport(List<String> command) {
347362
command.add("--langdef=scala"); // below is bug 61 to get full scala support
348-
command.add("--langmap=scala:+.scala");
363+
defaultLangMap.add(".SCALA", "scala"); // Upper-case file spec
349364
command.add("--regex-scala=/^[[:space:]]*((abstract|final|sealed|implicit|lazy)[[:space:]]*)*" +
350365
"(private|protected)?[[:space:]]*class[[:space:]]+([a-zA-Z0-9_]+)/\\4/c,classes/");
351366
command.add("--regex-scala=/^[[:space:]]*((abstract|final|sealed|implicit|lazy)[[:space:]]*)*" +

opengrok-indexer/src/main/java/org/opengrok/indexer/analysis/FileAnalyzer.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
/*
2121
* Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
2222
* Use is subject to license terms.
23-
* Portions Copyright (c) 2017-2018, Chris Fraire <[email protected]>.
23+
* Portions Copyright (c) 2017-2019, Chris Fraire <[email protected]>.
2424
*/
2525
package org.opengrok.indexer.analysis;
2626

@@ -59,6 +59,14 @@ public class FileAnalyzer extends AbstractAnalyzer {
5959

6060
private static final Logger LOGGER = LoggerFactory.getLogger(FileAnalyzer.class);
6161

62+
/**
63+
* @return {@code null} as there is no aligned language
64+
*/
65+
@Override
66+
public String getCtagsLang() {
67+
return null;
68+
}
69+
6270
/**
6371
* Gets a version number to be used to tag processed documents so that
6472
* re-analysis can be re-done later if a stored version number is different
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/*
2+
* CDDL HEADER START
3+
*
4+
* The contents of this file are subject to the terms of the
5+
* Common Development and Distribution License (the "License").
6+
* You may not use this file except in compliance with the License.
7+
*
8+
* See LICENSE.txt included in this distribution for the specific
9+
* language governing permissions and limitations under the License.
10+
*
11+
* When distributing Covered Code, include this CDDL HEADER in each
12+
* file and include the License file at LICENSE.txt.
13+
* If applicable, add the following below this CDDL HEADER, with the
14+
* fields enclosed by brackets "[]" replaced with your own identifying
15+
* information: Portions Copyright [yyyy] [name of copyright owner]
16+
*
17+
* CDDL HEADER END
18+
*/
19+
20+
/*
21+
* Copyright (c) 2019, Chris Fraire <[email protected]>.
22+
*/
23+
24+
package org.opengrok.indexer.analysis;
25+
26+
import java.util.List;
27+
import java.util.Map;
28+
import java.util.Set;
29+
30+
/**
31+
* Represents an API for mapping file specifications versus languages and
32+
* getting the ctags options representation (--langmap-&lt;LANG&gt; or
33+
* --map-&lt;LANG&gt;) thereof.
34+
*/
35+
public interface LangMap {
36+
37+
/**
38+
* Removes all settings from this map.
39+
*/
40+
void clear();
41+
42+
/**
43+
* Adds the specified mapping of a file specification to a language. Any
44+
* matching exclusion via {@link #exclude(String)} is undone.
45+
* @param fileSpec a value starting with a period ({@code '.'}) to specify
46+
* a file extension; otherwise specifying a prefix.
47+
* @throws IllegalArgumentException if {@code fileSpec} is {@code null} or
48+
* is an extension (i.e. starting with a period) but contains any other
49+
* periods, as that is not ctags-compatible
50+
*/
51+
void add(String fileSpec, String ctagsLang);
52+
53+
/**
54+
* Exclude the specified mapping of a file specification to any language.
55+
* Any matching addition via {@link #add(String, String)} is undone.
56+
* @throws IllegalArgumentException if {@code fileSpec} is {@code null}
57+
*/
58+
void exclude(String fileSpec);
59+
60+
/**
61+
* Gets the transformation of the instance's mappings to ctags arguments.
62+
*/
63+
List<String> getCtagsArgs();
64+
65+
/**
66+
* Creates a new instance, merging the settings from the current instance
67+
* overlaying a specified {@code other}. Additions from the current instance
68+
* take precedence, and exclusions from the {@code other} only take effect
69+
* if the current instance has no matching addition.
70+
* @param other a defined instance
71+
* @return a defined instance
72+
*/
73+
LangMap mergeSecondary(LangMap other);
74+
75+
/**
76+
* Gets an unmodifiable view of the current instance.
77+
*/
78+
LangMap unmodifiable();
79+
80+
/**
81+
* Gets an unmodifiable view of the current additions.
82+
*/
83+
Map<String, String> getAdditions();
84+
85+
/**
86+
* Gets an unmodifiable view of the current exclusions.
87+
*/
88+
Set<String> getExclusions();
89+
}

0 commit comments

Comments
 (0)