Skip to content
This repository was archived by the owner on Sep 30, 2024. It is now read-only.

Commit befb40e

Browse files
jtibshiranivovakulikov
authored andcommitted
SCIP ctags: add kinds for Kotlin (#57998)
Improved ctags kind output for Kotlin: * Split type into class, interface, object, and enum * Split variable into enumMember, constant, and property * Add type alias
1 parent 9aa9891 commit befb40e

File tree

5 files changed

+140
-78
lines changed

5 files changed

+140
-78
lines changed
Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,44 @@
11
(source_file
22
(package_header
33
(identifier)
4-
@descriptor.namespace)) @scope
4+
@descriptor.namespace @kind.package)) @scope
55

66
(function_declaration
7-
(simple_identifier) @descriptor.method
8-
(function_body) @local)
7+
(simple_identifier) @descriptor.method @kind.method
8+
(function_body)? @local)
99

10-
(anonymous_function (_ (type_identifier) @descriptor.type . (type_identifier) @descriptor.method)) @local
11-
(class_declaration (type_identifier) @descriptor.type) @scope
12-
(object_declaration (type_identifier) @descriptor.type) @scope
13-
(class_parameter (simple_identifier) @descriptor.term)
14-
(enum_entry (simple_identifier) @descriptor.term)
15-
(property_declaration (variable_declaration (simple_identifier) @descriptor.term))
10+
(anonymous_function) @local
1611

17-
(multi_variable_declaration (variable_declaration (simple_identifier) @descriptor.term))
12+
(class_declaration "interface" (type_identifier) @descriptor.type @kind.interface) @scope
13+
(class_declaration "enum" "class" (type_identifier) @descriptor.type @kind.enum) @scope
14+
15+
;; Exclude enums from the 'class' kind
16+
((class_declaration
17+
("enum")? @_enum "class"
18+
(type_identifier) @descriptor.type @kind.class)
19+
(#filter! @_enum "enum")) @scope
20+
21+
(object_declaration (type_identifier) @descriptor.type @kind.object) @scope
22+
(companion_object (type_identifier) @descriptor.type @kind.object) @scope
23+
24+
(type_alias (type_identifier) @descriptor.type @kind.typealias)
25+
26+
(class_parameter (simple_identifier) @descriptor.term @kind.property)
27+
(enum_entry (simple_identifier) @descriptor.term @kind.enummember)
28+
29+
;; In the grammar, property_modifier always represents 'const'
30+
(property_declaration
31+
(modifiers (property_modifier))
32+
(variable_declaration (simple_identifier) @descriptor.term @kind.constant))
33+
34+
;; Exclude constants from the 'property' kind
35+
((property_declaration
36+
(modifiers (property_modifier) @_const)?
37+
(variable_declaration (simple_identifier) @descriptor.term @kind.property))
38+
(#filter! @_const "property_modifier"))
39+
40+
(property_declaration
41+
(multi_variable_declaration (variable_declaration (simple_identifier) @descriptor.term @kind.property)))
1842

1943
;; Future TODOs:
2044
;; - Should probably unescape `Escaped` simple identifiers

docker-images/syntax-highlighter/crates/scip-syntax/src/snapshots/scip_syntax__test__scip_snapshot_globals.kt.snap

Lines changed: 52 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2,109 +2,127 @@
22
source: crates/scip-syntax/src/lib.rs
33
expression: dumped
44
---
5+
package org.example
6+
// ^^^^^^^^^^^ definition(Package) scip-ctags `org.example`/
7+
58
// Top level constant property
69
const val PI = 3.14
7-
// ^^ definition scip-ctags PI.
10+
// ^^ definition(Constant) scip-ctags `org.example`/PI.
811

912
// Top level property with getter
1013
val version: String
11-
// ^^^^^^^ definition scip-ctags version.
14+
// ^^^^^^^ definition(Property) scip-ctags `org.example`/version.
1215
get() = "1.0.0"
1316

1417
// Top level function
1518
fun printHello() {
16-
// ^^^^^^^^^^ definition scip-ctags printHello().
19+
// ^^^^^^^^^^ definition(Method) scip-ctags `org.example`/printHello().
1720
println("Hello, Kotlin!")
1821
}
1922

2023
// Class with properties and methods
2124
class MyKotlinClass {
22-
// ^^^^^^^^^^^^^ definition scip-ctags MyKotlinClass#
25+
// ^^^^^^^^^^^^^ definition(Class) scip-ctags `org.example`/MyKotlinClass#
2326
var prop: String = "property"
24-
// ^^^^ definition scip-ctags MyKotlinClass#prop.
27+
// ^^^^ definition(Property) scip-ctags `org.example`/MyKotlinClass#prop.
2528

2629
fun method() {
27-
// ^^^^^^ definition scip-ctags MyKotlinClass#method().
30+
// ^^^^^^ definition(Method) scip-ctags `org.example`/MyKotlinClass#method().
2831
println("This is a method")
2932
}
3033
}
3134

3235
// Data class
3336
data class User(val name: String, val age: Int)
34-
// ^^^^ definition scip-ctags User#
35-
// ^^^^ definition scip-ctags User#name.
36-
// ^^^ definition scip-ctags User#age.
37+
// ^^^^ definition(Class) scip-ctags `org.example`/User#
38+
// ^^^^ definition(Property) scip-ctags `org.example`/User#name.
39+
// ^^^ definition(Property) scip-ctags `org.example`/User#age.
3740

3841
// Enum class
3942
enum class Days {
40-
// ^^^^ definition scip-ctags Days#
43+
// ^^^^ definition(Enum) scip-ctags `org.example`/Days#
4144
MONDAY,
42-
// ^^^^^^ definition scip-ctags Days#MONDAY.
45+
// ^^^^^^ definition(EnumMember) scip-ctags `org.example`/Days#MONDAY.
4346
TUESDAY,
44-
// ^^^^^^^ definition scip-ctags Days#TUESDAY.
47+
// ^^^^^^^ definition(EnumMember) scip-ctags `org.example`/Days#TUESDAY.
4548
WEDNESDAY,
46-
// ^^^^^^^^^ definition scip-ctags Days#WEDNESDAY.
49+
// ^^^^^^^^^ definition(EnumMember) scip-ctags `org.example`/Days#WEDNESDAY.
4750
THURSDAY,
48-
// ^^^^^^^^ definition scip-ctags Days#THURSDAY.
51+
// ^^^^^^^^ definition(EnumMember) scip-ctags `org.example`/Days#THURSDAY.
4952
FRIDAY,
50-
// ^^^^^^ definition scip-ctags Days#FRIDAY.
53+
// ^^^^^^ definition(EnumMember) scip-ctags `org.example`/Days#FRIDAY.
5154
SATURDAY,
52-
// ^^^^^^^^ definition scip-ctags Days#SATURDAY.
55+
// ^^^^^^^^ definition(EnumMember) scip-ctags `org.example`/Days#SATURDAY.
5356
SUNDAY
54-
// ^^^^^^ definition scip-ctags Days#SUNDAY.
57+
// ^^^^^^ definition(EnumMember) scip-ctags `org.example`/Days#SUNDAY.
5558
}
5659

5760
// Object (singleton)
5861
object MyObject {
59-
// ^^^^^^^^ definition scip-ctags MyObject#
62+
// ^^^^^^^^ definition(Object) scip-ctags `org.example`/MyObject#
6063
val property = "Object property"
61-
// ^^^^^^^^ definition scip-ctags MyObject#property.
64+
// ^^^^^^^^ definition(Property) scip-ctags `org.example`/MyObject#property.
6265
}
6366

6467
// Interface
6568
interface MyInterface {
66-
// ^^^^^^^^^^^ definition scip-ctags MyInterface#
69+
// ^^^^^^^^^^^ definition(Interface) scip-ctags `org.example`/MyInterface#
6770
fun interfaceMethod(): String
71+
// ^^^^^^^^^^^^^^^ definition(Method) scip-ctags `org.example`/MyInterface#interfaceMethod().
72+
}
73+
74+
object SimpleSingleton {
75+
// ^^^^^^^^^^^^^^^ definition(Object) scip-ctags `org.example`/SimpleSingleton#
76+
val answer = 42;
77+
// ^^^^^^ definition(Property) scip-ctags `org.example`/SimpleSingleton#answer.
78+
fun greet(name: String) = "Hello, $name!"
79+
// ^^^^^ definition(Method) scip-ctags `org.example`/SimpleSingleton#greet().
6880
}
6981

7082
// Type alias
7183
typealias UserList = List<User>
84+
// ^^^^^^^^ definition(TypeAlias) scip-ctags `org.example`/UserList#
7285

7386
// Extension function
7487
fun String.print() {
75-
// ^^^^^ definition scip-ctags print().
88+
// ^^^^^ definition(Method) scip-ctags `org.example`/print().
7689
println(this)
7790
}
7891

7992
// Sealed class
8093
sealed class Result {
81-
// ^^^^^^ definition scip-ctags Result#
94+
// ^^^^^^ definition(Class) scip-ctags `org.example`/Result#
8295
data class Success(val message: String) : Result()
83-
// ^^^^^^^ definition scip-ctags Result#Success#
84-
// ^^^^^^^ definition scip-ctags Result#Success#message.
96+
// ^^^^^^^ definition(Class) scip-ctags `org.example`/Result#Success#
97+
// ^^^^^^^ definition(Property) scip-ctags `org.example`/Result#Success#message.
8598
data class Error(val error: Exception) : Result()
86-
// ^^^^^ definition scip-ctags Result#Error#
87-
// ^^^^^ definition scip-ctags Result#Error#error.
99+
// ^^^^^ definition(Class) scip-ctags `org.example`/Result#Error#
100+
// ^^^^^ definition(Property) scip-ctags `org.example`/Result#Error#error.
88101
}
89102

90103
// Inline class
91104
inline class Password(val value: String)
92-
// ^^^^^^^^ definition scip-ctags Password#
93-
// ^^^^^ definition scip-ctags Password#value.
105+
// ^^^^^^^^ definition(Class) scip-ctags `org.example`/Password#
106+
// ^^^^^ definition(Property) scip-ctags `org.example`/Password#value.
94107

95108
// Companion object
96109
class MyClassWithCompanion {
97-
// ^^^^^^^^^^^^^^^^^^^^ definition scip-ctags MyClassWithCompanion#
98-
companion object {
110+
// ^^^^^^^^^^^^^^^^^^^^ definition(Class) scip-ctags `org.example`/MyClassWithCompanion#
111+
companion object ConstantCompanion {
112+
// ^^^^^^^^^^^^^^^^^ definition(Object) scip-ctags `org.example`/MyClassWithCompanion#ConstantCompanion#
99113
const val CONSTANT = "Companion constant"
100-
// ^^^^^^^^ definition scip-ctags MyClassWithCompanion#CONSTANT.
114+
// ^^^^^^^^ definition(Constant) scip-ctags `org.example`/MyClassWithCompanion#ConstantCompanion#CONSTANT.
101115
}
102116
}
103117

104118
fun `Escaped`() {}
105-
// ^^^^^^^^^ definition scip-ctags . . . ``Escaped``().
119+
// ^^^^^^^^^ definition(Method) scip-ctags . . . `org.example`/``Escaped``().
106120

121+
// Multi-variable declaration
107122
val (left, right) = directions()
108-
// ^^^^ definition scip-ctags left.
109-
// ^^^^^ definition scip-ctags right.
123+
// ^^^^ definition(Property) scip-ctags `org.example`/left.
124+
// ^^^^^ definition(Property) scip-ctags `org.example`/right.
125+
126+
// Anonymous function
127+
fun(x: Int, y: Int): Int = x + y
110128

docker-images/syntax-highlighter/crates/scip-syntax/src/snapshots/scip_syntax__test__tags_snapshot_globals.kt.snap

Lines changed: 40 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2,37 +2,44 @@
22
source: crates/scip-syntax/src/lib.rs
33
expression: "String::from_utf8_lossy(buf_writer.buffer())"
44
---
5-
{"_type":"tag","name":"MyKotlinClass","path":"globals.kt","language":"kotlin","line":14,"kind":"type","scope":null}
6-
{"_type":"tag","name":"method","path":"globals.kt","language":"kotlin","line":17,"kind":"method","scope":"MyKotlinClass"}
7-
{"_type":"tag","name":"prop","path":"globals.kt","language":"kotlin","line":15,"kind":"variable","scope":"MyKotlinClass"}
8-
{"_type":"tag","name":"User","path":"globals.kt","language":"kotlin","line":23,"kind":"type","scope":null}
9-
{"_type":"tag","name":"age","path":"globals.kt","language":"kotlin","line":23,"kind":"variable","scope":"User"}
10-
{"_type":"tag","name":"name","path":"globals.kt","language":"kotlin","line":23,"kind":"variable","scope":"User"}
11-
{"_type":"tag","name":"Days","path":"globals.kt","language":"kotlin","line":26,"kind":"type","scope":null}
12-
{"_type":"tag","name":"SUNDAY","path":"globals.kt","language":"kotlin","line":33,"kind":"variable","scope":"Days"}
13-
{"_type":"tag","name":"SATURDAY","path":"globals.kt","language":"kotlin","line":32,"kind":"variable","scope":"Days"}
14-
{"_type":"tag","name":"FRIDAY","path":"globals.kt","language":"kotlin","line":31,"kind":"variable","scope":"Days"}
15-
{"_type":"tag","name":"THURSDAY","path":"globals.kt","language":"kotlin","line":30,"kind":"variable","scope":"Days"}
16-
{"_type":"tag","name":"WEDNESDAY","path":"globals.kt","language":"kotlin","line":29,"kind":"variable","scope":"Days"}
17-
{"_type":"tag","name":"TUESDAY","path":"globals.kt","language":"kotlin","line":28,"kind":"variable","scope":"Days"}
18-
{"_type":"tag","name":"MONDAY","path":"globals.kt","language":"kotlin","line":27,"kind":"variable","scope":"Days"}
19-
{"_type":"tag","name":"MyObject","path":"globals.kt","language":"kotlin","line":37,"kind":"type","scope":null}
20-
{"_type":"tag","name":"property","path":"globals.kt","language":"kotlin","line":38,"kind":"variable","scope":"MyObject"}
21-
{"_type":"tag","name":"MyInterface","path":"globals.kt","language":"kotlin","line":42,"kind":"type","scope":null}
22-
{"_type":"tag","name":"Result","path":"globals.kt","language":"kotlin","line":55,"kind":"type","scope":null}
23-
{"_type":"tag","name":"Success","path":"globals.kt","language":"kotlin","line":56,"kind":"type","scope":"Result"}
24-
{"_type":"tag","name":"message","path":"globals.kt","language":"kotlin","line":56,"kind":"variable","scope":"Result.Success"}
25-
{"_type":"tag","name":"Error","path":"globals.kt","language":"kotlin","line":57,"kind":"type","scope":"Result"}
26-
{"_type":"tag","name":"error","path":"globals.kt","language":"kotlin","line":57,"kind":"variable","scope":"Result.Error"}
27-
{"_type":"tag","name":"Password","path":"globals.kt","language":"kotlin","line":61,"kind":"type","scope":null}
28-
{"_type":"tag","name":"value","path":"globals.kt","language":"kotlin","line":61,"kind":"variable","scope":"Password"}
29-
{"_type":"tag","name":"MyClassWithCompanion","path":"globals.kt","language":"kotlin","line":64,"kind":"type","scope":null}
30-
{"_type":"tag","name":"CONSTANT","path":"globals.kt","language":"kotlin","line":66,"kind":"variable","scope":"MyClassWithCompanion"}
31-
{"_type":"tag","name":"right","path":"globals.kt","language":"kotlin","line":72,"kind":"variable","scope":null}
32-
{"_type":"tag","name":"left","path":"globals.kt","language":"kotlin","line":72,"kind":"variable","scope":null}
33-
{"_type":"tag","name":"`Escaped`","path":"globals.kt","language":"kotlin","line":70,"kind":"method","scope":null}
34-
{"_type":"tag","name":"print","path":"globals.kt","language":"kotlin","line":50,"kind":"method","scope":null}
35-
{"_type":"tag","name":"printHello","path":"globals.kt","language":"kotlin","line":9,"kind":"method","scope":null}
36-
{"_type":"tag","name":"version","path":"globals.kt","language":"kotlin","line":5,"kind":"variable","scope":null}
37-
{"_type":"tag","name":"PI","path":"globals.kt","language":"kotlin","line":2,"kind":"variable","scope":null}
5+
{"_type":"tag","name":"org.example","path":"globals.kt","language":"kotlin","line":1,"kind":"package","scope":null}
6+
{"_type":"tag","name":"MyKotlinClass","path":"globals.kt","language":"kotlin","line":16,"kind":"class","scope":"org.example"}
7+
{"_type":"tag","name":"method","path":"globals.kt","language":"kotlin","line":19,"kind":"method","scope":"org.example.MyKotlinClass"}
8+
{"_type":"tag","name":"prop","path":"globals.kt","language":"kotlin","line":17,"kind":"property","scope":"org.example.MyKotlinClass"}
9+
{"_type":"tag","name":"User","path":"globals.kt","language":"kotlin","line":25,"kind":"class","scope":"org.example"}
10+
{"_type":"tag","name":"age","path":"globals.kt","language":"kotlin","line":25,"kind":"property","scope":"org.example.User"}
11+
{"_type":"tag","name":"name","path":"globals.kt","language":"kotlin","line":25,"kind":"property","scope":"org.example.User"}
12+
{"_type":"tag","name":"Days","path":"globals.kt","language":"kotlin","line":28,"kind":"enum","scope":"org.example"}
13+
{"_type":"tag","name":"SUNDAY","path":"globals.kt","language":"kotlin","line":35,"kind":"enumMember","scope":"org.example.Days"}
14+
{"_type":"tag","name":"SATURDAY","path":"globals.kt","language":"kotlin","line":34,"kind":"enumMember","scope":"org.example.Days"}
15+
{"_type":"tag","name":"FRIDAY","path":"globals.kt","language":"kotlin","line":33,"kind":"enumMember","scope":"org.example.Days"}
16+
{"_type":"tag","name":"THURSDAY","path":"globals.kt","language":"kotlin","line":32,"kind":"enumMember","scope":"org.example.Days"}
17+
{"_type":"tag","name":"WEDNESDAY","path":"globals.kt","language":"kotlin","line":31,"kind":"enumMember","scope":"org.example.Days"}
18+
{"_type":"tag","name":"TUESDAY","path":"globals.kt","language":"kotlin","line":30,"kind":"enumMember","scope":"org.example.Days"}
19+
{"_type":"tag","name":"MONDAY","path":"globals.kt","language":"kotlin","line":29,"kind":"enumMember","scope":"org.example.Days"}
20+
{"_type":"tag","name":"MyObject","path":"globals.kt","language":"kotlin","line":39,"kind":"object","scope":"org.example"}
21+
{"_type":"tag","name":"property","path":"globals.kt","language":"kotlin","line":40,"kind":"property","scope":"org.example.MyObject"}
22+
{"_type":"tag","name":"MyInterface","path":"globals.kt","language":"kotlin","line":44,"kind":"interface","scope":"org.example"}
23+
{"_type":"tag","name":"interfaceMethod","path":"globals.kt","language":"kotlin","line":45,"kind":"method","scope":"org.example.MyInterface"}
24+
{"_type":"tag","name":"SimpleSingleton","path":"globals.kt","language":"kotlin","line":48,"kind":"object","scope":"org.example"}
25+
{"_type":"tag","name":"greet","path":"globals.kt","language":"kotlin","line":50,"kind":"method","scope":"org.example.SimpleSingleton"}
26+
{"_type":"tag","name":"answer","path":"globals.kt","language":"kotlin","line":49,"kind":"property","scope":"org.example.SimpleSingleton"}
27+
{"_type":"tag","name":"Result","path":"globals.kt","language":"kotlin","line":62,"kind":"class","scope":"org.example"}
28+
{"_type":"tag","name":"Success","path":"globals.kt","language":"kotlin","line":63,"kind":"class","scope":"org.example.Result"}
29+
{"_type":"tag","name":"message","path":"globals.kt","language":"kotlin","line":63,"kind":"property","scope":"org.example.Result.Success"}
30+
{"_type":"tag","name":"Error","path":"globals.kt","language":"kotlin","line":64,"kind":"class","scope":"org.example.Result"}
31+
{"_type":"tag","name":"error","path":"globals.kt","language":"kotlin","line":64,"kind":"property","scope":"org.example.Result.Error"}
32+
{"_type":"tag","name":"Password","path":"globals.kt","language":"kotlin","line":68,"kind":"class","scope":"org.example"}
33+
{"_type":"tag","name":"value","path":"globals.kt","language":"kotlin","line":68,"kind":"property","scope":"org.example.Password"}
34+
{"_type":"tag","name":"MyClassWithCompanion","path":"globals.kt","language":"kotlin","line":71,"kind":"class","scope":"org.example"}
35+
{"_type":"tag","name":"ConstantCompanion","path":"globals.kt","language":"kotlin","line":72,"kind":"object","scope":"org.example.MyClassWithCompanion"}
36+
{"_type":"tag","name":"CONSTANT","path":"globals.kt","language":"kotlin","line":73,"kind":"constant","scope":"org.example.MyClassWithCompanion.ConstantCompanion"}
37+
{"_type":"tag","name":"right","path":"globals.kt","language":"kotlin","line":80,"kind":"property","scope":"org.example"}
38+
{"_type":"tag","name":"left","path":"globals.kt","language":"kotlin","line":80,"kind":"property","scope":"org.example"}
39+
{"_type":"tag","name":"`Escaped`","path":"globals.kt","language":"kotlin","line":77,"kind":"method","scope":"org.example"}
40+
{"_type":"tag","name":"print","path":"globals.kt","language":"kotlin","line":57,"kind":"method","scope":"org.example"}
41+
{"_type":"tag","name":"UserList","path":"globals.kt","language":"kotlin","line":54,"kind":"typeAlias","scope":"org.example"}
42+
{"_type":"tag","name":"printHello","path":"globals.kt","language":"kotlin","line":11,"kind":"method","scope":"org.example"}
43+
{"_type":"tag","name":"version","path":"globals.kt","language":"kotlin","line":7,"kind":"property","scope":"org.example"}
44+
{"_type":"tag","name":"PI","path":"globals.kt","language":"kotlin","line":4,"kind":"constant","scope":"org.example"}
3845

docker-images/syntax-highlighter/crates/scip-syntax/src/ts_scip.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ pub fn captures_to_kind(kind: &Option<&String>) -> symbol_information::Kind {
3838
"kind.methodspec" => MethodSpecification,
3939
"kind.module" => Module,
4040
"kind.namespace" => Namespace,
41+
"kind.object" => Object,
4142
"kind.package" => Package,
4243
"kind.property" => Property,
4344
"kind.setter" => Setter,
@@ -71,6 +72,7 @@ pub fn symbol_kind_to_ctags_kind(kind: &symbol_information::Kind) -> Option<&'st
7172
MethodSpecification => Some("methodSpec"),
7273
Module => Some("module"),
7374
Namespace => Some("namespace"),
75+
Object => Some("object"),
7476
Package => Some("package"),
7577
Property => Some("property"),
7678
Setter => Some("setter"),

docker-images/syntax-highlighter/crates/scip-syntax/testdata/globals.kt

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
package org.example
2+
13
// Top level constant property
24
const val PI = 3.14
35

@@ -43,6 +45,11 @@ interface MyInterface {
4345
fun interfaceMethod(): String
4446
}
4547

48+
object SimpleSingleton {
49+
val answer = 42;
50+
fun greet(name: String) = "Hello, $name!"
51+
}
52+
4653
// Type alias
4754
typealias UserList = List<User>
4855

@@ -62,11 +69,15 @@ inline class Password(val value: String)
6269

6370
// Companion object
6471
class MyClassWithCompanion {
65-
companion object {
72+
companion object ConstantCompanion {
6673
const val CONSTANT = "Companion constant"
6774
}
6875
}
6976

7077
fun `Escaped`() {}
7178

79+
// Multi-variable declaration
7280
val (left, right) = directions()
81+
82+
// Anonymous function
83+
fun(x: Int, y: Int): Int = x + y

0 commit comments

Comments
 (0)