Token-aware search panel for PHP codebases. Searches inside chosen token
types only (strings, variables, funcs, consts, comments, numbers, inline
html, others), so uid in a string won't drown in $uid variables -
something plain-text search can't do. Live search, native-search-style UI,
results grouped by file with click-to-jump.
Features
- Search restricted to selected php token types; every type button shows a live match count (post-filter) whether selected or not.
- Match case / whole word / regex flags, native-style.
- Find-similar mode (
≈on the input): the input becomes a php snippet, matched as a token sequence - whitespace and comments ignored, variables may be renamed (consistently:$x=$xfinds$a=$a, never$a=$b). - Include / exclude file globs (
legacy.php,*.bak.php→**/legacy.php,**/*.bak.php). - Exclude filters: rows that disqualify hits by their surrounding line, each with its own match-case / whole-word / regex flags.
- Unsaved editor buffers are searched as typed, not stale disk content.
- Live search with 250ms debounce; results grouped by file, collapsible, token-true syntax-tinted previews, click or Enter to jump.
- Clicked hits get a dim
·mark (per search word) and become the arrow-nav position, so you can walk results sequentially across jumps;⟳re-runs and clears the marks. - Multi-root workspaces: results sectioned per root, collapsible; the status line shows searched-file counts per root.
- Hit cap (
ptsearch.maxHits) keeps huge searches from stalling the UI; the status line says when results were cut. - Panel state (word, flags, globs, filters, token toggles) survives window reload.
Usage
- Open: magnifier icon in the activity bar, command
PHP Token Search: open, orCtrl+Alt+F(Cmd+Alt+Fmac) to search the current selection / word under cursor. - Type to search;
···opens include/exclude globs and exclude filters (it lights up whenever filters are active but collapsed). - Token type buttons choose where matches may live. funcs = name followed
by
((calls + definitions;new Foo(counts), consts = bare names (class names included), others = everything unclassified (keywords, operators, tags, casts).
Find similar (≈)
The ≈ toggle on the search input flips it into find-similar mode: the
input is then a php snippet, matched as a token sequence. Formatting
and comments are invisible, non-variable tokens must match exactly,
variables match by consistent renaming (bijective: $x=$x finds $a=$a,
never $a=$b). Each hit is reported at the first token of the matched
sequence.
Wildcards (phpgrep-style):
| pattern | matches |
|---|---|
$x |
any variable, consistent: $x=$x finds $a=$a, never $a=$b |
$_ |
any single value token (name, var, number, string - never operators/keywords) |
${"var"} |
any variable |
${"int"} |
integer literal (incl. hex/bin/octal) |
${"float"} |
float literal |
${"num"} |
any number literal |
${"str"} |
string literal |
${"const"} |
bare name (class names included) |
${"func"} |
name followed by ( |
${"x:var"} |
named + typed: consistent across slots, unifies with plain $x |
Non-wildcard names and keywords compare case-insensitively (php
semantics); variables, strings and numbers compare exactly. Examples:
$_ == null (non-strict null compares), foo($_, ${"int"}),
stripos(${"str"}, $_) (misplaced args), setcookie(${"x:var"}, $x).
In this mode the Aa/ab/.* flags and the token type buttons gray
out (they're word-search concepts and don't apply), and a caption under
the input previews the exact searched sequence - plain = literal,
dotted-underline = consistent variable, dashed-underline = typed/anonymous
wildcard. The preview comes from the engine itself, so it always shows
what actually ran. Toggle ≈ off to return to word search.
Exclude filters
Each row disqualifies hits by the line they sit on (same line only):
- regex mode (
.*on, the default): the pattern runs on the hit's line; a hit lying fully inside any match span is excluded. Example://.*drops hits inside trailing comments. - literal mode (
.*off): paste a snippet containing the search word (e.g._GET('uid')when searchinguid); hits whose line aligns with the snippet around them are excluded. Aa= match case,ab= whole word - per row.
Keyboard & mouse shortcuts
| shortcut | action |
|---|---|
Ctrl+Alt+F / Cmd+Alt+F |
search selection (or word under cursor); a multi-token selection opens in find-similar mode, a single token auto-selects its token type |
Enter |
force search now (skips debounce, works in all inputs) |
↓ / ↑ |
move selection through results (works from the input) |
Enter on a row |
jump to the hit |
Tab |
walk result rows |
Ctrl+click token (Cmd mac) |
solo: select only that token type |
| click file header | collapse/expand that file's group |
| click root header | collapse/expand that root's section |
⊟ / ⊞ |
collapse/expand all groups |
⟳ |
re-run the search and clear visited marks |
API for other extensions
Anything that can run vscode commands (extensions, keybindings, tasks) can open the panel pre-filled and running:
vscode.commands.executeCommand('ptsearch.search',{
word:'uid', // the search word/pattern
types:'strings,comments', // token type labels, comma separated
flags:'ci,ww', // any of: re (regex), ci (ignore case), ww (whole word)
inc:'src/**', // files to include glob
exc:'legacy.php', // files to exclude glob
excl:[{p:'//.*',re:1,cs:1,ww:0}], // exclude filter rows
sim:"in_array($x,$arr,true)", // find-similar snippet; non-empty = runs instead of word search
});
All args optional - omitted ones keep the panel's current state.
ptsearch.searchSelection (the Ctrl+Alt+F command) grabs the active
editor's selection or the word under the cursor and calls the above.
Dependencies
- PHP CLI on the machine - vanilla php, any stock 8.x (minimum 7.2).
No composer, no pecl extensions, no php.ini requirements. If php isn't
found, the panel shows setup instructions with one-click access to the
ptsearch.phpsetting. - VS Code ≥ 1.75. No npm dependencies.
Settings
| setting | default | meaning |
|---|---|---|
ptsearch.php |
php |
php binary path |
ptsearch.exclude |
**/{node_modules,vendor}/** |
glob always excluded |
ptsearch.maxHits |
5000 |
stop after this many hits, skip the rest |
ptsearch.memory |
256M |
php daemon memory limit (shorthand: 256M, 1G); cache evicts to stay under it |
ptsearch.debug |
false |
per-search timing lines in Output → ptsearch |