Skip to content

feat: QueryCursor iterators#31

Open
bennypowers wants to merge 4 commits into
tree-sitter:masterfrom
bennypowers:feat/querycursor-iterators
Open

feat: QueryCursor iterators#31
bennypowers wants to merge 4 commits into
tree-sitter:masterfrom
bennypowers:feat/querycursor-iterators

Conversation

@bennypowers

@bennypowers bennypowers commented May 29, 2025

Copy link
Copy Markdown

Closes #30

Adds AllMatches and AllCaptures iterator methods to QueryCursor, following Go's iter naming conventions as suggested in #30.

  • AllMatches returns iter.Seq[*QueryMatch]
  • AllCaptures returns iter.Seq2[*QueryMatch, uint]

The existing Matches/Captures methods are unchanged.

@bennypowers

Copy link
Copy Markdown
Author

I'm not sure about the tests here, there's probably a better way to test IterCaptures

@bennypowers
bennypowers marked this pull request as ready for review May 29, 2025 11:44
Comment thread query.go
@bennypowers

bennypowers commented May 29, 2025

Copy link
Copy Markdown
Author

I tried something similar in a project i'm working on and got some super weird errors

func allMatches(qc *ts.QueryCursor, q *ts.Query, node *ts.Node, text []byte) iter.Seq2[*ts.QueryMatch, *ts.Query] {
	qm := qc.Matches(q, node, text)
	return func(yield func (qm *ts.QueryMatch, q *ts.Query) bool) {
		for {
			m := qm.Next()
			if m == nil {
				break
			}
			if !yield(m, q) {
				return
			}
		}
	}
}

in the yield call i got a panic:

1. Thread stopped due to exception ()
   Description: Error getting throw reason: could not find symbol value for s
   Stack trace:
   Stack:
   	3  0x00007faf6f3cd11c in C.__pthread_kill_implementation
   	    at /usr/src/debug/glibc-2.41-5.fc42.x86_64/nptl/pthread_kill.c:43
   	4  0x00007faf6f373afe in C.raise
   	    at ../sysdeps/posix/raise.c:26
   	5  0x00007faf6f35b6d0 in C.abort
   	    at /usr/src/debug/glibc-2.41-5.fc42.x86_64/stdlib/abort.c:73
   	6  0x00007faf6f35b639 in C.__assert_perror_fail
   	    at /usr/src/debug/glibc-2.41-5.fc42.x86_64/assert/assert-perr.c:31

edit: ok i need to learn more about go resource management. for now I'm doing this so i can close the resources when finished at the call site

func QueryMatches(queryName string,
									language *ts.Language,
									text []byte,
									node *ts.Node) (*ts.Query, *ts.QueryCursor, iter.Seq2[*ts.QueryMatch, *ts.Query]) {
	queryText, err := loadQueryFile(queryName)
	if err != nil {
		log.Fatal(nil)
	}
	q, qerr := ts.NewQuery(language, queryText)
	if qerr != nil {
		log.Fatal(qerr)
	}
	qc := ts.NewQueryCursor()
	qm := qc.Matches(q, node, text)
	return q, qc, func(yield func (qm *ts.QueryMatch, q *ts.Query) bool) {
		for {
			m := qm.Next()
			if m == nil {
				break
			}
			if !yield(m, q) {
				return
			}
		}
	}
}

I'm demoting this back to draft until i grok this better.

@bennypowers
bennypowers marked this pull request as draft May 29, 2025 16:00
@bennypowers
bennypowers marked this pull request as ready for review June 1, 2025 08:52
@bennypowers

Copy link
Copy Markdown
Author

Ok having played around with this, it was pebcak. I believe this code does what it says it does, I was just not properly managing the treesitter c object lifetimes

Fix tests to use the correct method names (AllMatches/AllCaptures
instead of IterMatches/IterCaptures) per Go iter naming conventions.
Add tests for early break, empty results, and multiple patterns.

Assisted-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@bennypowers
bennypowers force-pushed the feat/querycursor-iterators branch from e16aa6d to 305e1df Compare March 28, 2026 20:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Consider custom iterator for captures

2 participants