diff --git a/lib/ch_usi_si_seart_treesitter_TreeCursor.cc b/lib/ch_usi_si_seart_treesitter_TreeCursor.cc index a0c7c19b..d6510fbf 100644 --- a/lib/ch_usi_si_seart_treesitter_TreeCursor.cc +++ b/lib/ch_usi_si_seart_treesitter_TreeCursor.cc @@ -69,3 +69,19 @@ JNIEXPORT jboolean JNICALL Java_ch_usi_si_seart_treesitter_TreeCursor_gotoParent env->SetIntField(thisObject, _treeCursorContext1Field, cursor->context[1]); return result ? JNI_TRUE : JNI_FALSE; } + +JNIEXPORT jobject JNICALL Java_ch_usi_si_seart_treesitter_TreeCursor_clone( + JNIEnv* env, jobject thisObject) { + jobject treeObject = env->GetObjectField(thisObject, _treeCursorTreeField); + const TSTreeCursor* cursor = (const TSTreeCursor*)__getPointer(env, thisObject); + TSTreeCursor copy = ts_tree_cursor_copy(cursor); + return env->NewObject( + _treeCursorClass, + _treeCursorConstructor, + new TSTreeCursor(copy), + copy.context[0], + copy.context[1], + copy.id, + treeObject + ); +} diff --git a/lib/ch_usi_si_seart_treesitter_TreeCursor.h b/lib/ch_usi_si_seart_treesitter_TreeCursor.h index 50b632db..9d7cabfa 100644 --- a/lib/ch_usi_si_seart_treesitter_TreeCursor.h +++ b/lib/ch_usi_si_seart_treesitter_TreeCursor.h @@ -63,6 +63,14 @@ JNIEXPORT jboolean JNICALL Java_ch_usi_si_seart_treesitter_TreeCursor_gotoNextSi JNIEXPORT jboolean JNICALL Java_ch_usi_si_seart_treesitter_TreeCursor_gotoParent (JNIEnv *, jobject); +/* + * Class: ch_usi_si_seart_treesitter_TreeCursor + * Method: clone + * Signature: ()Lch/usi/si/seart/treesitter/TreeCursor; + */ +JNIEXPORT jobject JNICALL Java_ch_usi_si_seart_treesitter_TreeCursor_clone + (JNIEnv *, jobject); + #ifdef __cplusplus } #endif diff --git a/src/main/java/ch/usi/si/seart/treesitter/TreeCursor.java b/src/main/java/ch/usi/si/seart/treesitter/TreeCursor.java index 69d6806e..ed278c4b 100644 --- a/src/main/java/ch/usi/si/seart/treesitter/TreeCursor.java +++ b/src/main/java/ch/usi/si/seart/treesitter/TreeCursor.java @@ -18,7 +18,7 @@ * @author Ozren Dabić */ @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) -public class TreeCursor extends External { +public class TreeCursor extends External implements Cloneable { int context0; int context1; @@ -120,4 +120,13 @@ public void preorderTraversal(@NotNull Consumer callback) { public String toString() { return String.format("TreeCursor(id: %d, tree: %d)", id, tree.pointer); } + + /** + * Clone this cursor, creating a separate, independent instance. + * + * @return a clone of this instance + * @since 1.5.1 + */ + @Override + public native TreeCursor clone(); } diff --git a/src/test/java/ch/usi/si/seart/treesitter/TreeCursorTest.java b/src/test/java/ch/usi/si/seart/treesitter/TreeCursorTest.java index 3d2f0839..9ed01732 100644 --- a/src/test/java/ch/usi/si/seart/treesitter/TreeCursorTest.java +++ b/src/test/java/ch/usi/si/seart/treesitter/TreeCursorTest.java @@ -1,5 +1,6 @@ package ch.usi.si.seart.treesitter; +import lombok.Cleanup; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; @@ -76,6 +77,12 @@ void testPreorderTraversal() { Assertions.assertEquals(17, count.get()); } + @Test + void testClone() { + @Cleanup TreeCursor copy = cursor.clone(); + Assertions.assertNotEquals(cursor, copy); + } + @Test @SuppressWarnings("resource") void testWalkThrows() {