threads / patch / 57489

patchuserdiff: Add diff driver for Kotlin lang and tests

Subject: [GSoC][PATCH] userdiff: Add diff driver for Kotlin lang and tests

## tl;dr

48 messages between Mar 1, 2022 and Mar 13, 2022. Diffs are folded; open one to read it.

replies: 47people: 4as markdown or json

Jaydeep P Das· Mar 1, 2022, 07:02 UTC · re: Jaydeep P Das · lore

[PATCH] userdiff: Add diff driver for Kotlin lang and tests

The xfuncname pattern finds func/class declarations in diffs to display as a hunk header.

This patch adds xfuncname regex and some respective tests for Kotlin language.

Also modifies `Documentation./gitattributes.txt` to state the same.

Signed-off-by: Jaydeep P Das <jaydeepjd.8914@gmail.com>
---
 Documentation/gitattributes.txt | 2 ++
 t/t4018/kotlin-class            | 5 +++++
 t/t4018/kotlin-enum-class       | 5 +++++
 t/t4018/kotlin-fun              | 5 +++++
 t/t4018/kotlin-inheritace-class | 5 +++++
 t/t4018/kotlin-inline-class     | 5 +++++
 t/t4018/kotlin-interface        | 5 +++++
 t/t4018/kotlin-nested-fun       | 9 +++++++++
 t/t4018/kotlin-public-class     | 5 +++++
 t/t4018/kotlin-sealed-class     | 5 +++++
 userdiff.c                      | 8 ++++++++
 11 files changed, 59 insertions(+)
 create mode 100644 t/t4018/kotlin-class
 create mode 100644 t/t4018/kotlin-enum-class
 create mode 100644 t/t4018/kotlin-fun
 create mode 100644 t/t4018/kotlin-inheritace-class
 create mode 100644 t/t4018/kotlin-inline-class
 create mode 100644 t/t4018/kotlin-interface
 create mode 100644 t/t4018/kotlin-nested-fun
 create mode 100644 t/t4018/kotlin-public-class
 create mode 100644 t/t4018/kotlin-sealed-class
Show changes to 11 files +59 −0

Documentation/gitattributes.txt, t/t4018/kotlin-class, t/t4018/kotlin-enum-class, t/t4018/kotlin-fun, t/t4018/kotlin-inheritace-class, t/t4018/kotlin-inline-class, t/t4018/kotlin-interface, t/t4018/kotlin-nested-fun, t/t4018/kotlin-public-class, t/t4018/kotlin-sealed-class, userdiff.c

diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt
index a71dad2674..94d06dc337 100644
--- a/Documentation/gitattributes.txt
+++ b/Documentation/gitattributes.txt
@@ -829,6 +829,8 @@ patterns are available:
 
 - `java` suitable for source code in the Java language.
 
+- `kotlin` suitable for source code in the Kotlin language
+
 - `markdown` suitable for Markdown documents.
 
 - `matlab` suitable for source code in the MATLAB and Octave languages.
diff --git a/t/t4018/kotlin-class b/t/t4018/kotlin-class
new file mode 100644
index 0000000000..bb864f22e6
--- /dev/null
+++ b/t/t4018/kotlin-class
@@ -0,0 +1,5 @@
+class RIGHT {
+	//comment
+	//comment
+	return ChangeMe
+}
diff --git a/t/t4018/kotlin-enum-class b/t/t4018/kotlin-enum-class
new file mode 100644
index 0000000000..8885f908fd
--- /dev/null
+++ b/t/t4018/kotlin-enum-class
@@ -0,0 +1,5 @@
+enum class RIGHT{
+	// Left
+	// a comment
+	ChangeMe
+}
diff --git a/t/t4018/kotlin-fun b/t/t4018/kotlin-fun
new file mode 100644
index 0000000000..2a60280256
--- /dev/null
+++ b/t/t4018/kotlin-fun
@@ -0,0 +1,5 @@
+fun RIGHT(){
+	//a comment
+	//b comment
+    return ChangeMe()
+}
diff --git a/t/t4018/kotlin-inheritace-class b/t/t4018/kotlin-inheritace-class
new file mode 100644
index 0000000000..77376c1f05
--- /dev/null
+++ b/t/t4018/kotlin-inheritace-class
@@ -0,0 +1,5 @@
+open class RIGHT{
+	// a comment
+	// b comment
+	// ChangeMe
+}
diff --git a/t/t4018/kotlin-inline-class b/t/t4018/kotlin-inline-class
new file mode 100644
index 0000000000..7bf46dd8d4
--- /dev/null
+++ b/t/t4018/kotlin-inline-class
@@ -0,0 +1,5 @@
+value class RIGHT(Args){
+	// a comment
+	// b comment
+	ChangeMe
+}
diff --git a/t/t4018/kotlin-interface b/t/t4018/kotlin-interface
new file mode 100644
index 0000000000..f686ba7770
--- /dev/null
+++ b/t/t4018/kotlin-interface
@@ -0,0 +1,5 @@
+interface RIGHT{
+	//another comment
+	//another comment
+	//ChangeMe
+}
diff --git a/t/t4018/kotlin-nested-fun b/t/t4018/kotlin-nested-fun
new file mode 100644
index 0000000000..12186858cb
--- /dev/null
+++ b/t/t4018/kotlin-nested-fun
@@ -0,0 +1,9 @@
+class LEFT{
+	class CENTER{
+		fun RIGHT(  a:Int){
+			//comment
+			//comment
+			ChangeMe
+		}
+	}
+}
diff --git a/t/t4018/kotlin-public-class b/t/t4018/kotlin-public-class
new file mode 100644
index 0000000000..9433fcc226
--- /dev/null
+++ b/t/t4018/kotlin-public-class
@@ -0,0 +1,5 @@
+public class RIGHT{
+	//comment1
+	//comment2
+	ChangeMe
+}
diff --git a/t/t4018/kotlin-sealed-class b/t/t4018/kotlin-sealed-class
new file mode 100644
index 0000000000..0efa4a4eaf
--- /dev/null
+++ b/t/t4018/kotlin-sealed-class
@@ -0,0 +1,5 @@
+sealed class RIGHT {
+	// a comment
+	// b comment
+	ChangeMe
+}
diff --git a/userdiff.c b/userdiff.c
index 8578cb0d12..a6cc6dc3b7 100644
--- a/userdiff.c
+++ b/userdiff.c
@@ -168,6 +168,14 @@ PATTERNS("java",
 	 "|[-+0-9.e]+[fFlL]?|0[xXbB]?[0-9a-fA-F]+[lL]?"
 	 "|[-+*/<>%&^|=!]="
 	 "|--|\\+\\+|<<=?|>>>?=?|&&|\\|\\|"),
+PATTERNS("kotlin",
+	 /* fun, class, interface, declarations */
+  	 "^[ \t]*(([a-z]+[ \t]+)*(fun|class|interface)[ \t]+.*[ \t]*)$",
+	 /* -- */
+	 "[a-zA-Z_][a-zA-Z0-9_]*"
+	 "|[-+0-9.e]+[fFlL]?|0[xXbB]?[0-9a-fA-F]+[lL]?"
+	 "|[-+*/<>%&^|=!]="
+	 "|--|\\+\\+|<<=?|>>>?=?|&&|\\|\\|"),
 PATTERNS("markdown",
 	 "^ {0,3}#{1,6}[ \t].*",
 	 /* -- */
-- 
2.35.1
Junio C Hamano· Mar 1, 2022, 09:32 UTC · re: Jaydeep P Das · lore

Re: [PATCH] userdiff: Add diff driver for Kotlin lang and tests

Jaydeep P Das <jaydeepjd.8914@gmail.com> writes:
> Subject: Re: [PATCH] userdiff: Add diff driver for Kotlin lang and tests
"Add" -> "add".  "lang and tests" -> "language".
> The xfuncname pattern finds func/class declarations in diffs to
> display as a hunk header.

Yes, but an entry for a language in userdiff.c consists of the funcname pattern AND the word_regex. And I think the patch is adding both, not just funcname pattern.

Show 5 quoted lines
> This patch adds xfuncname regex and some respective
> tests for Kotlin language.
>
> Also modifies `Documentation./gitattributes.txt` to state
> the same.
See Documenation/SubmittingPatches::[[imperative-mood]].

But it probably is better to leave these unsaid. The patterns, tests and documentation updates go hand in hand.

Show 22 quoted lines
>  11 files changed, 59 insertions(+)
>  create mode 100644 t/t4018/kotlin-class
>  create mode 100644 t/t4018/kotlin-enum-class
>  create mode 100644 t/t4018/kotlin-fun
>  create mode 100644 t/t4018/kotlin-inheritace-class
>  create mode 100644 t/t4018/kotlin-inline-class
>  create mode 100644 t/t4018/kotlin-interface
>  create mode 100644 t/t4018/kotlin-nested-fun
>  create mode 100644 t/t4018/kotlin-public-class
>  create mode 100644 t/t4018/kotlin-sealed-class
>
> diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt
> index a71dad2674..94d06dc337 100644
> --- a/Documentation/gitattributes.txt
> +++ b/Documentation/gitattributes.txt
> @@ -829,6 +829,8 @@ patterns are available:
>  
>  - `java` suitable for source code in the Java language.
>  
> +- `kotlin` suitable for source code in the Kotlin language
> +
>  - `markdown` suitable for Markdown documents.

The entries before and after this new one both end with a full stop, and this new entry should do the same.

Show 11 quoted lines
> diff --git a/userdiff.c b/userdiff.c
> index 8578cb0d12..a6cc6dc3b7 100644
> --- a/userdiff.c
> +++ b/userdiff.c
> @@ -168,6 +168,14 @@ PATTERNS("java",
>  	 "|[-+0-9.e]+[fFlL]?|0[xXbB]?[0-9a-fA-F]+[lL]?"
>  	 "|[-+*/<>%&^|=!]="
>  	 "|--|\\+\\+|<<=?|>>>?=?|&&|\\|\\|"),
> +PATTERNS("kotlin",
> +	 /* fun, class, interface, declarations */
> +  	 "^[ \t]*(([a-z]+[ \t]+)*(fun|class|interface)[ \t]+.*[ \t]*)$",

With the three keywords clearly visible in the pattern, the comment looks somewhat redundant. I dunno.

Show 5 quoted lines
> +	 /* -- */
> +	 "[a-zA-Z_][a-zA-Z0-9_]*"
> +	 "|[-+0-9.e]+[fFlL]?|0[xXbB]?[0-9a-fA-F]+[lL]?"
> +	 "|[-+*/<>%&^|=!]="
> +	 "|--|\\+\\+|<<=?|>>>?=?|&&|\\|\\|"),

The latter half is word regex, which is tested in t4034 to at least ensure that it is well formed. We can also add t/t4034/$language/ to see the patterns hit the word boundary as expected.

>  PATTERNS("markdown",
>  	 "^ {0,3}#{1,6}[ \t].*",
>  	 /* -- */
Ævar Arnfjörð Bjarmason· Mar 1, 2022, 09:37 UTC · re: Jaydeep P Das · lore

Re: [PATCH] userdiff: Add diff driver for Kotlin lang and tests

On Tue, Mar 01 2022, Jaydeep P Das wrote:
Show 22 quoted lines
> The xfuncname pattern finds func/class declarations
> in diffs to display as a hunk header.
>
> This patch adds xfuncname regex and some respective
> tests for Kotlin language.
>
> Also modifies `Documentation./gitattributes.txt` to state
> the same.
>
> Signed-off-by: Jaydeep P Das <jaydeepjd.8914@gmail.com>
> ---
>  Documentation/gitattributes.txt | 2 ++
>  t/t4018/kotlin-class            | 5 +++++
>  t/t4018/kotlin-enum-class       | 5 +++++
>  t/t4018/kotlin-fun              | 5 +++++
>  t/t4018/kotlin-inheritace-class | 5 +++++
>  t/t4018/kotlin-inline-class     | 5 +++++
>  t/t4018/kotlin-interface        | 5 +++++
>  t/t4018/kotlin-nested-fun       | 9 +++++++++
>  t/t4018/kotlin-public-class     | 5 +++++
>  t/t4018/kotlin-sealed-class     | 5 +++++
>  userdiff.c                      | 8 ++++++++

I didn't look at the regexes etc. at a glance, but this is missing the corresponding tests for the word-diff part of the regexes. It would be nice to have those tests too.

See the t/t4034/ directory for that (and no, this whole setup isn't very discoverable, sorry!).

Jaydeep P Das· Mar 1, 2022, 15:54 UTC · re: Jaydeep P Das · lore

[PATCH] userdiff: add builtin diff driver for Kotlin language.

The xfuncname pattern finds func/class declarations in diffs to display as a hunk header. The word_regex pattern finds individual tokens in Kotlin code to generate appropriate diffs.

This patch adds xfuncname regex and word_regex for Kotlin language.

Signed-off-by: Jaydeep P Das <jaydeepjd.8914@gmail.com>
---
 Documentation/gitattributes.txt |  2 ++
 t/t4018/kotlin-class            |  5 +++++
 t/t4018/kotlin-enum-class       |  5 +++++
 t/t4018/kotlin-fun              |  5 +++++
 t/t4018/kotlin-inheritace-class |  5 +++++
 t/t4018/kotlin-inline-class     |  5 +++++
 t/t4018/kotlin-interface        |  5 +++++
 t/t4018/kotlin-nested-fun       |  9 +++++++++
 t/t4018/kotlin-public-class     |  5 +++++
 t/t4018/kotlin-sealed-class     |  5 +++++
 t/t4034-diff-words.sh           |  1 +
 t/t4034/kotlin/expect           | 33 +++++++++++++++++++++++++++++++++
 t/t4034/kotlin/post             | 16 ++++++++++++++++
 t/t4034/kotlin/pre              | 16 ++++++++++++++++
 userdiff.c                      |  7 +++++++
 15 files changed, 124 insertions(+)
 create mode 100644 t/t4018/kotlin-class
 create mode 100644 t/t4018/kotlin-enum-class
 create mode 100644 t/t4018/kotlin-fun
 create mode 100644 t/t4018/kotlin-inheritace-class
 create mode 100644 t/t4018/kotlin-inline-class
 create mode 100644 t/t4018/kotlin-interface
 create mode 100644 t/t4018/kotlin-nested-fun
 create mode 100644 t/t4018/kotlin-public-class
 create mode 100644 t/t4018/kotlin-sealed-class
 create mode 100644 t/t4034/kotlin/expect
 create mode 100644 t/t4034/kotlin/post
 create mode 100644 t/t4034/kotlin/pre
Show changes to 15 files +124 −0

Documentation/gitattributes.txt, t/t4018/kotlin-class, t/t4018/kotlin-enum-class, t/t4018/kotlin-fun, t/t4018/kotlin-inheritace-class, t/t4018/kotlin-inline-class, t/t4018/kotlin-interface, t/t4018/kotlin-nested-fun, t/t4018/kotlin-public-class, t/t4018/kotlin-sealed-class, t/t4034-diff-words.sh, t/t4034/kotlin/expect, t/t4034/kotlin/post, t/t4034/kotlin/pre, userdiff.c

diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt
index a71dad2674..4b36d51beb 100644
--- a/Documentation/gitattributes.txt
+++ b/Documentation/gitattributes.txt
@@ -829,6 +829,8 @@ patterns are available:
 
 - `java` suitable for source code in the Java language.
 
+- `kotlin` suitable for source code in the Kotlin language.
+
 - `markdown` suitable for Markdown documents.
 
 - `matlab` suitable for source code in the MATLAB and Octave languages.
diff --git a/t/t4018/kotlin-class b/t/t4018/kotlin-class
new file mode 100644
index 0000000000..bb864f22e6
--- /dev/null
+++ b/t/t4018/kotlin-class
@@ -0,0 +1,5 @@
+class RIGHT {
+	//comment
+	//comment
+	return ChangeMe
+}
diff --git a/t/t4018/kotlin-enum-class b/t/t4018/kotlin-enum-class
new file mode 100644
index 0000000000..8885f908fd
--- /dev/null
+++ b/t/t4018/kotlin-enum-class
@@ -0,0 +1,5 @@
+enum class RIGHT{
+	// Left
+	// a comment
+	ChangeMe
+}
diff --git a/t/t4018/kotlin-fun b/t/t4018/kotlin-fun
new file mode 100644
index 0000000000..2a60280256
--- /dev/null
+++ b/t/t4018/kotlin-fun
@@ -0,0 +1,5 @@
+fun RIGHT(){
+	//a comment
+	//b comment
+    return ChangeMe()
+}
diff --git a/t/t4018/kotlin-inheritace-class b/t/t4018/kotlin-inheritace-class
new file mode 100644
index 0000000000..77376c1f05
--- /dev/null
+++ b/t/t4018/kotlin-inheritace-class
@@ -0,0 +1,5 @@
+open class RIGHT{
+	// a comment
+	// b comment
+	// ChangeMe
+}
diff --git a/t/t4018/kotlin-inline-class b/t/t4018/kotlin-inline-class
new file mode 100644
index 0000000000..7bf46dd8d4
--- /dev/null
+++ b/t/t4018/kotlin-inline-class
@@ -0,0 +1,5 @@
+value class RIGHT(Args){
+	// a comment
+	// b comment
+	ChangeMe
+}
diff --git a/t/t4018/kotlin-interface b/t/t4018/kotlin-interface
new file mode 100644
index 0000000000..f686ba7770
--- /dev/null
+++ b/t/t4018/kotlin-interface
@@ -0,0 +1,5 @@
+interface RIGHT{
+	//another comment
+	//another comment
+	//ChangeMe
+}
diff --git a/t/t4018/kotlin-nested-fun b/t/t4018/kotlin-nested-fun
new file mode 100644
index 0000000000..12186858cb
--- /dev/null
+++ b/t/t4018/kotlin-nested-fun
@@ -0,0 +1,9 @@
+class LEFT{
+	class CENTER{
+		fun RIGHT(  a:Int){
+			//comment
+			//comment
+			ChangeMe
+		}
+	}
+}
diff --git a/t/t4018/kotlin-public-class b/t/t4018/kotlin-public-class
new file mode 100644
index 0000000000..9433fcc226
--- /dev/null
+++ b/t/t4018/kotlin-public-class
@@ -0,0 +1,5 @@
+public class RIGHT{
+	//comment1
+	//comment2
+	ChangeMe
+}
diff --git a/t/t4018/kotlin-sealed-class b/t/t4018/kotlin-sealed-class
new file mode 100644
index 0000000000..0efa4a4eaf
--- /dev/null
+++ b/t/t4018/kotlin-sealed-class
@@ -0,0 +1,5 @@
+sealed class RIGHT {
+	// a comment
+	// b comment
+	ChangeMe
+}
diff --git a/t/t4034-diff-words.sh b/t/t4034-diff-words.sh
index d5abcf4b4c..15764ee9ac 100755
--- a/t/t4034-diff-words.sh
+++ b/t/t4034-diff-words.sh
@@ -324,6 +324,7 @@ test_language_driver dts
 test_language_driver fortran
 test_language_driver html
 test_language_driver java
+test_language_driver kotlin
 test_language_driver matlab
 test_language_driver objc
 test_language_driver pascal
diff --git a/t/t4034/kotlin/expect b/t/t4034/kotlin/expect
new file mode 100644
index 0000000000..80eea3e386
--- /dev/null
+++ b/t/t4034/kotlin/expect
@@ -0,0 +1,33 @@
+<BOLD>diff --git a/pre b/post<RESET>
+<BOLD>index e8a199a..e6ebebb 100644<RESET>
+<BOLD>--- a/pre<RESET>
+<BOLD>+++ b/post<RESET>
+<CYAN>@@ -1,16 +1,16 @@<RESET>
+println("Hello World<RED>!\n<RESET><GREEN>?<RESET>")
+<GREEN>(<RESET>1<GREEN>) (<RESET>-1e10<RED>0xabcdef<RESET><GREEN>) (0xaybcdef)<RESET> '<RED>x<RESET><GREEN>y<RESET>'
+[<RED>a<RESET><GREEN>x<RESET>] <RED>a<RESET><GREEN>x<RESET>-><RED>b a<RESET><GREEN>y x<RESET>.<RED>b<RESET><GREEN>y<RESET>
+!<RED>a a<RESET><GREEN>x x<RESET>.inv() <RED>a<RESET><GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>&<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>/<RED>b a<RESET><GREEN>y x<RESET>%<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>+<RED>b a<RESET><GREEN>y x<RESET>-<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET> shl <RED>b a<RESET><GREEN>y x<RESET> shr <RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET><<RED>b a<RESET><GREEN>y x<RESET><=<RED>b a<RESET><GREEN>y x<RESET>><RED>b a<RESET><GREEN>y x<RESET>>=<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>==<RED>b a<RESET><GREEN>y x<RESET>!=<RED>b a<RESET><GREEN>y x<RESET>===<RED>b<RESET>
+<RED>a and b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x xnd y<RESET>
+<GREEN>x<RESET>^<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET> or <RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>&&<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>||<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>=<RED>b a<RESET><GREEN>y x<RESET>+=<RED>b a<RESET><GREEN>y x<RESET>-=<RED>b a<RESET><GREEN>y x<RESET>*=<RED>b a<RESET><GREEN>y x<RESET>/=<RED>b a<RESET><GREEN>y x<RESET>%=<RED>b a<RESET><GREEN>y x<RESET><<=<RED>b a<RESET><GREEN>y x<RESET>>>=<RED>b a<RESET><GREEN>y x<RESET>&=<RED>b a<RESET><GREEN>y x<RESET>^=<RED>b a<RESET><GREEN>y x<RESET>|=<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>,y
diff --git a/t/t4034/kotlin/post b/t/t4034/kotlin/post
new file mode 100644
index 0000000000..e6ebebb5e9
--- /dev/null
+++ b/t/t4034/kotlin/post
@@ -0,0 +1,16 @@
+println("Hello World?")
+(1) (-1e10) (0xaybcdef) 'y'
+[x] x->y x.y
+!x x.inv() x*y x&y
+x*y x/y x%y
+x+y x-y
+x shl y x shr y
+x<y x<=y x>y x>=y
+x==y x!=y x===y
+x xnd y
+x^y
+x or y
+x&&y
+x||y
+x=y x+=y x-=y x*=y x/=y x%=y x<<=y x>>=y x&=y x^=y x|=y
+x,y
diff --git a/t/t4034/kotlin/pre b/t/t4034/kotlin/pre
new file mode 100644
index 0000000000..e8a199adb0
--- /dev/null
+++ b/t/t4034/kotlin/pre
@@ -0,0 +1,16 @@
+println("Hello World!\n")
+1 -1e10 0xabcdef 'x'
+[a] a->b a.b
+!a a.inv() a*b a&b
+a*b a/b a%b
+a+b a-b
+a shl b a shr b
+a<b a<=b a>b a>=b
+a==b a!=b a===b
+a and b
+a^b
+a or b
+a&&b
+a||b
+a=b a+=b a-=b a*=b a/=b a%=b a<<=b a>>=b a&=b a^=b a|=b
+a,y
diff --git a/userdiff.c b/userdiff.c
index 8578cb0d12..f23f098f19 100644
--- a/userdiff.c
+++ b/userdiff.c
@@ -168,6 +168,13 @@ PATTERNS("java",
 	 "|[-+0-9.e]+[fFlL]?|0[xXbB]?[0-9a-fA-F]+[lL]?"
 	 "|[-+*/<>%&^|=!]="
 	 "|--|\\+\\+|<<=?|>>>?=?|&&|\\|\\|"),
+PATTERNS("kotlin",
+	 "^[ \t]*(([a-z]+[ \t]+)*(fun|class|interface)[ \t]+.*[ \t]*)$",
+	 /* -- */
+	 "[a-zA-Z_][a-zA-Z0-9_]*"
+	 "|[-+0-9.e]+[fFlL]?|0[xXbB]?[0-9a-fA-F]+[lL]?"
+	 "|[-+*/<>%&^|=!]="
+	 "|--|\\+\\+|<<=?|>>>?=?|&&|\\|\\|"),
 PATTERNS("markdown",
 	 "^ {0,3}#{1,6}[ \t].*",
 	 /* -- */
-- 
2.35.1
Junio C Hamano· Mar 1, 2022, 17:17 UTC · re: Jaydeep P Das · lore

Re: [PATCH] userdiff: add builtin diff driver for Kotlin language.

Jaydeep P Das <jaydeepjd.8914@gmail.com> writes:
Show 13 quoted lines
> diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt
> index a71dad2674..4b36d51beb 100644
> --- a/Documentation/gitattributes.txt
> +++ b/Documentation/gitattributes.txt
> @@ -829,6 +829,8 @@ patterns are available:
>  
>  - `java` suitable for source code in the Java language.
>  
> +- `kotlin` suitable for source code in the Kotlin language.
> +
>  - `markdown` suitable for Markdown documents.
>  
>  - `matlab` suitable for source code in the MATLAB and Octave languages.

I do not speak the language, but hopefully those who do will find issues and help us correct them if there still are any. The patch organization looks good. Will queue.

Thanks.
Show 18 quoted lines
> diff --git a/userdiff.c b/userdiff.c
> index 8578cb0d12..f23f098f19 100644
> --- a/userdiff.c
> +++ b/userdiff.c
> @@ -168,6 +168,13 @@ PATTERNS("java",
>  	 "|[-+0-9.e]+[fFlL]?|0[xXbB]?[0-9a-fA-F]+[lL]?"
>  	 "|[-+*/<>%&^|=!]="
>  	 "|--|\\+\\+|<<=?|>>>?=?|&&|\\|\\|"),
> +PATTERNS("kotlin",
> +	 "^[ \t]*(([a-z]+[ \t]+)*(fun|class|interface)[ \t]+.*[ \t]*)$",
> +	 /* -- */
> +	 "[a-zA-Z_][a-zA-Z0-9_]*"
> +	 "|[-+0-9.e]+[fFlL]?|0[xXbB]?[0-9a-fA-F]+[lL]?"
> +	 "|[-+*/<>%&^|=!]="
> +	 "|--|\\+\\+|<<=?|>>>?=?|&&|\\|\\|"),
>  PATTERNS("markdown",
>  	 "^ {0,3}#{1,6}[ \t].*",
>  	 /* -- */
jaydeepjd.8914@gmail.com· Mar 1, 2022, 18:09 UTC · re: Junio C Hamano · lore

Re: [PATCH] userdiff: add builtin diff driver for Kotlin language.

Thanks for the review.
I have some criticism regarding `t/t4018-diff-funcname.sh`.

When any test fails, its verbose output is not "verbose" enough. For example, If due to wrong xfuncname regex or wrong test, all of the following hunk headers

@@...@@ @@...@@fun right(){ @@...@@fun

produce the same verbose output:
`not ok:....hunk header:[testfilename]`

Initially, I had a difficult time to debug what was going wrong so as a temporary fix, I made `t/t4018-diff-funcname.sh` to `cat` out the hunk stored in `actual`.

```
# check each individual file
for i in $(git ls-files)
do
	test_expect_success "hunk header of file: $i" "
		git diff -U1 $i >actual &&
		echo 'hunk:' &&
		cat actual &&
		echo &&
		grep '@@ .* @@.*RIGHT' actual
	"
done
```

Is there another proper way to make the test script produce the hunk for each test?

Thanks, Jaydeep.

Johannes Sixt· Mar 1, 2022, 19:59 UTC · re: jaydeepjd.8914@gmail.com · lore

Re: [PATCH] userdiff: add builtin diff driver for Kotlin language.

Am 01.03.22 um 19:09 schrieb jaydeepjd.8914@gmail.com:
Show 11 quoted lines
> When any test fails, its verbose output is not "verbose" enough.
> For example, If due to wrong xfuncname regex or wrong test, all of the
> following hunk headers
> 
> @@...@@
> @@...@@fun right(){
> @@...@@fun
> 
> produce the same verbose output:
> 
> `not ok:....hunk header:[testfilename]`
You run
  ./t4018-diff-funcname.sh -v -i
which stops at the first failing test case. You get
expecting success of 4018.160 'hunk header: kotlin-interface':
                git diff -U1 kotlin-interface >actual &&
                grep '@@ .* @@.*RIGHT' actual

not ok 160 - hunk header: kotlin-interface # # git diff -U1 kotlin-interface >actual && # grep '@@ .* @@.*RIGHT' actual #

from which you see that you have to inspect the file actual:
  less trash\ directory.t4018-diff-funcname/actual
-- Hannes
Johannes Sixt· Mar 1, 2022, 19:47 UTC · re: Jaydeep P Das · lore

Re: [PATCH] userdiff: add builtin diff driver for Kotlin language.

Am 01.03.22 um 16:54 schrieb Jaydeep P Das:
Show 15 quoted lines
> diff --git a/t/t4018/kotlin-nested-fun b/t/t4018/kotlin-nested-fun
> new file mode 100644
> index 0000000000..12186858cb
> --- /dev/null
> +++ b/t/t4018/kotlin-nested-fun
> @@ -0,0 +1,9 @@
> +class LEFT{
> +	class CENTER{
> +		fun RIGHT(  a:Int){
> +			//comment
> +			//comment
> +			ChangeMe
> +		}
> +	}
> +}

Nice move to include a test with an indented key phrase. The t4018 test cases all look fine. I don't speek Kotlin, though, so...

Show 83 quoted lines
> diff --git a/t/t4034/kotlin/expect b/t/t4034/kotlin/expect
> new file mode 100644
> index 0000000000..80eea3e386
> --- /dev/null
> +++ b/t/t4034/kotlin/expect
> @@ -0,0 +1,33 @@
> +<BOLD>diff --git a/pre b/post<RESET>
> +<BOLD>index e8a199a..e6ebebb 100644<RESET>
> +<BOLD>--- a/pre<RESET>
> +<BOLD>+++ b/post<RESET>
> +<CYAN>@@ -1,16 +1,16 @@<RESET>
> +println("Hello World<RED>!\n<RESET><GREEN>?<RESET>")
> +<GREEN>(<RESET>1<GREEN>) (<RESET>-1e10<RED>0xabcdef<RESET><GREEN>) (0xaybcdef)<RESET> '<RED>x<RESET><GREEN>y<RESET>'
> +[<RED>a<RESET><GREEN>x<RESET>] <RED>a<RESET><GREEN>x<RESET>-><RED>b a<RESET><GREEN>y x<RESET>.<RED>b<RESET><GREEN>y<RESET>
> +!<RED>a a<RESET><GREEN>x x<RESET>.inv() <RED>a<RESET><GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>&<RED>b<RESET>
> +<RED>a<RESET><GREEN>y<RESET>
> +<GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>/<RED>b a<RESET><GREEN>y x<RESET>%<RED>b<RESET>
> +<RED>a<RESET><GREEN>y<RESET>
> +<GREEN>x<RESET>+<RED>b a<RESET><GREEN>y x<RESET>-<RED>b<RESET>
> +<RED>a<RESET><GREEN>y<RESET>
> +<GREEN>x<RESET> shl <RED>b a<RESET><GREEN>y x<RESET> shr <RED>b<RESET>
> +<RED>a<RESET><GREEN>y<RESET>
> +<GREEN>x<RESET><<RED>b a<RESET><GREEN>y x<RESET><=<RED>b a<RESET><GREEN>y x<RESET>><RED>b a<RESET><GREEN>y x<RESET>>=<RED>b<RESET>
> +<RED>a<RESET><GREEN>y<RESET>
> +<GREEN>x<RESET>==<RED>b a<RESET><GREEN>y x<RESET>!=<RED>b a<RESET><GREEN>y x<RESET>===<RED>b<RESET>
> +<RED>a and b<RESET>
> +<RED>a<RESET><GREEN>y<RESET>
> +<GREEN>x xnd y<RESET>
> +<GREEN>x<RESET>^<RED>b<RESET>
> +<RED>a<RESET><GREEN>y<RESET>
> +<GREEN>x<RESET> or <RED>b<RESET>
> +<RED>a<RESET><GREEN>y<RESET>
> +<GREEN>x<RESET>&&<RED>b<RESET>
> +<RED>a<RESET><GREEN>y<RESET>
> +<GREEN>x<RESET>||<RED>b<RESET>
> +<RED>a<RESET><GREEN>y<RESET>
> +<GREEN>x<RESET>=<RED>b a<RESET><GREEN>y x<RESET>+=<RED>b a<RESET><GREEN>y x<RESET>-=<RED>b a<RESET><GREEN>y x<RESET>*=<RED>b a<RESET><GREEN>y x<RESET>/=<RED>b a<RESET><GREEN>y x<RESET>%=<RED>b a<RESET><GREEN>y x<RESET><<=<RED>b a<RESET><GREEN>y x<RESET>>>=<RED>b a<RESET><GREEN>y x<RESET>&=<RED>b a<RESET><GREEN>y x<RESET>^=<RED>b a<RESET><GREEN>y x<RESET>|=<RED>b<RESET>
> +<RED>a<RESET><GREEN>y<RESET>
> +<GREEN>x<RESET>,y
> diff --git a/t/t4034/kotlin/post b/t/t4034/kotlin/post
> new file mode 100644
> index 0000000000..e6ebebb5e9
> --- /dev/null
> +++ b/t/t4034/kotlin/post
> @@ -0,0 +1,16 @@
> +println("Hello World?")
> +(1) (-1e10) (0xaybcdef) 'y'
> +[x] x->y x.y
> +!x x.inv() x*y x&y
> +x*y x/y x%y
> +x+y x-y
> +x shl y x shr y
> +x<y x<=y x>y x>=y
> +x==y x!=y x===y
> +x xnd y
> +x^y
> +x or y
> +x&&y
> +x||y
> +x=y x+=y x-=y x*=y x/=y x%=y x<<=y x>>=y x&=y x^=y x|=y
> +x,y
> diff --git a/t/t4034/kotlin/pre b/t/t4034/kotlin/pre
> new file mode 100644
> index 0000000000..e8a199adb0
> --- /dev/null
> +++ b/t/t4034/kotlin/pre
> @@ -0,0 +1,16 @@
> +println("Hello World!\n")
> +1 -1e10 0xabcdef 'x'
> +[a] a->b a.b
> +!a a.inv() a*b a&b
> +a*b a/b a%b
> +a+b a-b
> +a shl b a shr b
> +a<b a<=b a>b a>=b
> +a==b a!=b a===b
> +a and b
> +a^b
> +a or b
> +a&&b
> +a||b
> +a=b a+=b a-=b a*=b a/=b a%=b a<<=b a>>=b a&=b a^=b a|=b
> +a,y

I know you just copied an existing test case. But actually, it misses the important parts of the word regex patterns. In particular, it only tests that a change of a to x is found, but does not test that the operators are not split into individual characters. Please have a look at my series 1cf93847c1ed~..386076ec92c7 and in particular 1cf93847c1ed to see what you actually want to test. For example, you could test a change from a+=b to a-=b, i.e., that operators += and -= are not split into +, -, and =.

Show 10 quoted lines
> diff --git a/userdiff.c b/userdiff.c
> index 8578cb0d12..f23f098f19 100644
> --- a/userdiff.c
> +++ b/userdiff.c
> @@ -168,6 +168,13 @@ PATTERNS("java",
>  	 "|[-+0-9.e]+[fFlL]?|0[xXbB]?[0-9a-fA-F]+[lL]?"
>  	 "|[-+*/<>%&^|=!]="
>  	 "|--|\\+\\+|<<=?|>>>?=?|&&|\\|\\|"),
> +PATTERNS("kotlin",
> +	 "^[ \t]*(([a-z]+[ \t]+)*(fun|class|interface)[ \t]+.*[ \t]*)$",

I would guess that the trailing [ \t]* is pointless and always empty, because it is covered by the preceding .*, so you can remove it.

> +	 /* -- */
> +	 "[a-zA-Z_][a-zA-Z0-9_]*"
> +	 "|[-+0-9.e]+[fFlL]?|0[xXbB]?[0-9a-fA-F]+[lL]?"

The first part intends to match integers and floatingpoint numbers. Word regex can be loose. This one, however, is too loose. For example, it treats -e+2 as a single token, but that is actually a whole expression consisting of several tokens and is not unlikely to occur in real code. See also 350b87cd6585.

I am pretty sure that, e.g., -1 and +2.5 are both two tokens each, i.e., the sign is not part of the number token.

Also, it looks like 3.0e5 is a floating point number; is 3.0E5 not?
Show 5 quoted lines
> +	 "|[-+*/<>%&^|=!]="
> +	 "|--|\\+\\+|<<=?|>>>?=?|&&|\\|\\|"),
>  PATTERNS("markdown",
>  	 "^ {0,3}#{1,6}[ \t].*",
>  	 /* -- */
-- Hannes
Jaydeep P Das· Mar 2, 2022, 06:45 UTC · re: Jaydeep P Das · lore

[GSoC][PATCHv2] userdiff: add builtin driver for kotlin language

Thanks for the review. Yes. As Johannes pointed out, the word_regex was very loose and did not properly tokenise the code.

I have fixed(and added tests) for the following things in this patch:

+= or -= is not split into + = or - = -a or +a is split into 2 tokens(for each)

Since kotlin supports `_` in between digits to improve readability, therefore numbers like `100_000` are single tokens and not broken up by the regex in this patch.

Kotlin also does not support octal literals, and so the regex does not attempt to find it.

Jaydeep P Das· Mar 2, 2022, 06:45 UTC · re: Jaydeep P Das · lore

[PATCH] userdiff: add builtin driver for kotlin language

The xfuncname pattern finds func/class declarations in diffs to display as a hunk header. The word_regex pattern finds individual tokens in Kotlin code to generate appropriate diffs.

This patch adds xfuncname regex and word_regex for Kotlin language.

Signed-off-by: Jaydeep P Das <jaydeepjd.8914@gmail.com>
---
 Documentation/gitattributes.txt |  2 ++
 t/t4018/kotlin-class            |  5 +++++
 t/t4018/kotlin-enum-class       |  5 +++++
 t/t4018/kotlin-fun              |  5 +++++
 t/t4018/kotlin-inheritace-class |  5 +++++
 t/t4018/kotlin-inline-class     |  5 +++++
 t/t4018/kotlin-interface        |  5 +++++
 t/t4018/kotlin-nested-fun       |  9 +++++++++
 t/t4018/kotlin-public-class     |  5 +++++
 t/t4018/kotlin-sealed-class     |  5 +++++
 t/t4034-diff-words.sh           |  1 +
 t/t4034/kotlin/expect           | 35 +++++++++++++++++++++++++++++++++
 t/t4034/kotlin/post             | 19 ++++++++++++++++++
 t/t4034/kotlin/pre              | 19 ++++++++++++++++++
 userdiff.c                      |  8 ++++++++
 15 files changed, 133 insertions(+)
 create mode 100644 t/t4018/kotlin-class
 create mode 100644 t/t4018/kotlin-enum-class
 create mode 100644 t/t4018/kotlin-fun
 create mode 100644 t/t4018/kotlin-inheritace-class
 create mode 100644 t/t4018/kotlin-inline-class
 create mode 100644 t/t4018/kotlin-interface
 create mode 100644 t/t4018/kotlin-nested-fun
 create mode 100644 t/t4018/kotlin-public-class
 create mode 100644 t/t4018/kotlin-sealed-class
 create mode 100644 t/t4034/kotlin/expect
 create mode 100644 t/t4034/kotlin/post
 create mode 100644 t/t4034/kotlin/pre
Show changes to 15 files +133 −0

Documentation/gitattributes.txt, t/t4018/kotlin-class, t/t4018/kotlin-enum-class, t/t4018/kotlin-fun, t/t4018/kotlin-inheritace-class, t/t4018/kotlin-inline-class, t/t4018/kotlin-interface, t/t4018/kotlin-nested-fun, t/t4018/kotlin-public-class, t/t4018/kotlin-sealed-class, t/t4034-diff-words.sh, t/t4034/kotlin/expect, t/t4034/kotlin/post, t/t4034/kotlin/pre, userdiff.c

diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt
index a71dad2674..4b36d51beb 100644
--- a/Documentation/gitattributes.txt
+++ b/Documentation/gitattributes.txt
@@ -829,6 +829,8 @@ patterns are available:
 
 - `java` suitable for source code in the Java language.
 
+- `kotlin` suitable for source code in the Kotlin language.
+
 - `markdown` suitable for Markdown documents.
 
 - `matlab` suitable for source code in the MATLAB and Octave languages.
diff --git a/t/t4018/kotlin-class b/t/t4018/kotlin-class
new file mode 100644
index 0000000000..bb864f22e6
--- /dev/null
+++ b/t/t4018/kotlin-class
@@ -0,0 +1,5 @@
+class RIGHT {
+	//comment
+	//comment
+	return ChangeMe
+}
diff --git a/t/t4018/kotlin-enum-class b/t/t4018/kotlin-enum-class
new file mode 100644
index 0000000000..8885f908fd
--- /dev/null
+++ b/t/t4018/kotlin-enum-class
@@ -0,0 +1,5 @@
+enum class RIGHT{
+	// Left
+	// a comment
+	ChangeMe
+}
diff --git a/t/t4018/kotlin-fun b/t/t4018/kotlin-fun
new file mode 100644
index 0000000000..2a60280256
--- /dev/null
+++ b/t/t4018/kotlin-fun
@@ -0,0 +1,5 @@
+fun RIGHT(){
+	//a comment
+	//b comment
+    return ChangeMe()
+}
diff --git a/t/t4018/kotlin-inheritace-class b/t/t4018/kotlin-inheritace-class
new file mode 100644
index 0000000000..77376c1f05
--- /dev/null
+++ b/t/t4018/kotlin-inheritace-class
@@ -0,0 +1,5 @@
+open class RIGHT{
+	// a comment
+	// b comment
+	// ChangeMe
+}
diff --git a/t/t4018/kotlin-inline-class b/t/t4018/kotlin-inline-class
new file mode 100644
index 0000000000..7bf46dd8d4
--- /dev/null
+++ b/t/t4018/kotlin-inline-class
@@ -0,0 +1,5 @@
+value class RIGHT(Args){
+	// a comment
+	// b comment
+	ChangeMe
+}
diff --git a/t/t4018/kotlin-interface b/t/t4018/kotlin-interface
new file mode 100644
index 0000000000..f686ba7770
--- /dev/null
+++ b/t/t4018/kotlin-interface
@@ -0,0 +1,5 @@
+interface RIGHT{
+	//another comment
+	//another comment
+	//ChangeMe
+}
diff --git a/t/t4018/kotlin-nested-fun b/t/t4018/kotlin-nested-fun
new file mode 100644
index 0000000000..12186858cb
--- /dev/null
+++ b/t/t4018/kotlin-nested-fun
@@ -0,0 +1,9 @@
+class LEFT{
+	class CENTER{
+		fun RIGHT(  a:Int){
+			//comment
+			//comment
+			ChangeMe
+		}
+	}
+}
diff --git a/t/t4018/kotlin-public-class b/t/t4018/kotlin-public-class
new file mode 100644
index 0000000000..9433fcc226
--- /dev/null
+++ b/t/t4018/kotlin-public-class
@@ -0,0 +1,5 @@
+public class RIGHT{
+	//comment1
+	//comment2
+	ChangeMe
+}
diff --git a/t/t4018/kotlin-sealed-class b/t/t4018/kotlin-sealed-class
new file mode 100644
index 0000000000..0efa4a4eaf
--- /dev/null
+++ b/t/t4018/kotlin-sealed-class
@@ -0,0 +1,5 @@
+sealed class RIGHT {
+	// a comment
+	// b comment
+	ChangeMe
+}
diff --git a/t/t4034-diff-words.sh b/t/t4034-diff-words.sh
index d5abcf4b4c..15764ee9ac 100755
--- a/t/t4034-diff-words.sh
+++ b/t/t4034-diff-words.sh
@@ -324,6 +324,7 @@ test_language_driver dts
 test_language_driver fortran
 test_language_driver html
 test_language_driver java
+test_language_driver kotlin
 test_language_driver matlab
 test_language_driver objc
 test_language_driver pascal
diff --git a/t/t4034/kotlin/expect b/t/t4034/kotlin/expect
new file mode 100644
index 0000000000..8acdc83bcc
--- /dev/null
+++ b/t/t4034/kotlin/expect
@@ -0,0 +1,35 @@
+<BOLD>diff --git a/pre b/post<RESET>
+<BOLD>index 884560d..7e136e2 100644<RESET>
+<BOLD>--- a/pre<RESET>
+<BOLD>+++ b/post<RESET>
+<CYAN>@@ -1,19 +1,19 @@<RESET>
+println("Hello World<RED>!\n<RESET><GREEN>?<RESET>")
+<GREEN>(<RESET>1<GREEN>) (<RESET>-1e10<GREEN>) (<RESET>0xabcdef<GREEN>)<RESET> '<RED>x<RESET><GREEN>y<RESET>'
+<RED>100000<RESET><GREEN>100_000<RESET>
+[<RED>a<RESET><GREEN>x<RESET>] <RED>a<RESET><GREEN>x<RESET>-><RED>b a<RESET><GREEN>y x<RESET>.<RED>b<RESET><GREEN>y<RESET>
+!<RED>a a<RESET><GREEN>x x<RESET>.inv() <RED>a<RESET><GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>&<RED>b<RESET><GREEN>y<RESET>
+a<RED>+=<RESET><GREEN>-=<RESET>b
+<RED>a<RESET><GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>/<RED>b a<RESET><GREEN>y x<RESET>%<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>+<RED>b a<RESET><GREEN>y x<RESET>-<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET> shl <RED>b a<RESET><GREEN>y x<RESET> shr <RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET><<RED>b a<RESET><GREEN>y x<RESET><=<RED>b a<RESET><GREEN>y x<RESET>><RED>b a<RESET><GREEN>y x<RESET>>=<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>==<RED>b a<RESET><GREEN>y x<RESET>!=<RED>b a<RESET><GREEN>y x<RESET>===<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET> and <RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>^<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET> or <RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>&&<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>||<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>=<RED>b a<RESET><GREEN>y x<RESET>+=<RED>b a<RESET><GREEN>y x<RESET>-=<RED>b a<RESET><GREEN>y x<RESET>*=<RED>b a<RESET><GREEN>y x<RESET>/=<RED>b a<RESET><GREEN>y x<RESET>%=<RED>b a<RESET><GREEN>y x<RESET><<=<RED>b a<RESET><GREEN>y x<RESET>>>=<RED>b a<RESET><GREEN>y x<RESET>&=<RED>b a<RESET><GREEN>y x<RESET>^=<RED>b a<RESET><GREEN>y x<RESET>|=<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>,y
+-<RED>a<RESET><GREEN>x<RESET>+2
diff --git a/t/t4034/kotlin/post b/t/t4034/kotlin/post
new file mode 100644
index 0000000000..7e136e2bb4
--- /dev/null
+++ b/t/t4034/kotlin/post
@@ -0,0 +1,19 @@
+println("Hello World?")
+(1) (-1e10) (0xabcdef) 'y'
+100_000
+[x] x->y x.y
+!x x.inv() x*y x&y
+a-=b
+x*y x/y x%y
+x+y x-y
+x shl y x shr y
+x<y x<=y x>y x>=y
+x==y x!=y x===y
+x and y
+x^y
+x or y
+x&&y
+x||y
+x=y x+=y x-=y x*=y x/=y x%=y x<<=y x>>=y x&=y x^=y x|=y
+x,y
+-x+2
diff --git a/t/t4034/kotlin/pre b/t/t4034/kotlin/pre
new file mode 100644
index 0000000000..884560d60f
--- /dev/null
+++ b/t/t4034/kotlin/pre
@@ -0,0 +1,19 @@
+println("Hello World!\n")
+1 -1e10 0xabcdef 'x'
+100000
+[a] a->b a.b
+!a a.inv() a*b a&b
+a+=b
+a*b a/b a%b
+a+b a-b
+a shl b a shr b
+a<b a<=b a>b a>=b
+a==b a!=b a===b
+a and b
+a^b
+a or b
+a&&b
+a||b
+a=b a+=b a-=b a*=b a/=b a%=b a<<=b a>>=b a&=b a^=b a|=b
+a,y
+-a+2
diff --git a/userdiff.c b/userdiff.c
index 8578cb0d12..b92572b582 100644
--- a/userdiff.c
+++ b/userdiff.c
@@ -168,6 +168,14 @@ PATTERNS("java",
 	 "|[-+0-9.e]+[fFlL]?|0[xXbB]?[0-9a-fA-F]+[lL]?"
 	 "|[-+*/<>%&^|=!]="
 	 "|--|\\+\\+|<<=?|>>>?=?|&&|\\|\\|"),
+PATTERNS("kotlin",
+	 "^[ \t]*(([a-z]+[ \t]+)*(fun|class|interface)[ \t]+.*)$",
+	 /* -- */
+	 "[_]?[a-zA-Z][a-zA-Z0-9_]*"
+	 /*hexadecimal, integers and binary numbers*/
+	 "|(0x0F|0b)?[0-9._]+([Ee][-+]?[0-9]+)?[fFlLuU]*"
+	 /*match unary and binary operators*/
+	 "|[-+*/<>%&^|=!]*"),
 PATTERNS("markdown",
 	 "^ {0,3}#{1,6}[ \t].*",
 	 /* -- */
-- 
2.35.1
Johannes Sixt· Mar 2, 2022, 08:00 UTC · re: Jaydeep P Das · lore

Re: [PATCH] userdiff: add builtin driver for kotlin language

Added jc to Cc:.
Am 02.03.22 um 07:45 schrieb Jaydeep P Das:
Show 14 quoted lines
> diff --git a/t/t4034/kotlin/expect b/t/t4034/kotlin/expect
> new file mode 100644
> index 0000000000..8acdc83bcc
> --- /dev/null
> +++ b/t/t4034/kotlin/expect
> @@ -0,0 +1,35 @@
> +<BOLD>diff --git a/pre b/post<RESET>
> +<BOLD>index 884560d..7e136e2 100644<RESET>
> +<BOLD>--- a/pre<RESET>
> +<BOLD>+++ b/post<RESET>
> +<CYAN>@@ -1,19 +1,19 @@<RESET>
> +println("Hello World<RED>!\n<RESET><GREEN>?<RESET>")
> +<GREEN>(<RESET>1<GREEN>) (<RESET>-1e10<GREEN>) (<RESET>0xabcdef<GREEN>)<RESET> '<RED>x<RESET><GREEN>y<RESET>'
> +<RED>100000<RESET><GREEN>100_000<RESET>

This test does not demonstrates that numbers do not end at an '_', because if it did end there, the change would be from the single token 100000 to two tokens 100 and _000, and the mark-up would look exactly the same as we see here, and would remain undiagnosed.

Instead, write the pre-image as 100_000 and the post image as 200_000. Then the correct mark-up would be

<RED>100_000<RESET><GREEN>200_000<RESET>
and a bogus markup (that the test wants to diagnose) would look like
<RED>100<RESET><GREEN>200<RESET>_000
> +[<RED>a<RESET><GREEN>x<RESET>] <RED>a<RESET><GREEN>x<RESET>-><RED>b a<RESET><GREEN>y x<RESET>.<RED>b<RESET><GREEN>y<RESET>
> +!<RED>a a<RESET><GREEN>x x<RESET>.inv() <RED>a<RESET><GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>&<RED>b<RESET><GREEN>y<RESET>
> +a<RED>+=<RESET><GREEN>-=<RESET>b

OK, so you decided to check operator += and -=. But what about all the other multi-character operators?

Show 21 quoted lines
> +<RED>a<RESET><GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>/<RED>b a<RESET><GREEN>y x<RESET>%<RED>b<RESET>
> +<RED>a<RESET><GREEN>y<RESET>
> +<GREEN>x<RESET>+<RED>b a<RESET><GREEN>y x<RESET>-<RED>b<RESET>
> +<RED>a<RESET><GREEN>y<RESET>
> +<GREEN>x<RESET> shl <RED>b a<RESET><GREEN>y x<RESET> shr <RED>b<RESET>
> +<RED>a<RESET><GREEN>y<RESET>
> +<GREEN>x<RESET><<RED>b a<RESET><GREEN>y x<RESET><=<RED>b a<RESET><GREEN>y x<RESET>><RED>b a<RESET><GREEN>y x<RESET>>=<RED>b<RESET>
> +<RED>a<RESET><GREEN>y<RESET>
> +<GREEN>x<RESET>==<RED>b a<RESET><GREEN>y x<RESET>!=<RED>b a<RESET><GREEN>y x<RESET>===<RED>b<RESET>
> +<RED>a<RESET><GREEN>y<RESET>
> +<GREEN>x<RESET> and <RED>b<RESET>
> +<RED>a<RESET><GREEN>y<RESET>
> +<GREEN>x<RESET>^<RED>b<RESET>
> +<RED>a<RESET><GREEN>y<RESET>
> +<GREEN>x<RESET> or <RED>b<RESET>
> +<RED>a<RESET><GREEN>y<RESET>
> +<GREEN>x<RESET>&&<RED>b<RESET>
> +<RED>a<RESET><GREEN>y<RESET>
> +<GREEN>x<RESET>||<RED>b<RESET>
> +<RED>a<RESET><GREEN>y<RESET>
> +<GREEN>x<RESET>=<RED>b a<RESET><GREEN>y x<RESET>+=<RED>b a<RESET><GREEN>y x<RESET>-=<RED>b a<RESET><GREEN>y x<RESET>*=<RED>b a<RESET><GREEN>y x<RESET>/=<RED>b a<RESET><GREEN>y x<RESET>%=<RED>b a<RESET><GREEN>y x<RESET><<=<RED>b a<RESET><GREEN>y x<RESET>>>=<RED>b a<RESET><GREEN>y x<RESET>&=<RED>b a<RESET><GREEN>y x<RESET>^=<RED>b a<RESET><GREEN>y x<RESET>|=<RED>b<RESET>

This line is the best candidate to check many multi-character operators. For example, the pre-image could read

a=b c+=d e-=f g*=h i/=j k%=l m<<=n o>>=p q&=r s^=t u|=v
and the post-image
a+=b c=d e<=f g>=h i/j k%l m<<n o>>p q&r s^t u|v
but there are more operators to check.

Please either make these changes or drop this t4034 test case, because in its current form it gives a false sense of security, IMHO.

> +<RED>a<RESET><GREEN>y<RESET>
> +<GREEN>x<RESET>,y
> +-<RED>a<RESET><GREEN>x<RESET>+2

What do you want to demonstrate with this new test case? If you want to show that the + in +2 is not part of the number, then you must change, for example, "a+2" to "a+1". If you change only the a to x, then we do not know whether the +2 was regarded as one token or two.

Show 12 quoted lines
> diff --git a/userdiff.c b/userdiff.c
> index 8578cb0d12..b92572b582 100644
> --- a/userdiff.c
> +++ b/userdiff.c
> @@ -168,6 +168,14 @@ PATTERNS("java",
>  	 "|[-+0-9.e]+[fFlL]?|0[xXbB]?[0-9a-fA-F]+[lL]?"
>  	 "|[-+*/<>%&^|=!]="
>  	 "|--|\\+\\+|<<=?|>>>?=?|&&|\\|\\|"),
> +PATTERNS("kotlin",
> +	 "^[ \t]*(([a-z]+[ \t]+)*(fun|class|interface)[ \t]+.*)$",
> +	 /* -- */
> +	 "[_]?[a-zA-Z][a-zA-Z0-9_]*"

An underscore followed by a digit is not an identifier, but a number, right? Then this expression correctly does not match and the following expression dedicated to numbers takes care of it. Good.

> +	 /*hexadecimal, integers and binary numbers*/
> +	 "|(0x0F|0b)?[0-9._]+([Ee][-+]?[0-9]+)?[fFlLuU]*"

What is this "0x0F"? Did you mean just "0x"? And what about prefixes 0X and 0B? Are they not used as prefixes for hex and binary numbers? Moreover, I do not see how a hex number 0xff would be matched as a single token.

> +	 /*match unary and binary operators*/
> +	 "|[-+*/<>%&^|=!]*"),

Do not do this. There is an implicit single-character match that need not be written down in the regex. List all multi-character operators (but not the single-character operators) like you did in earlier rounds. As written, the "++!=" in an expression such as "a++!=b++" (which is not unlikely to be seen in real code) would be regarded as a single token.

The verb "match" in the comment does not match the style of the other comments (drop the word), and please insert blanks between the comment delimiters and the text.

>  PATTERNS("markdown",
>  	 "^ {0,3}#{1,6}[ \t].*",
>  	 /* -- */
-- Hannes
jaydeepjd.8914@gmail.com· Mar 2, 2022, 09:09 UTC · re: Johannes Sixt · lore

Re: [PATCH] userdiff: add builtin driver for kotlin language

> This test does not demonstrates that numbers do not end at an '_',
> because if it did end there, the change would be from the single token
> 100000 to two tokens 100 and _000, and the mark-up would look exactly
> the same as we see here, and would remain undiagnosed.

Yes but numbers ending in `_` would be illegal syntax in Kotlin so the regex assumes that user is writing correct code.

Show 8 quoted lines
> Instead, write the pre-image as 100_000 and the post image as 200_000.
> Then the correct mark-up would be
> 
> <RED>100_000<RESET><GREEN>200_000<RESET>
> 
> and a bogus markup (that the test wants to diagnose) would look like
> 
> <RED>100<RESET><GREEN>200<RESET>_000
Right. I will add that test too.
> What is this "0x0F"? Did you mean just "0x"? 
`0x0F` indicates that its a hexadecimal literal in Kotlin.
Show 7 quoted lines
> And what about prefixes 0X
> and 0B? Are they not used as prefixes for hex and binary numbers?
> Moreover, I do not see how a hex number 0xff would be matched as a
> single token.
> 
> > +	 /*match unary and binary operators*/
> > +	 "|[-+*/<>%&^|=!]*"),
Yes. I would make the changes.
Show 13 quoted lines
> Do not do this. There is an implicit single-character match that need
> not be written down in the regex. List all multi-character operators
> (but not the single-character operators) like you did in earlier rounds.
> As written, the "++!=" in an expression such as "a++!=b++" (which is not
> unlikely to be seen in real code) would be regarded as a single token.
> 
> The verb "match" in the comment does not match the style of the other
> comments (drop the word), and please insert blanks between the comment
> delimiters and the text.
> 
> >   PATTERNS("markdown",
> >   	 "^ {0,3}#{1,6}[ \t].*",
> >   	 /* -- */
Noted.

Thanks, Jaydeep.

Jaydeep P Das· Mar 2, 2022, 14:26 UTC · re: Jaydeep P Das · lore

[GSoC][PATCHv3] userdiff: add builtin driver for kotlin language

Thanks Johannes for the review.
This patch hopefully fixes the problems you mentioned:
- Hexadecimals, binary and numbers with `_` are considered a single
  token
	Pre                    Post
    0xFF_EC_DE_5E          0xFF_E1_DE_5E
	0b100_000              0b100_100
	100_000                200_000
  Even though a single character is changed in each of the above
  numbers, the diffs would be produced as if they were single tokens
- More tests added for "proper" multicharacter operators.
  
  Earlier regex would consider a++!=++b as 3 different tokens(a, ++!=++, b)
  This patch matches the tokens properly into (a, ++, !=, ++, b)
Jaydeep P Das· Mar 2, 2022, 14:26 UTC · re: Jaydeep P Das · lore

[PATCH] userdiff: add builtin driver for kotlin language

The xfuncname pattern finds func/class declarations in diffs to display as a hunk header. The word_regex pattern finds individual tokens in Kotlin code to generate appropriate diffs.

This patch adds xfuncname regex and word_regex for Kotlin language.

Signed-off-by: Jaydeep P Das <jaydeepjd.8914@gmail.com>
---
 Documentation/gitattributes.txt |  2 ++
 t/t4018/kotlin-class            |  5 +++++
 t/t4018/kotlin-enum-class       |  5 +++++
 t/t4018/kotlin-fun              |  5 +++++
 t/t4018/kotlin-inheritace-class |  5 +++++
 t/t4018/kotlin-inline-class     |  5 +++++
 t/t4018/kotlin-interface        |  5 +++++
 t/t4018/kotlin-nested-fun       |  9 +++++++++
 t/t4018/kotlin-public-class     |  5 +++++
 t/t4018/kotlin-sealed-class     |  5 +++++
 t/t4034-diff-words.sh           |  1 +
 t/t4034/kotlin/expect           | 34 +++++++++++++++++++++++++++++++++
 t/t4034/kotlin/post             | 21 ++++++++++++++++++++
 t/t4034/kotlin/pre              | 21 ++++++++++++++++++++
 userdiff.c                      | 10 ++++++++++
 15 files changed, 138 insertions(+)
 create mode 100644 t/t4018/kotlin-class
 create mode 100644 t/t4018/kotlin-enum-class
 create mode 100644 t/t4018/kotlin-fun
 create mode 100644 t/t4018/kotlin-inheritace-class
 create mode 100644 t/t4018/kotlin-inline-class
 create mode 100644 t/t4018/kotlin-interface
 create mode 100644 t/t4018/kotlin-nested-fun
 create mode 100644 t/t4018/kotlin-public-class
 create mode 100644 t/t4018/kotlin-sealed-class
 create mode 100644 t/t4034/kotlin/expect
 create mode 100644 t/t4034/kotlin/post
 create mode 100644 t/t4034/kotlin/pre
Show changes to 15 files +138 −0

Documentation/gitattributes.txt, t/t4018/kotlin-class, t/t4018/kotlin-enum-class, t/t4018/kotlin-fun, t/t4018/kotlin-inheritace-class, t/t4018/kotlin-inline-class, t/t4018/kotlin-interface, t/t4018/kotlin-nested-fun, t/t4018/kotlin-public-class, t/t4018/kotlin-sealed-class, t/t4034-diff-words.sh, t/t4034/kotlin/expect, t/t4034/kotlin/post, t/t4034/kotlin/pre, userdiff.c

diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt
index a71dad2674..4b36d51beb 100644
--- a/Documentation/gitattributes.txt
+++ b/Documentation/gitattributes.txt
@@ -829,6 +829,8 @@ patterns are available:
 
 - `java` suitable for source code in the Java language.
 
+- `kotlin` suitable for source code in the Kotlin language.
+
 - `markdown` suitable for Markdown documents.
 
 - `matlab` suitable for source code in the MATLAB and Octave languages.
diff --git a/t/t4018/kotlin-class b/t/t4018/kotlin-class
new file mode 100644
index 0000000000..bb864f22e6
--- /dev/null
+++ b/t/t4018/kotlin-class
@@ -0,0 +1,5 @@
+class RIGHT {
+	//comment
+	//comment
+	return ChangeMe
+}
diff --git a/t/t4018/kotlin-enum-class b/t/t4018/kotlin-enum-class
new file mode 100644
index 0000000000..8885f908fd
--- /dev/null
+++ b/t/t4018/kotlin-enum-class
@@ -0,0 +1,5 @@
+enum class RIGHT{
+	// Left
+	// a comment
+	ChangeMe
+}
diff --git a/t/t4018/kotlin-fun b/t/t4018/kotlin-fun
new file mode 100644
index 0000000000..2a60280256
--- /dev/null
+++ b/t/t4018/kotlin-fun
@@ -0,0 +1,5 @@
+fun RIGHT(){
+	//a comment
+	//b comment
+    return ChangeMe()
+}
diff --git a/t/t4018/kotlin-inheritace-class b/t/t4018/kotlin-inheritace-class
new file mode 100644
index 0000000000..77376c1f05
--- /dev/null
+++ b/t/t4018/kotlin-inheritace-class
@@ -0,0 +1,5 @@
+open class RIGHT{
+	// a comment
+	// b comment
+	// ChangeMe
+}
diff --git a/t/t4018/kotlin-inline-class b/t/t4018/kotlin-inline-class
new file mode 100644
index 0000000000..7bf46dd8d4
--- /dev/null
+++ b/t/t4018/kotlin-inline-class
@@ -0,0 +1,5 @@
+value class RIGHT(Args){
+	// a comment
+	// b comment
+	ChangeMe
+}
diff --git a/t/t4018/kotlin-interface b/t/t4018/kotlin-interface
new file mode 100644
index 0000000000..f686ba7770
--- /dev/null
+++ b/t/t4018/kotlin-interface
@@ -0,0 +1,5 @@
+interface RIGHT{
+	//another comment
+	//another comment
+	//ChangeMe
+}
diff --git a/t/t4018/kotlin-nested-fun b/t/t4018/kotlin-nested-fun
new file mode 100644
index 0000000000..12186858cb
--- /dev/null
+++ b/t/t4018/kotlin-nested-fun
@@ -0,0 +1,9 @@
+class LEFT{
+	class CENTER{
+		fun RIGHT(  a:Int){
+			//comment
+			//comment
+			ChangeMe
+		}
+	}
+}
diff --git a/t/t4018/kotlin-public-class b/t/t4018/kotlin-public-class
new file mode 100644
index 0000000000..9433fcc226
--- /dev/null
+++ b/t/t4018/kotlin-public-class
@@ -0,0 +1,5 @@
+public class RIGHT{
+	//comment1
+	//comment2
+	ChangeMe
+}
diff --git a/t/t4018/kotlin-sealed-class b/t/t4018/kotlin-sealed-class
new file mode 100644
index 0000000000..0efa4a4eaf
--- /dev/null
+++ b/t/t4018/kotlin-sealed-class
@@ -0,0 +1,5 @@
+sealed class RIGHT {
+	// a comment
+	// b comment
+	ChangeMe
+}
diff --git a/t/t4034-diff-words.sh b/t/t4034-diff-words.sh
index d5abcf4b4c..15764ee9ac 100755
--- a/t/t4034-diff-words.sh
+++ b/t/t4034-diff-words.sh
@@ -324,6 +324,7 @@ test_language_driver dts
 test_language_driver fortran
 test_language_driver html
 test_language_driver java
+test_language_driver kotlin
 test_language_driver matlab
 test_language_driver objc
 test_language_driver pascal
diff --git a/t/t4034/kotlin/expect b/t/t4034/kotlin/expect
new file mode 100644
index 0000000000..7062b67319
--- /dev/null
+++ b/t/t4034/kotlin/expect
@@ -0,0 +1,34 @@
+<BOLD>diff --git a/pre b/post<RESET>
+<BOLD>index 3cfa271..20d26cc 100644<RESET>
+<BOLD>--- a/pre<RESET>
+<BOLD>+++ b/post<RESET>
+<CYAN>@@ -1,21 +1,21 @@<RESET>
+println("Hello World<RED>!\n<RESET><GREEN>?<RESET>")
+<GREEN>(<RESET>1<GREEN>) (<RESET>-1e10<GREEN>) (<RESET>0xabcdef<GREEN>)<RESET> '<RED>x<RESET><GREEN>y<RESET>'
+[<RED>a<RESET><GREEN>x<RESET>] <RED>a<RESET><GREEN>x<RESET>-><RED>b a<RESET><GREEN>y x<RESET>.<RED>b<RESET><GREEN>y<RESET>
+!<RED>a a<RESET><GREEN>x x<RESET>.inv() <RED>a<RESET><GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>&<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>/<RED>b a<RESET><GREEN>y x<RESET>%<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>+<RED>b a<RESET><GREEN>y x<RESET>-<RED>b<RESET><GREEN>y<RESET>
+a <RED>shr<RESET><GREEN>shl<RESET> b
+<RED>a<RESET><GREEN>x<RESET><<RED>b a<RESET><GREEN>y x<RESET><=<RED>b a<RESET><GREEN>y x<RESET>><RED>b a<RESET><GREEN>y x<RESET>>=<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>==<RED>b a<RESET><GREEN>y x<RESET>!=<RED>b a<RESET><GREEN>y x<RESET>===<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET> and <RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>^<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET> or <RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>&&<RED>b a<RESET><GREEN>y x<RESET>||<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>=<RED>b a<RESET><GREEN>y x<RESET>+=<RED>b a<RESET><GREEN>y x<RESET>-=<RED>b a<RESET><GREEN>y x<RESET>*=<RED>b a<RESET><GREEN>y x<RESET>/=<RED>b a<RESET><GREEN>y x<RESET>%=<RED>b a<RESET><GREEN>y x<RESET><<=<RED>b a<RESET><GREEN>y x<RESET>>>=<RED>b a<RESET><GREEN>y x<RESET>&=<RED>b a<RESET><GREEN>y x<RESET>^=<RED>b a<RESET><GREEN>y x<RESET>|=<RED>b<RESET><GREEN>y<RESET>
+a<RED>=<RESET><GREEN>+=<RESET>b c<RED>+=<RESET><GREEN>=<RESET>d e<RED>-=<RESET><GREEN><=<RESET>f g<RED>*=<RESET><GREEN>>=<RESET>h i<RED>/=<RESET><GREEN>/<RESET>j k<RED>%=<RESET><GREEN>%<RESET>l m<RED><<=<RESET><GREEN><<<RESET>n o<RED>>>=<RESET><GREEN>>><RESET>p q<RED>&=<RESET><GREEN>&<RESET>r s<RED>^=<RESET><GREEN>^<RESET>t u<RED>|=<RESET><GREEN>|<RESET>v
+a<RED><<=<RESET><GREEN><=<RESET>b
+a<RED>||<RESET><GREEN>|<RESET>b a<RED>&&<RESET><GREEN>&<RESET>b
+<RED>a<RESET><GREEN>x<RESET>,y
+--a<RED>==<RESET><GREEN>!=<RESET>--b
+a++<RED>==<RESET><GREEN>!=<RESET>++b
+<RED>0xFF_EC_DE_5E 0b100_000 100_000<RESET><GREEN>0xFF_E1_DE_5E 0b100_100 200_000<RESET>
diff --git a/t/t4034/kotlin/post b/t/t4034/kotlin/post
new file mode 100644
index 0000000000..20d26cca5f
--- /dev/null
+++ b/t/t4034/kotlin/post
@@ -0,0 +1,21 @@
+println("Hello World?")
+(1) (-1e10) (0xabcdef) 'y'
+[x] x->y x.y
+!x x.inv() x*y x&y
+x*y x/y x%y
+x+y x-y
+a shl b
+x<y x<=y x>y x>=y
+x==y x!=y x===y
+x and y
+x^y
+x or y
+x&&y x||y
+x=y x+=y x-=y x*=y x/=y x%=y x<<=y x>>=y x&=y x^=y x|=y
+a+=b c=d e<=f g>=h i/j k%l m<<n o>>p q&r s^t u|v
+a<=b
+a|b a&b
+x,y
+--a!=--b
+a++!=++b
+0xFF_E1_DE_5E 0b100_100 200_000
diff --git a/t/t4034/kotlin/pre b/t/t4034/kotlin/pre
new file mode 100644
index 0000000000..3cfa271e37
--- /dev/null
+++ b/t/t4034/kotlin/pre
@@ -0,0 +1,21 @@
+println("Hello World!\n")
+1 -1e10 0xabcdef 'x'
+[a] a->b a.b
+!a a.inv() a*b a&b
+a*b a/b a%b
+a+b a-b
+a shr b
+a<b a<=b a>b a>=b
+a==b a!=b a===b
+a and b
+a^b
+a or b
+a&&b a||b
+a=b a+=b a-=b a*=b a/=b a%=b a<<=b a>>=b a&=b a^=b a|=b
+a=b c+=d e-=f g*=h i/=j k%=l m<<=n o>>=p q&=r s^=t u|=v
+a<<=b
+a||b a&&b
+a,y
+--a==--b
+a++==++b
+0xFF_EC_DE_5E 0b100_000 100_000
diff --git a/userdiff.c b/userdiff.c
index 8578cb0d12..bb701100c6 100644
--- a/userdiff.c
+++ b/userdiff.c
@@ -168,6 +168,16 @@ PATTERNS("java",
 	 "|[-+0-9.e]+[fFlL]?|0[xXbB]?[0-9a-fA-F]+[lL]?"
 	 "|[-+*/<>%&^|=!]="
 	 "|--|\\+\\+|<<=?|>>>?=?|&&|\\|\\|"),
+PATTERNS("kotlin",
+	 "^[ \t]*(([a-z]+[ \t]+)*(fun|class|interface)[ \t]+.*)$",
+	 /* -- */
+	 "[_]?[a-zA-Z][a-zA-Z0-9_]*"
+	 /* hexadecimal and binary numbers */
+	 "|0[xXbB][0-9a-fA-F_]+[lLuU]*"
+	 /* integers and floats */
+	 "|[0-9._]+([Ee][-+]?[0-9]+)?[fFlLuU]*"
+	 /* unary and binary operators */
+	 "|[-+*/<>%&^|=!]?=(=)?|--|\\+\\+|<<?=?|>>?=?|&&?|[|]?\\||\\|->\\*?|\\.\\*"),
 PATTERNS("markdown",
 	 "^ {0,3}#{1,6}[ \t].*",
 	 /* -- */
-- 
2.35.1
Johannes Sixt· Mar 2, 2022, 20:18 UTC · re: Jaydeep P Das · lore

Re: [PATCH] userdiff: add builtin driver for kotlin language

Am 02.03.22 um 15:26 schrieb Jaydeep P Das:
Show 40 quoted lines
> diff --git a/t/t4034/kotlin/expect b/t/t4034/kotlin/expect
> new file mode 100644
> index 0000000000..7062b67319
> --- /dev/null
> +++ b/t/t4034/kotlin/expect
> @@ -0,0 +1,34 @@
> +<BOLD>diff --git a/pre b/post<RESET>
> +<BOLD>index 3cfa271..20d26cc 100644<RESET>
> +<BOLD>--- a/pre<RESET>
> +<BOLD>+++ b/post<RESET>
> +<CYAN>@@ -1,21 +1,21 @@<RESET>
> +println("Hello World<RED>!\n<RESET><GREEN>?<RESET>")
> +<GREEN>(<RESET>1<GREEN>) (<RESET>-1e10<GREEN>) (<RESET>0xabcdef<GREEN>)<RESET> '<RED>x<RESET><GREEN>y<RESET>'
> +[<RED>a<RESET><GREEN>x<RESET>] <RED>a<RESET><GREEN>x<RESET>-><RED>b a<RESET><GREEN>y x<RESET>.<RED>b<RESET><GREEN>y<RESET>
> +!<RED>a a<RESET><GREEN>x x<RESET>.inv() <RED>a<RESET><GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>&<RED>b<RESET>
> +<RED>a<RESET><GREEN>y<RESET>
> +<GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>/<RED>b a<RESET><GREEN>y x<RESET>%<RED>b<RESET>
> +<RED>a<RESET><GREEN>y<RESET>
> +<GREEN>x<RESET>+<RED>b a<RESET><GREEN>y x<RESET>-<RED>b<RESET><GREEN>y<RESET>
> +a <RED>shr<RESET><GREEN>shl<RESET> b
> +<RED>a<RESET><GREEN>x<RESET><<RED>b a<RESET><GREEN>y x<RESET><=<RED>b a<RESET><GREEN>y x<RESET>><RED>b a<RESET><GREEN>y x<RESET>>=<RED>b<RESET>
> +<RED>a<RESET><GREEN>y<RESET>
> +<GREEN>x<RESET>==<RED>b a<RESET><GREEN>y x<RESET>!=<RED>b a<RESET><GREEN>y x<RESET>===<RED>b<RESET>
> +<RED>a<RESET><GREEN>y<RESET>
> +<GREEN>x<RESET> and <RED>b<RESET>
> +<RED>a<RESET><GREEN>y<RESET>
> +<GREEN>x<RESET>^<RED>b<RESET>
> +<RED>a<RESET><GREEN>y<RESET>
> +<GREEN>x<RESET> or <RED>b<RESET>
> +<RED>a<RESET><GREEN>y<RESET>
> +<GREEN>x<RESET>&&<RED>b a<RESET><GREEN>y x<RESET>||<RED>b<RESET>
> +<RED>a<RESET><GREEN>y<RESET>
> +<GREEN>x<RESET>=<RED>b a<RESET><GREEN>y x<RESET>+=<RED>b a<RESET><GREEN>y x<RESET>-=<RED>b a<RESET><GREEN>y x<RESET>*=<RED>b a<RESET><GREEN>y x<RESET>/=<RED>b a<RESET><GREEN>y x<RESET>%=<RED>b a<RESET><GREEN>y x<RESET><<=<RED>b a<RESET><GREEN>y x<RESET>>>=<RED>b a<RESET><GREEN>y x<RESET>&=<RED>b a<RESET><GREEN>y x<RESET>^=<RED>b a<RESET><GREEN>y x<RESET>|=<RED>b<RESET><GREEN>y<RESET>
> +a<RED>=<RESET><GREEN>+=<RESET>b c<RED>+=<RESET><GREEN>=<RESET>d e<RED>-=<RESET><GREEN><=<RESET>f g<RED>*=<RESET><GREEN>>=<RESET>h i<RED>/=<RESET><GREEN>/<RESET>j k<RED>%=<RESET><GREEN>%<RESET>l m<RED><<=<RESET><GREEN><<<RESET>n o<RED>>>=<RESET><GREEN>>><RESET>p q<RED>&=<RESET><GREEN>&<RESET>r s<RED>^=<RESET><GREEN>^<RESET>t u<RED>|=<RESET><GREEN>|<RESET>v
> +a<RED><<=<RESET><GREEN><=<RESET>b
> +a<RED>||<RESET><GREEN>|<RESET>b a<RED>&&<RESET><GREEN>&<RESET>b
> +<RED>a<RESET><GREEN>x<RESET>,y
> +--a<RED>==<RESET><GREEN>!=<RESET>--b
> +a++<RED>==<RESET><GREEN>!=<RESET>++b
> +<RED>0xFF_EC_DE_5E 0b100_000 100_000<RESET><GREEN>0xFF_E1_DE_5E 0b100_100 200_000<RESET>

Many of the a->x, b->y changes are redundant IMHO, but they do not hurt. This looks good.

Show 18 quoted lines
> diff --git a/userdiff.c b/userdiff.c
> index 8578cb0d12..bb701100c6 100644
> --- a/userdiff.c
> +++ b/userdiff.c
> @@ -168,6 +168,16 @@ PATTERNS("java",
>  	 "|[-+0-9.e]+[fFlL]?|0[xXbB]?[0-9a-fA-F]+[lL]?"
>  	 "|[-+*/<>%&^|=!]="
>  	 "|--|\\+\\+|<<=?|>>>?=?|&&|\\|\\|"),
> +PATTERNS("kotlin",
> +	 "^[ \t]*(([a-z]+[ \t]+)*(fun|class|interface)[ \t]+.*)$",
> +	 /* -- */
> +	 "[_]?[a-zA-Z][a-zA-Z0-9_]*"
> +	 /* hexadecimal and binary numbers */
> +	 "|0[xXbB][0-9a-fA-F_]+[lLuU]*"
> +	 /* integers and floats */
> +	 "|[0-9._]+([Ee][-+]?[0-9]+)?[fFlLuU]*"
> +	 /* unary and binary operators */
> +	 "|[-+*/<>%&^|=!]?=(=)?|--|\\+\\+|<<?=?|>>?=?|&&?|[|]?\\||\\|->\\*?|\\.\\*"),

Some of these sub-expressions match single-character operators, but that does not hurt.

How many tokens will the word-regex find in the expression X.e+200UL? .e+200UL is a single token. Also, X.Find consists of the three tokens X .F ind.

It's most easily fixed by requiring a digit before the fullstop. But if floatingpoint numbers can begin with a fullstop, then we need a second expression that requires a digit after a leading fullstop.

>  PATTERNS("markdown",
>  	 "^ {0,3}#{1,6}[ \t].*",
>  	 /* -- */
-- Hannes
Jaydeep Das· Mar 3, 2022, 11:41 UTC · re: Johannes Sixt · lore

Re: [PATCH] userdiff: add builtin driver for kotlin language

How about modifying the number match regex to:
`[0-9._]+([Ee][-+]?[0-9]+)?[fFlLuU]*[^a-zA-Z]` ?

The `[^a-zA-Z]` in the end would make sure to not match the `.F` in `X.Find`.

Additionally, we can add another regex for matching just the method calls:

`[.][a-zA-Z()0-9]+`

Both of these changes would make word_regex match 2 tokens in X.Find() : X and .Find() (Here X can be any valid identifier name)

> How many tokens will the word-regex find in the expression X.e+200UL?
> .e+200UL is a single token. > It's most easily fixed by requiring a digit before the fullstop. But if
> floatingpoint numbers can begin with a fullstop, then we need a second
> expression that requires a digit after a leading fullstop.

But that syntax would be wrong. I tried making a condition like you said, but it always ended up breaking something else(like breaking 2.e+200UL into 2, .e, + and 200UL)

Also, I realized I did a bit of mistake in the identifier regex. Both _abc and __abc are valid identifiers. _3432, __3232 are valid identifiers too.(not numbers)

The previous regex matched only one `_`, so in the next patch, I plan to implement the following regex:

Identifier: `([_]*[a-zA-Z]|[_]+[0-9]+)[a-zA-Z0-9_]*`
Numbers: `[0-9_.]+([Ee][-+]?[0-9]+)?[fFlLuU]*[^a-zA-Z]`
(It makes sure that in X.Find, .F is not matched )
Additionally, An extra regex for method calls:
`[.][a-zA-Z()0-9]+`
What do you think?

Thanks, Jaydeep.

Ævar Arnfjörð Bjarmason· Mar 3, 2022, 16:54 UTC · re: Jaydeep Das · lore

Re: [PATCH] userdiff: add builtin driver for kotlin language

On Thu, Mar 03 2022, Jaydeep Das wrote:
Show 40 quoted lines
> How about modifying the number match regex to:
>
> `[0-9._]+([Ee][-+]?[0-9]+)?[fFlLuU]*[^a-zA-Z]` ?
>
> The `[^a-zA-Z]` in the end would make sure to not match
> the `.F` in `X.Find`.
>
> Additionally, we can add another regex for matching just
> the method calls:
>
> `[.][a-zA-Z()0-9]+`
>
> Both of these changes would make word_regex match 2 tokens in
> X.Find() : X and .Find() (Here X can be any valid identifier name)
>
>
>> How many tokens will the word-regex find in the expression X.e+200UL?
>> .e+200UL is a single token. > It's most easily fixed by requiring a digit before the fullstop. But if
>> floatingpoint numbers can begin with a fullstop, then we need a second
>> expression that requires a digit after a leading fullstop.
>
> But that syntax would be wrong. I tried making a condition like you said,
> but it always ended up breaking something else(like breaking 2.e+200UL into 2, .e, + and 200UL)
>
> Also, I realized I did a bit of mistake in the identifier regex.
> Both _abc and __abc are valid identifiers. _3432, __3232 are valid identifiers too.(not numbers)
>
> The previous regex matched only one `_`, so in the next patch,
> I plan to implement the following regex:
>
> Identifier: `([_]*[a-zA-Z]|[_]+[0-9]+)[a-zA-Z0-9_]*`
>
> Numbers: `[0-9_.]+([Ee][-+]?[0-9]+)?[fFlLuU]*[^a-zA-Z]`
> (It makes sure that in X.Find, .F is not matched )
>
> Additionally, An extra regex for method calls:
>
> `[.][a-zA-Z()0-9]+`
>
> What do you think?

Just a small note on rx syntax> [.] can be handy to escape "." (but you can also use "\\.", but that's arguably not as easy to read.

But there's no reason to use [_]* over just _*..

(Also, I have an in-flight change to userdiff.c that would conflict, but I wonder if it wouldn't be handy to make the word_regex a "struct userdiff_funcname". Then we could specify icase flags, which in this case would make it a lot easier to read).

Junio C Hamano· Mar 3, 2022, 19:47 UTC · re: Jaydeep Das · lore

Re: [PATCH] userdiff: add builtin driver for kotlin language

Jaydeep Das <jaydeepjd.8914@gmail.com> writes:
Show 6 quoted lines
> How about modifying the number match regex to:
>
> `[0-9._]+([Ee][-+]?[0-9]+)?[fFlLuU]*[^a-zA-Z]` ?
>
> The `[^a-zA-Z]` in the end would make sure to not match
> the `.F` in `X.Find`.

Do we want to match "foo.F<EOL>"? If requiring at least one non-alpha after [fFlLuU]* is OK, then please ignore this message ;-)

Thanks.
Johannes Sixt· Mar 3, 2022, 20:04 UTC · re: Jaydeep Das · lore

Re: [PATCH] userdiff: add builtin driver for kotlin language

Am 03.03.22 um 12:41 schrieb Jaydeep Das:
Show 6 quoted lines
> How about modifying the number match regex to:
> 
> `[0-9._]+([Ee][-+]?[0-9]+)?[fFlLuU]*[^a-zA-Z]` ?
> 
> The `[^a-zA-Z]` in the end would make sure to not match
> the `.F` in `X.Find`.

No, you cannot do that, because then in X.u+1 you have three tokens X .u+ 1, which you do not want, either.

Show 7 quoted lines
> Additionally, we can add another regex for matching just
> the method calls:
> 
> `[.][a-zA-Z()0-9]+`
> 
> Both of these changes would make word_regex match 2 tokens in
> X.Find() : X and .Find() (Here X can be any valid identifier name)

Well, you can do that. But I would not do that if it is allowed to have a blank between the fullstop and a method name.

Show 18 quoted lines
>> How many tokens will the word-regex find in the expression X.e+200UL?
>> .e+200UL is a single token. > It's most easily fixed by requiring a
>> digit before the fullstop. But if
>> floatingpoint numbers can begin with a fullstop, then we need a second
>> expression that requires a digit after a leading fullstop.
> 
> But that syntax would be wrong. I tried making a condition like you said,
> but it always ended up breaking something else(like breaking 2.e+200UL
> into 2, .e, + and 200UL)
> 
> Also, I realized I did a bit of mistake in the identifier regex.
> Both _abc and __abc are valid identifiers. _3432, __3232 are valid
> identifiers too.(not numbers)
> 
> The previous regex matched only one `_`, so in the next patch,
> I plan to implement the following regex:
> 
> Identifier: `([_]*[a-zA-Z]|[_]+[0-9]+)[a-zA-Z0-9_]*`
But then you can use the regex you had in the first round:
   [a-zA-Z_][a-zA-Z0-9_]*
Show 9 quoted lines
> 
> Numbers: `[0-9_.]+([Ee][-+]?[0-9]+)?[fFlLuU]*[^a-zA-Z]`
> (It makes sure that in X.Find, .F is not matched )
> 
> Additionally, An extra regex for method calls:
> 
> `[.][a-zA-Z()0-9]+`
> 
> What do you think?

Have a look at the regex in the cpp driver. I think we need something like this:

  /* integers floatingpoint numbers */
  "|[0-9][0-9_.]*([Ee][*-]?[0-9]+)?[FfLl]*"
  /* floatingpoint numbers that begin with a decimal point */
  "|[.][0-9][0-9_]*([Ee][*-]?[0-9]+)?[FfLl]*"
Drop the second option if numbers such as .5 are invalid syntax in Kotlin.
-- Hannes
Jaydeep Das· Mar 4, 2022, 12:28 UTC · re: Johannes Sixt · lore

Re: [PATCH] userdiff: add builtin driver for kotlin language

On 3/4/22 01:34, Johannes Sixt wrote:
Show 7 quoted lines
> Am 03.03.22 um 12:41 schrieb Jaydeep Das:
>> How about modifying the number match regex to:
>>
>> `[0-9._]+([Ee][-+]?[0-9]+)?[fFlLuU]*[^a-zA-Z]` ?
>>
>> The `[^a-zA-Z]` in the end would make sure to not match
>> the `.F` in `X.Find`.
> No, you cannot do that, because then in X.u+1 you have three tokens X
> .u+ 1, which you do not want, either.
If X is an integer here, then

In C/C++ 2.f is equivalent to 2.000000 However in Kotlin 2.f is invalid syntax. 2.0f is valid.

So is implementing a proper regex for invalid syntax really necessary?

> But then you can use the regex you had in the first round:
> 
>     [a-zA-Z_][a-zA-Z0-9_]*
Right. I will change that.
  
Show 16 quoted lines
>> Numbers: `[0-9_.]+([Ee][-+]?[0-9]+)?[fFlLuU]*[^a-zA-Z]`
>> (It makes sure that in X.Find, .F is not matched )
>>
>> Additionally, An extra regex for method calls:
>>
>> `[.][a-zA-Z()0-9]+`
>>
>> What do you think?
> 
> Have a look at the regex in the cpp driver. I think we need something
> like this:
> 
>    /* integers floatingpoint numbers */
>    "|[0-9][0-9_.]*([Ee][*-]?[0-9]+)?[FfLl]*"
>    /* floatingpoint numbers that begin with a decimal point */
>    "|[.][0-9][0-9_]*([Ee][*-]?[0-9]+)?[FfLl]*"
> Drop the second option if numbers such as .5 are invalid syntax in Kotlin.
.5 is valid syntax in Kotlin.

-- Thanks, Jaydeep.

  
Johannes Sixt· Mar 4, 2022, 13:59 UTC · re: Jaydeep Das · lore

Re: [PATCH] userdiff: add builtin driver for kotlin language

Am 04.03.22 um 13:28 schrieb Jaydeep Das:
Show 13 quoted lines
> On 3/4/22 01:34, Johannes Sixt wrote:
>> Am 03.03.22 um 12:41 schrieb Jaydeep Das:
>>> How about modifying the number match regex to:
>>>
>>> `[0-9._]+([Ee][-+]?[0-9]+)?[fFlLuU]*[^a-zA-Z]` ?
>>>
>>> The `[^a-zA-Z]` in the end would make sure to not match
>>> the `.F` in `X.Find`.
>  
>> No, you cannot do that, because then in X.u+1 you have three tokens X
>> .u+ 1, which you do not want, either.
> 
> If X is an integer here, then
No, I mean X literally, i.e., an identifier.
Show 6 quoted lines
> 
> In C/C++ 2.f is equivalent to 2.000000
> However in Kotlin 2.f is invalid syntax. 2.0f is valid.
> 
> So is implementing a proper regex for invalid syntax really
> necessary?

No, that's not necessary. It can be assumed that invalid syntax does not occur. For this reason...

Show 5 quoted lines
>> Have a look at the regex in the cpp driver. I think we need something
>> like this:
>>
>>    /* integers floatingpoint numbers */
>>    "|[0-9][0-9_.]*([Ee][*-]?[0-9]+)?[FfLl]*"

... I propose this loose [0-9_.]* after the first digit, even though it would match "9.8_7._65"; we can assume that this invalid token will not occur.

BTW, make that [FfLlUl] near the end.
Show 7 quoted lines
>>    /* floatingpoint numbers that begin with a decimal point */
>>    "|[.][0-9][0-9_]*([Ee][*-]?[0-9]+)?[FfLl]*"
> 
> 
>> Drop the second option if numbers such as .5 are invalid syntax in
>> Kotlin.
> .5 is valid syntax in Kotlin.

OK, then we need this second branch, which ensures that there is a digit after the fullstop.

-- Hannes
Jaydeep P Das· Mar 3, 2022, 18:15 UTC · re: Jaydeep P Das · lore

[PATCH] userdiff: add builtin diff driver for Kotlin language.

The xfuncname pattern finds func/class declarations in diffs to display as a hunk header. The word_regex pattern finds individual tokens in Kotlin code to generate appropriate diffs.

This patch adds xfuncname regex and word_regex for Kotlin language.

Signed-off-by: Jaydeep P Das <jaydeepjd.8914@gmail.com>
---
 Documentation/gitattributes.txt |  2 ++
 t/t4018/kotlin-class            |  5 +++++
 t/t4018/kotlin-enum-class       |  5 +++++
 t/t4018/kotlin-fun              |  5 +++++
 t/t4018/kotlin-inheritace-class |  5 +++++
 t/t4018/kotlin-inline-class     |  5 +++++
 t/t4018/kotlin-interface        |  5 +++++
 t/t4018/kotlin-nested-fun       |  9 ++++++++
 t/t4018/kotlin-public-class     |  5 +++++
 t/t4018/kotlin-sealed-class     |  5 +++++
 t/t4034-diff-words.sh           |  1 +
 t/t4034/kotlin/expect           | 37 +++++++++++++++++++++++++++++++++
 t/t4034/kotlin/post             | 24 +++++++++++++++++++++
 t/t4034/kotlin/pre              | 24 +++++++++++++++++++++
 userdiff.c                      | 12 +++++++++++
 15 files changed, 149 insertions(+)
 create mode 100644 t/t4018/kotlin-class
 create mode 100644 t/t4018/kotlin-enum-class
 create mode 100644 t/t4018/kotlin-fun
 create mode 100644 t/t4018/kotlin-inheritace-class
 create mode 100644 t/t4018/kotlin-inline-class
 create mode 100644 t/t4018/kotlin-interface
 create mode 100644 t/t4018/kotlin-nested-fun
 create mode 100644 t/t4018/kotlin-public-class
 create mode 100644 t/t4018/kotlin-sealed-class
 create mode 100644 t/t4034/kotlin/expect
 create mode 100644 t/t4034/kotlin/post
 create mode 100644 t/t4034/kotlin/pre
Show changes to 15 files +149 −0

Documentation/gitattributes.txt, t/t4018/kotlin-class, t/t4018/kotlin-enum-class, t/t4018/kotlin-fun, t/t4018/kotlin-inheritace-class, t/t4018/kotlin-inline-class, t/t4018/kotlin-interface, t/t4018/kotlin-nested-fun, t/t4018/kotlin-public-class, t/t4018/kotlin-sealed-class, t/t4034-diff-words.sh, t/t4034/kotlin/expect, t/t4034/kotlin/post, t/t4034/kotlin/pre, userdiff.c

diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt
index a71dad2674..4b36d51beb 100644
--- a/Documentation/gitattributes.txt
+++ b/Documentation/gitattributes.txt
@@ -829,6 +829,8 @@ patterns are available:
 
 - `java` suitable for source code in the Java language.
 
+- `kotlin` suitable for source code in the Kotlin language.
+
 - `markdown` suitable for Markdown documents.
 
 - `matlab` suitable for source code in the MATLAB and Octave languages.
diff --git a/t/t4018/kotlin-class b/t/t4018/kotlin-class
new file mode 100644
index 0000000000..bb864f22e6
--- /dev/null
+++ b/t/t4018/kotlin-class
@@ -0,0 +1,5 @@
+class RIGHT {
+	//comment
+	//comment
+	return ChangeMe
+}
diff --git a/t/t4018/kotlin-enum-class b/t/t4018/kotlin-enum-class
new file mode 100644
index 0000000000..8885f908fd
--- /dev/null
+++ b/t/t4018/kotlin-enum-class
@@ -0,0 +1,5 @@
+enum class RIGHT{
+	// Left
+	// a comment
+	ChangeMe
+}
diff --git a/t/t4018/kotlin-fun b/t/t4018/kotlin-fun
new file mode 100644
index 0000000000..2a60280256
--- /dev/null
+++ b/t/t4018/kotlin-fun
@@ -0,0 +1,5 @@
+fun RIGHT(){
+	//a comment
+	//b comment
+    return ChangeMe()
+}
diff --git a/t/t4018/kotlin-inheritace-class b/t/t4018/kotlin-inheritace-class
new file mode 100644
index 0000000000..77376c1f05
--- /dev/null
+++ b/t/t4018/kotlin-inheritace-class
@@ -0,0 +1,5 @@
+open class RIGHT{
+	// a comment
+	// b comment
+	// ChangeMe
+}
diff --git a/t/t4018/kotlin-inline-class b/t/t4018/kotlin-inline-class
new file mode 100644
index 0000000000..7bf46dd8d4
--- /dev/null
+++ b/t/t4018/kotlin-inline-class
@@ -0,0 +1,5 @@
+value class RIGHT(Args){
+	// a comment
+	// b comment
+	ChangeMe
+}
diff --git a/t/t4018/kotlin-interface b/t/t4018/kotlin-interface
new file mode 100644
index 0000000000..f686ba7770
--- /dev/null
+++ b/t/t4018/kotlin-interface
@@ -0,0 +1,5 @@
+interface RIGHT{
+	//another comment
+	//another comment
+	//ChangeMe
+}
diff --git a/t/t4018/kotlin-nested-fun b/t/t4018/kotlin-nested-fun
new file mode 100644
index 0000000000..12186858cb
--- /dev/null
+++ b/t/t4018/kotlin-nested-fun
@@ -0,0 +1,9 @@
+class LEFT{
+	class CENTER{
+		fun RIGHT(  a:Int){
+			//comment
+			//comment
+			ChangeMe
+		}
+	}
+}
diff --git a/t/t4018/kotlin-public-class b/t/t4018/kotlin-public-class
new file mode 100644
index 0000000000..9433fcc226
--- /dev/null
+++ b/t/t4018/kotlin-public-class
@@ -0,0 +1,5 @@
+public class RIGHT{
+	//comment1
+	//comment2
+	ChangeMe
+}
diff --git a/t/t4018/kotlin-sealed-class b/t/t4018/kotlin-sealed-class
new file mode 100644
index 0000000000..0efa4a4eaf
--- /dev/null
+++ b/t/t4018/kotlin-sealed-class
@@ -0,0 +1,5 @@
+sealed class RIGHT {
+	// a comment
+	// b comment
+	ChangeMe
+}
diff --git a/t/t4034-diff-words.sh b/t/t4034-diff-words.sh
index d5abcf4b4c..15764ee9ac 100755
--- a/t/t4034-diff-words.sh
+++ b/t/t4034-diff-words.sh
@@ -324,6 +324,7 @@ test_language_driver dts
 test_language_driver fortran
 test_language_driver html
 test_language_driver java
+test_language_driver kotlin
 test_language_driver matlab
 test_language_driver objc
 test_language_driver pascal
diff --git a/t/t4034/kotlin/expect b/t/t4034/kotlin/expect
new file mode 100644
index 0000000000..f135eb2ab0
--- /dev/null
+++ b/t/t4034/kotlin/expect
@@ -0,0 +1,37 @@
+<BOLD>diff --git a/pre b/post<RESET>
+<BOLD>index a569cfc..c4b213b 100644<RESET>
+<BOLD>--- a/pre<RESET>
+<BOLD>+++ b/post<RESET>
+<CYAN>@@ -1,24 +1,24 @@<RESET>
+println("Hello World<RED>!\n<RESET><GREEN>?<RESET>")
+<RED>1 -1e10 <RESET><GREEN>(1) (-1e10) (<RESET>0xabcdef<GREEN>)<RESET> '<RED>x<RESET><GREEN>y<RESET>'
+[<RED>a<RESET><GREEN>x<RESET>] <RED>a<RESET><GREEN>x<RESET>-><RED>b a.b<RESET><GREEN>y x.y<RESET>
+!<RED>a a<RESET><GREEN>x x<RESET>.inv() <RED>a<RESET><GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>&<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>/<RED>b a<RESET><GREEN>y x<RESET>%<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>+<RED>b a<RESET><GREEN>y x<RESET>-<RED>b<RESET><GREEN>y<RESET>
+a <RED>shr<RESET><GREEN>shl<RESET> b
+<RED>a<RESET><GREEN>x<RESET><<RED>b a<RESET><GREEN>y x<RESET><=<RED>b a<RESET><GREEN>y x<RESET>><RED>b a<RESET><GREEN>y x<RESET>>=<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>==<RED>b a<RESET><GREEN>y x<RESET>!=<RED>b a<RESET><GREEN>y x<RESET>===<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET> and <RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>^<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET> or <RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>&&<RED>b a<RESET><GREEN>y x<RESET>||<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>=<RED>b a<RESET><GREEN>y x<RESET>+=<RED>b a<RESET><GREEN>y x<RESET>-=<RED>b a<RESET><GREEN>y x<RESET>*=<RED>b a<RESET><GREEN>y x<RESET>/=<RED>b a<RESET><GREEN>y x<RESET>%=<RED>b a<RESET><GREEN>y x<RESET><<=<RED>b a<RESET><GREEN>y x<RESET>>>=<RED>b a<RESET><GREEN>y x<RESET>&=<RED>b a<RESET><GREEN>y x<RESET>^=<RED>b a<RESET><GREEN>y x<RESET>|=<RED>b<RESET><GREEN>y<RESET>
+a<RED>=<RESET><GREEN>+=<RESET>b c<RED>+=<RESET><GREEN>=<RESET>d e<RED>-=<RESET><GREEN><=<RESET>f g<RED>*=<RESET><GREEN>>=<RESET>h i<RED>/=<RESET><GREEN>/<RESET>j k<RED>%=<RESET><GREEN>%<RESET>l m<RED><<=<RESET><GREEN><<<RESET>n o<RED>>>=<RESET><GREEN>>><RESET>p q<RED>&=<RESET><GREEN>&<RESET>r s<RED>^=<RESET><GREEN>^<RESET>t u<RED>|=<RESET><GREEN>|<RESET>v
+a<RED><<=<RESET><GREEN><=<RESET>b
+a<RED>||<RESET><GREEN>|<RESET>b a<RED>&&<RESET><GREEN>&<RESET>b
+<RED>a<RESET><GREEN>x<RESET>,y
+--a<RED>==<RESET><GREEN>!=<RESET>--b
+a++<RED>==<RESET><GREEN>!=<RESET>++b
+<RED>0xFF_EC_DE_5E 0b100_000 100_000<RESET><GREEN>0xFF_E1_DE_5E 0b100_100 200_000<RESET>
+a<RED>==<RESET><GREEN>===<RESET>b
+<RED>_32<RESET><GREEN>_33<RESET>.find(arr)
+X<RED>.fill()<RESET><GREEN>.find()<RESET>
diff --git a/t/t4034/kotlin/post b/t/t4034/kotlin/post
new file mode 100644
index 0000000000..c4b213b89e
--- /dev/null
+++ b/t/t4034/kotlin/post
@@ -0,0 +1,24 @@
+println("Hello World?")
+(1) (-1e10) (0xabcdef) 'y'
+[x] x->y x.y
+!x x.inv() x*y x&y
+x*y x/y x%y
+x+y x-y
+a shl b
+x<y x<=y x>y x>=y
+x==y x!=y x===y
+x and y
+x^y
+x or y
+x&&y x||y
+x=y x+=y x-=y x*=y x/=y x%=y x<<=y x>>=y x&=y x^=y x|=y
+a+=b c=d e<=f g>=h i/j k%l m<<n o>>p q&r s^t u|v
+a<=b
+a|b a&b
+x,y
+--a!=--b
+a++!=++b
+0xFF_E1_DE_5E 0b100_100 200_000
+a===b
+_33.find(arr)
+X.find()
diff --git a/t/t4034/kotlin/pre b/t/t4034/kotlin/pre
new file mode 100644
index 0000000000..a569cfcc6e
--- /dev/null
+++ b/t/t4034/kotlin/pre
@@ -0,0 +1,24 @@
+println("Hello World!\n")
+1 -1e10 0xabcdef 'x'
+[a] a->b a.b
+!a a.inv() a*b a&b
+a*b a/b a%b
+a+b a-b
+a shr b
+a<b a<=b a>b a>=b
+a==b a!=b a===b
+a and b
+a^b
+a or b
+a&&b a||b
+a=b a+=b a-=b a*=b a/=b a%=b a<<=b a>>=b a&=b a^=b a|=b
+a=b c+=d e-=f g*=h i/=j k%=l m<<=n o>>=p q&=r s^=t u|=v
+a<<=b
+a||b a&&b
+a,y
+--a==--b
+a++==++b
+0xFF_EC_DE_5E 0b100_000 100_000
+a==b
+_32.find(arr)
+X.fill()
diff --git a/userdiff.c b/userdiff.c
index 8578cb0d12..b98961dd55 100644
--- a/userdiff.c
+++ b/userdiff.c
@@ -168,6 +168,18 @@ PATTERNS("java",
 	 "|[-+0-9.e]+[fFlL]?|0[xXbB]?[0-9a-fA-F]+[lL]?"
 	 "|[-+*/<>%&^|=!]="
 	 "|--|\\+\\+|<<=?|>>>?=?|&&|\\|\\|"),
+PATTERNS("kotlin",
+	 "^[ \t]*(([a-z]+[ \t]+)*(fun|class|interface)[ \t]+.*)$",
+	 /* -- */
+	 "(_*[a-zA-Z]|_+[0-9])[a-zA-Z0-9_]*"
+	 /* hexadecimal and binary numbers */
+	 "|0[xXbB][0-9a-fA-F_]+[lLuU]*"
+	 /* integers and floats */
+	 "|[^_\n][0-9_.]+([Ee][-+]?[0-9]+)?[fFlLuU]*[^a-zA-Z]"
+	 /* method calls */
+	 "|[.][a-zA-Z()0-9]+"
+	 /* unary and binary operators */
+	 "|[-+*/<>%&^|=!]?=(=)?|--|\\+\\+|<<?=?|>>?=?|&&?|[|]?\\||\\|->\\*?|\\.\\*"),
 PATTERNS("markdown",
 	 "^ {0,3}#{1,6}[ \t].*",
 	 /* -- */
-- 
2.35.1
Junio C Hamano· Mar 4, 2022, 02:44 UTC · re: Jaydeep P Das · lore

Re: [PATCH] userdiff: add builtin diff driver for Kotlin language.

Jaydeep P Das <jaydeepjd.8914@gmail.com> writes:
> Subject: Re: [PATCH] userdiff: add builtin diff driver for Kotlin language.

"git format-patch --help" and look for "-v <n>", perhaps. This is the fourth iteration, so [PATCH v4], I guess?

jaydeepjd.8914@gmail.com· Mar 4, 2022, 05:16 UTC · re: Junio C Hamano · lore

Re: [PATCH] userdiff: add builtin diff driver for Kotlin language.

On 3/4/22 8:14 AM, Junio C Hamano <gitster@pobox.com> wrote:
Show 7 quoted lines
> Jaydeep P Das <jaydeepjd.8914@gmail.com> writes:
> 
> > Subject: Re: [PATCH] userdiff: add builtin diff driver for Kotlin language.
> 
> "git format-patch --help" and look for "-v <n>", perhaps.  This is
> the fourth iteration, so [PATCH v4], I guess?
> 

Yes. I think I forgot to fill in the subject so it was sent with the default. I didn't know format-patch allows to specify version numbers. I will check it out. Also, In the next patch, should I do it as v4 or v5?

Thanks, Jaydeep

Johannes Sixt· Mar 4, 2022, 07:25 UTC · re: Junio C Hamano · lore

Re: [PATCH] userdiff: add builtin diff driver for Kotlin language.

Am 04.03.22 um 03:44 schrieb Junio C Hamano:
Show 6 quoted lines
> Jaydeep P Das <jaydeepjd.8914@gmail.com> writes:
> 
>> Subject: Re: [PATCH] userdiff: add builtin diff driver for Kotlin language.
> 
> "git format-patch --help" and look for "-v <n>", perhaps.  This is
> the fourth iteration, so [PATCH v4], I guess?

Note though, that this iteration is a step in the wrong direction. Let's forget that it has been submitted. (I saw this submission only long after I responded in the thread on the earlier round https://lore.kernel.org/git/c1298c9d-0f4a-40b8-b337-896f4d4777f3@kdbg.org/)

-- Hannes
Jaydeep P Das· Mar 5, 2022, 09:40 UTC · re: Jaydeep P Das · lore

[PATCH v4] userdiff: add builtin diff driver for Kotlin language.

The xfuncname pattern finds func/class declarations in diffs to display as a hunk header. The word_regex pattern finds individual tokens in Kotlin code to generate appropriate diffs.

This patch adds xfuncname regex and word_regex for Kotlin language.

Signed-off-by: Jaydeep P Das <jaydeepjd.8914@gmail.com>
---
 Documentation/gitattributes.txt |  2 ++
 t/t4018/kotlin-class            |  5 +++++
 t/t4018/kotlin-enum-class       |  5 +++++
 t/t4018/kotlin-fun              |  5 +++++
 t/t4018/kotlin-inheritace-class |  5 +++++
 t/t4018/kotlin-inline-class     |  5 +++++
 t/t4018/kotlin-interface        |  5 +++++
 t/t4018/kotlin-nested-fun       |  9 ++++++++
 t/t4018/kotlin-public-class     |  5 +++++
 t/t4018/kotlin-sealed-class     |  5 +++++
 t/t4034-diff-words.sh           |  1 +
 t/t4034/kotlin/expect           | 39 +++++++++++++++++++++++++++++++++
 t/t4034/kotlin/post             | 26 ++++++++++++++++++++++
 t/t4034/kotlin/pre              | 26 ++++++++++++++++++++++
 userdiff.c                      | 12 ++++++++++
 15 files changed, 155 insertions(+)
 create mode 100644 t/t4018/kotlin-class
 create mode 100644 t/t4018/kotlin-enum-class
 create mode 100644 t/t4018/kotlin-fun
 create mode 100644 t/t4018/kotlin-inheritace-class
 create mode 100644 t/t4018/kotlin-inline-class
 create mode 100644 t/t4018/kotlin-interface
 create mode 100644 t/t4018/kotlin-nested-fun
 create mode 100644 t/t4018/kotlin-public-class
 create mode 100644 t/t4018/kotlin-sealed-class
 create mode 100644 t/t4034/kotlin/expect
 create mode 100644 t/t4034/kotlin/post
 create mode 100644 t/t4034/kotlin/pre
Show changes to 15 files +155 −0

Documentation/gitattributes.txt, t/t4018/kotlin-class, t/t4018/kotlin-enum-class, t/t4018/kotlin-fun, t/t4018/kotlin-inheritace-class, t/t4018/kotlin-inline-class, t/t4018/kotlin-interface, t/t4018/kotlin-nested-fun, t/t4018/kotlin-public-class, t/t4018/kotlin-sealed-class, t/t4034-diff-words.sh, t/t4034/kotlin/expect, t/t4034/kotlin/post, t/t4034/kotlin/pre, userdiff.c

diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt
index a71dad2674..4b36d51beb 100644
--- a/Documentation/gitattributes.txt
+++ b/Documentation/gitattributes.txt
@@ -829,6 +829,8 @@ patterns are available:
 
 - `java` suitable for source code in the Java language.
 
+- `kotlin` suitable for source code in the Kotlin language.
+
 - `markdown` suitable for Markdown documents.
 
 - `matlab` suitable for source code in the MATLAB and Octave languages.
diff --git a/t/t4018/kotlin-class b/t/t4018/kotlin-class
new file mode 100644
index 0000000000..bb864f22e6
--- /dev/null
+++ b/t/t4018/kotlin-class
@@ -0,0 +1,5 @@
+class RIGHT {
+	//comment
+	//comment
+	return ChangeMe
+}
diff --git a/t/t4018/kotlin-enum-class b/t/t4018/kotlin-enum-class
new file mode 100644
index 0000000000..8885f908fd
--- /dev/null
+++ b/t/t4018/kotlin-enum-class
@@ -0,0 +1,5 @@
+enum class RIGHT{
+	// Left
+	// a comment
+	ChangeMe
+}
diff --git a/t/t4018/kotlin-fun b/t/t4018/kotlin-fun
new file mode 100644
index 0000000000..2a60280256
--- /dev/null
+++ b/t/t4018/kotlin-fun
@@ -0,0 +1,5 @@
+fun RIGHT(){
+	//a comment
+	//b comment
+    return ChangeMe()
+}
diff --git a/t/t4018/kotlin-inheritace-class b/t/t4018/kotlin-inheritace-class
new file mode 100644
index 0000000000..77376c1f05
--- /dev/null
+++ b/t/t4018/kotlin-inheritace-class
@@ -0,0 +1,5 @@
+open class RIGHT{
+	// a comment
+	// b comment
+	// ChangeMe
+}
diff --git a/t/t4018/kotlin-inline-class b/t/t4018/kotlin-inline-class
new file mode 100644
index 0000000000..7bf46dd8d4
--- /dev/null
+++ b/t/t4018/kotlin-inline-class
@@ -0,0 +1,5 @@
+value class RIGHT(Args){
+	// a comment
+	// b comment
+	ChangeMe
+}
diff --git a/t/t4018/kotlin-interface b/t/t4018/kotlin-interface
new file mode 100644
index 0000000000..f686ba7770
--- /dev/null
+++ b/t/t4018/kotlin-interface
@@ -0,0 +1,5 @@
+interface RIGHT{
+	//another comment
+	//another comment
+	//ChangeMe
+}
diff --git a/t/t4018/kotlin-nested-fun b/t/t4018/kotlin-nested-fun
new file mode 100644
index 0000000000..12186858cb
--- /dev/null
+++ b/t/t4018/kotlin-nested-fun
@@ -0,0 +1,9 @@
+class LEFT{
+	class CENTER{
+		fun RIGHT(  a:Int){
+			//comment
+			//comment
+			ChangeMe
+		}
+	}
+}
diff --git a/t/t4018/kotlin-public-class b/t/t4018/kotlin-public-class
new file mode 100644
index 0000000000..9433fcc226
--- /dev/null
+++ b/t/t4018/kotlin-public-class
@@ -0,0 +1,5 @@
+public class RIGHT{
+	//comment1
+	//comment2
+	ChangeMe
+}
diff --git a/t/t4018/kotlin-sealed-class b/t/t4018/kotlin-sealed-class
new file mode 100644
index 0000000000..0efa4a4eaf
--- /dev/null
+++ b/t/t4018/kotlin-sealed-class
@@ -0,0 +1,5 @@
+sealed class RIGHT {
+	// a comment
+	// b comment
+	ChangeMe
+}
diff --git a/t/t4034-diff-words.sh b/t/t4034-diff-words.sh
index d5abcf4b4c..15764ee9ac 100755
--- a/t/t4034-diff-words.sh
+++ b/t/t4034-diff-words.sh
@@ -324,6 +324,7 @@ test_language_driver dts
 test_language_driver fortran
 test_language_driver html
 test_language_driver java
+test_language_driver kotlin
 test_language_driver matlab
 test_language_driver objc
 test_language_driver pascal
diff --git a/t/t4034/kotlin/expect b/t/t4034/kotlin/expect
new file mode 100644
index 0000000000..228da3e95e
--- /dev/null
+++ b/t/t4034/kotlin/expect
@@ -0,0 +1,39 @@
+<BOLD>diff --git a/pre b/post<RESET>
+<BOLD>index 0c2a5a8..a9e7b41 100644<RESET>
+<BOLD>--- a/pre<RESET>
+<BOLD>+++ b/post<RESET>
+<CYAN>@@ -1,26 +1,26 @@<RESET>
+println("Hello World<RED>!\n<RESET><GREEN>?<RESET>")
+<GREEN>(<RESET>1<GREEN>) (<RESET>-1e10<GREEN>) (<RESET>0xabcdef<GREEN>)<RESET> '<RED>x<RESET><GREEN>y<RESET>'
+[<RED>a<RESET><GREEN>x<RESET>] <RED>a<RESET><GREEN>x<RESET>-><RED>b a.b<RESET><GREEN>y x.y<RESET>
+!<RED>a a<RESET><GREEN>x x<RESET>.inv() <RED>a<RESET><GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>&<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>/<RED>b a<RESET><GREEN>y x<RESET>%<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>+<RED>b a<RESET><GREEN>y x<RESET>-<RED>b<RESET><GREEN>y<RESET>
+a <RED>shr<RESET><GREEN>shl<RESET> b
+<RED>a<RESET><GREEN>x<RESET><<RED>b a<RESET><GREEN>y x<RESET><=<RED>b a<RESET><GREEN>y x<RESET>><RED>b a<RESET><GREEN>y x<RESET>>=<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>==<RED>b a<RESET><GREEN>y x<RESET>!=<RED>b a<RESET><GREEN>y x<RESET>===<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET> and <RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>^<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET> or <RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>&&<RED>b a<RESET><GREEN>y x<RESET>||<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>=<RED>b a<RESET><GREEN>y x<RESET>+=<RED>b a<RESET><GREEN>y x<RESET>-=<RED>b a<RESET><GREEN>y x<RESET>*=<RED>b a<RESET><GREEN>y x<RESET>/=<RED>b a<RESET><GREEN>y x<RESET>%=<RED>b a<RESET><GREEN>y x<RESET><<=<RED>b a<RESET><GREEN>y x<RESET>>>=<RED>b a<RESET><GREEN>y x<RESET>&=<RED>b a<RESET><GREEN>y x<RESET>^=<RED>b a<RESET><GREEN>y x<RESET>|=<RED>b<RESET><GREEN>y<RESET>
+a<RED>=<RESET><GREEN>+=<RESET>b c<RED>+=<RESET><GREEN>=<RESET>d e<RED>-=<RESET><GREEN><=<RESET>f g<RED>*=<RESET><GREEN>>=<RESET>h i<RED>/=<RESET><GREEN>/<RESET>j k<RED>%=<RESET><GREEN>%<RESET>l m<RED><<=<RESET><GREEN><<<RESET>n o<RED>>>=<RESET><GREEN>>><RESET>p q<RED>&=<RESET><GREEN>&<RESET>r s<RED>^=<RESET><GREEN>^<RESET>t u<RED>|=<RESET><GREEN>|<RESET>v
+a<RED><<=<RESET><GREEN><=<RESET>b
+a<RED>||<RESET><GREEN>|<RESET>b a<RED>&&<RESET><GREEN>&<RESET>b
+<RED>a<RESET><GREEN>x<RESET>,y
+--a<RED>==<RESET><GREEN>!=<RESET>--b
+a++<RED>==<RESET><GREEN>!=<RESET>++b
+<RED>0xFF_EC_DE_5E 0b100_000 100_000<RESET><GREEN>0xFF_E1_DE_5E 0b100_100 200_000<RESET>
+a<RED>==<RESET><GREEN>===<RESET>b
+<RED>_32<RESET><GREEN>_33<RESET>.find(arr)
+X<RED>.fill()<RESET><GREEN>.find()<RESET>
+X<RED>.u<RESET><GREEN>.f<RESET>+1
+X.u<RED>-<RESET><GREEN>+<RESET>2
diff --git a/t/t4034/kotlin/post b/t/t4034/kotlin/post
new file mode 100644
index 0000000000..a9e7b41631
--- /dev/null
+++ b/t/t4034/kotlin/post
@@ -0,0 +1,26 @@
+println("Hello World?")
+(1) (-1e10) (0xabcdef) 'y'
+[x] x->y x.y
+!x x.inv() x*y x&y
+x*y x/y x%y
+x+y x-y
+a shl b
+x<y x<=y x>y x>=y
+x==y x!=y x===y
+x and y
+x^y
+x or y
+x&&y x||y
+x=y x+=y x-=y x*=y x/=y x%=y x<<=y x>>=y x&=y x^=y x|=y
+a+=b c=d e<=f g>=h i/j k%l m<<n o>>p q&r s^t u|v
+a<=b
+a|b a&b
+x,y
+--a!=--b
+a++!=++b
+0xFF_E1_DE_5E 0b100_100 200_000
+a===b
+_33.find(arr)
+X.find()
+X.f+1
+X.u+2
diff --git a/t/t4034/kotlin/pre b/t/t4034/kotlin/pre
new file mode 100644
index 0000000000..0c2a5a82b3
--- /dev/null
+++ b/t/t4034/kotlin/pre
@@ -0,0 +1,26 @@
+println("Hello World!\n")
+1 -1e10 0xabcdef 'x'
+[a] a->b a.b
+!a a.inv() a*b a&b
+a*b a/b a%b
+a+b a-b
+a shr b
+a<b a<=b a>b a>=b
+a==b a!=b a===b
+a and b
+a^b
+a or b
+a&&b a||b
+a=b a+=b a-=b a*=b a/=b a%=b a<<=b a>>=b a&=b a^=b a|=b
+a=b c+=d e-=f g*=h i/=j k%=l m<<=n o>>=p q&=r s^=t u|=v
+a<<=b
+a||b a&&b
+a,y
+--a==--b
+a++==++b
+0xFF_EC_DE_5E 0b100_000 100_000
+a==b
+_32.find(arr)
+X.fill()
+X.u+1
+X.u-2
diff --git a/userdiff.c b/userdiff.c
index 8578cb0d12..24821a0f69 100644
--- a/userdiff.c
+++ b/userdiff.c
@@ -168,6 +168,18 @@ PATTERNS("java",
 	 "|[-+0-9.e]+[fFlL]?|0[xXbB]?[0-9a-fA-F]+[lL]?"
 	 "|[-+*/<>%&^|=!]="
 	 "|--|\\+\\+|<<=?|>>>?=?|&&|\\|\\|"),
+PATTERNS("kotlin",
+	 "^[ \t]*(([a-z]+[ \t]+)*(fun|class|interface)[ \t]+.*)$",
+	 /* -- */
+	 "[a-zA-Z_][a-zA-Z0-9_]*"
+	 /* hexadecimal and binary numbers */
+	 "|0[xXbB][0-9a-fA-F_]+[lLuU]*"
+	 /* integers and floats */
+	 "|[0-9][0-9_.]*([Ee][-+]?[0-9]+)?[fFlL]*"
+	 /* method calls */
+	 "|[.][a-zA-Z()0-9]+"
+	 /* unary and binary operators */
+	 "|[-+*/<>%&^|=!]?=(=)?|--|\\+\\+|<<?=?|>>?=?|&&?|[|]?\\||\\|->\\*?|\\.\\*"),
 PATTERNS("markdown",
 	 "^ {0,3}#{1,6}[ \t].*",
 	 /* -- */
-- 
2.35.1
Johannes Sixt· Mar 5, 2022, 14:17 UTC · re: Jaydeep P Das · lore

Re: [PATCH v4] userdiff: add builtin diff driver for Kotlin language.

Am 05.03.22 um 10:40 schrieb Jaydeep P Das:
> +<RED>_32<RESET><GREEN>_33<RESET>.find(arr)
> +X<RED>.fill()<RESET><GREEN>.find()<RESET>
> +X<RED>.u<RESET><GREEN>.f<RESET>+1
> +X.u<RED>-<RESET><GREEN>+<RESET>2
Nice move to include these new tests!
Show 16 quoted lines
> diff --git a/userdiff.c b/userdiff.c
> index 8578cb0d12..24821a0f69 100644
> --- a/userdiff.c
> +++ b/userdiff.c
> @@ -168,6 +168,18 @@ PATTERNS("java",
>  	 "|[-+0-9.e]+[fFlL]?|0[xXbB]?[0-9a-fA-F]+[lL]?"
>  	 "|[-+*/<>%&^|=!]="
>  	 "|--|\\+\\+|<<=?|>>>?=?|&&|\\|\\|"),
> +PATTERNS("kotlin",
> +	 "^[ \t]*(([a-z]+[ \t]+)*(fun|class|interface)[ \t]+.*)$",
> +	 /* -- */
> +	 "[a-zA-Z_][a-zA-Z0-9_]*"
> +	 /* hexadecimal and binary numbers */
> +	 "|0[xXbB][0-9a-fA-F_]+[lLuU]*"
> +	 /* integers and floats */
> +	 "|[0-9][0-9_.]*([Ee][-+]?[0-9]+)?[fFlL]*"
Good!
> +	 /* method calls */
> +	 "|[.][a-zA-Z()0-9]+"

This matches both .empty() as well as .125, but only the .5e part of .5e-3 and only the .find(x part of .find(x/2). Is that intended?

I find the desire to have method calls as an entire token a bit strange. In other languages, the last expression part is actually split into many tokens: . find ( x / 2 ).

BTW, I'm in no way saying that this must be changed (personally I do not care at all as I'm not writing Kotlin), so if you say that is how people want Kotlin code to be split with --word-diff, I will believe you.

> +	 /* unary and binary operators */
> +	 "|[-+*/<>%&^|=!]?=(=)?|--|\\+\\+|<<?=?|>>?=?|&&?|[|]?\\||\\|->\\*?|\\.\\*"),
Is the part
	 "|\\|->\\*?|"

actually meant to be something else? Does Kotlin have the tokens "|->" and "|->*"?

A final minor nit: There is "|&&?|[|]?\\||" that could just be "|&&|\\|\\||" (remember: single character operators are matched implicitly).

>  PATTERNS("markdown",
>  	 "^ {0,3}#{1,6}[ \t].*",
>  	 /* -- */
-- Hannes
jaydeepjd.8914@gmail.com· Mar 5, 2022, 19:18 UTC · re: Johannes Sixt · lore

Re: [PATCH v4] userdiff: add builtin diff driver for Kotlin language.

Show 5 quoted lines
> > +	 /* method calls */
> > +	 "|[.][a-zA-Z()0-9]+"
> 
> This matches both .empty() as well as .125, but only the .5e part of
> .5e-3 and only the .find(x part of .find(x/2). Is that intended?

Oh. It completely missed my mind. Anyways, that method call regex is better gone. For matching these, Maybe we could just use cpp's regex for floating numbers starting with decimal point:

"|\\.[0-9][0-9]*([Ee][-+]?[0-9]+)?[fFlL]?"
Or maybe, we can make the current regex for floats and integers a bit more loose:
"|[0-9.][0-9_.]*([Ee][*-]?[0-9]+)?[FfLl]*" 
What do you think would be better?
Show 7 quoted lines
> I find the desire to have method calls as an entire token a bit strange.
> In other languages, the last expression part is actually split into many
> tokens: . find ( x / 2 ).
> 
> BTW, I'm in no way saying that this must be changed (personally I do not
> care at all as I'm not writing Kotlin), so if you say that is how people
> want Kotlin code to be split with --word-diff, I will believe you.

Yes. The tokenisation does not make sense if its something like `X.find(2)`. I think I should remove it.

Show 9 quoted lines
> > +	 /* unary and binary operators */
> > +	 "|[-+*/<>%&^|=!]?=(=)?|--|\\+\\+|<<?=?|>>?=?|&&?|[|]?\\||\\|->\\*?|\\.\\*"),
> 
> Is the part
> 
> 	 "|\\|->\\*?|"
> 
> actually meant to be something else? Does Kotlin have the tokens "|->"
> and "|->*"?
Ah. yes. Kotlin does have "->" operator but not "|->". Also there are a few
more compound operators like ".." , "!!" etc which I forgot to add. I will add these in the next patch.
  
 
> A final minor nit: There is "|&&?|[|]?\\||" that could just be
> "|&&|\\|\\||" (remember: single character operators are matched implicitly).
> 
Yes. Right.

-- Thanks :] Jaydeep

Johannes Sixt· Mar 5, 2022, 22:17 UTC · re: jaydeepjd.8914@gmail.com · lore

Re: [PATCH v4] userdiff: add builtin diff driver for Kotlin language.

Am 05.03.22 um 20:18 schrieb jaydeepjd.8914@gmail.com:
> Maybe we could just use cpp's regex for floating numbers starting with
> decimal point:
> 
> "|\\.[0-9][0-9]*([Ee][-+]?[0-9]+)?[fFlL]?"
Yes, but with '_' permitted after the first digit:
	"|\\.[0-9][0-9_]*([Ee][-+]?[0-9]+)?[fFlL]?"
Show 6 quoted lines
> 
> Or maybe, we can make the current regex for floats and integers a bit
> more loose:
> 
> "|[0-9.][0-9_.]*([Ee][*-]?[0-9]+)?[FfLl]*"
> What do you think would be better?

No, that does not work, either, because it splits X.Find into X .F ind. I fixed that very problem with the cpp driver recently. We do need a separate alternative for the floatingpoint numbers that start with a decimal point.

-- Hannes
Jaydeep P Das· Mar 6, 2022, 11:15 UTC · re: Jaydeep P Das · lore

[PATCH v5] userdiff: add builtin diff driver for kotlin language.

The xfuncname pattern finds func/class declarations in diffs to display as a hunk header. The word_regex pattern finds individual tokens in Kotlin code to generate appropriate diffs.

This patch adds xfuncname regex and word_regex for Kotlin language.

Signed-off-by: Jaydeep P Das <jaydeepjd.8914@gmail.com>
---
 Documentation/gitattributes.txt |  2 ++
 t/t4018/kotlin-class            |  5 ++++
 t/t4018/kotlin-enum-class       |  5 ++++
 t/t4018/kotlin-fun              |  5 ++++
 t/t4018/kotlin-inheritace-class |  5 ++++
 t/t4018/kotlin-inline-class     |  5 ++++
 t/t4018/kotlin-interface        |  5 ++++
 t/t4018/kotlin-nested-fun       |  9 +++++++
 t/t4018/kotlin-public-class     |  5 ++++
 t/t4018/kotlin-sealed-class     |  5 ++++
 t/t4034-diff-words.sh           |  1 +
 t/t4034/kotlin/expect           | 42 +++++++++++++++++++++++++++++++++
 t/t4034/kotlin/post             | 29 +++++++++++++++++++++++
 t/t4034/kotlin/pre              | 29 +++++++++++++++++++++++
 userdiff.c                      | 12 ++++++++++
 15 files changed, 164 insertions(+)
 create mode 100644 t/t4018/kotlin-class
 create mode 100644 t/t4018/kotlin-enum-class
 create mode 100644 t/t4018/kotlin-fun
 create mode 100644 t/t4018/kotlin-inheritace-class
 create mode 100644 t/t4018/kotlin-inline-class
 create mode 100644 t/t4018/kotlin-interface
 create mode 100644 t/t4018/kotlin-nested-fun
 create mode 100644 t/t4018/kotlin-public-class
 create mode 100644 t/t4018/kotlin-sealed-class
 create mode 100644 t/t4034/kotlin/expect
 create mode 100644 t/t4034/kotlin/post
 create mode 100644 t/t4034/kotlin/pre
Show changes to 15 files +164 −0

Documentation/gitattributes.txt, t/t4018/kotlin-class, t/t4018/kotlin-enum-class, t/t4018/kotlin-fun, t/t4018/kotlin-inheritace-class, t/t4018/kotlin-inline-class, t/t4018/kotlin-interface, t/t4018/kotlin-nested-fun, t/t4018/kotlin-public-class, t/t4018/kotlin-sealed-class, t/t4034-diff-words.sh, t/t4034/kotlin/expect, t/t4034/kotlin/post, t/t4034/kotlin/pre, userdiff.c

diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt
index a71dad2674..4b36d51beb 100644
--- a/Documentation/gitattributes.txt
+++ b/Documentation/gitattributes.txt
@@ -829,6 +829,8 @@ patterns are available:
 
 - `java` suitable for source code in the Java language.
 
+- `kotlin` suitable for source code in the Kotlin language.
+
 - `markdown` suitable for Markdown documents.
 
 - `matlab` suitable for source code in the MATLAB and Octave languages.
diff --git a/t/t4018/kotlin-class b/t/t4018/kotlin-class
new file mode 100644
index 0000000000..bb864f22e6
--- /dev/null
+++ b/t/t4018/kotlin-class
@@ -0,0 +1,5 @@
+class RIGHT {
+	//comment
+	//comment
+	return ChangeMe
+}
diff --git a/t/t4018/kotlin-enum-class b/t/t4018/kotlin-enum-class
new file mode 100644
index 0000000000..8885f908fd
--- /dev/null
+++ b/t/t4018/kotlin-enum-class
@@ -0,0 +1,5 @@
+enum class RIGHT{
+	// Left
+	// a comment
+	ChangeMe
+}
diff --git a/t/t4018/kotlin-fun b/t/t4018/kotlin-fun
new file mode 100644
index 0000000000..2a60280256
--- /dev/null
+++ b/t/t4018/kotlin-fun
@@ -0,0 +1,5 @@
+fun RIGHT(){
+	//a comment
+	//b comment
+    return ChangeMe()
+}
diff --git a/t/t4018/kotlin-inheritace-class b/t/t4018/kotlin-inheritace-class
new file mode 100644
index 0000000000..77376c1f05
--- /dev/null
+++ b/t/t4018/kotlin-inheritace-class
@@ -0,0 +1,5 @@
+open class RIGHT{
+	// a comment
+	// b comment
+	// ChangeMe
+}
diff --git a/t/t4018/kotlin-inline-class b/t/t4018/kotlin-inline-class
new file mode 100644
index 0000000000..7bf46dd8d4
--- /dev/null
+++ b/t/t4018/kotlin-inline-class
@@ -0,0 +1,5 @@
+value class RIGHT(Args){
+	// a comment
+	// b comment
+	ChangeMe
+}
diff --git a/t/t4018/kotlin-interface b/t/t4018/kotlin-interface
new file mode 100644
index 0000000000..f686ba7770
--- /dev/null
+++ b/t/t4018/kotlin-interface
@@ -0,0 +1,5 @@
+interface RIGHT{
+	//another comment
+	//another comment
+	//ChangeMe
+}
diff --git a/t/t4018/kotlin-nested-fun b/t/t4018/kotlin-nested-fun
new file mode 100644
index 0000000000..12186858cb
--- /dev/null
+++ b/t/t4018/kotlin-nested-fun
@@ -0,0 +1,9 @@
+class LEFT{
+	class CENTER{
+		fun RIGHT(  a:Int){
+			//comment
+			//comment
+			ChangeMe
+		}
+	}
+}
diff --git a/t/t4018/kotlin-public-class b/t/t4018/kotlin-public-class
new file mode 100644
index 0000000000..9433fcc226
--- /dev/null
+++ b/t/t4018/kotlin-public-class
@@ -0,0 +1,5 @@
+public class RIGHT{
+	//comment1
+	//comment2
+	ChangeMe
+}
diff --git a/t/t4018/kotlin-sealed-class b/t/t4018/kotlin-sealed-class
new file mode 100644
index 0000000000..0efa4a4eaf
--- /dev/null
+++ b/t/t4018/kotlin-sealed-class
@@ -0,0 +1,5 @@
+sealed class RIGHT {
+	// a comment
+	// b comment
+	ChangeMe
+}
diff --git a/t/t4034-diff-words.sh b/t/t4034-diff-words.sh
index d5abcf4b4c..15764ee9ac 100755
--- a/t/t4034-diff-words.sh
+++ b/t/t4034-diff-words.sh
@@ -324,6 +324,7 @@ test_language_driver dts
 test_language_driver fortran
 test_language_driver html
 test_language_driver java
+test_language_driver kotlin
 test_language_driver matlab
 test_language_driver objc
 test_language_driver pascal
diff --git a/t/t4034/kotlin/expect b/t/t4034/kotlin/expect
new file mode 100644
index 0000000000..d80e17d2c5
--- /dev/null
+++ b/t/t4034/kotlin/expect
@@ -0,0 +1,42 @@
+<BOLD>diff --git a/pre b/post<RESET>
+<BOLD>index 1db2197..ec0a891 100644<RESET>
+<BOLD>--- a/pre<RESET>
+<BOLD>+++ b/post<RESET>
+<CYAN>@@ -1,29 +1,29 @@<RESET>
+println("Hello World<RED>!\n<RESET><GREEN>?<RESET>")
+<GREEN>(<RESET>1<GREEN>) (<RESET>-1e10<GREEN>) (<RESET>0xabcdef<GREEN>)<RESET> '<RED>x<RESET><GREEN>y<RESET>'
+[<RED>a<RESET><GREEN>x<RESET>] <RED>a<RESET><GREEN>x<RESET>-><RED>b a<RESET><GREEN>y x<RESET>.<RED>b<RESET><GREEN>y<RESET>
+!<RED>a a<RESET><GREEN>x x<RESET>.inv() <RED>a<RESET><GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>&<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>/<RED>b a<RESET><GREEN>y x<RESET>%<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>+<RED>b a<RESET><GREEN>y x<RESET>-<RED>b<RESET><GREEN>y<RESET>
+a <RED>shr<RESET><GREEN>shl<RESET> b
+<RED>a<RESET><GREEN>x<RESET><<RED>b a<RESET><GREEN>y x<RESET><=<RED>b a<RESET><GREEN>y x<RESET>><RED>b a<RESET><GREEN>y x<RESET>>=<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>==<RED>b a<RESET><GREEN>y x<RESET>!=<RED>b a<RESET><GREEN>y x<RESET>===<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET> and <RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>^<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET> or <RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>&&<RED>b a<RESET><GREEN>y x<RESET>||<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>=<RED>b a<RESET><GREEN>y x<RESET>+=<RED>b a<RESET><GREEN>y x<RESET>-=<RED>b a<RESET><GREEN>y x<RESET>*=<RED>b a<RESET><GREEN>y x<RESET>/=<RED>b a<RESET><GREEN>y x<RESET>%=<RED>b a<RESET><GREEN>y x<RESET><<=<RED>b a<RESET><GREEN>y x<RESET>>>=<RED>b a<RESET><GREEN>y x<RESET>&=<RED>b a<RESET><GREEN>y x<RESET>^=<RED>b a<RESET><GREEN>y x<RESET>|=<RED>b<RESET><GREEN>y<RESET>
+a<RED>=<RESET><GREEN>+=<RESET>b c<RED>+=<RESET><GREEN>=<RESET>d e<RED>-=<RESET><GREEN><=<RESET>f g<RED>*=<RESET><GREEN>>=<RESET>h i<RED>/=<RESET><GREEN>/<RESET>j k<RED>%=<RESET><GREEN>%<RESET>l m<RED><<=<RESET><GREEN><<<RESET>n o<RED>>>=<RESET><GREEN>>><RESET>p q<RED>&=<RESET><GREEN>&<RESET>r s<RED>^=<RESET><GREEN>^<RESET>t u<RED>|=<RESET><GREEN>|<RESET>v
+a<RED><<=<RESET><GREEN><=<RESET>b
+a<RED>||<RESET><GREEN>|<RESET>b a<RED>&&<RESET><GREEN>&<RESET>b
+<RED>a<RESET><GREEN>x<RESET>,y
+--a<RED>==<RESET><GREEN>!=<RESET>--b
+a++<RED>==<RESET><GREEN>!=<RESET>++b
+<RED>0xFF_EC_DE_5E 0b100_000 100_000<RESET><GREEN>0xFF_E1_DE_5E 0b100_100 200_000<RESET>
+a<RED>==<RESET><GREEN>===<RESET>b
+a<RED>!!<RESET><GREEN>!=<RESET>b
+<RED>_32<RESET><GREEN>_33<RESET>.find(arr)
+X.<RED>fill<RESET><GREEN>find<RESET>()
+X.<RED>u<RESET><GREEN>f<RESET>+1
+X.u<RED>-<RESET><GREEN>+<RESET>2
+a<RED>.<RESET><GREEN>..<RESET>b
+a<RED>?.<RESET><GREEN>?:<RESET>b
diff --git a/t/t4034/kotlin/post b/t/t4034/kotlin/post
new file mode 100644
index 0000000000..ec0a8919e9
--- /dev/null
+++ b/t/t4034/kotlin/post
@@ -0,0 +1,29 @@
+println("Hello World?")
+(1) (-1e10) (0xabcdef) 'y'
+[x] x->y x.y
+!x x.inv() x*y x&y
+x*y x/y x%y
+x+y x-y
+a shl b
+x<y x<=y x>y x>=y
+x==y x!=y x===y
+x and y
+x^y
+x or y
+x&&y x||y
+x=y x+=y x-=y x*=y x/=y x%=y x<<=y x>>=y x&=y x^=y x|=y
+a+=b c=d e<=f g>=h i/j k%l m<<n o>>p q&r s^t u|v
+a<=b
+a|b a&b
+x,y
+--a!=--b
+a++!=++b
+0xFF_E1_DE_5E 0b100_100 200_000
+a===b
+a!=b
+_33.find(arr)
+X.find()
+X.f+1
+X.u+2
+a..b
+a?:b
diff --git a/t/t4034/kotlin/pre b/t/t4034/kotlin/pre
new file mode 100644
index 0000000000..1db2197baa
--- /dev/null
+++ b/t/t4034/kotlin/pre
@@ -0,0 +1,29 @@
+println("Hello World!\n")
+1 -1e10 0xabcdef 'x'
+[a] a->b a.b
+!a a.inv() a*b a&b
+a*b a/b a%b
+a+b a-b
+a shr b
+a<b a<=b a>b a>=b
+a==b a!=b a===b
+a and b
+a^b
+a or b
+a&&b a||b
+a=b a+=b a-=b a*=b a/=b a%=b a<<=b a>>=b a&=b a^=b a|=b
+a=b c+=d e-=f g*=h i/=j k%=l m<<=n o>>=p q&=r s^=t u|=v
+a<<=b
+a||b a&&b
+a,y
+--a==--b
+a++==++b
+0xFF_EC_DE_5E 0b100_000 100_000
+a==b
+a!!b
+_32.find(arr)
+X.fill()
+X.u+1
+X.u-2
+a.b
+a?.b
diff --git a/userdiff.c b/userdiff.c
index 8578cb0d12..cd2155bbfe 100644
--- a/userdiff.c
+++ b/userdiff.c
@@ -168,6 +168,18 @@ PATTERNS("java",
 	 "|[-+0-9.e]+[fFlL]?|0[xXbB]?[0-9a-fA-F]+[lL]?"
 	 "|[-+*/<>%&^|=!]="
 	 "|--|\\+\\+|<<=?|>>>?=?|&&|\\|\\|"),
+PATTERNS("kotlin",
+	 "^[ \t]*(([a-z]+[ \t]+)*(fun|class|interface)[ \t]+.*)$",
+	 /* -- */
+	 "[a-zA-Z_][a-zA-Z0-9_]*"
+	 /* hexadecimal and binary numbers */
+	 "|0[xXbB][0-9a-fA-F_]+[lLuU]*"
+	 /* integers and floats */
+	 "|[0-9][.]?[0-9_]+([Ee][-+]?[0-9]+)?[fFlL]*"
+	 /* floating point numbers beginning with decimal point */
+	 "|[.][0-9][0-9]*([Ee][-+]?[0-9]+)?[fFlLuU]?"
+	 /* unary and binary operators */
+	 "|[-+*/<>%&^|=!]?==?|--|\\+\\+|<<?=?|>>?=?|&&|\\|[|]?|->|\\.\\*|!!|::|[?:.][.:]"),
 PATTERNS("markdown",
 	 "^ {0,3}#{1,6}[ \t].*",
 	 /* -- */
-- 
2.35.1
Johannes Sixt· Mar 7, 2022, 07:07 UTC · re: Jaydeep P Das · lore

Re: [PATCH v5] userdiff: add builtin diff driver for kotlin language.

Am 06.03.22 um 12:15 schrieb Jaydeep P Das:
Show 18 quoted lines
> diff --git a/userdiff.c b/userdiff.c
> index 8578cb0d12..cd2155bbfe 100644
> --- a/userdiff.c
> +++ b/userdiff.c
> @@ -168,6 +168,18 @@ PATTERNS("java",
>  	 "|[-+0-9.e]+[fFlL]?|0[xXbB]?[0-9a-fA-F]+[lL]?"
>  	 "|[-+*/<>%&^|=!]="
>  	 "|--|\\+\\+|<<=?|>>>?=?|&&|\\|\\|"),
> +PATTERNS("kotlin",
> +	 "^[ \t]*(([a-z]+[ \t]+)*(fun|class|interface)[ \t]+.*)$",
> +	 /* -- */
> +	 "[a-zA-Z_][a-zA-Z0-9_]*"
> +	 /* hexadecimal and binary numbers */
> +	 "|0[xXbB][0-9a-fA-F_]+[lLuU]*"
> +	 /* integers and floats */
> +	 "|[0-9][.]?[0-9_]+([Ee][-+]?[0-9]+)?[fFlL]*"
> +	 /* floating point numbers beginning with decimal point */
> +	 "|[.][0-9][0-9]*([Ee][-+]?[0-9]+)?[fFlLuU]?"

I guess that the suffix u is intended to mark unsigned integers. So, I would say that the alternatives [fFlL] and [fFlLuU] should be swapped.

Furthermore, is it intentional that you do not recognize the '_' digit separator in floating point numbers that begin with a decimal point?

> +	 /* unary and binary operators */
> +	 "|[-+*/<>%&^|=!]?==?|--|\\+\\+|<<?=?|>>?=?|&&|\\|[|]?|->|\\.\\*|!!|::|[?:.][.:]"),

What is the justification that there is still "|&&|\\|[|]?|" instead of "|&&|\\|\\||" that I suggested (and I think I stressed that the point is that single-character operators are matched elsewhere) and to which you said "yes, right"?

Also, the part "|<<?=?|>>?=?|" can match <, >, <=, and >=, all of which are matched by other expressions, so you could reduce it to "|<<=|>>=|", because that are the only tokens that they must match.

-- Hannes
jaydeepjd.8914@gmail.com· Mar 8, 2022, 16:54 UTC · re: Johannes Sixt · lore

Re: [PATCH v5] userdiff: add builtin diff driver for kotlin language.

> I guess that the suffix u is intended to mark unsigned integers. So, I
> would say that the alternatives [fFlL] and [fFlLuU] should be swapped.
Okay.
> Furthermore, is it intentional that you do not recognize the '_' digit
> separator in floating point numbers that begin with a decimal point?
No. I will fix it.
Show 7 quoted lines
> > +	 /* unary and binary operators */
> > +	 "|[-+*/<>%&^|=!]?==?|--|\\+\\+|<<?=?|>>?=?|&&|\\|[|]?|->|\\.\\*|!!|::|[?:.][.:]"),
> 
> What is the justification that there is still "|&&|\\|[|]?|" instead of
> "|&&|\\|\\||" that I suggested (and I think I stressed that the point is
> that single-character operators are matched elsewhere) and to which you
> said "yes, right"?
Yes. Must have slipped my mind. Sorry.
> Also, the part "|<<?=?|>>?=?|" can match <, >, <=, and >=, all of which
> are matched by other expressions, so you could reduce it to "|<<=|>>=|",
> because that are the only tokens that they must match.
Alright.
So, the final regexes are these, right?: 
	 "[a-zA-Z_][a-zA-Z0-9_]*"
	 /* hexadecimal and binary numbers */
	 "|0[xXbB][0-9a-fA-F_]+[lLuU]*"
	 /* integers and floats */
	 "|[0-9][.]?[0-9_]+([Ee][-+]?[0-9]+)?[fFlLuU]*"
	 /* floating point numbers beginning with decimal point */
	 "|[.][0-9][0-9_]*([Ee][-+]?[0-9]+)?[fFlL]?"
	 /* unary and binary operators */
	 "|[-+*/<>%&^|=!]?==?|--|\\+\\+|<<=|>>=|&&|[||]|->|\\.\\*|!!|::|[?:.][.:]"),

Thanks, Jaydeep.

Johannes Sixt· Mar 8, 2022, 18:32 UTC · re: jaydeepjd.8914@gmail.com · lore

Re: [PATCH v5] userdiff: add builtin diff driver for kotlin language.

Am 08.03.22 um 17:54 schrieb jaydeepjd.8914@gmail.com:
> So, the final regexes are these, right?:
Not quite.
Show 6 quoted lines
> 
>      "[a-zA-Z_][a-zA-Z0-9_]*"
>      /* hexadecimal and binary numbers */
>      "|0[xXbB][0-9a-fA-F_]+[lLuU]*"
>      /* integers and floats */
>      "|[0-9][.]?[0-9_]+([Ee][-+]?[0-9]+)?[fFlLuU]*"

This would not match 12.5 because you allow only a single digit before the decimal point. Perhaps

	"|[0-9][.0-9_]*([Ee][-+]?[0-9]+)?[fFlLuU]*"
Show 5 quoted lines
>      /* floating point numbers beginning with decimal point */
>      "|[.][0-9][0-9_]*([Ee][-+]?[0-9]+)?[fFlL]?"
>      /* unary and binary operators */
>     
> "|[-+*/<>%&^|=!]?==?|--|\\+\\+|<<=|>>=|&&|[||]|->|\\.\\*|!!|::|[?:.][.:]"),

[||] does not work as you intend. A new suggestion: do not start with an initial optional character in order to reduce the number of backtrackings that the regular expression evaluation has to do. I would write this line as

	"|[-+*/<>%&^|=!]==?|--|\\+\\+|<<=|>>=|&&|\\|\\||->|\\.\\*|!!|::|[?:.][.:]"),

BTW which operators are handled by "[?:.][.:]"? I'm asking because you list :: separatly that would also be matched by this sub-expression.

-- Hannes
jaydeepjd.8914@gmail.com· Mar 10, 2022, 10:52 UTC · re: Johannes Sixt · lore

Re: [PATCH v5] userdiff: add builtin diff driver for kotlin language.

Sorry for the late reply. 
On 3/9/22 12:02 AM, Johannes Sixt <j6t@kdbg.org> wrote:
Show 16 quoted lines
> Am 08.03.22 um 17:54 schrieb jaydeepjd.8914@gmail.com:
> > So, the final regexes are these, right?:
> 
> Not quite.
> 
> >
> >       "[a-zA-Z_][a-zA-Z0-9_]*"
> >       /* hexadecimal and binary numbers */
> >       "|0[xXbB][0-9a-fA-F_]+[lLuU]*"
> >       /* integers and floats */
> >       "|[0-9][.]?[0-9_]+([Ee][-+]?[0-9]+)?[fFlLuU]*"
> 
> This would not match 12.5 because you allow only a single digit before
> the decimal point. Perhaps
> 
> 	"|[0-9][.0-9_]*([Ee][-+]?[0-9]+)?[fFlLuU]*"
Okay. 
Show 15 quoted lines
> >       /* floating point numbers beginning with decimal point */
> >       "|[.][0-9][0-9_]*([Ee][-+]?[0-9]+)?[fFlL]?"
> >       /* unary and binary operators */
> >      
> > "|[-+*/<>%&^|=!]?==?|--|\\+\\+|<<=|>>=|&&|[||]|->|\\.\\*|!!|::|[?:.][.:]"),
> 
> [||] does not work as you intend. A new suggestion: do not start with an
> initial optional character in order to reduce the number of
> backtrackings that the regular expression evaluation has to do. I would
> write this line as
> 
> 	"|[-+*/<>%&^|=!]==?|--|\\+\\+|<<=|>>=|&&|\\|\\||->|\\.\\*|!!|::|[?:.][.:]"),
> 
> BTW which operators are handled by "[?:.][.:]"? I'm asking because you
> list :: separatly that would also be matched by this sub-expression.

It matches the following operators: `?:`, `?.`, `..` `::`. Although matching `::` is unnecessary since its matched before.

https://kotlinlang.org/docs/keyword-reference.html#operators-and-special-symbols
 
Jaydeep Das· Mar 10, 2022, 16:29 UTC · re: Johannes Sixt · lore

Re: [PATCH v5] userdiff: add builtin diff driver for kotlin language.

On 3/9/22 00:02, Johannes Sixt wrote:
Show 17 quoted lines
> Am 08.03.22 um 17:54 schrieb jaydeepjd.8914@gmail.com:
>> So, the final regexes are these, right?:
> 
> Not quite.
> 
>>
>>       "[a-zA-Z_][a-zA-Z0-9_]*"
>>       /* hexadecimal and binary numbers */
>>       "|0[xXbB][0-9a-fA-F_]+[lLuU]*"
>>       /* integers and floats */
>>       "|[0-9][.]?[0-9_]+([Ee][-+]?[0-9]+)?[fFlLuU]*"
> 
> This would not match 12.5 because you allow only a single digit before
> the decimal point. Perhaps
> 
> 	"|[0-9][.0-9_]*([Ee][-+]?[0-9]+)?[fFlLuU]*"
> 

The problem with this approach is that it matches `2..5` as a single token. However in Kotlin, `..` is used to specify a range so 2..5 should be broken into 2 .. and 5.

Johannes Sixt· Mar 10, 2022, 19:11 UTC · re: Jaydeep Das · lore

Re: [PATCH v5] userdiff: add builtin diff driver for kotlin language.

Am 10.03.22 um 17:29 schrieb Jaydeep Das:
Show 7 quoted lines
>>     "|[0-9][.0-9_]*([Ee][-+]?[0-9]+)?[fFlLuU]*"
>>
> 
> The problem with this approach is that it matches `2..5` as a single token.
> However in Kotlin, `..` is used to specify a range so 2..5 should be
> broken into
> 2 .. and 5.
Good catch. Then we have to be more restrictive with the fractional part:
	"|[0-9][0-9_]*([.][0-9_]*)([Ee][-+]?[0-9]+)?[fFlLuU]*"
-- Hannes
Jaydeep P Das· Mar 11, 2022, 07:27 UTC · re: Jaydeep P Das · lore

[PATCH v6] userdiff: add builtin diff driver for kotlin language.

The xfuncname pattern finds func/class declarations in diffs to display as a hunk header. The word_regex pattern finds individual tokens in Kotlin code to generate appropriate diffs.

This patch adds xfuncname regex and word_regex for Kotlin language.

Signed-off-by: Jaydeep P Das <jaydeepjd.8914@gmail.com>
---
 Documentation/gitattributes.txt |  2 ++
 t/t4018/kotlin-class            |  5 ++++
 t/t4018/kotlin-enum-class       |  5 ++++
 t/t4018/kotlin-fun              |  5 ++++
 t/t4018/kotlin-inheritace-class |  5 ++++
 t/t4018/kotlin-inline-class     |  5 ++++
 t/t4018/kotlin-interface        |  5 ++++
 t/t4018/kotlin-nested-fun       |  9 +++++++
 t/t4018/kotlin-public-class     |  5 ++++
 t/t4018/kotlin-sealed-class     |  5 ++++
 t/t4034-diff-words.sh           |  1 +
 t/t4034/kotlin/expect           | 43 +++++++++++++++++++++++++++++++++
 t/t4034/kotlin/post             | 30 +++++++++++++++++++++++
 t/t4034/kotlin/pre              | 30 +++++++++++++++++++++++
 userdiff.c                      | 12 +++++++++
 15 files changed, 167 insertions(+)
 create mode 100644 t/t4018/kotlin-class
 create mode 100644 t/t4018/kotlin-enum-class
 create mode 100644 t/t4018/kotlin-fun
 create mode 100644 t/t4018/kotlin-inheritace-class
 create mode 100644 t/t4018/kotlin-inline-class
 create mode 100644 t/t4018/kotlin-interface
 create mode 100644 t/t4018/kotlin-nested-fun
 create mode 100644 t/t4018/kotlin-public-class
 create mode 100644 t/t4018/kotlin-sealed-class
 create mode 100644 t/t4034/kotlin/expect
 create mode 100644 t/t4034/kotlin/post
 create mode 100644 t/t4034/kotlin/pre
Show changes to 15 files +167 −0

Documentation/gitattributes.txt, t/t4018/kotlin-class, t/t4018/kotlin-enum-class, t/t4018/kotlin-fun, t/t4018/kotlin-inheritace-class, t/t4018/kotlin-inline-class, t/t4018/kotlin-interface, t/t4018/kotlin-nested-fun, t/t4018/kotlin-public-class, t/t4018/kotlin-sealed-class, t/t4034-diff-words.sh, t/t4034/kotlin/expect, t/t4034/kotlin/post, t/t4034/kotlin/pre, userdiff.c

diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt
index a71dad2674..4b36d51beb 100644
--- a/Documentation/gitattributes.txt
+++ b/Documentation/gitattributes.txt
@@ -829,6 +829,8 @@ patterns are available:
 
 - `java` suitable for source code in the Java language.
 
+- `kotlin` suitable for source code in the Kotlin language.
+
 - `markdown` suitable for Markdown documents.
 
 - `matlab` suitable for source code in the MATLAB and Octave languages.
diff --git a/t/t4018/kotlin-class b/t/t4018/kotlin-class
new file mode 100644
index 0000000000..bb864f22e6
--- /dev/null
+++ b/t/t4018/kotlin-class
@@ -0,0 +1,5 @@
+class RIGHT {
+	//comment
+	//comment
+	return ChangeMe
+}
diff --git a/t/t4018/kotlin-enum-class b/t/t4018/kotlin-enum-class
new file mode 100644
index 0000000000..8885f908fd
--- /dev/null
+++ b/t/t4018/kotlin-enum-class
@@ -0,0 +1,5 @@
+enum class RIGHT{
+	// Left
+	// a comment
+	ChangeMe
+}
diff --git a/t/t4018/kotlin-fun b/t/t4018/kotlin-fun
new file mode 100644
index 0000000000..2a60280256
--- /dev/null
+++ b/t/t4018/kotlin-fun
@@ -0,0 +1,5 @@
+fun RIGHT(){
+	//a comment
+	//b comment
+    return ChangeMe()
+}
diff --git a/t/t4018/kotlin-inheritace-class b/t/t4018/kotlin-inheritace-class
new file mode 100644
index 0000000000..77376c1f05
--- /dev/null
+++ b/t/t4018/kotlin-inheritace-class
@@ -0,0 +1,5 @@
+open class RIGHT{
+	// a comment
+	// b comment
+	// ChangeMe
+}
diff --git a/t/t4018/kotlin-inline-class b/t/t4018/kotlin-inline-class
new file mode 100644
index 0000000000..7bf46dd8d4
--- /dev/null
+++ b/t/t4018/kotlin-inline-class
@@ -0,0 +1,5 @@
+value class RIGHT(Args){
+	// a comment
+	// b comment
+	ChangeMe
+}
diff --git a/t/t4018/kotlin-interface b/t/t4018/kotlin-interface
new file mode 100644
index 0000000000..f686ba7770
--- /dev/null
+++ b/t/t4018/kotlin-interface
@@ -0,0 +1,5 @@
+interface RIGHT{
+	//another comment
+	//another comment
+	//ChangeMe
+}
diff --git a/t/t4018/kotlin-nested-fun b/t/t4018/kotlin-nested-fun
new file mode 100644
index 0000000000..12186858cb
--- /dev/null
+++ b/t/t4018/kotlin-nested-fun
@@ -0,0 +1,9 @@
+class LEFT{
+	class CENTER{
+		fun RIGHT(  a:Int){
+			//comment
+			//comment
+			ChangeMe
+		}
+	}
+}
diff --git a/t/t4018/kotlin-public-class b/t/t4018/kotlin-public-class
new file mode 100644
index 0000000000..9433fcc226
--- /dev/null
+++ b/t/t4018/kotlin-public-class
@@ -0,0 +1,5 @@
+public class RIGHT{
+	//comment1
+	//comment2
+	ChangeMe
+}
diff --git a/t/t4018/kotlin-sealed-class b/t/t4018/kotlin-sealed-class
new file mode 100644
index 0000000000..0efa4a4eaf
--- /dev/null
+++ b/t/t4018/kotlin-sealed-class
@@ -0,0 +1,5 @@
+sealed class RIGHT {
+	// a comment
+	// b comment
+	ChangeMe
+}
diff --git a/t/t4034-diff-words.sh b/t/t4034-diff-words.sh
index d5abcf4b4c..15764ee9ac 100755
--- a/t/t4034-diff-words.sh
+++ b/t/t4034-diff-words.sh
@@ -324,6 +324,7 @@ test_language_driver dts
 test_language_driver fortran
 test_language_driver html
 test_language_driver java
+test_language_driver kotlin
 test_language_driver matlab
 test_language_driver objc
 test_language_driver pascal
diff --git a/t/t4034/kotlin/expect b/t/t4034/kotlin/expect
new file mode 100644
index 0000000000..74516cc453
--- /dev/null
+++ b/t/t4034/kotlin/expect
@@ -0,0 +1,43 @@
+<BOLD>diff --git a/pre b/post<RESET>
+<BOLD>index 11ea3de..2e1df4c 100644<RESET>
+<BOLD>--- a/pre<RESET>
+<BOLD>+++ b/post<RESET>
+<CYAN>@@ -1,30 +1,30 @@<RESET>
+println("Hello World<RED>!\n<RESET><GREEN>?<RESET>")
+<GREEN>(<RESET>1<GREEN>) (<RESET>-1e10<GREEN>) (<RESET>0xabcdef<GREEN>)<RESET> '<RED>x<RESET><GREEN>y<RESET>'
+[<RED>a<RESET><GREEN>x<RESET>] <RED>a<RESET><GREEN>x<RESET>-><RED>b a<RESET><GREEN>y x<RESET>.<RED>b<RESET><GREEN>y<RESET>
+!<RED>a a<RESET><GREEN>x x<RESET>.inv() <RED>a<RESET><GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>&<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>/<RED>b a<RESET><GREEN>y x<RESET>%<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>+<RED>b a<RESET><GREEN>y x<RESET>-<RED>b<RESET><GREEN>y<RESET>
+a <RED>shr<RESET><GREEN>shl<RESET> b
+<RED>a<RESET><GREEN>x<RESET><<RED>b a<RESET><GREEN>y x<RESET><=<RED>b a<RESET><GREEN>y x<RESET>><RED>b a<RESET><GREEN>y x<RESET>>=<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>==<RED>b a<RESET><GREEN>y x<RESET>!=<RED>b a<RESET><GREEN>y x<RESET>===<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET> and <RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>^<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET> or <RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>&&<RED>b a<RESET><GREEN>y x<RESET>||<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>=<RED>b a<RESET><GREEN>y x<RESET>+=<RED>b a<RESET><GREEN>y x<RESET>-=<RED>b a<RESET><GREEN>y x<RESET>*=<RED>b a<RESET><GREEN>y x<RESET>/=<RED>b a<RESET><GREEN>y x<RESET>%=<RED>b a<RESET><GREEN>y x<RESET><<=<RED>b a<RESET><GREEN>y x<RESET>>>=<RED>b a<RESET><GREEN>y x<RESET>&=<RED>b a<RESET><GREEN>y x<RESET>^=<RED>b a<RESET><GREEN>y x<RESET>|=<RED>b<RESET><GREEN>y<RESET>
+a<RED>=<RESET><GREEN>+=<RESET>b c<RED>+=<RESET><GREEN>=<RESET>d e<RED>-=<RESET><GREEN><=<RESET>f g<RED>*=<RESET><GREEN>>=<RESET>h i<RED>/=<RESET><GREEN>/<RESET>j k<RED>%=<RESET><GREEN>%<RESET>l m<RED><<=<RESET><GREEN><<<RESET>n o<RED>>>=<RESET><GREEN>>><RESET>p q<RED>&=<RESET><GREEN>&<RESET>r s<RED>^=<RESET><GREEN>^<RESET>t u<RED>|=<RESET><GREEN>|<RESET>v
+a<RED><<=<RESET><GREEN><=<RESET>b
+a<RED>||<RESET><GREEN>|<RESET>b a<RED>&&<RESET><GREEN>&<RESET>b
+<RED>a<RESET><GREEN>x<RESET>,y
+--a<RED>==<RESET><GREEN>!=<RESET>--b
+a++<RED>==<RESET><GREEN>!=<RESET>++b
+<RED>0xFF_EC_DE_5E 0b100_000 1<RESET><GREEN>0xFF_E1_DE_5E 0b100_100 2<RESET>00_000
+a<RED>==<RESET><GREEN>===<RESET>b
+a<RED>!!<RESET><GREEN>!=<RESET>b
+<RED>_32<RESET><GREEN>_33<RESET>.find(arr)
+X.<RED>fill<RESET><GREEN>find<RESET>()
+X.<RED>u<RESET><GREEN>f<RESET>+1
+X.u<RED>-<RESET><GREEN>+<RESET>2
+a<RED>.<RESET><GREEN>..<RESET>b
+a<RED>?.<RESET><GREEN>?:<RESET>b
+<RED>.32_00_456<RESET><GREEN>.32_00_446<RESET>
diff --git a/t/t4034/kotlin/post b/t/t4034/kotlin/post
new file mode 100644
index 0000000000..2e1df4c6d5
--- /dev/null
+++ b/t/t4034/kotlin/post
@@ -0,0 +1,30 @@
+println("Hello World?")
+(1) (-1e10) (0xabcdef) 'y'
+[x] x->y x.y
+!x x.inv() x*y x&y
+x*y x/y x%y
+x+y x-y
+a shl b
+x<y x<=y x>y x>=y
+x==y x!=y x===y
+x and y
+x^y
+x or y
+x&&y x||y
+x=y x+=y x-=y x*=y x/=y x%=y x<<=y x>>=y x&=y x^=y x|=y
+a+=b c=d e<=f g>=h i/j k%l m<<n o>>p q&r s^t u|v
+a<=b
+a|b a&b
+x,y
+--a!=--b
+a++!=++b
+0xFF_E1_DE_5E 0b100_100 200_000
+a===b
+a!=b
+_33.find(arr)
+X.find()
+X.f+1
+X.u+2
+a..b
+a?:b
+.32_00_446
diff --git a/t/t4034/kotlin/pre b/t/t4034/kotlin/pre
new file mode 100644
index 0000000000..11ea3de665
--- /dev/null
+++ b/t/t4034/kotlin/pre
@@ -0,0 +1,30 @@
+println("Hello World!\n")
+1 -1e10 0xabcdef 'x'
+[a] a->b a.b
+!a a.inv() a*b a&b
+a*b a/b a%b
+a+b a-b
+a shr b
+a<b a<=b a>b a>=b
+a==b a!=b a===b
+a and b
+a^b
+a or b
+a&&b a||b
+a=b a+=b a-=b a*=b a/=b a%=b a<<=b a>>=b a&=b a^=b a|=b
+a=b c+=d e-=f g*=h i/=j k%=l m<<=n o>>=p q&=r s^=t u|=v
+a<<=b
+a||b a&&b
+a,y
+--a==--b
+a++==++b
+0xFF_EC_DE_5E 0b100_000 100_000
+a==b
+a!!b
+_32.find(arr)
+X.fill()
+X.u+1
+X.u-2
+a.b
+a?.b
+.32_00_456
diff --git a/userdiff.c b/userdiff.c
index 8578cb0d12..c416c9b426 100644
--- a/userdiff.c
+++ b/userdiff.c
@@ -168,6 +168,18 @@ PATTERNS("java",
 	 "|[-+0-9.e]+[fFlL]?|0[xXbB]?[0-9a-fA-F]+[lL]?"
 	 "|[-+*/<>%&^|=!]="
 	 "|--|\\+\\+|<<=?|>>>?=?|&&|\\|\\|"),
+PATTERNS("kotlin",
+	 "^[ \t]*(([a-z]+[ \t]+)*(fun|class|interface)[ \t]+.*)$",
+	 /* -- */
+	 "[a-zA-Z_][a-zA-Z0-9_]*"
+	 /* hexadecimal and binary numbers */
+	 "|0[xXbB][0-9a-fA-F_]+[lLuU]*"
+	 /* integers and floats */
+	 "|[0-9][0-9_]*([.][0-9_]*)([Ee][-+]?[0-9]+)?[fFlLuU]*"
+	 /* floating point numbers beginning with decimal point */
+	 "|[.][0-9][0-9_]*([Ee][-+]?[0-9]+)?[fFlLuU]?"
+	 /* unary and binary operators */
+	 "|[-+*/<>%&^|=!]==?|--|\\+\\+|<<=|>>=|&&|\\|\\||->|\\.\\*|!!|[?:.][.:]"),
 PATTERNS("markdown",
 	 "^ {0,3}#{1,6}[ \t].*",
 	 /* -- */
-- 
2.35.1
Johannes Sixt· Mar 11, 2022, 20:07 UTC · re: Jaydeep P Das · lore

Re: [PATCH v6] userdiff: add builtin diff driver for kotlin language.

Am 11.03.22 um 08:27 schrieb Jaydeep P Das:
Show 10 quoted lines
> The xfuncname pattern finds func/class declarations
> in diffs to display as a hunk header. The word_regex
> pattern finds individual tokens in Kotlin code to generate
> appropriate diffs.
> 
> This patch adds xfuncname regex and word_regex for Kotlin
> language.
> 
> Signed-off-by: Jaydeep P Das <jaydeepjd.8914@gmail.com>
> ---

Thank you. At first, I thought this round is it, but then I noticed this line:

> +<RED>0xFF_EC_DE_5E 0b100_000 1<RESET><GREEN>0xFF_E1_DE_5E 0b100_100 2<RESET>00_000

Notice how the change from 100_000 to 200_000 breaks out the first digit into its own token.

Show 16 quoted lines
> diff --git a/userdiff.c b/userdiff.c
> index 8578cb0d12..c416c9b426 100644
> --- a/userdiff.c
> +++ b/userdiff.c
> @@ -168,6 +168,18 @@ PATTERNS("java",
>  	 "|[-+0-9.e]+[fFlL]?|0[xXbB]?[0-9a-fA-F]+[lL]?"
>  	 "|[-+*/<>%&^|=!]="
>  	 "|--|\\+\\+|<<=?|>>>?=?|&&|\\|\\|"),
> +PATTERNS("kotlin",
> +	 "^[ \t]*(([a-z]+[ \t]+)*(fun|class|interface)[ \t]+.*)$",
> +	 /* -- */
> +	 "[a-zA-Z_][a-zA-Z0-9_]*"
> +	 /* hexadecimal and binary numbers */
> +	 "|0[xXbB][0-9a-fA-F_]+[lLuU]*"
> +	 /* integers and floats */
> +	 "|[0-9][0-9_]*([.][0-9_]*)([Ee][-+]?[0-9]+)?[fFlLuU]*"

This line matches a non-empty digit sequence of any length, and I thought the longest match would win. Why is that not the case here? Frankly, I'm scratching my head over it. Any ideas?

Show 7 quoted lines
> +	 /* floating point numbers beginning with decimal point */
> +	 "|[.][0-9][0-9_]*([Ee][-+]?[0-9]+)?[fFlLuU]?"
> +	 /* unary and binary operators */
> +	 "|[-+*/<>%&^|=!]==?|--|\\+\\+|<<=|>>=|&&|\\|\\||->|\\.\\*|!!|[?:.][.:]"),
>  PATTERNS("markdown",
>  	 "^ {0,3}#{1,6}[ \t].*",
>  	 /* -- */
-- Hannes
jaydeepjd.8914@gmail.com· Mar 12, 2022, 04:36 UTC · re: Johannes Sixt · lore

Re: [PATCH v6] userdiff: add builtin diff driver for kotlin language.

On 3/12/22 1:37 AM, Johannes Sixt <j6t@kdbg.org> wrote:
Show 19 quoted lines
> Am 11.03.22 um 08:27 schrieb Jaydeep P Das:
> > The xfuncname pattern finds func/class declarations
> > in diffs to display as a hunk header. The word_regex
> > pattern finds individual tokens in Kotlin code to generate
> > appropriate diffs.
> >
> > This patch adds xfuncname regex and word_regex for Kotlin
> > language.
> >
> > Signed-off-by: Jaydeep P Das <jaydeepjd.8914@gmail.com>
> > ---
> 
> Thank you. At first, I thought this round is it, but then I noticed this
> line:
> 
> > +<RED>0xFF_EC_DE_5E 0b100_000 1<RESET><GREEN>0xFF_E1_DE_5E 0b100_100 2<RESET>00_000
> 
> Notice how the change from 100_000 to 200_000 breaks out the first digit
> into its own token.
Wow. I completely missed it.
Show 20 quoted lines
> > diff --git a/userdiff.c b/userdiff.c
> > index 8578cb0d12..c416c9b426 100644
> > --- a/userdiff.c
> > +++ b/userdiff.c
> > @@ -168,6 +168,18 @@ PATTERNS("java",
> >   	 "|[-+0-9.e]+[fFlL]?|0[xXbB]?[0-9a-fA-F]+[lL]?"
> >   	 "|[-+*/<>%&^|=!]="
> >   	 "|--|\\+\\+|<<=?|>>>?=?|&&|\\|\\|"),
> > +PATTERNS("kotlin",
> > +	 "^[ \t]*(([a-z]+[ \t]+)*(fun|class|interface)[ \t]+.*)$",
> > +	 /* -- */
> > +	 "[a-zA-Z_][a-zA-Z0-9_]*"
> > +	 /* hexadecimal and binary numbers */
> > +	 "|0[xXbB][0-9a-fA-F_]+[lLuU]*"
> > +	 /* integers and floats */
> > +	 "|[0-9][0-9_]*([.][0-9_]*)([Ee][-+]?[0-9]+)?[fFlLuU]*"
> 
> This line matches a non-empty digit sequence of any length, and I
> thought the longest match would win. Why is that not the case here?
> Frankly, I'm scratching my head over it. Any ideas?

Yes. The capture group ([.][0-9_]*) should occur once or zero times. So this `([.][0-9_]*)?` will fix it.

Johannes Sixt· Mar 12, 2022, 08:36 UTC · re: jaydeepjd.8914@gmail.com · lore

Re: [PATCH v6] userdiff: add builtin diff driver for kotlin language.

Am 12.03.22 um 05:36 schrieb jaydeepjd.8914@gmail.com:
Show 25 quoted lines
> On 3/12/22 1:37 AM, Johannes Sixt <j6t@kdbg.org> wrote:
>> Am 11.03.22 um 08:27 schrieb Jaydeep P Das:
>> > diff --git a/userdiff.c b/userdiff.c
>> > index 8578cb0d12..c416c9b426 100644
>> > --- a/userdiff.c
>> > +++ b/userdiff.c
>> > @@ -168,6 +168,18 @@ PATTERNS("java",
>> >        "|[-+0-9.e]+[fFlL]?|0[xXbB]?[0-9a-fA-F]+[lL]?"
>> >        "|[-+*/<>%&^|=!]="
>> >        "|--|\\+\\+|<<=?|>>>?=?|&&|\\|\\|"),
>> > +PATTERNS("kotlin",
>> > +     "^[ \t]*(([a-z]+[ \t]+)*(fun|class|interface)[ \t]+.*)$",
>> > +     /* -- */
>> > +     "[a-zA-Z_][a-zA-Z0-9_]*"
>> > +     /* hexadecimal and binary numbers */
>> > +     "|0[xXbB][0-9a-fA-F_]+[lLuU]*"
>> > +     /* integers and floats */
>> > +     "|[0-9][0-9_]*([.][0-9_]*)([Ee][-+]?[0-9]+)?[fFlLuU]*"
>>
>> This line matches a non-empty digit sequence of any length, and I
>> thought the longest match would win. Why is that not the case here?
>> Frankly, I'm scratching my head over it. Any ideas?
> 
> Yes. The capture group ([.][0-9_]*) should occur once or zero times. So
> this `([.][0-9_]*)?` will fix it.
Oh, good catch! That's the missing piece.
-- Hannes
Jaydeep P Das· Mar 12, 2022, 04:48 UTC · re: Jaydeep P Das · lore

[PATCH v7] userdiff: add builtin diff driver for kotlin language.

The xfuncname pattern finds func/class declarations in diffs to display as a hunk header. The word_regex pattern finds individual tokens in Kotlin code to generate appropriate diffs.

This patch adds xfuncname regex and word_regex for Kotlin language.

Signed-off-by: Jaydeep P Das <jaydeepjd.8914@gmail.com>
---
 Documentation/gitattributes.txt |  2 ++
 t/t4018/kotlin-class            |  5 ++++
 t/t4018/kotlin-enum-class       |  5 ++++
 t/t4018/kotlin-fun              |  5 ++++
 t/t4018/kotlin-inheritace-class |  5 ++++
 t/t4018/kotlin-inline-class     |  5 ++++
 t/t4018/kotlin-interface        |  5 ++++
 t/t4018/kotlin-nested-fun       |  9 +++++++
 t/t4018/kotlin-public-class     |  5 ++++
 t/t4018/kotlin-sealed-class     |  5 ++++
 t/t4034-diff-words.sh           |  1 +
 t/t4034/kotlin/expect           | 43 +++++++++++++++++++++++++++++++++
 t/t4034/kotlin/post             | 30 +++++++++++++++++++++++
 t/t4034/kotlin/pre              | 30 +++++++++++++++++++++++
 userdiff.c                      | 12 +++++++++
 15 files changed, 167 insertions(+)
 create mode 100644 t/t4018/kotlin-class
 create mode 100644 t/t4018/kotlin-enum-class
 create mode 100644 t/t4018/kotlin-fun
 create mode 100644 t/t4018/kotlin-inheritace-class
 create mode 100644 t/t4018/kotlin-inline-class
 create mode 100644 t/t4018/kotlin-interface
 create mode 100644 t/t4018/kotlin-nested-fun
 create mode 100644 t/t4018/kotlin-public-class
 create mode 100644 t/t4018/kotlin-sealed-class
 create mode 100644 t/t4034/kotlin/expect
 create mode 100644 t/t4034/kotlin/post
 create mode 100644 t/t4034/kotlin/pre
Show changes to 15 files +167 −0

Documentation/gitattributes.txt, t/t4018/kotlin-class, t/t4018/kotlin-enum-class, t/t4018/kotlin-fun, t/t4018/kotlin-inheritace-class, t/t4018/kotlin-inline-class, t/t4018/kotlin-interface, t/t4018/kotlin-nested-fun, t/t4018/kotlin-public-class, t/t4018/kotlin-sealed-class, t/t4034-diff-words.sh, t/t4034/kotlin/expect, t/t4034/kotlin/post, t/t4034/kotlin/pre, userdiff.c

diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt
index a71dad2674..4b36d51beb 100644
--- a/Documentation/gitattributes.txt
+++ b/Documentation/gitattributes.txt
@@ -829,6 +829,8 @@ patterns are available:
 
 - `java` suitable for source code in the Java language.
 
+- `kotlin` suitable for source code in the Kotlin language.
+
 - `markdown` suitable for Markdown documents.
 
 - `matlab` suitable for source code in the MATLAB and Octave languages.
diff --git a/t/t4018/kotlin-class b/t/t4018/kotlin-class
new file mode 100644
index 0000000000..bb864f22e6
--- /dev/null
+++ b/t/t4018/kotlin-class
@@ -0,0 +1,5 @@
+class RIGHT {
+	//comment
+	//comment
+	return ChangeMe
+}
diff --git a/t/t4018/kotlin-enum-class b/t/t4018/kotlin-enum-class
new file mode 100644
index 0000000000..8885f908fd
--- /dev/null
+++ b/t/t4018/kotlin-enum-class
@@ -0,0 +1,5 @@
+enum class RIGHT{
+	// Left
+	// a comment
+	ChangeMe
+}
diff --git a/t/t4018/kotlin-fun b/t/t4018/kotlin-fun
new file mode 100644
index 0000000000..2a60280256
--- /dev/null
+++ b/t/t4018/kotlin-fun
@@ -0,0 +1,5 @@
+fun RIGHT(){
+	//a comment
+	//b comment
+    return ChangeMe()
+}
diff --git a/t/t4018/kotlin-inheritace-class b/t/t4018/kotlin-inheritace-class
new file mode 100644
index 0000000000..77376c1f05
--- /dev/null
+++ b/t/t4018/kotlin-inheritace-class
@@ -0,0 +1,5 @@
+open class RIGHT{
+	// a comment
+	// b comment
+	// ChangeMe
+}
diff --git a/t/t4018/kotlin-inline-class b/t/t4018/kotlin-inline-class
new file mode 100644
index 0000000000..7bf46dd8d4
--- /dev/null
+++ b/t/t4018/kotlin-inline-class
@@ -0,0 +1,5 @@
+value class RIGHT(Args){
+	// a comment
+	// b comment
+	ChangeMe
+}
diff --git a/t/t4018/kotlin-interface b/t/t4018/kotlin-interface
new file mode 100644
index 0000000000..f686ba7770
--- /dev/null
+++ b/t/t4018/kotlin-interface
@@ -0,0 +1,5 @@
+interface RIGHT{
+	//another comment
+	//another comment
+	//ChangeMe
+}
diff --git a/t/t4018/kotlin-nested-fun b/t/t4018/kotlin-nested-fun
new file mode 100644
index 0000000000..12186858cb
--- /dev/null
+++ b/t/t4018/kotlin-nested-fun
@@ -0,0 +1,9 @@
+class LEFT{
+	class CENTER{
+		fun RIGHT(  a:Int){
+			//comment
+			//comment
+			ChangeMe
+		}
+	}
+}
diff --git a/t/t4018/kotlin-public-class b/t/t4018/kotlin-public-class
new file mode 100644
index 0000000000..9433fcc226
--- /dev/null
+++ b/t/t4018/kotlin-public-class
@@ -0,0 +1,5 @@
+public class RIGHT{
+	//comment1
+	//comment2
+	ChangeMe
+}
diff --git a/t/t4018/kotlin-sealed-class b/t/t4018/kotlin-sealed-class
new file mode 100644
index 0000000000..0efa4a4eaf
--- /dev/null
+++ b/t/t4018/kotlin-sealed-class
@@ -0,0 +1,5 @@
+sealed class RIGHT {
+	// a comment
+	// b comment
+	ChangeMe
+}
diff --git a/t/t4034-diff-words.sh b/t/t4034-diff-words.sh
index d5abcf4b4c..15764ee9ac 100755
--- a/t/t4034-diff-words.sh
+++ b/t/t4034-diff-words.sh
@@ -324,6 +324,7 @@ test_language_driver dts
 test_language_driver fortran
 test_language_driver html
 test_language_driver java
+test_language_driver kotlin
 test_language_driver matlab
 test_language_driver objc
 test_language_driver pascal
diff --git a/t/t4034/kotlin/expect b/t/t4034/kotlin/expect
new file mode 100644
index 0000000000..7f76f7540d
--- /dev/null
+++ b/t/t4034/kotlin/expect
@@ -0,0 +1,43 @@
+<BOLD>diff --git a/pre b/post<RESET>
+<BOLD>index 11ea3de..2e1df4c 100644<RESET>
+<BOLD>--- a/pre<RESET>
+<BOLD>+++ b/post<RESET>
+<CYAN>@@ -1,30 +1,30 @@<RESET>
+println("Hello World<RED>!\n<RESET><GREEN>?<RESET>")
+<GREEN>(<RESET>1<GREEN>) (<RESET>-1e10<GREEN>) (<RESET>0xabcdef<GREEN>)<RESET> '<RED>x<RESET><GREEN>y<RESET>'
+[<RED>a<RESET><GREEN>x<RESET>] <RED>a<RESET><GREEN>x<RESET>-><RED>b a<RESET><GREEN>y x<RESET>.<RED>b<RESET><GREEN>y<RESET>
+!<RED>a a<RESET><GREEN>x x<RESET>.inv() <RED>a<RESET><GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>&<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>/<RED>b a<RESET><GREEN>y x<RESET>%<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>+<RED>b a<RESET><GREEN>y x<RESET>-<RED>b<RESET><GREEN>y<RESET>
+a <RED>shr<RESET><GREEN>shl<RESET> b
+<RED>a<RESET><GREEN>x<RESET><<RED>b a<RESET><GREEN>y x<RESET><=<RED>b a<RESET><GREEN>y x<RESET>><RED>b a<RESET><GREEN>y x<RESET>>=<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>==<RED>b a<RESET><GREEN>y x<RESET>!=<RED>b a<RESET><GREEN>y x<RESET>===<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET> and <RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>^<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET> or <RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>&&<RED>b a<RESET><GREEN>y x<RESET>||<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>=<RED>b a<RESET><GREEN>y x<RESET>+=<RED>b a<RESET><GREEN>y x<RESET>-=<RED>b a<RESET><GREEN>y x<RESET>*=<RED>b a<RESET><GREEN>y x<RESET>/=<RED>b a<RESET><GREEN>y x<RESET>%=<RED>b a<RESET><GREEN>y x<RESET><<=<RED>b a<RESET><GREEN>y x<RESET>>>=<RED>b a<RESET><GREEN>y x<RESET>&=<RED>b a<RESET><GREEN>y x<RESET>^=<RED>b a<RESET><GREEN>y x<RESET>|=<RED>b<RESET><GREEN>y<RESET>
+a<RED>=<RESET><GREEN>+=<RESET>b c<RED>+=<RESET><GREEN>=<RESET>d e<RED>-=<RESET><GREEN><=<RESET>f g<RED>*=<RESET><GREEN>>=<RESET>h i<RED>/=<RESET><GREEN>/<RESET>j k<RED>%=<RESET><GREEN>%<RESET>l m<RED><<=<RESET><GREEN><<<RESET>n o<RED>>>=<RESET><GREEN>>><RESET>p q<RED>&=<RESET><GREEN>&<RESET>r s<RED>^=<RESET><GREEN>^<RESET>t u<RED>|=<RESET><GREEN>|<RESET>v
+a<RED><<=<RESET><GREEN><=<RESET>b
+a<RED>||<RESET><GREEN>|<RESET>b a<RED>&&<RESET><GREEN>&<RESET>b
+<RED>a<RESET><GREEN>x<RESET>,y
+--a<RED>==<RESET><GREEN>!=<RESET>--b
+a++<RED>==<RESET><GREEN>!=<RESET>++b
+<RED>0xFF_EC_DE_5E 0b100_000 100_000<RESET><GREEN>0xFF_E1_DE_5E 0b100_100 200_000<RESET>
+a<RED>==<RESET><GREEN>===<RESET>b
+a<RED>!!<RESET><GREEN>!=<RESET>b
+<RED>_32<RESET><GREEN>_33<RESET>.find(arr)
+X.<RED>fill<RESET><GREEN>find<RESET>()
+X.<RED>u<RESET><GREEN>f<RESET>+1
+X.u<RED>-<RESET><GREEN>+<RESET>2
+a<RED>.<RESET><GREEN>..<RESET>b
+a<RED>?.<RESET><GREEN>?:<RESET>b
+<RED>.32_00_456<RESET><GREEN>.32_00_446<RESET>
diff --git a/t/t4034/kotlin/post b/t/t4034/kotlin/post
new file mode 100644
index 0000000000..2e1df4c6d5
--- /dev/null
+++ b/t/t4034/kotlin/post
@@ -0,0 +1,30 @@
+println("Hello World?")
+(1) (-1e10) (0xabcdef) 'y'
+[x] x->y x.y
+!x x.inv() x*y x&y
+x*y x/y x%y
+x+y x-y
+a shl b
+x<y x<=y x>y x>=y
+x==y x!=y x===y
+x and y
+x^y
+x or y
+x&&y x||y
+x=y x+=y x-=y x*=y x/=y x%=y x<<=y x>>=y x&=y x^=y x|=y
+a+=b c=d e<=f g>=h i/j k%l m<<n o>>p q&r s^t u|v
+a<=b
+a|b a&b
+x,y
+--a!=--b
+a++!=++b
+0xFF_E1_DE_5E 0b100_100 200_000
+a===b
+a!=b
+_33.find(arr)
+X.find()
+X.f+1
+X.u+2
+a..b
+a?:b
+.32_00_446
diff --git a/t/t4034/kotlin/pre b/t/t4034/kotlin/pre
new file mode 100644
index 0000000000..11ea3de665
--- /dev/null
+++ b/t/t4034/kotlin/pre
@@ -0,0 +1,30 @@
+println("Hello World!\n")
+1 -1e10 0xabcdef 'x'
+[a] a->b a.b
+!a a.inv() a*b a&b
+a*b a/b a%b
+a+b a-b
+a shr b
+a<b a<=b a>b a>=b
+a==b a!=b a===b
+a and b
+a^b
+a or b
+a&&b a||b
+a=b a+=b a-=b a*=b a/=b a%=b a<<=b a>>=b a&=b a^=b a|=b
+a=b c+=d e-=f g*=h i/=j k%=l m<<=n o>>=p q&=r s^=t u|=v
+a<<=b
+a||b a&&b
+a,y
+--a==--b
+a++==++b
+0xFF_EC_DE_5E 0b100_000 100_000
+a==b
+a!!b
+_32.find(arr)
+X.fill()
+X.u+1
+X.u-2
+a.b
+a?.b
+.32_00_456
diff --git a/userdiff.c b/userdiff.c
index 8578cb0d12..0f6c14659b 100644
--- a/userdiff.c
+++ b/userdiff.c
@@ -168,6 +168,18 @@ PATTERNS("java",
 	 "|[-+0-9.e]+[fFlL]?|0[xXbB]?[0-9a-fA-F]+[lL]?"
 	 "|[-+*/<>%&^|=!]="
 	 "|--|\\+\\+|<<=?|>>>?=?|&&|\\|\\|"),
+PATTERNS("kotlin",
+	 "^[ \t]*(([a-z]+[ \t]+)*(fun|class|interface)[ \t]+.*)$",
+	 /* -- */
+	 "[a-zA-Z_][a-zA-Z0-9_]*"
+	 /* hexadecimal and binary numbers */
+	 "|0[xXbB][0-9a-fA-F_]+[lLuU]*"
+	 /* integers and floats */
+	 "|[0-9][0-9_]*([.][0-9_]*)?([Ee][-+]?[0-9]+)?[fFlLuU]*"
+	 /* floating point numbers beginning with decimal point */
+	 "|[.][0-9][0-9_]*([Ee][-+]?[0-9]+)?[fFlLuU]?"
+	 /* unary and binary operators */
+	 "|[-+*/<>%&^|=!]==?|--|\\+\\+|<<=|>>=|&&|\\|\\||->|\\.\\*|!!|[?:.][.:]"),
 PATTERNS("markdown",
 	 "^ {0,3}#{1,6}[ \t].*",
 	 /* -- */
-- 
2.35.1
Johannes Sixt· Mar 12, 2022, 08:59 UTC · re: Jaydeep P Das · lore

Re: [PATCH v7] userdiff: add builtin diff driver for kotlin language.

Am 12.03.22 um 05:48 schrieb Jaydeep P Das:
Show 9 quoted lines
> The xfuncname pattern finds func/class declarations
> in diffs to display as a hunk header. The word_regex
> pattern finds individual tokens in Kotlin code to generate
> appropriate diffs.
> 
> This patch adds xfuncname regex and word_regex for Kotlin
> language.
> 
> Signed-off-by: Jaydeep P Das <jaydeepjd.8914@gmail.com>
This round looks good. Thank you for your perseverance.
Acked-by: Johannes Sixt <j6t@kdbg.org>
Show 302 quoted lines
> ---
>  Documentation/gitattributes.txt |  2 ++
>  t/t4018/kotlin-class            |  5 ++++
>  t/t4018/kotlin-enum-class       |  5 ++++
>  t/t4018/kotlin-fun              |  5 ++++
>  t/t4018/kotlin-inheritace-class |  5 ++++
>  t/t4018/kotlin-inline-class     |  5 ++++
>  t/t4018/kotlin-interface        |  5 ++++
>  t/t4018/kotlin-nested-fun       |  9 +++++++
>  t/t4018/kotlin-public-class     |  5 ++++
>  t/t4018/kotlin-sealed-class     |  5 ++++
>  t/t4034-diff-words.sh           |  1 +
>  t/t4034/kotlin/expect           | 43 +++++++++++++++++++++++++++++++++
>  t/t4034/kotlin/post             | 30 +++++++++++++++++++++++
>  t/t4034/kotlin/pre              | 30 +++++++++++++++++++++++
>  userdiff.c                      | 12 +++++++++
>  15 files changed, 167 insertions(+)
>  create mode 100644 t/t4018/kotlin-class
>  create mode 100644 t/t4018/kotlin-enum-class
>  create mode 100644 t/t4018/kotlin-fun
>  create mode 100644 t/t4018/kotlin-inheritace-class
>  create mode 100644 t/t4018/kotlin-inline-class
>  create mode 100644 t/t4018/kotlin-interface
>  create mode 100644 t/t4018/kotlin-nested-fun
>  create mode 100644 t/t4018/kotlin-public-class
>  create mode 100644 t/t4018/kotlin-sealed-class
>  create mode 100644 t/t4034/kotlin/expect
>  create mode 100644 t/t4034/kotlin/post
>  create mode 100644 t/t4034/kotlin/pre
> 
> diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt
> index a71dad2674..4b36d51beb 100644
> --- a/Documentation/gitattributes.txt
> +++ b/Documentation/gitattributes.txt
> @@ -829,6 +829,8 @@ patterns are available:
>  
>  - `java` suitable for source code in the Java language.
>  
> +- `kotlin` suitable for source code in the Kotlin language.
> +
>  - `markdown` suitable for Markdown documents.
>  
>  - `matlab` suitable for source code in the MATLAB and Octave languages.
> diff --git a/t/t4018/kotlin-class b/t/t4018/kotlin-class
> new file mode 100644
> index 0000000000..bb864f22e6
> --- /dev/null
> +++ b/t/t4018/kotlin-class
> @@ -0,0 +1,5 @@
> +class RIGHT {
> +	//comment
> +	//comment
> +	return ChangeMe
> +}
> diff --git a/t/t4018/kotlin-enum-class b/t/t4018/kotlin-enum-class
> new file mode 100644
> index 0000000000..8885f908fd
> --- /dev/null
> +++ b/t/t4018/kotlin-enum-class
> @@ -0,0 +1,5 @@
> +enum class RIGHT{
> +	// Left
> +	// a comment
> +	ChangeMe
> +}
> diff --git a/t/t4018/kotlin-fun b/t/t4018/kotlin-fun
> new file mode 100644
> index 0000000000..2a60280256
> --- /dev/null
> +++ b/t/t4018/kotlin-fun
> @@ -0,0 +1,5 @@
> +fun RIGHT(){
> +	//a comment
> +	//b comment
> +    return ChangeMe()
> +}
> diff --git a/t/t4018/kotlin-inheritace-class b/t/t4018/kotlin-inheritace-class
> new file mode 100644
> index 0000000000..77376c1f05
> --- /dev/null
> +++ b/t/t4018/kotlin-inheritace-class
> @@ -0,0 +1,5 @@
> +open class RIGHT{
> +	// a comment
> +	// b comment
> +	// ChangeMe
> +}
> diff --git a/t/t4018/kotlin-inline-class b/t/t4018/kotlin-inline-class
> new file mode 100644
> index 0000000000..7bf46dd8d4
> --- /dev/null
> +++ b/t/t4018/kotlin-inline-class
> @@ -0,0 +1,5 @@
> +value class RIGHT(Args){
> +	// a comment
> +	// b comment
> +	ChangeMe
> +}
> diff --git a/t/t4018/kotlin-interface b/t/t4018/kotlin-interface
> new file mode 100644
> index 0000000000..f686ba7770
> --- /dev/null
> +++ b/t/t4018/kotlin-interface
> @@ -0,0 +1,5 @@
> +interface RIGHT{
> +	//another comment
> +	//another comment
> +	//ChangeMe
> +}
> diff --git a/t/t4018/kotlin-nested-fun b/t/t4018/kotlin-nested-fun
> new file mode 100644
> index 0000000000..12186858cb
> --- /dev/null
> +++ b/t/t4018/kotlin-nested-fun
> @@ -0,0 +1,9 @@
> +class LEFT{
> +	class CENTER{
> +		fun RIGHT(  a:Int){
> +			//comment
> +			//comment
> +			ChangeMe
> +		}
> +	}
> +}
> diff --git a/t/t4018/kotlin-public-class b/t/t4018/kotlin-public-class
> new file mode 100644
> index 0000000000..9433fcc226
> --- /dev/null
> +++ b/t/t4018/kotlin-public-class
> @@ -0,0 +1,5 @@
> +public class RIGHT{
> +	//comment1
> +	//comment2
> +	ChangeMe
> +}
> diff --git a/t/t4018/kotlin-sealed-class b/t/t4018/kotlin-sealed-class
> new file mode 100644
> index 0000000000..0efa4a4eaf
> --- /dev/null
> +++ b/t/t4018/kotlin-sealed-class
> @@ -0,0 +1,5 @@
> +sealed class RIGHT {
> +	// a comment
> +	// b comment
> +	ChangeMe
> +}
> diff --git a/t/t4034-diff-words.sh b/t/t4034-diff-words.sh
> index d5abcf4b4c..15764ee9ac 100755
> --- a/t/t4034-diff-words.sh
> +++ b/t/t4034-diff-words.sh
> @@ -324,6 +324,7 @@ test_language_driver dts
>  test_language_driver fortran
>  test_language_driver html
>  test_language_driver java
> +test_language_driver kotlin
>  test_language_driver matlab
>  test_language_driver objc
>  test_language_driver pascal
> diff --git a/t/t4034/kotlin/expect b/t/t4034/kotlin/expect
> new file mode 100644
> index 0000000000..7f76f7540d
> --- /dev/null
> +++ b/t/t4034/kotlin/expect
> @@ -0,0 +1,43 @@
> +<BOLD>diff --git a/pre b/post<RESET>
> +<BOLD>index 11ea3de..2e1df4c 100644<RESET>
> +<BOLD>--- a/pre<RESET>
> +<BOLD>+++ b/post<RESET>
> +<CYAN>@@ -1,30 +1,30 @@<RESET>
> +println("Hello World<RED>!\n<RESET><GREEN>?<RESET>")
> +<GREEN>(<RESET>1<GREEN>) (<RESET>-1e10<GREEN>) (<RESET>0xabcdef<GREEN>)<RESET> '<RED>x<RESET><GREEN>y<RESET>'
> +[<RED>a<RESET><GREEN>x<RESET>] <RED>a<RESET><GREEN>x<RESET>-><RED>b a<RESET><GREEN>y x<RESET>.<RED>b<RESET><GREEN>y<RESET>
> +!<RED>a a<RESET><GREEN>x x<RESET>.inv() <RED>a<RESET><GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>&<RED>b<RESET>
> +<RED>a<RESET><GREEN>y<RESET>
> +<GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>/<RED>b a<RESET><GREEN>y x<RESET>%<RED>b<RESET>
> +<RED>a<RESET><GREEN>y<RESET>
> +<GREEN>x<RESET>+<RED>b a<RESET><GREEN>y x<RESET>-<RED>b<RESET><GREEN>y<RESET>
> +a <RED>shr<RESET><GREEN>shl<RESET> b
> +<RED>a<RESET><GREEN>x<RESET><<RED>b a<RESET><GREEN>y x<RESET><=<RED>b a<RESET><GREEN>y x<RESET>><RED>b a<RESET><GREEN>y x<RESET>>=<RED>b<RESET>
> +<RED>a<RESET><GREEN>y<RESET>
> +<GREEN>x<RESET>==<RED>b a<RESET><GREEN>y x<RESET>!=<RED>b a<RESET><GREEN>y x<RESET>===<RED>b<RESET>
> +<RED>a<RESET><GREEN>y<RESET>
> +<GREEN>x<RESET> and <RED>b<RESET>
> +<RED>a<RESET><GREEN>y<RESET>
> +<GREEN>x<RESET>^<RED>b<RESET>
> +<RED>a<RESET><GREEN>y<RESET>
> +<GREEN>x<RESET> or <RED>b<RESET>
> +<RED>a<RESET><GREEN>y<RESET>
> +<GREEN>x<RESET>&&<RED>b a<RESET><GREEN>y x<RESET>||<RED>b<RESET>
> +<RED>a<RESET><GREEN>y<RESET>
> +<GREEN>x<RESET>=<RED>b a<RESET><GREEN>y x<RESET>+=<RED>b a<RESET><GREEN>y x<RESET>-=<RED>b a<RESET><GREEN>y x<RESET>*=<RED>b a<RESET><GREEN>y x<RESET>/=<RED>b a<RESET><GREEN>y x<RESET>%=<RED>b a<RESET><GREEN>y x<RESET><<=<RED>b a<RESET><GREEN>y x<RESET>>>=<RED>b a<RESET><GREEN>y x<RESET>&=<RED>b a<RESET><GREEN>y x<RESET>^=<RED>b a<RESET><GREEN>y x<RESET>|=<RED>b<RESET><GREEN>y<RESET>
> +a<RED>=<RESET><GREEN>+=<RESET>b c<RED>+=<RESET><GREEN>=<RESET>d e<RED>-=<RESET><GREEN><=<RESET>f g<RED>*=<RESET><GREEN>>=<RESET>h i<RED>/=<RESET><GREEN>/<RESET>j k<RED>%=<RESET><GREEN>%<RESET>l m<RED><<=<RESET><GREEN><<<RESET>n o<RED>>>=<RESET><GREEN>>><RESET>p q<RED>&=<RESET><GREEN>&<RESET>r s<RED>^=<RESET><GREEN>^<RESET>t u<RED>|=<RESET><GREEN>|<RESET>v
> +a<RED><<=<RESET><GREEN><=<RESET>b
> +a<RED>||<RESET><GREEN>|<RESET>b a<RED>&&<RESET><GREEN>&<RESET>b
> +<RED>a<RESET><GREEN>x<RESET>,y
> +--a<RED>==<RESET><GREEN>!=<RESET>--b
> +a++<RED>==<RESET><GREEN>!=<RESET>++b
> +<RED>0xFF_EC_DE_5E 0b100_000 100_000<RESET><GREEN>0xFF_E1_DE_5E 0b100_100 200_000<RESET>
> +a<RED>==<RESET><GREEN>===<RESET>b
> +a<RED>!!<RESET><GREEN>!=<RESET>b
> +<RED>_32<RESET><GREEN>_33<RESET>.find(arr)
> +X.<RED>fill<RESET><GREEN>find<RESET>()
> +X.<RED>u<RESET><GREEN>f<RESET>+1
> +X.u<RED>-<RESET><GREEN>+<RESET>2
> +a<RED>.<RESET><GREEN>..<RESET>b
> +a<RED>?.<RESET><GREEN>?:<RESET>b
> +<RED>.32_00_456<RESET><GREEN>.32_00_446<RESET>
> diff --git a/t/t4034/kotlin/post b/t/t4034/kotlin/post
> new file mode 100644
> index 0000000000..2e1df4c6d5
> --- /dev/null
> +++ b/t/t4034/kotlin/post
> @@ -0,0 +1,30 @@
> +println("Hello World?")
> +(1) (-1e10) (0xabcdef) 'y'
> +[x] x->y x.y
> +!x x.inv() x*y x&y
> +x*y x/y x%y
> +x+y x-y
> +a shl b
> +x<y x<=y x>y x>=y
> +x==y x!=y x===y
> +x and y
> +x^y
> +x or y
> +x&&y x||y
> +x=y x+=y x-=y x*=y x/=y x%=y x<<=y x>>=y x&=y x^=y x|=y
> +a+=b c=d e<=f g>=h i/j k%l m<<n o>>p q&r s^t u|v
> +a<=b
> +a|b a&b
> +x,y
> +--a!=--b
> +a++!=++b
> +0xFF_E1_DE_5E 0b100_100 200_000
> +a===b
> +a!=b
> +_33.find(arr)
> +X.find()
> +X.f+1
> +X.u+2
> +a..b
> +a?:b
> +.32_00_446
> diff --git a/t/t4034/kotlin/pre b/t/t4034/kotlin/pre
> new file mode 100644
> index 0000000000..11ea3de665
> --- /dev/null
> +++ b/t/t4034/kotlin/pre
> @@ -0,0 +1,30 @@
> +println("Hello World!\n")
> +1 -1e10 0xabcdef 'x'
> +[a] a->b a.b
> +!a a.inv() a*b a&b
> +a*b a/b a%b
> +a+b a-b
> +a shr b
> +a<b a<=b a>b a>=b
> +a==b a!=b a===b
> +a and b
> +a^b
> +a or b
> +a&&b a||b
> +a=b a+=b a-=b a*=b a/=b a%=b a<<=b a>>=b a&=b a^=b a|=b
> +a=b c+=d e-=f g*=h i/=j k%=l m<<=n o>>=p q&=r s^=t u|=v
> +a<<=b
> +a||b a&&b
> +a,y
> +--a==--b
> +a++==++b
> +0xFF_EC_DE_5E 0b100_000 100_000
> +a==b
> +a!!b
> +_32.find(arr)
> +X.fill()
> +X.u+1
> +X.u-2
> +a.b
> +a?.b
> +.32_00_456
> diff --git a/userdiff.c b/userdiff.c
> index 8578cb0d12..0f6c14659b 100644
> --- a/userdiff.c
> +++ b/userdiff.c
> @@ -168,6 +168,18 @@ PATTERNS("java",
>  	 "|[-+0-9.e]+[fFlL]?|0[xXbB]?[0-9a-fA-F]+[lL]?"
>  	 "|[-+*/<>%&^|=!]="
>  	 "|--|\\+\\+|<<=?|>>>?=?|&&|\\|\\|"),
> +PATTERNS("kotlin",
> +	 "^[ \t]*(([a-z]+[ \t]+)*(fun|class|interface)[ \t]+.*)$",
> +	 /* -- */
> +	 "[a-zA-Z_][a-zA-Z0-9_]*"
> +	 /* hexadecimal and binary numbers */
> +	 "|0[xXbB][0-9a-fA-F_]+[lLuU]*"
> +	 /* integers and floats */
> +	 "|[0-9][0-9_]*([.][0-9_]*)?([Ee][-+]?[0-9]+)?[fFlLuU]*"
> +	 /* floating point numbers beginning with decimal point */
> +	 "|[.][0-9][0-9_]*([Ee][-+]?[0-9]+)?[fFlLuU]?"
> +	 /* unary and binary operators */
> +	 "|[-+*/<>%&^|=!]==?|--|\\+\\+|<<=|>>=|&&|\\|\\||->|\\.\\*|!!|[?:.][.:]"),
>  PATTERNS("markdown",
>  	 "^ {0,3}#{1,6}[ \t].*",
>  	 /* -- */
jaydeepjd.8914@gmail.com· Mar 13, 2022, 17:02 UTC · re: Johannes Sixt · lore

Re: [PATCH v7] userdiff: add builtin diff driver for kotlin language.

On 3/12/22 2:29 PM, Johannes Sixt <j6t@kdbg.org> wrote:
Show 14 quoted lines
> Am 12.03.22 um 05:48 schrieb Jaydeep P Das:
> > The xfuncname pattern finds func/class declarations
> > in diffs to display as a hunk header. The word_regex
> > pattern finds individual tokens in Kotlin code to generate
> > appropriate diffs.
> >
> > This patch adds xfuncname regex and word_regex for Kotlin
> > language.
> >
> > Signed-off-by: Jaydeep P Das <jaydeepjd.8914@gmail.com>
> 
> This round looks good. Thank you for your perseverance.
> 
> Acked-by: Johannes Sixt <j6t@kdbg.org>
Thanks. Should I CC Junio or will it be here for some more reviews?
jaydeepjd.8914@gmail.com· Mar 13, 2022, 17:09 UTC · re: jaydeepjd.8914@gmail.com · lore

Re: [PATCH v7] userdiff: add builtin diff driver for kotlin language.

Also, since according to GSoC timeline, the current period is to discuss application ideas with mentoring organizations, what should I do next?

I have seen the GSoC application ideas and integrating the remaining git commands to work with sparse-index looks interesting. Maybe I could start off with that?

Thanks, Jaydeep.

Johannes Sixt· Mar 13, 2022, 21:36 UTC · re: jaydeepjd.8914@gmail.com · lore

Re: [PATCH v7] userdiff: add builtin diff driver for kotlin language.

Am 13.03.22 um 18:02 schrieb jaydeepjd.8914@gmail.com:
> Thanks. Should I CC Junio or will it be here for some more reviews?

In my previous reply I Cc'ed Junio to notify him that we have reached a conclusion. Usually, he'll pick up the patch after that. If you do not see the topic mentioned in the next "What's cooking" report or it refers to an outdated version, that would be an appropriate time for a reminder.

-- Hannes

← back to recent threads