Functions

The exported functions form a command/query split over a JuliaWorkspace: mutation functions change the workspace inputs, while query functions read derived results.

Constructing a workspace from disc

JuliaWorkspaces.workspace_from_folders — Function
workspace_from_folders(workspace_folders::Vector{String}; dynamic=DynamicOff, symbolcache_download=false, symbolcache_upstream=DEFAULT_SYMBOLCACHE_UPSTREAM, store_path=nothing, max_concurrent_djps=4, max_failure_attempts=DEFAULT_MAX_FAILURE_ATTEMPTS, djp_request_timeout_seconds=DEFAULT_DJP_REQUEST_TIMEOUT_SECONDS, scope=nothing)

Create a new JuliaWorkspace and populate it by recursively reading every folder in workspace_folders from disc. This is the most convenient entry point for analysing a project that lives on the local file system.

Keyword arguments

  • dynamic::DynamicMode: Whether and how to run the out-of-process dynamic feature. See DynamicMode. Defaults to DynamicOff.
  • symbolcache_download::Bool: If true, allow downloading precomputed package symbol caches from symbolcache_upstream instead of indexing locally.
  • symbolcache_upstream::String: Upstream URL for symbol-cache downloads. Defaults to DEFAULT_SYMBOLCACHE_UPSTREAM.
  • scope: Restricts the walk to what one or more config kinds select, so an excluded subtree is never read from disc. See collect_workspace_paths. Defaults to nothing, which reads everything.
  • store_path, max_concurrent_djps, max_failure_attempts, djp_request_timeout_seconds, progress_callback, status_callback: forwarded verbatim to JuliaWorkspace, which documents them.

Returns

source
JuliaWorkspaces.add_folder_from_disc! — Function
add_folder_from_disc!(jw::JuliaWorkspace, path; ignore_io_errors=false, scope=nothing, gitignore=GitIgnoreFilter([path]))

Recursively read all relevant files under the local folder path from disc and add them to the workspace jw. Julia sources, Project.toml/Manifest.toml, and configuration files are picked up. The whole batch is added before a single reconciliation step runs, so this is more efficient than calling add_file! per file.

If ignore_io_errors is true, files that cannot be read are skipped instead of raising an error. scope restricts the walk to what one or more config kinds select, and folders git ignores are skipped unless gitignore=nothing; see collect_workspace_paths.

source
JuliaWorkspaces.add_file_from_disc! — Function
add_file_from_disc!(jw::JuliaWorkspace, path)

Read the file at the local path from disc and add it to the workspace jw as a new file (see add_file!). The file content is read eagerly and the file's language is inferred from its extension.

Throws if a file with the same URI is already part of the workspace.

source
JuliaWorkspaces.update_file_from_disc! — Function
update_file_from_disc!(jw::JuliaWorkspace, path)

Re-read the file at the local path from disc and update its content in the workspace jw (see update_file!). Use this to refresh a file whose on-disc content changed outside of the workspace.

Throws if no file with the corresponding URI is part of the workspace.

source
JuliaWorkspaces.collect_workspace_paths — Function
collect_workspace_paths(root; scope=nothing, file_limit=nothing, ignore_io_errors=false, gitignore=GitIgnoreFilter([root]))
    -> Union{Vector{String},Nothing}

Every workspace-relevant file under the local directory root: Julia sources, Project.toml/Manifest.toml, the three tool config files, Markdown and Julia Markdown.

scope restricts the walk to what one or more config kinds select — a Symbol or a collection of them, drawn from keys(SCOPE_CONFIG_PREDICATES) (:testitems, :lint, :format). Directories that provably cannot hold a selected file are never descended into, so an excluded subtree costs nothing at all. nothing, the default, walks everything.

Project.toml, Manifest.toml and config files are kept even when the globs do not select them, as long as their directory survives: they carry package and environment attribution, and the per-file queries downstream need the config files themselves in order to agree with this walk.

When file_limit is set and more than that many Julia files are selected, returns nothing — the tree is deemed too large to load. Callers passing a file_limit must handle that.

With ignore_io_errors, directories and entries that cannot be read or statted during the walk are skipped. Non-regular entries are always skipped, even when their names look like files this workspace would otherwise read.

Folders that git ignores are not walked (see GitIgnoreFilter), and when root itself lies in one the result is empty. The default filter treats root as the workspace folder. A host walking a subfolder of a workspace folder (one its file watcher reported as created, say) passes a filter built from its workspace folders, so the rules above that subfolder apply. gitignore=nothing walks ignored folders too.

source

Path selection

The directory walk above and the per-file config attribution both answer to these predicates on a PathFilter.

JuliaWorkspaces.path_selected — Function
path_selected(filter, relpath) -> Bool

Whether relpath (relative to the config file's directory, /-separated) is selected by filter.

source
JuliaWorkspaces.dir_selected — Function
dir_selected(filter, reldir) -> Bool

Whether the directory reldir (relative to the config file's directory, /-separated, no trailing slash, "" for the config's own directory) can still hold a file selected by filter.

This is the directory-level counterpart of path_selected, and it is deliberately conservative: false means provably nothing below reldir is selected, so a walker may skip it entirely.

source

Folders that git ignores are left out of the walk:

JuliaWorkspaces.GitIgnoreFilter — Type
GitIgnoreFilter(roots)

Decides which folders below the workspace folders roots git ignores. Used by collect_workspace_paths to prune the walk, and by hosts through is_in_ignored_folder to drop file watcher events.

The rules are those of the .gitignore files and of the repository's info/exclude; git itself is not needed. A workspace folder is never ignored because of rules above it: opening a folder that git ignores (a dotfiles repository in the home folder that ignores /*, say) must not hide all of it. Below a folder that contains a .git, that nested repository's rules apply.

The filter caches the rules it has read, so it does not notice later edits to them. Build a new one when that matters (a language server does when a .gitignore changes).

source
JuliaWorkspaces.is_in_ignored_folder — Function
is_in_ignored_folder(f::GitIgnoreFilter, path) -> Bool

Whether the file or folder at path is in a folder that git ignores, by the rules described at GitIgnoreFilter. path itself counts when it is a folder; a file is never ignored on its own, only through its folders.

source

Mutating a workspace

JuliaWorkspaces.add_file! — Function
add_file!(jw::JuliaWorkspace, file::TextFile)

Add a file to the workspace. If the file already exists as a regular file, it will throw an error. If the URI is currently tracked as an indirect file (reached via include from another file), it is promoted to a regular file and any existing lazy indirect content is cleared.

source
JuliaWorkspaces.remove_file! — Function
remove_file!(jw::JuliaWorkspace, uri::URI)

Remove a file from the workspace. If the file does not exist, it will throw an error.

source
JuliaWorkspaces.set_active_project! — Function
set_active_project!(jw::JuliaWorkspace, uri_or_nothing::Union{URI,Nothing})

Set the active project for the workspace. The active project serves as the fallback environment for files that are not inside any project folder and also as the fallback test project when determining test environments.

As a test project it is subject to the same conditions as any other: it is used only if it has a readable manifest, and only if that manifest devs the package that owns the file (or it is that package's folder). Setting it is therefore frequently a no-op for test items — see get_test_env.

Pass nothing to clear the active project.

When the active project is outside the workspace folders, its Project.toml and Manifest.toml will be loaded lazily via the indirect file mechanism, which triggers the indirect_file_watch_callback so the host (e.g. the LS) can register file watchers for them.

source
JuliaWorkspaces.set_indirect_file_content! — Function
set_indirect_file_content!(jw::JuliaWorkspace, uri::URI, file::Union{TextFile,Nothing})

Update the content of an indirect file (a file referenced via include from a regular file but not itself added as a regular file). Pass nothing if the file no longer exists on disc. This is intended to be called by the LS in response to file-watcher notifications.

source
JuliaWorkspaces.clear_indirect_file! — Function
clear_indirect_file!(jw::JuliaWorkspace, uri::URI)

Drop tracking for an indirect file. Any cached lazy content is removed; if the include graph still references the URI, the next query will re-trigger the lazy disc read and the watcher callback.

source

Files and source text

JuliaWorkspaces.get_indirect_files — Function
get_indirect_files(jw::JuliaWorkspace)

Return the set of URIs currently tracked as indirect files — i.e. files reached only via include(...) traversal that are not regular workspace files.

source
JuliaWorkspaces.is_indirect_file — Function
is_indirect_file(jw::JuliaWorkspace, uri::URI)

Return true if uri is currently part of the include graph as an indirect file (i.e. reached only via include and not added as a regular file).

source
JuliaWorkspaces.position_at — Function
position_at(source_text::SourceText, x::Int) -> Position

Convert the 1-based byte offset x within source_text into a Position (a 1-based line number and a 1-based UTF-8 byte column).

source

Syntax trees

JuliaWorkspaces.get_julia_syntax_tree — Function
get_julia_syntax_tree(jw::JuliaWorkspace, uri::URI)

Get the syntax tree of a Julia file from the workspace. The tree is parsed on demand and not cached.

Returns

  • The JuliaSyntax.SyntaxNode root of the parsed file.

Throws JWNotAJuliaFile if uri is not a Julia document, and JWUnknownFile if it has no content.

source
JuliaWorkspaces.parse_files_blocking — Function
parse_files_blocking(jw::JuliaWorkspace; cancel_token::Union{CancellationTokens.CancellationToken,Nothing}=nothing, progress_callback::Union{Nothing,Function}=nothing)

Parse every Julia file of the workspace, warming the memoized syntax-tree caches. Parsing is environment-independent, so this is useful for CLI tools that want to overlap the parse work with dynamic environment indexing (the per-file yield lets the dynamic feature keep processing results) before running a single full analysis pass via get_diagnostics_blocking. If progress_callback is provided, it is called as progress_callback(done::Int, total::Int) after each file is parsed. If cancel_token is provided, throws CancellationTokens.OperationCanceledException when the token is cancelled.

source

Diagnostics

JuliaWorkspaces.get_diagnostic — Function
get_diagnostic(jw::JuliaWorkspace, uri::URI)

Get the diagnostics of a file from the workspace.

Returns

  • A vector of Diagnostic structs.
source
JuliaWorkspaces.get_diagnostics_blocking — Function
get_diagnostics_blocking(jw::JuliaWorkspace; cancel_token::Union{CancellationTokens.CancellationToken,Nothing}=nothing, progress_callback::Union{Nothing,Function}=nothing)

Wait for the dynamic environment to finish loading, then return all diagnostics. This is useful for CLI tools that want the full, accurate set of diagnostics. If cancel_token is provided, throws CancellationTokens.OperationCanceledException when the token is cancelled. If progress_callback is provided, it is called as progress_callback(done::Int, total::Int) after each file's diagnostics are computed. The count restarts when newly loaded environments require another pass over the workspace.

source

Projects, packages and tests

JuliaWorkspaces.get_test_env — Function
get_test_env(jw::JuliaWorkspace, uri::URI)

Resolve what a test item in uri needs in order to run, for the workspace jw.

The package is the innermost enclosing folder whose Project.toml has a name, a uuid and a valid version, among the folders discovered under the workspace folders plus the active project.

The project is the innermost enclosing folder that has both a project file and a readable manifest; when there is none, the active project, which likewise needs a manifest to qualify. Either way it is kept only if it is the package folder or if its manifest devs the package — a project that merely contains the package on disk, or depends on it as a registered package, is discarded and the result carries no project at all.

Note that this returns the ingredients of a test environment, not a resolved one: the project supplies version pins, while the dependencies come from the package's test target when a runner builds the environment.

Returns

source

The dynamic feature

JuliaWorkspaces.is_ready — Function
is_ready(jw::JuliaWorkspace)

Check whether the workspace's dynamic environment loading has completed. Returns true if no dynamic feature is configured, or if at least one result has been consumed (successful or failed) and no work item is pending.

This is a whole-workspace question and stays coarse: per-file consumers want the internal derived_file_env_ready query instead, which is settled per project.

source
JuliaWorkspaces.wait_until_ready — Function
wait_until_ready(jw::JuliaWorkspace; cancel_token::Union{CancellationTokens.CancellationToken,Nothing}=nothing)

Block until the workspace's dynamic environment loading has completed. If cancel_token is provided, throws CancellationTokens.OperationCanceledException when the token is cancelled.

source
JuliaWorkspaces.get_update_channel — Function
get_update_channel(jw::JuliaWorkspace)

Return the Channel{Symbol} that receives notifications when dynamic data becomes available. Returns nothing if no dynamic feature is configured. Consumers can take! or wait on this channel to be notified of updates.

source
JuliaWorkspaces.retry_failed_dynamic_projects! — Function
retry_failed_dynamic_projects!(jw::JuliaWorkspace)

Forget every terminal dynamic-work failure, so projects that previously failed to index are attempted again on the next reconcile.

The dynamic feature otherwise gives each project a bounded number of attempts (max_failure_attempts) and never forgets a failure on its own. That bound is what stops a deterministically unresolvable environment — an unsatisfiable test env, an unregistered dependency — from launching a fresh child process on every edit to its Project.toml. Hosts should wire this function to an explicit user action such as "restart language server" or "reindex", which is the intended way past the bound.

No-op when the workspace has no dynamic feature.

source
JuliaWorkspaces.shutdown! — Function
shutdown!(jw::JuliaWorkspace; cancel_token::Union{CancellationTokens.CancellationToken,Nothing}=nothing)

Stop the workspace's dynamic feature and kill every indexing child process. Hosts should call this when they exit (for a language server, on the exit notification), so children do not outlive them.

Blocks until the reactor has stopped and every indexing child it launched has exited. If cancel_token is provided, throws CancellationTokens.OperationCanceledException when it is cancelled first; the shutdown itself still goes ahead. Pass a token from CancellationTokenSource(seconds) to bound the wait.

Children get SIGTERM and, if still alive after a grace period (DJP_KILL_GRACE_SECONDS), SIGKILL, so a child stuck in its SIGTERM handling holds this up for that long. A host that abandons the wait and exits relies on the children's own parent-death handling instead. The workspace does no further dynamic work afterwards. No-op when the workspace has no dynamic feature or was already shut down.

source

Language features

JuliaWorkspaces.get_hover_text — Function
get_hover_text(jw::JuliaWorkspace, uri::URI, index::Integer)

Return a Markdown documentation string for the expression at index (1-based Julia string index) in the file identified by uri, or nothing if there is no hover information for that position.

Returns nothing when uri is not a Julia document.

source
JuliaWorkspaces.get_doc_from_word — Function
get_doc_from_word(jw::JuliaWorkspace, word::AbstractString)

Search all loaded symbol stores for symbols matching word (fuzzy match) and return their documentation as a single markdown string. Returns "No results found." when no matches are found.

source
JuliaWorkspaces.get_completions — Function
get_completions(jw::JuliaWorkspace, uri::URI, index::Integer, completion_mode::Symbol=:import)

Return a CompletionResult with completion items at the given index (1-based Julia string index) in the file identified by uri.

completion_mode may be :import (default) or :qualify to control whether additional using statements are inserted for out-of-scope symbols.

Returns an empty, complete result when uri is not a Julia document.

source
JuliaWorkspaces.get_expr1 — Function
get_expr1(x, offset, pos=0)

Walk a CSTParser EXPR tree and return the leaf EXPR whose span covers offset (0-based byte offset). Returns nothing if no match is found.

source
JuliaWorkspaces.completion_type — Function
completion_type(b) -> Union{Symbol,Missing}

Infer the type of a binding b as a Symbol suitable for display in hover and completion results, stripping a leading Core. qualifier. Returns missing when the type cannot be determined or b is not a StaticLint.Binding.

source
JuliaWorkspaces.get_typed_definition — Function
get_typed_definition(b) -> Union{String,Symbol,Missing}

Return a human-readable definition string for the binding b with its inferred type annotation inserted where possible (for example x::Int). Falls back to completion_type when b is not a StaticLint.Binding.

source
JuliaWorkspaces.get_definitions — Function
get_definitions(jw::JuliaWorkspace, uri::URI, index::Integer)

Return a vector of DefinitionResult for the symbol at index (1-based Julia string index) in the file identified by uri.

Returns an empty vector when uri is not a Julia document.

source
JuliaWorkspaces.get_references — Function
get_references(jw::JuliaWorkspace, uri::URI, index::Integer)

Return a vector of ReferenceResult for all references to the symbol at index (1-based Julia string index) in the file identified by uri.

Returns an empty vector when uri is not a Julia document.

source
JuliaWorkspaces.get_rename_edits — Function
get_rename_edits(jw::JuliaWorkspace, uri::URI, index::Integer, new_name::String)

Return a vector of RenameEdit for renaming the symbol at index (1-based Julia string index) in uri to new_name.

Returns an empty vector when uri is not a Julia document.

source
JuliaWorkspaces.get_highlights — Function
get_highlights(jw::JuliaWorkspace, uri::URI, index::Integer)

Return a vector of HighlightResult for highlighted occurrences of the symbol at index (1-based Julia string index) in the same file.

Returns an empty vector when uri is not a Julia document.

source
JuliaWorkspaces.can_rename — Function
can_rename(jw::JuliaWorkspace, uri::URI, index::Integer)

Check whether the symbol at index (1-based Julia string index) can be renamed. Returns a named tuple (; start::Position, stop::Position) describing the range of the renamable symbol (both positions use 1-based line and column), or nothing if the symbol cannot be renamed.

Returns nothing when uri is not a Julia document.

source
JuliaWorkspaces.get_signature_help — Function
get_signature_help(jw::JuliaWorkspace, uri::URI, index::Integer)

Return a SignatureResult with signature information for the function call at index (1-based Julia string index) in the file identified by uri.

Returns an empty result when uri is not a Julia document.

source
JuliaWorkspaces.get_document_symbols — Function
get_document_symbols(jw::JuliaWorkspace, uri::URI)

Return a vector of DocumentSymbolResult representing the document outline for the file identified by uri. Each result has start_offset and end_offset as 0-based byte offsets, plus name, kind (LSP SymbolKind integer), and children.

Returns an empty vector when uri is not a Julia document.

source
JuliaWorkspaces.get_workspace_symbols — Function
get_workspace_symbols(jw::JuliaWorkspace, query::String)

Search all files for top-level bindings whose name starts with query. Returns a vector of WorkspaceSymbolResult.

source
JuliaWorkspaces.get_selection_ranges — Function
get_selection_ranges(jw::JuliaWorkspace, uri::URI, indices::Vector{Int})

For each 1-based string index in indices, compute a nested selection range. Returns a vector of Union{Nothing, SelectionRangeResult}.

Returns all-nothing when uri is not a Julia document.

source
JuliaWorkspaces.get_current_block_range — Function
get_current_block_range(jw::JuliaWorkspace, uri::URI, index::Integer)

Find the current top-level block at index (1-based Julia string index). Returns a BlockRangeResult with 0-based byte offsets, or nothing.

Returns nothing when uri is not a Julia document.

source
JuliaWorkspaces.get_module_at — Function
get_module_at(jw::JuliaWorkspace, uri::URI, index::Integer)

Return the fully qualified module name at index (1-based Julia string index), or "Main" if no module scope is found.

Returns "Main" when uri is not a Julia document.

source
JuliaWorkspaces.get_document_links — Function
get_document_links(jw::JuliaWorkspace, uri::URI) → Vector{DocumentLinkResult}

Return clickable document links (string literals that resolve to files). Offsets in results are 0-based byte offsets for direct use with CST spans.

Returns an empty vector when uri is not a Julia document.

source
JuliaWorkspaces.get_inlay_hints — Function
get_inlay_hints(jw::JuliaWorkspace, uri::URI, start_index::Integer, end_index::Integer, config::InlayHintConfig) → Vector{InlayHintResult}

Return inlay hints (parameter names, variable types) for the given range. start_index and end_index are 1-based Julia string indices.

Returns an empty vector when uri is not a Julia document.

source
JuliaWorkspaces.get_code_actions — Function
get_code_actions(jw::JuliaWorkspace, uri::URI, index::Integer, diagnostic_messages::Vector{String}, workspace_folders::Vector{String}=String[]) → Vector{CodeActionInfo}

Return the list of applicable code actions at index (1-based Julia string index). diagnostic_messages should contain the text of any diagnostics overlapping the cursor. workspace_folders is an optional list of workspace folder paths (used by license actions).

Returns an empty vector when uri is not a Julia document.

source
JuliaWorkspaces.execute_code_action — Function
execute_code_action(jw::JuliaWorkspace, action_id::String, uri::URI, index::Integer, workspace_folders::Vector{String}=String[]) → Vector{WorkspaceFileEdit}

Execute the code action identified by action_id at index (1-based Julia string index). Returns a vector of workspace file edits. Each edit contains a URI and a vector of TextEditResults with 0-based byte offsets.

Returns an empty vector when uri is not a Julia document.

source
JuliaWorkspaces.get_format_edits — Function
get_format_edits(jw::JuliaWorkspace, uri::URI) → WorkspaceFileEdit

Format the entire document uri and return a WorkspaceFileEdit describing the edits required to apply the formatting. The formatting style and options are taken from the nearest JuliaFormat.toml configuration file (see derived_format_configuration); when no configuration is found the minimal JuliaFormatter style is used. A style of "runic" routes formatting through Runic.jl.

If the document is already correctly formatted the returned edit list is empty. Returns nothing if the file is excluded by its JuliaFormat.toml include/exclude globs. Throws an error if formatting fails (for example because of a syntax error).

source
get_format_edits(jw::JuliaWorkspace, uri::URI, start_line::Integer, stop_line::Integer) → WorkspaceFileEdit

Format the whole-line range [start_line, stop_line] (1-based, inclusive) of the document uri and return a WorkspaceFileEdit. Configuration is resolved the same way as for full-document formatting.

If the targeted range is already correctly formatted the returned edit list is empty. Returns nothing if the file is excluded by its JuliaFormat.toml include/exclude globs. Throws an error if formatting fails.

source
JuliaWorkspaces.is_format_excluded — Function
is_format_excluded(jw::JuliaWorkspace, uri::URI) → Bool

Whether the governing JuliaFormat.toml excludes uri from formatting through its include/exclude globs.

Callers that format many files can consult this to skip excluded files cheaply before reading their content; get_format_edits reports exclusion by returning nothing.

source

StaticLint and environment accessors

JuliaWorkspaces.get_legacy_cst — Function
get_legacy_cst(jw::JuliaWorkspace, uri::URI)

Get the CSTParser legacy syntax tree for a Julia file.

Returns

  • An EXPR (CSTParser expression tree).

Throws JWNotAJuliaFile if uri is not a Julia document, and JWUnknownFile if it has no content.

source
JuliaWorkspaces.get_roots_for_uri — Function
get_roots_for_uri(jw::JuliaWorkspace, uri::URI)

Get all root files whose include tree contains the given URI.

Returns

  • A Set{URI} of root file URIs.
source
JuliaWorkspaces.get_best_root_for_uri — Function
get_best_root_for_uri(jw::JuliaWorkspace, uri::URI)

Get the single best root file for a given URI. Prefers package src/ roots over test roots when a file is reachable from multiple roots. Returns nothing if the URI is not part of any root's include tree.

Returns

  • A URI or nothing.
source
JuliaWorkspaces.get_static_lint_data — Function
get_static_lint_data(jw::JuliaWorkspace, uri::URI)

Get the static lint analysis data for the best root containing uri. This includes the metadata dictionary, environment, and workspace packages needed by LS request handlers.

Returns

  • A named tuple (meta_dict, env, workspace_packages, root) or nothing if no root contains the URI.
    • meta_dict::Dict{UInt64, StaticLint.Meta} — maps EXPR objectid → metadata. Since the inventories refactor this is the CURRENT-FILE per-file analysis meta (`derivedfile_analysis(rt, root, uri).meta), carrying onlyuri's own EXPRs; a name declared in a sibling file resolves as aStaticLint.TreeRefrather than a mergedBinding`.
    • env::StaticLint.ExternalEnv — resolved environment (symbols, methods, deps)
    • workspace_packages::Dict{String,Any} — vestigial: always an empty Dict since the per-file migration (deved-package method sets are now reached request-time through the module tree). Deletion candidate for M5.
    • root::URI — the root file that was used

Returns nothing when uri is not a Julia document.

source
JuliaWorkspaces.get_environment — Function
get_environment(jw::JuliaWorkspace, uri::URI)

Get the resolved environment for the best root containing uri.

Returns

  • A StaticLint.ExternalEnv or nothing.
source
JuliaWorkspaces.get_expr_location — Function
get_expr_location(jw::JuliaWorkspace, x::CSTParser.EXPR)

Given an EXPR node from a CST obtained via get_legacy_cst, return the URI and byte offset of x within its owning file.

Walks x.parent pointers up to the file-root EXPR, computes the byte offset by descending through the tree, then looks up the root's objectid in a Salsa-memoized expr→URI mapping.

Returns

  • (uri::URI, offset::Int) if the owning file is found
  • nothing if the EXPR cannot be mapped to a file
source

Private functions

JuliaWorkspaces.update_file! — Function
update_file!(jw::JuliaWorkspace, file::TextFile)

Update a file in the workspace. If the file does not exist, it will throw an error.

source

URI helper functions (submodule URIs2)