Open rjmholt opened 4 years ago
I wonder if we could get some inspiration by looking at how Roslyn/OmniSharp handles that? There are various NuGet libraries from both of them, maybe we could even re-se some of their code (either as a NuGet package or just extract a few essentials from their ScriptEditor classes)
I had a brief look through Roslyn
and I didn't find much to inspire me, but may not have looked hard enough
Ok, looks like I didn't look hard enough. Here are Roslyn's formatting APIs:
Currently in PSScriptAnalyzer, script formatting occurs by writing a ScriptRule that emits corrections. Formatting is done by running rules one at a time, applying the first of any corrections on each diagnostic, re-assembling and re-parsing the script and running again until all rules have been run.
Looking at this, we should be able to improve the efficiency of formatting significantly with a good implementation, but ideally the design does not constrain the implementation beyond what is essential to the domain problem. Therefore a formatting design should:
A simple proposal for this is:
This could then be encapsulated into an object that actually runs the editors as a formatter:
This design is nice because:
ScriptEditorInfo
object can be passed to the formatter implicitly, without requiring the implementer to hook anything up or opening the possibility that they will hook things up wrongScriptFormatter
object andScriptEditor
base class are free to choose an implementation, whether that serially runs, applies and reparses rules or concurrently runs them, reifies the edits into objects, applies them serially in order, and then reruns those that couldn't be applied (this kind of choice could also be captured by something like anIScriptFormattingStrategy
, to generalise the relationship betweenScriptFormatter
andScriptEditor
)The main drawback is that it's less simple to implement a rule and a formatter in the same class. One way to accomplish this might be a compositional approach, where rules declare themselves to also be formatters with an attribute or by implementing an interface, and then we have a
ScriptEditor
implementation that uses those rules internally:Doing this might enable the traditional approach of rules that format, while encouraging the decoupling of the two functions into two more cohesive APIs.
A final alternative to this is to make formatting APIs purely interface-based:
The big problems here are:
editorInfo
in the first argument and cause issues for the engineScriptEditorInfo
object into implementing classes so we can enforce nice uniqueness/referential equality properties