Repository: xonsh/xonsh
Pull request: Do not load `~/.xonshrc` in not interactive mode
### Motivation

In #5099 was introduced the logic where all RC files are loaded in interactive and non-interactive modes. This logic is not working good for home based `~/.xonshrc` file.

First of all `~/.xonshrc` is the buffer of settings focused on interactive mode. Most tools with integration with xonsh (e.g. `conda`, `zoxide`, etc) offer to just do `echo "init_tool()" >> ~/.xonshrc` (`conda` has around 20 lines of init code) to start using the tool and users are doing this without any doubts.

But because of after 5099 `~/.xonshrc` is executed in non-interactive mode the adding code to it leads to unexpected and unintended side effects: 

* If you run a script with shebang (e.g. `#!/usr/bin/env xonsh` or [xonsh-awesome-cli-app](https://github.com/anki-code/xonsh-awesome-cli-app)) or just from `xonsh script.xsh` the code will be unexpected and unintended slower.

* If you're using xonsh-based tools (e.g. you install them using pip) and run them in environment that has no packages that initiated in `~/.xonshrc` you will see epic errors.

* Additional context: 
  * Bash and Zsh do not load `~/.bashrc` and `~/.zshrc` in non-interactive mode by the same reasons.
  * We have welcome message `Create ~/.xonshrc file manually or use xonfig to suppress the welcome message` and we don't want to make the process of creating this file complex.

All of this leads to bad unexpected and unintended experience. This PR is to fix this.

### Expectation

By doing this fix we assume that experienced user who wants to build good repeatable run control files will use another ways to create config files and this has [reflection in docs](https://github.com/xonsh/xonsh/blob/8860f2bd5273d5f3fc08ccf6be6af8163bfec0bd/docs/xonshrc.rst). In the nutshell if you want to create the RC files that affect every run of code you should use one or many of these ways:

* Cross-desktop group (XDG) compliant `~/.config/xonsh/rc.xsh` control file.
* The system-wide control file `/etc/xonsh/xonshrc` for Linux and OSX and in `%ALLUSERSPROFILE%\xonsh\xonshrc` on Windows. It controls options that are applied to all users of Xonsh on a given system.
* The home-based directory `~/.config/xonsh/rc.d/` and system `/etc/xonsh/rc.d/` can contain .xsh files. They will be executed at startup in order. This allows for drop-in configuration where your configuration can be split across scripts and common and local configurations more easily separated.

In your configs you need to check `$XONSH_INTERACTIVE` and `$XONSH_LOGIN` explicitly.

### Before

`~/.xonshrc` is used in non-interactive mode.

```xsh
echo "echo RC" >> ~/.xonshrc
cd /tmp
echo "echo Script" > script.xsh
xonsh script.xsh
# RC
# Script
```
```xsh
cd /tmp
echo 'echo RC' >> ~/.xonshrc
echo '#!/usr/bin/env xonsh' > myscript
chmod +x myscript

./myscript
# RC
```

### After

`~/.xonshrc` is not used in non-interactive mode. Use `-i` if you need it.

```xsh
echo "echo RC" >> ~/.xonshrc
cd /tmp
echo "echo Script" > script.xsh
xonsh script.xsh
# Script

xonsh -i script.xsh
# RC
# Script
```
```xsh
cd /tmp
echo 'echo RC' >> ~/.xonshrc
echo '#!/usr/bin/env xonsh' > myscript
chmod +x myscript

./myscript
```
Closes #5488 #4096 #5496

### Fun

I want to leave here some nice representation of how it works in bash/sh/zsh from [twitter post](https://twitter.com/paxx39/status/1742768007154479109):

![image](https://github.com/xonsh/xonsh/assets/1708680/cd7b3803-483f-4d5d-bf9d-baa61c794f68)

[How it works in xonsh](https://github.com/xonsh/xonsh/blob/20081b5a5179afa82b587e0bd3795b72caa2a2a5/docs/xonshrc.rst):
* Non-interactive ->  `$XONSHRC` and `$XONSHRC_DIR`
* Interactive -> The same + `~/.xonshrc`

And all logic inside files ;)

## For community
⬇️  **Please click the 👍 reaction instead of leaving a `+1` or 👍  comment**


Problem statement:
Unintended loading `xonshrc` file in script mode
My xonshrc is pretty silent and I suddenly noticed that xonshrc is loaded in script mode:

```xsh
cd /tmp
echo 'echo RC' >> ~/.xonshrc
echo '#!/usr/bin/env xonsh' > myscript
chmod +x myscript

./myscript
# RC

xonsh myscript.xsh
# RC
```

When I run any xonsh script I have no any expectation that my huge `.xonshrc` with features for prompt will be loaded.

Bash/zsh also don't load RC files when you run script:

```xsh
cd /tmp
echo 'echo RC' >> ~/.bashrc
echo 'echo 1' > script.sh
bash script.sh
# 1  # No RC

echo 'echo RC' >> ~/.zshrc
echo 'echo 1' > script.zsh
zsh script.zsh
# 1  # No RC
```

## For community
⬇️  **Please click the 👍 reaction instead of leaving a `+1` or 👍  comment**

Hints from issue discussion:
I think this is the result of #5099 (@cosineFish @bestlem).

@gforsyth I think we need to fix/revert this in 0.17.0 because:
* All xonsh scripts are affected.
* If you have many libs in xonshrc and want to run xonsh script in env you will face with unintended errors about missing libs. It's bad experience.

The user own xonshrc that is mostly for using it in prompt must NOT be loaded in script mode.
> The user own xonshrc that is mostly for using it in prompt must NOT be loaded in script mode.

I mean, that's the bash approach, but `zsh` and `fish` do load those files in script mode.

A user can run using `--no-rc` to avoid loading their `xonshrc` file
@gforsyth 
1. zsh does not do this (see example in the first message).
2. I believe that if I have CLI xonsh `script.xsh` with shebang I should not do anything with `--no-rc`. I expect that it just works. See also [xonsh-awesome-cli-app](https://github.com/anki-code/xonsh-awesome-cli-app).

So I'm completely for disabling load `~/.xonshrc` for scripts accordingly with expectations and bash, zsh behavior. 
If user wants to create xonshrc to load forever on user base level we already have `~/.config/xonsh/rc.xsh` ([doc](https://xon.sh/xonshrc.html)). 
ah, right, `zsh` does load `zshenv` though -- I don't want to get into having a million special cased startup files, though.

I'm fine with this either way.  If we do disable loading `rc` files in script mode, then we should ensure that a user can force loading them by passing `-i`
I understand the idea from [here](https://github.com/xonsh/xonsh/issues/4096#issuecomment-792035141) to have this in every xonshrc file:
```xsh
if $XONSH_INTERACTIVE:
    # ...
```
It looks clear BUT you forget about software around (e.g. `conda`, `zoxide`, `xonsh wizard`, `xonsh web`, etc) that just do:
```xsh
echo "some_init_code()" >> ~/.xonshrc
```
And this kind of tools don't know about `$XONSH_INTERACTIVE`. And when they add init code into xonshrc directly ALL scripts will be affected by this and will produce errors and slow timings! This is why I think it's a not so good idea @gforsyth .

We need more complex behavior. I'm thinking about at least push out `~/.xonshrc` to interactive mode.
And one moment. I want to remember you all that we have already stepped on this rake when we had loading history on every xonsh run - #4178. Before this fix we observed all kinds of unexpected errors and bad experience with scripts.
Do not do unexpected unintended work undercover.
> I understand the idea from [here](https://github.com/xonsh/xonsh/issues/4096#issuecomment-792035141) to have this in every xonshrc file:
> 
> ```python
> if $XONSH_INTERACTIVE:
>     # ...
> ```
> 
> It looks clear BUT you forget about software around (e.g. `conda`, `zoxide`, `xonsh wizard`, `xonsh web`, etc) that just do:
> 
> ```python
> echo "some_init_code()" >> ~/.xonshrc
> ```
> 
> And this kind of tools don't know about `$XONSH_INTERACTIVE`. And when they add init code into xonshrc directly ALL scripts will be affected by this and will produce errors and slow timings! This is why I think it's a not so good idea @gforsyth .
> 
> We need more complex behavior. I'm thinking about at least push out `~/.xonshrc` to interactive mode.

This is exactly how fish does it - load the same config.fish in all cases but have test for --is-interactive and --is-login Why is this not an issue for fish? 
@bestlem I think it's issue for fish. Let's consider the situation. I want to write script `myscript` using fish and then I want to apply it for 1000 files. Why I need to load fish RC file with setting up fancy prompt 1000 times?
If the answer - "you must know about checking for interactive usage and add checking in the RC file or add --no-rc in your script" - I treat this as "you must know everything in the world" and I don't like this.

Second thing is from practice. All home `~/.*rc` files xonsh/bash/zsh are ordinarily unmanageable trash on most of systems I saw and applying the code from there to every execution of scripts is the shoot in the leg.

I'm ok to keep the rest of RC places like it works now but not for `~/.xonshrc`. I'm in preparing the PR.
Looking at my fish config item and fzf look at --is-interactive others don't affect script usage. 
In my experience I use my ~/.zshenv,  config.fish etc to enforce a sane set of constant stuff across all my environments. and the PATH and environment variables will differ between Windows / WSL / MacOS/ Solaris /NeXT / Linux and if my machine is in London or Chicago when travelling or remote logging in. I don't what to have to make each script I write deal with all those cases when I can with any other shell just change one or two files for each OS.

The environment configuration is not the job of my script.

Actually I have been commenting on SO question that you must understand what each line in your shell config files does. If you don't then leave that line out.  
With experience you don't have to know the details of what that line does but you do have to understand its effect on your environment.


There MUST be a way to run xonsh for scripts loading ~/.xonshrc - if you don't want it then there is --no-rc which you can put in the shebang of your script.

The major problem before was that there was --no-rc but setting XONSH_INTERACTIVE was being done in the wrong place so I think if you loaded a config file ir set it to true in all cases.

@bestlem I'm thinking about `~/.xonshrc` as an unmanageable buffer for random configurations. If you are experienced user who knows life you will use `~/.config/` and I assume you know what you are doing. So this is why in the PR I will make `~/.xonshrc` active only of interactive mode to prevent unexpected and unintended using in scripts. The rest behavior will stay as implemented.

(JFYI I'm completely against of adding `--no-rc` to shebangs by default. This decision completely annihilates the value of `/etc/xonsh/xonshrc` and others. At the end we will have tons of tools with `--no-rc` in shebangs. What a hell will be.)

Commit message: docs

Patch to review:
diff --git a/docs/xonshrc.rst b/docs/xonshrc.rst
index 0dda09bf6a..ae5cc25485 100644
--- a/docs/xonshrc.rst
+++ b/docs/xonshrc.rst
@@ -2,26 +2,30 @@ Run Control File
 =========================
 Xonsh allows you to customize your shell behavior with run control files, called "xonshrc" files.
 These files are written either in the Xonsh language (a superset of Python) or in Python and are executed
-exactly once at startup, only when running in interactive mode.
+exactly once at startup.
 
 The control file usually contains:
 
-* Assignment statements setting `environment variables <envvars.html>`_.  This includes standard OS environment variables that affect other programs and many that Xonsh uses for itself.
-* ``xonfig`` commands to load selected add-ins ("`xontribs<tutorial_xontrib.html#loading-xontribs>`")
-* Xonsh function definitions
+* Assignment statements setting `environment variables <envvars.html>`_. This includes standard OS environment variables that affect other programs and many that Xonsh uses for itself.
+* ``xontrib`` commands to load selected add-ins ("`xontribs<tutorial_xontrib.html#loading-xontribs>`").
+* Xonsh function definitions.
 * `Alias definitions <aliases.html>`_, many of which invoke the above functions with specified arguments.
 
-The system-wide ``xonshrc`` file controls options that are applied to all users of Xonsh on a given system.
-You can create this file in ``/etc/xonsh/xonshrc`` for Linux and OSX and in ``%ALLUSERSPROFILE%\xonsh\xonshrc`` on Windows.
+First of all, you need to know about the home directory ``~/.xonshrc`` control file. This file is commonly used to put configurations for the user interactive prompt and it is executed automatically only for interactive Xonsh sessions.
 
-Xonsh also allows a per-user run control file in your home directory, either
-directly in the home directory at ``~/.xonshrc`` or, for XDG compliance, at ``~/.config/xonsh/rc.xsh``.
-The options set per user override settings in the system-wide control file.
+There are also a few places where Xonsh looks for run control files. These files will be executed automatically in both interactive and non-interactive modes, and you need to use the `$XONSH_INTERACTIVE <envvars.html#xonsh-interactive>`_ and `$XONSH_LOGIN <envvars.html#xonsh-login>`_ environment variables to determine what code you want to execute in each mode. Here is the list of run control files and directories:
+
+* Cross-desktop group (XDG) compliant ``~/.config/xonsh/rc.xsh`` control file.
+* The system-wide control file ``/etc/xonsh/xonshrc`` for Linux and OSX and in ``%ALLUSERSPROFILE%\xonsh\xonshrc`` on Windows. It controls options that are applied to all users of Xonsh on a given system.
+* The home-based directory ``~/.config/xonsh/rc.d/`` and system ``/etc/xonsh/rc.d/`` can contain ``.xsh`` files. They will be executed at startup in order. This allows for drop-in configuration where your configuration can be split across scripts and common and local configurations more easily separated.
+
+In addition:
 
-Xonsh also supports configuration directories, from which all ``.xsh`` files will be sourced in order.
-This allows for drop-in configuration where your configuration can be split across scripts and common
-and local configuration more easily separated. By default, if the directory ``~/.config/xonsh/rc.d``
-exists, any ``*.xsh`` files within will be sourced at startup.
+* Use ``xonsh --no-rc`` to prevent using control files.
+* Use ``xonsh --rc snail.xsh`` to run only a certain control file.
+* Use ``xonsh -i script.xsh`` to run xonsh in interactive mode with loading all possible control files.
+
+The options set per user override settings in the system-wide control file.
 
 Xonsh provides 2 wizards to create your own "xonshrc".  ``xonfig web`` provides basic settings, and ``xonfig wizard``
 steps you through all the available options.
diff --git a/xonsh/environ.py b/xonsh/environ.py
index a234d920f6..14118086f5 100644
--- a/xonsh/environ.py
+++ b/xonsh/environ.py
@@ -1156,7 +1156,9 @@ class GeneralSetting(Xettings):
     )
     XONSH_INTERACTIVE = Var.with_default(
         True,
-        "``True`` if xonsh is running interactively, and ``False`` otherwise.",
+        "``True`` if xonsh is running interactively, and ``False`` otherwise. "
+        "It's highly recommended to use this variable in your ``xonshrc`` files "
+        "to split the code execution for interactive and non-interactive modes.",
         is_configurable=False,
     )
     XONSH_LOGIN = Var.with_default(
diff --git a/xonsh/main.py b/xonsh/main.py
index cb710e6921..d44a4db0d3 100644
--- a/xonsh/main.py
+++ b/xonsh/main.py
@@ -308,6 +308,16 @@ def _get_rc_files(shell_kwargs: dict, args, env):
     # otherwise, get the RC files from XONSHRC, and RC dirs from XONSHRC_DIR
     rc = env.get("XONSHRC")
     rcd = env.get("XONSHRC_DIR")
+
+    if not env.get("XONSH_INTERACTIVE", False):
+        """
+        Home ``~/.xonshrc`` file has special meaning and history. The ecosystem around shells treat this kind of files
+        as the place where interactive tools and configs may be added. To avoid unintended and unexpected affection
+        of this file on non interactive behavior we remote this file in non interactive mode e.g. script with shebang.
+        """
+        home_xonshrc = os.path.expanduser("~/.xonshrc")
+        rc = tuple(c for c in rc if c != home_xonshrc)
+
     return rc, rcd
 
 


Code review comments:
diff_hunk: @@ -308,6 +308,16 @@ def _get_rc_files(shell_kwargs: dict, args, env):
     # otherwise, get the RC files from XONSHRC, and RC dirs from XONSHRC_DIR
     rc = env.get("XONSHRC")
     rcd = env.get("XONSHRC_DIR")
+
+    if not env.get("XONSH_INTERACTIVE", False):
+        """
+        Home ``~/.xonshrc`` file has special meaning and history. The ecosystem around shells treat this kind of files
+        as the place where interactive tools and configs may be added. To avoid unintended and unexpected affection
+        of this file on non interactive behavior we remote this file in non interactive mode e.g. script with shebang.
+        """
+        home_xonshrc = os.path.expanduser("~/.xonshrc")
path: xonsh/main.py
text: @user1:
Does this work on Windows?  Maybe instead you can do
```suggestion
        home_xonshrc = str((Path("~") / ".xonshrc").expanduser())
```

@author:
I've added tests for this but it looks [Github CI is down](https://www.githubstatus.com/). The line you highlighted I copied from `default_xonshrc()` for consistency so I think it should work but if no I will use your proposal, thanks!