Skip to content

get_cwd() variable substitution#262

Merged
edvilme merged 4 commits intomainfrom
copilot/expand-get-cwd-variables
Feb 27, 2026
Merged

get_cwd() variable substitution#262
edvilme merged 4 commits intomainfrom
copilot/expand-get-cwd-variables

Conversation

Copy link
Contributor

Copilot AI commented Feb 26, 2026

get_cwd() gained support for nine VS Code file-related variables but had no tests. Adds 17 focused unit tests covering every variable, composite patterns, multi-variable strings, and no-document fallback behaviour.

Changes

  • src/test/python_tests/test_get_cwd.py — new self-contained test file; includes a _setup_mocks() helper that stubs out the bundled LSP dependencies (pygls, lsprotocol, lsp_jsonrpc, lsp_utils) at module level so lsp_server can be imported without the full VS Code extension environment. No conftest.py needed.
# Tests cover each variable individually...
def test_file_dirname_resolved():
    settings = _make_settings(cwd="${fileDirname}")
    assert lsp_server.get_cwd(settings, DOC) == "/home/user/myproject/src"

# ...composite patterns...
def test_composite_pattern_resolved():
    settings = _make_settings(cwd="${fileDirname}/subdir")
    assert lsp_server.get_cwd(settings, DOC) == "/home/user/myproject/src/subdir"

# ...and fallback when no document is available
def test_file_variable_no_document_falls_back_to_workspace():
    for token in ["${file}", "${fileDirname}", "${fileWorkspaceFolder}", ...]:
        settings = _make_settings(cwd=token + "/extra")
        assert lsp_server.get_cwd(settings, None) == WORKSPACE
Original prompt

Context

PR #260 added a configurable cwd setting with variable substitution. The TypeScript client (src/common/settings.ts resolveVariables()) pre-resolves ${workspaceFolder}, ${userHome}, ${cwd}, and ${workspaceFolder:name} before sending settings to the Python server. The Python server's get_cwd() in bundled/tool/lsp_server.py then handles document-dependent variables that can't be resolved at settings-load time.

However, as @rchiodo pointed out in #260 (comment), the current get_cwd() only resolves ${fileDirname}. There are more file-related variables from VS Code's variables reference (https://code.visualstudio.com/docs/reference/variables-reference) that should also be resolved server-side since they depend on the current document.

Required Change

Only modify bundled/tool/lsp_server.py — expand the get_cwd() function (currently at line 292) to resolve additional file-related VS Code variables using a substitution-map approach.

The current implementation on main at line 292-306 is:

def get_cwd(settings: dict, document: Optional[workspace.Document]) -> str:
    """Returns the working directory for running the tool.

    Resolves ``${fileDirname}`` to the directory of the current document.
    If no document is available, falls back to the workspace root.

    Examples of supported patterns: ``${fileDirname}``, ``${fileDirname}/subdir``.
    """
    cwd = settings.get("cwd", settings["workspaceFS"])
    if "${fileDirname}" in cwd:
        if document and document.path:
            cwd = cwd.replace("${fileDirname}", os.path.dirname(document.path))
        else:
            cwd = settings["workspaceFS"]
    return cwd

Replace it with a version that builds a substitution map of all document-dependent variables and applies them. Here's what the new function should look like:

def get_cwd(settings: dict, document: Optional[workspace.Document]) -> str:
    """Returns the working directory for running the tool.

    Resolves the following VS Code file-related variable substitutions when
    a document is available:

    - ``${file}`` – absolute path of the current document.
    - ``${fileBasename}`` – file name with extension (e.g. ``foo.py``).
    - ``${fileBasenameNoExtension}`` – file name without extension (e.g. ``foo``).
    - ``${fileExtname}`` – file extension including the dot (e.g. ``.py``).
    - ``${fileDirname}`` – directory containing the current document.
    - ``${fileDirnameBasename}`` – name of the directory containing the document.
    - ``${relativeFile}`` – document path relative to the workspace root.
    - ``${relativeFileDirname}`` – document directory relative to the workspace root.
    - ``${fileWorkspaceFolder}`` – workspace root folder for the document.

    Variables that do not depend on the document (``${workspaceFolder}``,
    ``${userHome}``, ``${cwd}``) are pre-resolved by the TypeScript client.

    If no document is available and the value contains any unresolvable
    file-variable, the workspace root is returned as a fallback.

    See https://code.visualstudio.com/docs/reference/variables-reference
    """
    cwd = settings.get("cwd", settings["workspaceFS"])

    workspace_fs = settings["workspaceFS"]

    if document and document.path:
        file_path = document.path
        file_dir = os.path.dirname(file_path)
        file_basename = os.path.basename(file_path)
        file_stem, file_ext = os.path.splitext(file_basename)

        substitutions = {
            "${file}": file_path,
            "${fileBasename}": file_basename,
            "${fileBasenameNoExtension}": file_stem,
            "${fileExtname}": file_ext,
            "${fileDirname}": file_dir,
            "${fileDirnameBasename}": os.path.basename(file_dir),
            "${relativeFile}": os.path.relpath(file_path, workspace_fs),
            "${relativeFileDirname}": os.path.relpath(file_dir, workspace_fs),
            "${fileWorkspaceFolder}": workspace_fs,
        }

        for token, value in substitutions.items():
            cwd = cwd.replace(token, value)
    else:
        # Without a document we cannot resolve file-related variables.
        # Fall back to workspace root if any remain.
        if "${file" in cwd or "${relativeFile" in cwd:
            cwd = workspace_fs

    return cwd

Do NOT modify settings.ts, package.json, or any other file — only bundled/tool/lsp_server.py.

This pull request was created from Copilot chat.


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Co-authored-by: edvilme <5952839+edvilme@users.noreply.github.com>
Copilot AI changed the title [WIP] Expand get_cwd function to resolve additional file-related variables Expand get_cwd() to resolve all file-related VS Code variables Feb 26, 2026
@edvilme
Copy link
Contributor

edvilme commented Feb 26, 2026

Originated from #260 (comment) (@rchiodo)

@edvilme edvilme marked this pull request as ready for review February 26, 2026 23:40
If no document is available, falls back to the workspace root.

Examples of supported patterns: ``${fileDirname}``, ``${fileDirname}/subdir``.
Resolves the following VS Code file-related variable substitutions when
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should there be a unit test for all of these?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot Generate unit tests to check that the replacements actually work. Remember this repo is a bootstrapper, so try to keep it simple and straight to the point.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added 17 unit tests in src/test/python_tests/test_get_cwd.py (commit 0e48096). A conftest.py stubs out the heavy LSP dependencies so lsp_server can be imported in a plain pytest run. The tests cover every variable (${file}, ${fileBasename}, ${fileBasenameNoExtension}, ${fileExtname}, ${fileDirname}, ${fileDirnameBasename}, ${relativeFile}, ${relativeFileDirname}, ${fileWorkspaceFolder}), composite patterns, fallback-to-workspace-root when no document is available, and unchanged passthrough for plain paths.

Co-authored-by: edvilme <5952839+edvilme@users.noreply.github.com>
Co-authored-by: edvilme <5952839+edvilme@users.noreply.github.com>
Copilot AI changed the title Expand get_cwd() to resolve all file-related VS Code variables Add unit tests for get_cwd() variable substitution Feb 26, 2026
@edvilme edvilme merged commit 0b38c8e into main Feb 27, 2026
2 checks passed
@edvilme edvilme deleted the copilot/expand-get-cwd-variables branch February 27, 2026 00:03
@edvilme edvilme changed the title Add unit tests for get_cwd() variable substitution get_cwd() variable substitution Feb 27, 2026
github-actions bot pushed a commit to microsoft/vscode-mypy that referenced this pull request Feb 27, 2026
Applies changes from:
- microsoft/vscode-python-tools-extension-template#262 (get_cwd variable substitution)
- microsoft/vscode-python-tools-extension-template#260 (cwd setting - lsp_server.py portion)

Updates get_cwd() in bundled/tool/lsp_server.py to support all VS Code
file-related variable substitutions: ${file}, ${fileBasename},
${fileBasenameNoExtension}, ${fileExtname}, ${fileDirname},
${fileDirnameBasename}, ${relativeFile}, ${relativeFileDirname},
${fileWorkspaceFolder}.

Replaces the previous equality-based checks with substring replacement,
allowing variables to be embedded inside longer paths (e.g.
${fileDirname}/subdir). Preserves the mypy-specific ${nearestConfig}
behaviour. Fixes the dmypy (no-document) path to correctly return a
plain cwd value rather than always falling back to workspaceFS.

Adds src/test/python_tests/test_get_cwd.py with unit tests covering
all variables, composite patterns, no-document fallbacks, and the
mypy-specific ${nearestConfig} option.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
github-actions bot pushed a commit to microsoft/vscode-flake8 that referenced this pull request Feb 27, 2026
Applies changes from upstream template PRs:
- microsoft/vscode-python-tools-extension-template#260 (cwd setting - already applied)
- microsoft/vscode-python-tools-extension-template#262 (get_cwd variable substitution)

Expands get_cwd() to resolve nine VS Code file-related variables:
${file}, ${fileBasename}, ${fileBasenameNoExtension}, ${fileExtname},
${fileDirname}, ${fileDirnameBasename}, ${relativeFile},
${relativeFileDirname}, ${fileWorkspaceFolder}.

Adds 17 unit tests covering every variable, composite patterns,
multi-variable strings, and no-document fallback behaviour.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
github-actions bot pushed a commit to microsoft/vscode-pylint that referenced this pull request Feb 27, 2026
Sync changes from upstream template PRs:
- microsoft/vscode-python-tools-extension-template#260 (Add configurable cwd setting)
- microsoft/vscode-python-tools-extension-template#262 (get_cwd() variable substitution)

Expands get_cwd() to support 9 VS Code file-related variable substitutions:
${file}, ${fileBasename}, ${fileBasenameNoExtension}, ${fileExtname},
${fileDirname}, ${fileDirnameBasename}, ${relativeFile},
${relativeFileDirname}, ${fileWorkspaceFolder}.

Also adds unit tests for get_cwd() helper.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
github-actions bot pushed a commit to microsoft/vscode-black-formatter that referenced this pull request Feb 27, 2026
…ution

- Add `${namespace}.cwd` to checkIfConfigurationChanged in settings.ts
  (from microsoft/vscode-python-tools-extension-template#260)
- Update get_cwd() in lsp_server.py to support full VS Code variable
  substitution (9 file-related variables) instead of exact-match only
  (from microsoft/vscode-python-tools-extension-template#262)
- Add unit tests for get_cwd() helper (test_get_cwd.py)
  (from microsoft/vscode-python-tools-extension-template#262)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
github-actions bot pushed a commit to microsoft/vscode-isort that referenced this pull request Feb 27, 2026
…le substitution

Syncs changes from:
- microsoft/vscode-python-tools-extension-template#260 (Add configurable cwd setting)
- microsoft/vscode-python-tools-extension-template#262 (get_cwd() variable substitution)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
edvilme added a commit to microsoft/vscode-mypy that referenced this pull request Feb 27, 2026
* Sync get_cwd() variable substitution from template

Applies changes from:
- microsoft/vscode-python-tools-extension-template#262 (get_cwd variable substitution)
- microsoft/vscode-python-tools-extension-template#260 (cwd setting - lsp_server.py portion)

Updates get_cwd() in bundled/tool/lsp_server.py to support all VS Code
file-related variable substitutions: ${file}, ${fileBasename},
${fileBasenameNoExtension}, ${fileExtname}, ${fileDirname},
${fileDirnameBasename}, ${relativeFile}, ${relativeFileDirname},
${fileWorkspaceFolder}.

Replaces the previous equality-based checks with substring replacement,
allowing variables to be embedded inside longer paths (e.g.
${fileDirname}/subdir). Preserves the mypy-specific ${nearestConfig}
behaviour. Fixes the dmypy (no-document) path to correctly return a
plain cwd value rather than always falling back to workspaceFS.

Adds src/test/python_tests/test_get_cwd.py with unit tests covering
all variables, composite patterns, no-document fallbacks, and the
mypy-specific ${nearestConfig} option.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix _MockLS stub missing window_log_message and LogMessageParams in test_get_cwd.py (#445)

* Initial plan

* Fix _MockLS missing window_log_message and LogMessageParams kwargs in test_get_cwd.py

Co-authored-by: edvilme <5952839+edvilme@users.noreply.github.com>

* Fix linting issues in test_get_cwd.py (flake8 E302, black formatting)

Co-authored-by: edvilme <5952839+edvilme@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: edvilme <5952839+edvilme@users.noreply.github.com>

---------

Co-authored-by: GitHub Copilot <copilot@github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants