> That's tricky, because nowhere in IEx ends-up loading multiple dot_iex files, so it would be a departure. Very true - while it is technically trivial to load multiple files it is a departure workflow wise and you _could_ end up with some conflicts between the files - that being said, that why I had originally though a different key name would provide a different context for the two things - there could be the existing dot-iex concept that would work the same way as it currently does with the addition of an IEx.Config.configuration_file(s?) that would be an additional file(s) that are loaded either before or after the dot-iex file
> But you can always emulate multiple files with import_if_available. This is also very true! I think the only potential downside I could think of for this is that it would be slightly more restrictive than the multiple file approach. If you had a `dot-iex` file configured in your project and then ran `iex --dot-iex other_file.exs -S mix` you may be confused by the fact that your file didn't get loaded as expected That being said - I defer to your judgement on the best approach here and if this is valuable! As always, really appreciate your time and all of your work! On Thu, Jun 6, 2024 at 2:29 PM José Valim <jose.va...@dashbit.co> wrote: > That's tricky, because nowhere in IEx ends-up loading multiple dot_iex > files, so it would be a departure. But you can always emulate multiple > files with import_if_available. > > On Thu, Jun 6, 2024 at 9:26 PM Chris Miller <camiller...@gmail.com> wrote: > >> I think that would get us pretty close to the behavior I was hoping for - >> but I was generally hoping that instead of taking precedence over an >> existing dot-iex configured file it could be used in addition to the >> existing dot-iex file. This might be hyper specific to my individual >> workflow, but I was hoping that we could add a feature to allow for >> application level configuration while also still using the existing dot-iex >> files to provide local configuration >> >> An example would be that we would use the new application level >> configuration to import some helper function and cat out some introduction >> / instruction to the prompt, while the local would be some functions or >> data that I as a developer have around for development / debugging but are >> very specific to my development. >> >> What are your thoughts on this multi-file configuration? >> >> On Thu, Jun 6, 2024 at 2:19 PM José Valim <jose.va...@dashbit.co> wrote: >> >>> Yeah, we can add a IEx.configure(dot_iex: "..."), which takes precedence >>> over the other ones if set. And we should read it in the same place we read >>> everything else. >>> >>> On Thu, Jun 6, 2024 at 9:08 PM Chris Miller <camiller...@gmail.com> >>> wrote: >>> >>>> I hadn't considered the config, but thats an interesting thought - not >>>> entirely sure if I totally get your though on the matter, but I was able to >>>> extend the IEx.Config to track a new key (:configuration_files) and then >>>> extended the IEx.Evaluator to pull that value from the config and load the >>>> configured files plus the `.iex.exs` file. This allows the feature to be >>>> used either through a call to `IEx.configure/1` before the evaluator >>>> starts, or the config can be added into any config file, which would allow >>>> you to easily swap config files per env if desired >>>> >>>> On Thursday, June 6, 2024 at 1:50:44 PM UTC-5 José Valim wrote: >>>> >>>>> I wonder if you could call something like "IEx.configure(...)" from >>>>> the top of your mix.exs and that would be enough to configure its >>>>> location. >>>>> Or maybe it would only require a small tweak to make it work. >>>>> >>>>> On Thu, Jun 6, 2024 at 8:22 PM Chris Miller <camil...@gmail.com> >>>>> wrote: >>>>> >>>>>> Actually - I am a little confused by the startup dependencies between >>>>>> mix and iex as it seems like the Evaluator is starting after mix (or at >>>>>> least that how it appears in my tests), this patch to the IEx.Evaluator >>>>>> seems to accomplish what I was hoping to achieve (but it does make IEx >>>>>> depend on Mix which may have been something you wanted to avoid, but >>>>>> perhaps there is some more abstract way of getting this information from >>>>>> the mix project to the evaluator) >>>>>> >>>>>> ```elixir >>>>>> defp load_dot_iex(state, path) do >>>>>> candidates = >>>>>> if path do >>>>>> [path] >>>>>> else >>>>>> # Do not assume there is a $HOME >>>>>> for dir <- [".", System.get_env("IEX_HOME") || >>>>>> System.user_home()], >>>>>> dir != nil, >>>>>> do: dir |> Path.join(".iex.exs") |> Path.expand() >>>>>> end >>>>>> >>>>>> mix_config_file = >>>>>> List.wrap(Mix.Project.get().cli()[:iex_configuration_file]) >>>>>> >>>>>> candidates >>>>>> |> Enum.filter(&File.regular?/1) >>>>>> |> Enum.take(1) >>>>>> |> Enum.concat(mix_config_file) >>>>>> |> Enum.reduce(state, fn path, state -> >>>>>> eval_dot_iex(state, path) >>>>>> end) >>>>>> end >>>>>> ``` >>>>>> Once again - sorry for the noise if this in not a feature you are >>>>>> interested in introducing! >>>>>> >>>>>> On Thursday, June 6, 2024 at 12:43:09 PM UTC-5 Chris Miller wrote: >>>>>> >>>>>>> Thanks for the reply Jose! The dependency order makes sense as an >>>>>>> issue with my initial thought - one other approach is that a project >>>>>>> could >>>>>>> define its own method of configuring IEx if there were a hook to allow >>>>>>> that >>>>>>> - looking at the IEx.Evaluator I was able to make a pretty small patch >>>>>>> to >>>>>>> allow for this type of configuration by adding a new public function and >>>>>>> extending the `loop` function >>>>>>> >>>>>>> ```elixir >>>>>>> @spec load_dot_iex(pid, pid, String.t()) :: :ok | :error >>>>>>> def load_dot_iex(evaluator, server, path) do >>>>>>> ref = make_ref() >>>>>>> send(evaluator, {:load_dot_iex, server, ref, self(), path}) >>>>>>> >>>>>>> receive do >>>>>>> {^ref, result} -> result >>>>>>> after >>>>>>> 5000 -> :error >>>>>>> end >>>>>>> end >>>>>>> >>>>>>> ... >>>>>>> >>>>>>> defp loop(%{server: server, ref: ref} = state) do >>>>>>> receive do >>>>>>> {:eval, ^server, code, counter, parser_state} -> >>>>>>> {status, parser_state, state} = parse_eval_inspect(code, >>>>>>> counter, parser_state, state) >>>>>>> send(server, {:evaled, self(), status, parser_state}) >>>>>>> loop(state) >>>>>>> >>>>>>> {:fields_from_env, ^server, ref, receiver, fields} -> >>>>>>> send(receiver, {ref, Map.take(state.env, fields)}) >>>>>>> loop(state) >>>>>>> >>>>>>> {:value_from_binding, ^server, ref, receiver, var_name, >>>>>>> map_key_path} -> >>>>>>> value = traverse_binding(state.binding, var_name, >>>>>>> map_key_path) >>>>>>> send(receiver, {ref, value}) >>>>>>> loop(state) >>>>>>> >>>>>>> {:variables_from_binding, ^server, ref, receiver, var_prefix} >>>>>>> -> >>>>>>> value = find_matched_variables(state.binding, var_prefix) >>>>>>> send(receiver, {ref, value}) >>>>>>> loop(state) >>>>>>> >>>>>>> # NEW RECEIVE CASE TO LOAD A DOT IEX FILE PROGRAMMATICALY >>>>>>> {:load_dot_iex, ^server, ref, receiver, path} -> >>>>>>> next_state = load_dot_iex(state, path) >>>>>>> send(receiver, {ref, :ok}) >>>>>>> loop(next_state) >>>>>>> >>>>>>> {:done, ^server, next?} -> >>>>>>> {:ok, next?} >>>>>>> >>>>>>> {:done, ^ref, next?} -> >>>>>>> {:ok, next?} >>>>>>> end >>>>>>> end >>>>>>> ... >>>>>>> >>>>>>> I think that combining this overriding the default mix task would >>>>>>> allow for the type of configuration that I was hoping to achieve - or if >>>>>>> there is desire for this functionality a small change could be >>>>>>> incorporated >>>>>>> into mix to do this as a feature using >>>>>>> `project.cli()[:iex_configuration_file]` or something of the sort. >>>>>>> >>>>>>> If you don't think any of this is necessary in Elixir proper I can >>>>>>> move my work towards something at the project level, but wanted to see >>>>>>> if >>>>>>> there was any interest in upstreaming this concept >>>>>>> On Thursday, June 6, 2024 at 11:40:51 AM UTC-5 José Valim wrote: >>>>>>> >>>>>>>> Hi Chris, thanks for writing. >>>>>>>> >>>>>>>> > • will be used when `iex` is run from that directory not in the >>>>>>>> context of that mix project >>>>>>>> >>>>>>>> The reason this happens is exactly because IEx starts before Mix, >>>>>>>> so we can't use Mix to configure IEx. And I think that will get in >>>>>>>> the way >>>>>>>> of your proposal too. I hope this helps narrow down a bit the paths to >>>>>>>> explore. >>>>>>>> >>>>>>>> On Thu, Jun 6, 2024 at 4:23 PM Chris Miller <camil...@gmail.com> >>>>>>>> wrote: >>>>>>>> >>>>>>>>> Currently we use the `dot-iex` file to configure an iex shell. >>>>>>>>> The `dot-iex` file that gets loaded is the first of these three >>>>>>>>> things that >>>>>>>>> is found >>>>>>>>> • --dot-iex PATH command line argument supplied to the iex command >>>>>>>>> • '.iex.exs' file in the directory that iex is run from >>>>>>>>> • '.iex.exs' file in directory found in the env var "IEX_HOME" OR >>>>>>>>> the users home directory >>>>>>>>> >>>>>>>>> The issue I am facing currently is that project level shell >>>>>>>>> configuration is hard to manage in a way that achieves these goals >>>>>>>>> • will apply configuration when running a shell in the context of >>>>>>>>> a particular (mix) project >>>>>>>>> • will allow for a developer to apply their own particular >>>>>>>>> customization >>>>>>>>> • does not require any additional scripts / arguments to start the >>>>>>>>> project >>>>>>>>> >>>>>>>>> Existing partial solutions for a project level iex configuration >>>>>>>>> >>>>>>>>> • create and commit a `.iex.exs` file for the project >>>>>>>>> -- PROS: >>>>>>>>> • the file will be loaded when `iex -S mix` is run >>>>>>>>> • configuration can be specific to the project as it is part of >>>>>>>>> the source code written for the project and tracked through whatever >>>>>>>>> svc is >>>>>>>>> used >>>>>>>>> -- CONS: >>>>>>>>> • does not allow for an individual developer to include their >>>>>>>>> own configuration as expected (you could add an >>>>>>>>> `import_if_avaiable(".dev.iex.exs")` line to the project level >>>>>>>>> `.iex.exs` >>>>>>>>> file to allow for this extension, but it makes the file name >>>>>>>>> arbitrary and >>>>>>>>> could cause some confusion) >>>>>>>>> • will be used when `iex` is run from that directory not in >>>>>>>>> the context of that mix project >>>>>>>>> >>>>>>>>> • create a project specific configuration file and use the >>>>>>>>> --dot-iex command line arg >>>>>>>>> -- PROS: >>>>>>>>> • does not interfere with running `iex` outside of the context >>>>>>>>> of the mix project >>>>>>>>> • can load additional configuration files by include >>>>>>>>> `import_if_avaiable` statements >>>>>>>>> -- CONS: >>>>>>>>> • Requires including the --dot-iex arg when running the `iex >>>>>>>>> -S mix` command, which is prone to being forgotten, this could be >>>>>>>>> wrapped >>>>>>>>> in a very simple start script, but you would still need to remember >>>>>>>>> to run >>>>>>>>> that (I work with a largish number of elixir services and having >>>>>>>>> individual >>>>>>>>> start scripts or args per project can be cumbersome to remember) >>>>>>>>> >>>>>>>>> I think an ideal solution would be a way to configure a mix >>>>>>>>> project to load a particular configuration file that will be loaded >>>>>>>>> when >>>>>>>>> the IEx.Evaluator starts IN ADDITION to the existing `dot-iex` file >>>>>>>>> options. I believe this would allow for maintainers of a project to >>>>>>>>> normalize some shell configuration while still allowing developers >>>>>>>>> the full >>>>>>>>> ability to add their own configuration while also keeping the >>>>>>>>> workflow of >>>>>>>>> starting the shell more standardized across projects. >>>>>>>>> >>>>>>>>> A secondary goal might be that this could be incorporated into >>>>>>>>> releases as well so that the `./bin/project remote` and similar >>>>>>>>> commands >>>>>>>>> could also load some particular configuration >>>>>>>>> >>>>>>>>> Thanks in advance for any thoughts you had, and if I missed any >>>>>>>>> existing options for this type of configuration, let me know! >>>>>>>>> >>>>>>>>> -- >>>>>>>>> You received this message because you are subscribed to the Google >>>>>>>>> Groups "elixir-lang-core" group. >>>>>>>>> To unsubscribe from this group and stop receiving emails from it, >>>>>>>>> send an email to elixir-lang-co...@googlegroups.com. >>>>>>>>> To view this discussion on the web visit >>>>>>>>> https://groups.google.com/d/msgid/elixir-lang-core/a956613f-7ef1-435c-8aaf-ab3af8058d5dn%40googlegroups.com >>>>>>>>> <https://groups.google.com/d/msgid/elixir-lang-core/a956613f-7ef1-435c-8aaf-ab3af8058d5dn%40googlegroups.com?utm_medium=email&utm_source=footer> >>>>>>>>> . >>>>>>>>> >>>>>>>> -- >>>>>> You received this message because you are subscribed to the Google >>>>>> Groups "elixir-lang-core" group. >>>>>> To unsubscribe from this group and stop receiving emails from it, >>>>>> send an email to elixir-lang-co...@googlegroups.com. >>>>>> >>>>> To view this discussion on the web visit >>>>>> https://groups.google.com/d/msgid/elixir-lang-core/085f777f-3b9c-4ef1-8787-d1396c13fc88n%40googlegroups.com >>>>>> <https://groups.google.com/d/msgid/elixir-lang-core/085f777f-3b9c-4ef1-8787-d1396c13fc88n%40googlegroups.com?utm_medium=email&utm_source=footer> >>>>>> . >>>>>> >>>>> -- >>>> You received this message because you are subscribed to the Google >>>> Groups "elixir-lang-core" group. >>>> To unsubscribe from this group and stop receiving emails from it, send >>>> an email to elixir-lang-core+unsubscr...@googlegroups.com. >>>> To view this discussion on the web visit >>>> https://groups.google.com/d/msgid/elixir-lang-core/a01b0032-13ee-45a1-b59b-5320a70e3322n%40googlegroups.com >>>> <https://groups.google.com/d/msgid/elixir-lang-core/a01b0032-13ee-45a1-b59b-5320a70e3322n%40googlegroups.com?utm_medium=email&utm_source=footer> >>>> . >>>> >>> -- >>> You received this message because you are subscribed to a topic in the >>> Google Groups "elixir-lang-core" group. >>> To unsubscribe from this topic, visit >>> https://groups.google.com/d/topic/elixir-lang-core/qphuwdQxcsc/unsubscribe >>> . >>> To unsubscribe from this group and all its topics, send an email to >>> elixir-lang-core+unsubscr...@googlegroups.com. >>> To view this discussion on the web visit >>> https://groups.google.com/d/msgid/elixir-lang-core/CAGnRm4JX6KYe1En8WsCQeLhHF8SXnMB7jqps-qcwYKQwNWRimw%40mail.gmail.com >>> <https://groups.google.com/d/msgid/elixir-lang-core/CAGnRm4JX6KYe1En8WsCQeLhHF8SXnMB7jqps-qcwYKQwNWRimw%40mail.gmail.com?utm_medium=email&utm_source=footer> >>> . >>> >> -- >> You received this message because you are subscribed to the Google Groups >> "elixir-lang-core" group. >> To unsubscribe from this group and stop receiving emails from it, send an >> email to elixir-lang-core+unsubscr...@googlegroups.com. >> To view this discussion on the web visit >> https://groups.google.com/d/msgid/elixir-lang-core/CAOZBLdORTXogFXez02uX1NCU1dskL2opqFB9HQRpdGAFNEM8NA%40mail.gmail.com >> <https://groups.google.com/d/msgid/elixir-lang-core/CAOZBLdORTXogFXez02uX1NCU1dskL2opqFB9HQRpdGAFNEM8NA%40mail.gmail.com?utm_medium=email&utm_source=footer> >> . >> > -- > You received this message because you are subscribed to a topic in the > Google Groups "elixir-lang-core" group. > To unsubscribe from this topic, visit > https://groups.google.com/d/topic/elixir-lang-core/qphuwdQxcsc/unsubscribe > . > To unsubscribe from this group and all its topics, send an email to > elixir-lang-core+unsubscr...@googlegroups.com. > To view this discussion on the web visit > https://groups.google.com/d/msgid/elixir-lang-core/CAGnRm4Kd6NeDoZQ%2Bx6i%3DwNj4yHK0pmoby5ay_CGkQqDcMCiCRg%40mail.gmail.com > <https://groups.google.com/d/msgid/elixir-lang-core/CAGnRm4Kd6NeDoZQ%2Bx6i%3DwNj4yHK0pmoby5ay_CGkQqDcMCiCRg%40mail.gmail.com?utm_medium=email&utm_source=footer> > . > -- You received this message because you are subscribed to the Google Groups "elixir-lang-core" group. To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-core+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/CAOZBLdOBYmuwaURE0uXNfJa-%2B4hyjbiDjYnkMs5XowXGasNp5g%40mail.gmail.com.