Search code examples
visual-studio-code

Why don't other programs see the changes I made to a file in VS Code until I save those changes?


I've noticed that when I'm making changes to a file in VS Code (see also What does having a white dot in the handle of a VS Code tab mean?), until I save those changes, other programs will still see the last-saved version of the file. Other programs don't see the changes until I save. Also, if it's a new file and it hasn't been saved at all yet, other programs will say that the file doesn't exist.

Those files and programs might be - for example - running a shell/JavaScript/Python script, compiling C/C++ or Java code, transpiling TypeScript to JavaScript, staging file changes to source control like Git, or a local development webserver.

Why does this happen?


Solution

  • This happens because there are "two copies" of the file (terminology not quite accurate here with respect to the word "file", and I'm not decided whether it's better to say "copy" or "version" here). One copy is an actual file stored on the machine's filesystem (which is typically backed by some form of "external storage" in secondary storage), and one copy is not really a "file" in the filesystem sense of the word, but rather a "working copy" held and maintained in the memory (primary storage) allocated to the VS Code process.

    The copy in memory is maintained by the VS Code process. The changes that you make as you type in the editor tab are reflected in that in-memory copy and displayed back to you in the UI. See also the TextDocument interface in the VS Code extension API. VS Code (and many other text editor programs) calls the act of writing its in-memory copy to the filesystem "saving". You can find its official (brief) docs on the subject here. In VS Code, you can save the "file" / "text document" open in the active editor tab by pressing ctrl/cmd+s, or using the menu's File > Save item, or using File: Save in the command palette. You can also save all files using Save All in the command palette, or ctrl/cmd+k,s. VS Code doesn't save files automatically upon every change you make to the file. You can configure it to save changes periodically with the following settings (quoting from the defaultSettings.json pseudo-file):

    // Controls [auto save](https://code.visualstudio.com/docs/editor/codebasics#_save-auto-save) of editors that have unsaved changes.
    //  - off: An editor with changes is never automatically saved.
    //  - afterDelay: An editor with changes is automatically saved after the configured `files.autoSaveDelay`.
    //  - onFocusChange: An editor with changes is automatically saved when the editor loses focus.
    //  - onWindowChange: An editor with changes is automatically saved when the window loses focus.
    "files.autoSave": "off",
    
    // Controls the delay in milliseconds after which an editor with unsaved changes is saved automatically. Only applies when `files.autoSave` is set to `afterDelay`.
    "files.autoSaveDelay": 1000,> 
    

    (you might also be interested in the builtin VS Code settings with saveBefore in their IDs, including task.saveBeforeRun, debug.saveBeforeStart, testing.saveBeforeTest, git.promptToSaveFilesBeforeCommit, and git.promptToSaveFilesBeforeStash. Also check your extensions' settings to see if they contribute features for saving before doing things, such as CMake Tools' cmake.saveBeforeBuild), Makefile Tools' makefile.saveBeforeBuild, and Code Runner's code-runner.saveAllFilesBeforeRun and code-runner.saveFileBeforeRun.

    The reason why other programs don't see the unsaved changes is because the other programs each have their own processes, and in most operating systems, each process has its own memory, and processes are isolated from each other by the operating system, which includes preventing them from reading from or writing to each other's allocated memory (this is for several reasons, security being a big one). So they can't see VS Code's in-memory copy of the file- only that which is on the filesystem. To spell this out a bit, when you try to run a shell script, a NodeJS script, a Python script, etc., the interpreter of that script cannot see the copy of the script with your unsaved changes in VS Code's memory- only whatever was last written ("saved") to the filesystem. Same goes for trying to compile/transpile files with unsaved changes, or staging unsaved changes to version control software like Git, or running a local webserver serving files from your filesystem.

    This is speaking generally. There are ways for processes to communicate information between each other (often depends on your OS) other than the filesystem, and VS Code extensions that provide language support can have access to the in-memory contents (see the TextDocument API I linked to earlier), but whether or not they choose to use that information is up to them (or more accurately, the maintainers of the extensions). A really really basic example of this would be the Python extension's Python: Run Selection/Line in Python Terminal and related commands, which work even in untitled files.

    As for new files, if the file has never been written to the filesystem, then now it should be pretty obvious why other programs complain that the file doesn't exist: It doesn't exist in the filesystem yet. So you need to save it and give it a location in the filesystem to be written to.

    Writing the changes to the filesystem is enough for other programs that aren't long-running, such as a short script, or running compilation once. But for some use-cases, writing the changes to the filesystem is not enough to get the other program to use updated file. If a program is long running, such as a REPL like NodeJS', if you have loaded a module file with require, the version which has been loaded will be cached in memory. You'd need to use a program-specific provided mechanism to get it to refresh its cache of the file (Ex. For NodeJS require, see node.js require() cache - possible to invalidate?), or just restart the program. Or, for a different example, with a development webserver, a client that has had the old copy of the file served to it by that server will not automatically know about the new copy of the file. It would need to make a new request to the server (Ex. by refreshing the page in the browser) for that (and HTTP caching is a whole 'nother thing).

    Extra tidbits: Why not automatically save immediately upon every little change?

    Finally, you might be asking why not just have VS Code write the changes to the filesystem after every single change you make to the (in-memory) "file" / "text document". I can't speak authoritatively on this, but I can give my somewhat-educated guesses. There are a couple reasons why this might not be desirable:

    • If you have a external storage that is slow to write to (Ex. disk drives tend to be slower than solid-state drives for writing) you'd be queuing up a lot of slow operations, and being somewhat wasteful with calls to the operating system (which typically manages interactions between user-level programs and the filesystem).

    • Drives have various lifespans, which factor in the maximum number of times each section of memory can be written to before they don't work anymore. There are typically various techniques in place to mitigate that, Ex. Wear-levelling / write caching, but writing every single change immediately to the filesystem is a bit excessive and could contribute to a shorter storage lifespan.

    • It could just be user-specific workflow reasons. For example, if you set up filesystem "listeners"/"watchers" to perform things like automatic rebuilds of programs when their source files change, or other developer tooling, you might not want them to get tasks queued up every time you type a character. Another example: How to disable auto hot reload on flutter? (but also, see Flutter hot reload doesn't work on autosave in VSCode).

    Extra tidbits: How VS Code handles conflicts between copies

    This separation between filesystem and memory copies is also why when you- outside of VS Code- write changes to the filesystem for a file that is currently open in VS Code with unsaved changes, VS Code will either

    • open a popup that asks something like "Do you want to save the changes you made to <filename>? Your changes will be lost if you don't save them". And from that popup, give you the options: "Don't Save", "Cancel", "Save",
    • or when you later try to save in VS Code, it will open a notification "Failed to save '<filename>': The content of the file is newer. Please compare your version with the file contents or overwrite the content of the file with your changes.", giving you the option to Overwrite the filesystem copy's changes, or Compare with the filesystem copy, or the implicit option to close the editor tab, at which point it will give you the aforementioned prompt of whether or not to save before closing.