6 — Navigating & refactoring
As soon as a stylesheet passes a few hundred lines and spreads across several xsl:include /
xsl:import modules, the question is no longer "what does this template do?" but:
- where is it declared?
- who calls it?
- what breaks if I rename it?
This chapter covers the five tools that answer: go to definition, find references, rename, search and replace across the whole workspace, and read the module graph.
The first three work only on .xsl / .xslt tabs: they understand the XSLT vocabulary, they
do not look for text.
6.1 Go to definition
Place the cursor on a symbol and press F12. Or, without touching the keyboard: Ctrl + click straight on the symbol. The editor context menu offers the same thing, under Go to definition.
The declaring file opens and the exact name is selected.
Four families of symbols are recognised:
| Symbol | Cursor example |
|---|---|
| Named template | <xsl:call-template name="format-price"> |
| Function | my:format($price) |
| Variable / parameter | $price, $currency |
| Mode | mode="summary" |
Three behaviours worth knowing:
- navigation crosses the
xsl:include/xsl:importclosure, both ways: a template called from module A and declared in module B is reached; - scope is respected: on a
$pricelocal to a template, F12 leads to the local declaration, not to a global variable of the same name; - it works on what you see, unsaved content included: a template added three seconds ago is already navigable.
If the cursor is on no symbol — a comment, free text — the gesture is inert: nothing opens, no error appears.
When several declarations are candidates
If the symbol may refer to several declarations, the application does not choose for you: the References tab opens with the header format-price — 2 candidate declaration(s) and one Declaration at line N row per candidate. Click the one that interests you.
matchtemplates are deliberately not covered. The template applied to a node is decided at run time, according to pattern, mode and priority: no static analysis can honestly answer. It is the debugger that gives the answer, by stopping in the template actually chosen.
6.2 Finding every reference
Shift+F12 on a symbol — or Find references in the context menu — fills the References tab of the bottom panel, which comes to the front.
The header announces the count: format-price — 2 reference(s). Below, the occurrences are grouped by file, each with its line number and an excerpt.
A single click on an occurrence opens the file and selects the name — no need to double-click.
The gesture works as well from the declaration as from any of its callers: the result is the same.
Two particular cases:
- no use → No references for “…”. — a named template never called, for example;
- an occurrence of the same name belonging to another module graph is flagged Outside include/import closure. It is shown, but it does not designate the same symbol.
Before any use, the panel shows No references to display.
6.3 Renaming a symbol
Renaming a template by hand means hunting its calls one by one and missing one. F2 — or Rename symbol in the context menu — does it across all the modules concerned.
The Rename "format-price" dialogue opens.
The dialogue
| Element | Role |
|---|---|
| New name: | the input field, validated as you type |
| 2 occurrence(s) in 2 file(s) | the exact extent of the change |
| Preview | the tree of occurrences, by file — line 8 · declaration, line 30 |
| Rename | applies; disabled while the name typed is invalid |
A rejected name blocks the button and says why: Invalid name (NCName expected, no ":"), Reserved name not allowed (#all, #default), or The new name is identical to the old one.
Warnings, these non-blocking, appear where relevant:
- ⚠ "format-money" already exists in the closure (possible conflict) — yours to judge;
- ⚠ main.xsl has unsaved changes (edited in memory — save after the rename);
- ⚠ Outside the closure — not renamed (N) — a group at the end of the preview, sub-grouped by file, which names one by one the same-named occurrences of another module graph. They are shown to you precisely because they will never be touched.
What gets renamed
The declaration and all its references, throughout the xsl:include / xsl:import closure —
named templates, functions, variables and parameters (scope respected), modes.
Renaming an xsl:param also updates the xsl:with-param of the callers: no silent breakage at
the next run.
What happens on confirmation
Files open in a tab are modified in the editor: the tab becomes modified "•", and a single Ctrl+Z undoes the whole rename in that tab — after which the tab is clean again.
Closed files are rewritten directly on disk.
The console reports both:
Renamed "format-price" → "format-money": 2 occurrence(s), 2 file(s) (1 on disk)
The rename is all-or-nothing: if a file has changed between the opening of the dialogue and the confirmation, nothing is written and the console shows File is being modified — please retry. You will never get a half-applied rename.
Careful with undo. Ctrl+Z only undoes open tabs. Closed files rewritten on disk are not restored. On a wide rename, open the files concerned first — the preview names them for you — or work under version control.
On a parameter, put yourself on a reference (
$pricein the body of the template) rather than on its declaration: F2 is inert there.
6.4 Searching the whole workspace
Ctrl+Shift+F brings the Search tab to the front and places the cursor in the Search in files… field. Type, confirm with Enter.
The results arrive grouped by file, with the count in plain words: 17 result(s) in 5 file(s).
Three toggles refine the search; changing one of them re-runs it immediately:
| Toggle | Effect |
|---|---|
| Match case | Book no longer finds book |
| Whole word | book no longer finds bookstore |
| Regular expression | the input becomes a regex — id="\d" |
A single click on a match opens the file and selects the text found.
Possible answers from the panel:
- No results;
- Expression error: … — a malformed regex, an unclosed bracket;
- Type a term and press Enter — before any search.
Two important points of behaviour:
- the search covers the same files as the explorer — neither your images nor your hidden folders;
- it applies to the current content, not to the disk: the buffers of open tabs prevail. An unsaved change is therefore found, and an occurrence deleted in memory is no longer listed.
6.5 Replacing in files
Replacement unfolds from the same panel.
- Click the chevron ▸ to the left of the search field: the Replace with… row appears.
- Type the replacement text. The preview updates in the results: the old text struck through in red, the new one in green. No file has been touched yet.
- Click Replace All — the button is active only if there are results.
- Confirm: Replace 3 occurrence(s) in 2 file(s)? If unsaved tabs are concerned, the dialogue lists them under Unsaved tabs will be modified:.
The summary goes to the console, and the results are recomputed:
Replaced: 3 occurrence(s) in 2 file(s) (1 on disk)
Replacement by regular expression
With Regular expression ticked, the replacement text accepts captured groups: searching
(\d+)-(\d+) and replacing with $2/$1 swaps the two numbers.
A reference to a group that does not exist is refused outright: Invalid replacement expression, and no file is modified. Like the rename, replacement is all-or-nothing.
Where replacement applies
Exactly like the rename: buffer for open tabs — a Ctrl+Z undoes the whole replacement in that tab —, disk for closed files, not undoable.
A replacement that is too wide is refused rather than truncated: Too many occurrences to replace (cap reached). Refine the search and start again.
6.6 Seeing the graph of includes and imports
Which modules does this stylesheet really pull in? And if I change this one, what breaks?
Right-click in the explorer on an .xsl, an .xslt or an .xsd →
Hierarchy/dependencies. The Hierarchy tab of the bottom panel opens.
Two directions, two buttons:
| Button | Question asked | Header |
|---|---|---|
| Hierarchy | what this file includes, cascading | a.xsl — 3 direct include(s) |
| Dependencies | who includes this file | base.xsl — 2 direct dependent(s) |
A Refresh button recomputes the tree.
Each row carries an include or import badge, the name of the file and the line number
of the directive. Double-click: the file carrying the directive opens at the line of that
directive — not the target file. That is what you need in order to fix a path.
Three flags:
(not found)followed by the raw path — the target does not exist. The double-click is still useful: it takes you to the faulty directive;(cycle)— the branch loops back onto a file already traversed; it is marked and not expanded;- an
xs:importwith noschemaLocationis labelled by its namespace.
The view covers XSL ↔ XSL and XSD ↔ XSD.
6.7 The stylesheet outline
To move inside a file rather than between files, the right-hand panel shows the outline of the
active stylesheet — match templates, named templates, functions, global variables/params, keys,
modules — and double-clicking selects the name.
It is described in the chapter The interface §1.5. What matters here: it follows your typing, with no saving.
6.8 Limits worth knowing
- Symbol navigation only concerns
.xsl/.xslttabs. On an.xmlor an.xsd, F12, Shift+F12 and F2 have no effect. matchtemplates are excluded from it (§6.1): resolving them is the debugger's business.- The rename never leaves the
xsl:include/xsl:importclosure. Same-named symbols in other modules are listed for you, but never modified. - Rename and replace are only undoable in open tabs. Closed files are rewritten on disk with no application-level undo.
- The search ignores files larger than 2 MB and those not readable as UTF-8. Beyond 5,000 results, the display is truncated and says so — limit reached.
- The hierarchy does not cross types: an XSL graph and an XSD graph stay separate.
What next
- Analysing — profiler, template coverage, back-mapping.
- Validating & comparing — batch validation, structural comparison, XSpec tests.
- Reference — every shortcut, button, menu and gesture, in tables.
- Editing — completion, formatting, validation as you type.