MCPcopy Create free account
hub / github.com/sourcebot-dev/sourcebot / hasUnmatchedOpenParen

Function hasUnmatchedOpenParen

packages/queryLanguage/src/tokens.ts:345–419  ·  view source on GitHub ↗

* Checks if we're currently inside a ParenExpr by looking backwards in the input * to count unmatched opening parens that likely started a ParenExpr. * * We only consider a '(' as a ParenExpr start if it's preceded by whitespace or * start-of-input, since "test()" has a '(' that's part of a word

(input: InputStream)

Source from the content-addressed store, hash-verified

343 * Handles escaped characters (backslash followed by any character).
344 */
345function hasUnmatchedOpenParen(input: InputStream): boolean {
346 // Count parens backwards from current position
347 let depth = 0;
348 let offset = -1;
349
350 // Look backwards up to 1000 characters (reasonable limit)
351 while (offset >= -1000) {
352 const ch = input.peek(offset);
353 if (ch === EOF) {
354 // Reached start of input - if we have negative depth, there's an unmatched '('
355 return depth < 0;
356 }
357
358 // Check if this character is escaped (preceded by backslash)
359 // Note: we need to be careful about escaped backslashes (\\)
360 // For simplicity, if we see a backslash immediately before, skip this char
361 const prevCh = input.peek(offset - 1);
362 if (prevCh === 92 /* backslash */) {
363 // Check if the backslash itself is escaped
364 const prevPrevCh = input.peek(offset - 2);
365 if (prevPrevCh !== 92) {
366 // Single backslash - this char is escaped, skip it
367 offset--;
368 continue;
369 }
370 // Double backslash - the backslash is escaped, so current char is not
371 }
372
373 if (ch === CLOSE_PAREN) {
374 depth++;
375 } else if (ch === OPEN_PAREN) {
376 // Check what's before this '('
377 const beforeParen = input.peek(offset - 1);
378
379 // A '(' starts a ParenExpr if it's preceded by:
380 // - EOF or whitespace (e.g., "(hello)" or "test (hello)")
381 // - '-' for negation (e.g., "-(hello)")
382 // - ':' for prefix values (e.g., "repo:(foo or bar)")
383 const isDefinitelyParenExprStart =
384 beforeParen === EOF ||
385 isWhitespace(beforeParen) ||
386 beforeParen === DASH ||
387 beforeParen === COLON;
388
389 // Special case: '(' preceded by '(' could be nested ParenExprs like "((hello))"
390 // BUT it could also be part of a word like "test((nested))"
391 // To distinguish: if prev is '(', check what's before THAT '('
392 let isParenExprStart = isDefinitelyParenExprStart;
393 if (!isParenExprStart && beforeParen === OPEN_PAREN) {
394 // Check what's before the previous '('
395 const prevPrevCh = input.peek(offset - 2);
396 // Only count as ParenExpr if the preceding '(' is also at a token boundary
397 isParenExprStart =
398 prevPrevCh === EOF ||
399 isWhitespace(prevPrevCh) ||
400 prevPrevCh === DASH ||
401 prevPrevCh === COLON;
402 }

Callers 1

isInsideParenExprFunction · 0.85

Calls 1

isWhitespaceFunction · 0.85

Tested by

no test coverage detected