# File References

A file reference is text that points to a file. It may also point to a location inside that file, or a file inside that file (virtual path).

```text
source.cpp
source.cpp:40
source.cpp:40:8
source.cpp:40-47,100-110
```

The first example names only a file. The other examples also carry one or more locations.

*Lx* uses the same form in several places:

- Command-line file names can open at specific lines, ranges, or offsets
- Local links in a Markdown preview can open a file at their locations
- File-reference commands can select references found in source text
- Some viewers use virtual paths for items stored inside another file

## File paths

A reference may use a relative or absolute path:

```text
example.md
docs/example.md
C:\Projects\Lx\example.md
/home/user/project/example.md
```

A relative command-line path starts from the command line's current folder. A relative Markdown link starts beside the Markdown file.

Selecting a reference does not check whether the file exists. It only selects text which the current file format describes as a reference.

## File locations

A location is the part after a file path. It tells *Lx* where to place the cursor or what text to select after opening the file.

The colon before the first location separates it from the path:

```text
source.cpp:40
```

This means line 40 in `source.cpp`.

### Lines and columns

Use another colon to add a column:

| Reference | Result |
| --- | --- |
| `source.cpp:40` | Cursor at line 40 |
| `source.cpp:40:8` | Cursor at line 40, column 8 |
| `source.cpp:40-47` | Lines 40 through 47 selected |
| `source.cpp:40:8-47` | From line 40, column 8 through line 47 |
| `source.cpp:40-47:12` | From the start of line 40 through line 47, column 12 |
| `source.cpp:40:8-47:12` | From line 40, column 8 through line 47, column 12 |

Lines and columns normally start at 1. A range includes its last line or character.

### Several locations

Separate locations with commas:

```text
source.cpp:40,80,120
source.cpp:40-47,100-110,200
source.cpp:10:5-20:8,50:2
```

*Lx* creates one cursor or selection for each location. It also adds a session bookmark at each starting line. Use *F2* and *Shift+F2* to move through those bookmarks.

### File offsets

An offset counts from the start of the file instead of using a line and column. Start it with `@`:

| Reference | Result |
| --- | --- |
| `data.bin:@100` | Position at offset 100 |
| `data.bin:@100-200` | Offsets 100 through 200 selected |
| `source.cpp:40-47,@500-700` | One line range and one offset range |

Offsets normally start at 0 and count bytes. Some features can count text characters instead. Binary files require byte offsets.

### Complete location forms

These are all supported forms after the separating colon:

```text
line
line:column
line-line
line:column-line
line-line:column
line:column-line:column
@offset
@offset-offset
```

Any of these forms may be joined with commas.

### Counting positions

Lines and columns normally start at 1. Offsets normally start at 0. A feature may offer another starting number or another way to count text characters. These choices change how the numbers are read, not how a reference is written.

See the guide for the feature you are using when its counting can be changed. [Command Line](cli.md) keeps all command-line choices together.

### Positioning errors

Malformed location syntax is always an error. When the syntax is valid but a line or column cannot be resolved, `config.file_locations.position_mode` controls what happens:

1. `"quiet"` — recover silently
2. `"warn"` — recover and write one cumulative F12 log entry per file
3. `"strict"` — reject all locations for that file if any position cannot be resolved

The default is `"warn"`:

```lua
local config = require("core.config")
config.file_locations.position_mode = "warn"
```

Recovery keeps every usable part of a location. An oversized starting column moves to the end of its valid line. Other invalid starting columns use column 1. An invalid ending column ends the range at the end of its valid line, while an invalid ending line keeps only the range start. An invalid starting line skips that location. If every location is skipped, the file still opens without changing its selection.

For inclusive ranges, the exact column immediately after the final character is accepted without a warning. This allows tools which report an end-of-line caret instead of the final character column.

### File names which look like locations

When locations are enabled, a final part such as `:10` is read as a location. A feature may provide a way to treat the complete text as a literal file name instead. [Command Line](cli.md) explains its literal file option.

An invalid location-looking ending is rejected instead of being treated as part of the file name. This prevents a mistyped range from silently pointing somewhere else.

## Virtual paths

A virtual path points to an item stored inside another file. The exact separator is `:/`:

```text
report.odt:/Pictures/image.png
icons.ico:/2
```

The part on the left is the physical file on disk. The part on the right identifies something inside it.

In these examples:

- `report.odt` is the physical document and `Pictures/image.png` is an image stored inside it
- `icons.ico` is the physical icon file and `2` identifies one image in it

Use forward slashes inside the virtual part. The physical path may still use the normal separators for your system:

```text
C:\Documents\report.odt:/Pictures/image.png
```

A location comes after the complete virtual path:

```text
archive.zip:/src/source.cpp:40-47
```

This keeps three separate pieces: the physical file, the path inside it, and the location inside that item.

A virtual path does not extract a file by itself. The viewer or plugin handling the physical file must understand the item on the right. *Lx* currently uses virtual paths for embedded document images and individual images inside multi-image icon files. Other file types may not support opening their stored items yet.

## Selecting references in text

Each text format decides what clearly marks a file reference. For example:

- C and C++ recognize paths in `#include` lines and source paths carrying locations
- C# recognizes local files in `#load`, `#r`, `#line`, and checksum directives
- CMake recognizes direct `include`, `add_subdirectory`, and `configure_file` inputs
- CSS recognizes local files in `url(...)` and quoted `@import` targets
- HTML recognizes local files in common quoted link, media, and form attributes
- `.htaccess` recognizes literal local files in direct file-taking directives, including `HeaderName` and `ReadmeName`
- Java recognizes direct type imports and the declaring types behind static imports
- JavaScript recognizes relative static, dynamic, exported, and CommonJS module targets
- Lua recognizes literal modules passed to `require` and literal paths passed to `dofile` or `loadfile`
- Markdown recognizes inline link targets and paths inside backticks or quotes
- Pascal recognizes units in `uses`, explicit unit files, and compiler include files
- Perl recognizes literal quoted files passed to standalone `require` and `do`
- GNU Make recognizes plain files in `include`, `-include`, and `sinclude` directives
- Go recognizes literal `//go:embed` files and cgo include targets
- PHP recognizes quoted path pieces following `include`, `include_once`, `require`, and `require_once`, including paths inside concatenated expressions
- Python recognizes dotted modules in direct `import` and `from` statements
- Rust recognizes external `mod name;` declarations, literal include macros, and explicit `path` attributes
- Sass recognizes quoted `@use`, `@forward`, and `@import` targets
- Shell scripts recognize literal files passed to `source` or the `.` command
- Visual Studio solutions recognize project files and simple solution items
- Visual Studio project files recognize direct local file attributes
- TypeScript recognizes relative module targets using TypeScript files before JavaScript fallbacks

This is intentionally based on visible text, not on whether a matching file exists. A Markdown word inside backticks may look like a file reference even when it is only code.

Run these actions from the Command Palette:

| Command | Selection |
| --- | --- |
| `file:select-under-cursor` | Reference under the cursor |
| `file:select-first-in-line` | First reference on the current line |
| `file:select-all-in-line` | Every reference on the current line |
| `file:select-all-visible` | Every reference which starts in the visible editor area |

A visible reference is included when its beginning is on screen, even when its end continues past the right edge.

Run the same command again to restore the earlier selection. The cursor stays where it was.

## Following references with the mouse

Hold *Ctrl* on Windows or Linux, or *Cmd* on macOS. After a short pause, confirmed file references in the visible editor area fade into view. Moving over an eligible reference shows its underline immediately with the hover color and changes the pointer to a hand. Click it to open the file. The source cursor and selections stay unchanged.

Pressing another key, such as *Ctrl+D*, cancels the reveal for that complete Ctrl or Cmd hold. Releasing the other key does not resume it. Release Ctrl or Cmd and press it again to start a new reveal.

While the key is held, left-clicks in the editor text area are reserved for file links. Clicking or double-clicking other text does not move the cursor or create a selection. Gutters and scrollbars continue to work normally.

The links fade out quickly when you release the key. Their regular and hover colors are `style.link` and `style.link_hover`. Set `config.file_reference_links = false` to turn this feature off.

Only references confirmed by the current text format become links. Ordinary path-shaped words do not. Showing the links does not check the filesystem; *Lx* searches for the file only after you click.

Lua module names are translated during that search. For example, `require("core.style")` tries `core/style.lua` and then `core/style/init.lua`. The module text in the editor is not changed.

## Opening references

Some features can open a reference and apply its locations. The command line supports this; [Command Line](cli.md) keeps its complete commands and options in one place.

In an editor, run `file:open-under-cursor` to open the reference touching the cursor, or `file:open-first-in-line` to open the first clear reference on the current line. The source cursor and selections stay unchanged.

For a relative path, *Lx* checks these places in order:

1. Beside the current document
2. Each parent folder, nearest first
3. Folders listed in `config.file_reference_search_paths`
4. Files already present in the project index

When a path beginning with `/` does not exist as written, *Lx* also removes the leading slash and tries the same relative search. This handles quoted path pieces such as `/php/Bootstrap.php` when they appear inside a larger source expression.

Search paths may be absolute or relative to the project folder:

```lua
config.file_reference_search_paths = {
	"include",
	"../shared",
}
```

The project fallback compares complete path endings. A reference to `parser/file.cpp` can match `src/parser/file.cpp`, while `file.cpp` can match that file by name. *Lx* opens an indexed match only when exactly one existing file matches. It does not guess when the name is ambiguous.

The project fallback uses the existing index instead of scanning the disk again. Set `config.project_scan_enabled = true` when you want that index built and kept current from startup. Other project features may also fill it while they are active.

When no matching file is found, the source line briefly flashes red.

Use `navigate:back` to return to the earlier document position. Use `navigate:forward` to revisit the opened reference.

When developer details are on, the Log View shows each folder checked, the project-index result, any ambiguity, and the final result. See [Settings](settings.md#developer-details) to turn these reports on.

When the format confirms no reference there, this one command also tries the path-shaped text under the cursor. It opens only when that path resolves to an existing file. Line and visible bulk selections remain strict and never use this fallback.

In a Markdown preview, a local link can carry the same location text:

```markdown
[Open the parser](src/parser.cpp:40-47)
```

Clicking the link opens the file, applies its cursors or selections, and creates session bookmarks for their starting lines.

## Strong Lx references

The special `lx:` prefix marks a strong reference created by *Lx* itself:

```text
lx:report.odt:/Pictures/image.png
```

`lx:` is not part of the file name. *Lx* removes the prefix, then reads the remaining physical path and virtual path normally.

A strong reference tells *Lx* that generated content intentionally points to an internal resource. This allows an embedded item, such as an image inside an Office document, in places where an ordinary Markdown image target would reject a virtual path.

Generated Markdown usually wraps the reference in angle brackets:

```markdown
![Embedded image](<lx:report.odt:/Pictures/image.png>)
```

Generated image references may also carry their intended display size:

```text
lx:report.docx:/word/media/image1.png?width=96&height=48
```

The width and height are display hints. They are not part of the file path.

You normally do not need to write `lx:` references yourself. Office and OpenDocument extraction creates them so previews can show images which remain inside the source document. The prefix does not turn a remote address into a local file or bypass normal safety checks.

## Related guides

- [Command Line](cli.md) explains how file references fit among other command-line options
- [Markdown Preview](markdown_preview.md) explains local links and rendered pages
- [Format Modules](formats.md) explains how a format describes the references it recognizes
