Closed dankessler closed 6 months ago
I think the problem is happening here where the "configured" version of the layer is already in the hash table, but then the dependency (which has no config) gets added next and overwrites it.
It wouldn't be too hard to add a bit of logic here so that layers that are added earlier get priority (and the hash table is only updated if the key doesn't already exist) which I think would fix this since dependency layers get added after those that are explicitly added by the user, although of course if that logic changes (e.g., gets reversed) we could be right back where we started.
Happy to do a quick PR if this is the desired approach, but I'm new to the deeper internals of spacemacs
and don't want to inadvertantly undermine this behavior if it's a deliberately engineered principle.
you can go ahead and try to fix it
Turns out this is trickier than I thought. As far as I can tell, the hash table, which holds layers and their configs, gets populated three times.
configuration-layer/discover-layers
While my attempt at just making the hash table refuse to take additional entries does prevent step 3 from overwriting step 2, however it also prevents step 2 from overwriting step 1, which is necessary in order for the user config (like disabled-for org
) to have any effect.
Essentially, I think I need to know the rules governing the "addition" operation for layers, i.e., what do we do when a layer (with config) is explicitly declared by a user and it is declared as a dependency (possibly with config) by one or more layers (either explicitly declared or themselves a dependency of an explicitly declared layer or another dependency).
As an example, suppose the user specifies the following for dotspacemacs-configuration-layers
`((auto-completion :variables some-var t :disabled-for org)
other-layer)
and other-layer
has a file layers.el
which specifies
(configuration-layer/declare-layer-dependencies
`(auto-completion :variables some-var nil :disabled-for emacs-lisp)
what should the "winning" configuration of the auto-completion
layer be? It seems reasonably to use the object-add-to-list
function for things like :disabled-for
and perhaps we could do something similar for :variables
(although the extreme case where varx
has different values in the layers being "added" is thorny).
The docstring for configuration-layer/make-layer
suggests that if an obj
(layer) is passed, then the layer-specs
will be copied to it, but that means literally copied overwriting whatever is there. Perhaps this could be changed so that it returns the "union" (in some sensibly defined sense) of the respective slots of both obj
and the specification in layer-specs
.
ideally we should discover layer and identify any dependencies, then topologically sort them by out-degree (number of times being a dependency of other layer), then load the layer config altogether.
layer config declared in dotspacemacs should always take priority over dependency layers. Should they conflict, just throw an error.
we can refrain ourselves that a dependency layer must have empty (or default) config, and when it's also directly declared in dotspacemacs, we just take the config from dotspacemacs.
((layer-name . layer-config) ...)
layers.el
of the layers found in step 1, and store them in a hashtable where keys are names of dependency layers and values are lists of other layers that require them.Note that the total number of layers is rather small, at least currently, so any naive implementation of sorting algorithm won't be too slow.
After all we are only sorting those layers required by other layers, which is of an even smaller number. (Should this number be large, it would already been an issue for our layer system as we explicitly want to avoid dependencies.)
I went searching across GitHub for topological-sort implementations and found links back to this implementation in Common Lisp (but which at a quick glance looks already elisp-compatible).
No other updates for now; I'll need to wrap my head back around the layer discovery/configuration flow, but once I do that I can take a crack at this.
After some more digging and thinking, I believe this is less complex than it appeared.
The only way to declare a dependency is with the function configuration-layer/declare-layer-dependencies
, which takes only layer names. Thus, at present it's not possible to specify further customization when declaring a dependency. In this case, I think the only place the customizations can come into play is with layers that are manually specified by the user.
So, the priority scheme should be that user-specified customizations are always honored (as previously suggested), but I think there's no need to further determine priority among (sub)-dependencies since they are all specified in vanilla form.
A crude hack (which I've confirmed seems to work) is to modify configuration-layer--declare-used-layers
so that it loops over layer-specs
(which adds the customized layers to the hash table), then handles dependencies (which potentially overwrites the customizations), then loops over layer-specs
again (overwriting with the customizations again), but that's ugly.
I'm working on a (hopefully more elegant) solution where I add a slot to the cfgl-layer
class which tracks whether a layer is a "user-layer" (i.e., specified in the dotfile) or not (e.g., a dependency). I then adjust some relevant functions to both set this correctly and to respect it to avoid clobbering user customizations. I'll submit a PR once I have it working locally so that I can get input on the design pattern I'm using.
Along the way I noticed an issue with cfgl-layer
which I've tried to fix in #15376
you can define a subclass user-layer that inherits from our official layer class. And instantiated user-layers can be determined by user-layer-p.
That's an interesting idea. I can then tweak the logic that retrieves/overwrites the hash table of layers to behave (slightly) differently if the object retrieved (or object to be inserted) is of the (say) cfgl-user-layer
subclasss
Still experience this. Any solution besides disabling auto-completion completely?
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Please let us know if this issue is still valid!
Description :octocat:
When I have the
lsp
layer enabled,auto-completion
does not respect the:disabled-for org
property and socompany
remains enabled forOrg
buffers. This seems to be a symptom of a much more general issue where layer dependencies mask user-configured layersReproduction guide :beetle:
SPC b b tmp.org
)Thi
Observed behaviour: :eyes: :broken_heart: Company jumps in to attempt to auto-complete, even though when I load auto-completion, I use
Expected behaviour: :heart: :smile: Company is disabled in
Org
buffers by dint of the:disabled-for org
option given whenauto-completion
is loadedSystem Info :computer:
Explanation
Above I have described how to reproduce this issue specifically for org mode (somewhat relevant to #8175 as I am using the "idiomatic" way of disabling auto-completion for org as documented in the manual), but I think this issue is more general. Because the
lsp
layer declaresauto-completion
as a dependency, spacemacs ignores any configuration I had set explicitly in my(auto-completion :disabled-for org)
invocation. This happens regardless of ordering (I've tried movinglsp
earlier/later in the layer list). A specific consequence is that wheneverlsp
layer is enabled,auto-completion
layer will be enabled and will ignore any user-config specified forauto-completion
layer. For example, in #13464 the OP is trying to do virtually the same thing as me but for python mode, and I notice that they have thelsp
layer enabled. I suspect that whenlsp
's dependencyauto-completion
is loaded, it tramples the configuration OP had specified.From reading through
core-configuration-layer.el
, I think that dependencies are added to the layer hash table last and so mask the original layer object. In my layer definition above, you can see that I've added:variables some-var nil
to theauto-completion
setup. If I run(oref (configuration-layer/get-layer 'auto-completion) :variables)
, the response isnil
. If I disable thelsp
layer and relaunch spacemacs, then not only iscompany
appropriately disabled inorg
buffers, but running(oref (configuration-layer/get-layer 'auto-completion) :variables)
returns thesome-var
variable I had defined.The fix is probably to first check whether "dependency" layers were also explicitly activated by the user, and if so, to just stop there and only add the layer with a "vanilla" configuration if the user did not also explicitly add the layer.