Limitations

July 24, 2026 · View on GitHub

Raven is under active development. The gaps below reflect features that exist in comparable tools but aren't yet in Raven, or where Raven's implementation differs meaningfully from the comparable tool's. Each entry links to the doc where it's discussed in context.

Language server

  • Stan analysis is conservative name resolution, not compilation — Complete .stan programs get native syntax and undeclared-variable diagnostics, but Raven does not type-check expressions, validate shapes or overloads, diagnose whether a called function or sampling distribution exists, preprocess #include, or assemble project-specific source fragments. A file with no real top-level Stan block is treated as a fragment and receives no undeclared-variable findings; any include suppresses that semantic pass for the whole file because it may supply declarations. See Diagnostics — Stan Undeclared Variables.

  • Full lintr coverage — Raven ships a built-in, opt-in style linter that re-implements 18 of lintr's rules natively — most of its default set (see Linting). REditorSupport/languageserver runs the full lintr package, including rules Raven doesn't replicate (object_usage_linter, the full set of style checks, etc.). You can run both language servers at once; see Coexistence: Language servers.

  • Session-aware completions — Raven's completions are purely static. REditorSupport can complete symbols from the live R session's globalenv(), including column names from data frames that only exist at runtime. See Comparison: Language intelligence.

  • useDynLib native routine symbols — When a package registers native routines via useDynLib(pkg, .registration = TRUE), R creates R-level bindings (e.g. rlang's ffi_enquo, ffi_quos_interp) in the package namespace at load time. These names live in C source (src/init.c) and are not statically derivable from R or NAMESPACE files alone, so Raven flags them as undefined. This affects packages that call their own registered routines directly (most notably rlang). Suppress with # raven: ignore-next or a directive.

  • data() alias expansion not inherited through backward dependencies — When a parent file calls data(api, package = "survey"), the individual object names it binds (apiclus1, apistrat, …) are not propagated to child files that inherit the parent's scope via a backward dependency (# raven: sourced-by or auto-inferred). The literal stem (api) does flow. Forward source() children receive full expansion. See Cross-File & Package Awareness — data() calls for the workarounds.

  • Raw path identity for closed symlink spellings — Raven's dependency graph, file caches, workspace indexes, and diagnostic publication keep raw URI spellings rather than globally canonicalizing paths, so closed files reached through different symlink spellings can remain distinct identities. Open buffers are bridged: a case or symlink alias of an on-disk file is authoritative for the corresponding graph URI while it is open, including package-internal scope and workspace .Rprofile prelude ownership; diagnostics still publish to the URI spelling the editor opened. Raven still avoids full filesystem canonicalization because it follows symlinks and can diverge from the uncanonicalized paths used by the workspace index. The source-path resolver may correct case-only mismatches so graph edges match the on-disk workspace-index spelling. See Cross-File & Package Awareness — Open buffers, disk state, and closing files.

  • Member navigation only for static $/@/literal-[[ accessors — go-to-definition, hover, and find-references treat a member access as navigable only when it is statically a name: an identifier RHS of $/@ (foo$bar), or a single, positional, literal string subscript of [[ (foo[["bar"]], the $-equivalent extractor). A subscript that R only resolves at runtime is intentionally not unified: computed/dynamic indices (x[[i]], x[[paste0("a", "b")]]), numeric indices (x[[1]]), named or multi-argument subscripts (x[[name = "a"]], x[["a", exact = FALSE]]), strings with escapes, and the single-bracket form x["bar"] (which returns a sub-container, not the element). See Go-to-Definition and Find References.

box module system (box::use)

Raven models the statically analyzable subset of the box module system across diagnostics, completion, hover, go-to-definition, find-references, dependency revalidation, the language server, and raven check. See Module & import systems — box modules.

Only static box::use() is recognised. The call must be a literal box::use(...) / box:::use(...). Programmatic invocation — do.call(box::use, ...), aliasing box::use to another name, or building the argument list at runtime — is not recognised.

Local modules must be explicit relative paths. A bare name is always treated as an installed package; a local module must begin with ./ or ../. The following non-local module lookups are not supported and fail conservatively (they neither bind names nor emit misleading diagnostics):

  • Non-local search-path specs such as foo/bar (a module found via a search path rather than relative to the importing file).
  • options(box.path = ...) and the R_BOX_PATH environment variable.
  • Remote modules and box's global-module directory.

Local resolution differs from source(). box paths resolve relative to the importing file's own directory and intentionally ignore # raven: cd, the implicit testthat/testit working directory, and the workspace-root fallback. Resolution is case-sensitive: a path that exists only under a different case is reported as a mismatch, not silently corrected. Ambiguous case-insensitive collisions (only possible on a case-sensitive filesystem) fail closed.

import package

Raven models the static first phase of import::from(), import::here(), and import::into(): literal package or .R/.r script sources, literal .directory and named destinations, explicit/renamed selections, .all, and static .except. It does not execute R, model detach/S3 side effects, follow URL or pins modules, or evaluate dynamic .character_only, .library, .directory, .into, source, or member expressions. Environment-valued destinations and import::: internal imports are not modeled. Unsupported calls are inert rather than partially guessed.

No runtime module execution. Raven does not execute module code, evaluate load/unload hooks or other side effects, or inspect dynamically-created exports. Marker-less legacy export sets are therefore treated as incomplete: known members are available, but absence is not diagnosed unless the module has an authoritative explicit export interface. Installed-package imports use Raven's installed, frozen, or downloaded package export metadata under the same completeness rule.

Static member access only. Namespace-member completion, hover, navigation, and identity-aware references cover $, @, and a single positional literal-string [[...]] subscript. Computed subscripts and nested runtime values are not evaluated. Installed-package members are available for completion and diagnostics but do not navigate to package source files.

targets and tarchetypes

Raven models target declarations and report relationships only when their source spelling is statically trustworthy. Direct namespace-qualified calls are recognized; bare calls require a top-level package attachment and no local shadow. Aliases, do.call(), partial argument names, malformed calls, calls inside functions/quoted code, and arbitrary metaprogramming are inert.

The supported tar_map() subset requires a literal list() / data.frame() / tibble() table with named scalar or literal-vector columns, target-definition objects statically bound to ..., a static unshadowed column-name selection, compatible lengths, no target-name/value-column collision, and a literal delimiter. Expansion is all-or-nothing: Raven does not retain partial targets or report links when one generated name is unsupported. Raven does not predict the runtime hash fallback, non-ASCII or locale-sensitive make.names() results, dynamic values/selections/delimiters, replication factories, or other dynamic branching. Raw/string-expression variants, tar_eval(), tar_sub(), AST walkers, and internal _run helpers are not modeled.

Report identity requires a static target name and a literal supported document path: .Rmd / .Rmarkdown for tar_render() and tar_knit(), or a single .qmd / .Rmd / .Rmarkdown file for tar_quarto(). Computed paths, Quarto project directories, and rendering are outside the analysis. Helpers sourced only by the report do not lend target declarations back into the pipeline. tar_load() references are enumerated only from a direct name or literal unshadowed c(name, ...); dynamic tidyselect expressions are not expanded. See Cross-file awareness — tarchetypes target factories and report documents.

R Markdown / Quarto

R chunk bodies in .Rmd / .Rmarkdown / .qmd documents are fully analyzed as first-class R code. The following gaps are accepted limitations of the current implementation:

  • Inline R expressions (\r expr`` in prose) are not analyzed. Only fenced chunk bodies (```{r} ... ``` ) are treated as R.
  • Cross-chunk delimiter leak — chunk bodies are analyzed as a single concatenated R program. An unclosed delimiter (", (, {) in one chunk body can swallow the opening of the next chunk, causing the next chunk's parse to fail. The unclosed delimiter in the offending chunk is itself flagged as a parse error. This is a consequence of Raven's single-parse analysis model (knitr itself evaluates chunks one at a time and would stop at the offending chunk).
  • Non-R chunks not analyzed{python}, {bash}, {julia}, and other non-R fenced blocks are never analyzed or linted.
  • knitr chunk-reuse lines (<<label>>) are blanked (treated as empty lines) and not resolved.
  • Quarto preview scope — Raven provides CLI-backed Raven: Quarto Preview, Raven: Quarto Render, and Raven: Stop Quarto Preview for .qmd files. Preview delegates refresh-on-save to Quarto's watcher, but it is not a Shiny lifecycle: Raven rejects document-level server: shiny best-effort and does not detect project-level Shiny configuration before launch. Non-browser-previewable formats such as DOCX and PPTX fail Preview with a 404 message and must use Render. Preview requires a trusted workspace, is owned by the current VS Code window, and is not guaranteed in Codespaces. See Quarto preview and render — Limitations.

R-session features

  • Workspace viewer — REditorSupport has a sidebar panel that introspects the live R session, showing objects in globalenv() with their types and dimensions, plus attached and loaded namespaces; objects can be viewed or removed from the panel. Raven has no equivalent. See Comparison: What REditorSupport's VS Code extension offers that Raven doesn't.
  • htmlwidget / Shiny viewer — Interactive HTML output (plotly, DT, profvis, etc.) and Shiny apps render in REditorSupport's webview panels. Raven has no equivalent.
  • Auto-refresh R Markdown knit preview — Raven's Raven: Knit Preview for .Rmd / .Rmarkdown files is a static HTML viewer with a manual Knit again button (Shift+Cmd+Enter / Shift+Ctrl+Enter saves and re-knits in one keystroke). REditorSupport's .Rmd preview adds an opt-in auto-refresh mode. Raven's separate Quarto Preview does refresh .qmd output on save through Quarto's built-in watcher; it does not change the deliberately manual Knit Preview pipeline.
  • List / environment viewer — REditorSupport's View() on lists and environments opens a collapsible tree view. Raven's View() only handles data frames and matrices. See Data Viewer.

If you rely on any of the fully-absent features above (workspace viewer, htmlwidget/Shiny viewer, list/environment viewer) and have REditorSupport installed, see Coexistence for how to run both extensions together.