Extensible / multiline config?

In my package (pandoc-pdf, not yet published), I would like to enable the user to configure different behavior for different file extensions.

Concretely that means having a mapping from strings that define file extensions to strings that specify the behavior. For example:

“md” → “gfm”
“text” → “markdown+hard_line_breaks”

It should be up to the user how many and which extensions are configured; the list can also be empty.

Because of the latter requirement, I can not simply include a sequence of config settings in the package.

I could instruct the user to instead edit config.cson manually, as is required by some other packages, too. Maybe like this:

pandoc-pdf:
    ...
    pandocMap:
      "md": "gfm"
      "text": "markdown+hard_line_breaks"

The drawback is that these settings show up slightly weird in the settings dialog:

I guess I could add a hook that adds normalized descriptions like Extension 'md' instead of Pandoc Map Md.

Another possibility would be to use a multiline text field that contains something like

md: gfm
text: markdown+hard_line_breaks

which I then parse myself. It is possible to put multiline strings into a config value, and it shows up as a scrollable text field, which is however styled to a height of 50px and therefore unusable. I guess I could try hacking the CSS, but doesn’t seem like a good idea.

What do you think / recommend?

Before I dive into it… I think the package settings are one of the areas that definitely needs improvement. The existing field types are a troublesome to work with and there could be many more types to add (e.g. radio buttons, checkboxes, textareas).

The existing the array type feels very neglected, its uncomfortable for the user (“add a comma-separated list!”) and is prone to errors (elements cannot include a comma, I guess). I think Visual Studio Code solved this much better.

For comparison, here is how the array type works in Atom:

I’m mentioning the array field type, because it could be a field that suits your needs. At the worst, you could enter key/value pairs (e.g. md=gfm,text=markdown+had_line_breaks). At best, there would be a field type for that.

But, of course, the “hackable text editor for the 21st Century” offers many ways to achieve the same (or similar).

Custom HTML View

Atom is all HTML, so you could always create a custom view to circumvent the limitations of the existing package settings. Settings could be stored elsewhere (not in config.cson, e.g. localStorage), so the package settings view doesn’t get cluttered.

Alternatively, you could use commands to add/edit/remove settings and use list-views and modals to handle the data.

Sublime Text-inspired

Similarly to the above, you could simply store an object (e.g. as JSON, CSON or YAML) in localStorage and simply have the user edit it in Atom. This saves you from creating an interactive HTML view, but you still have to think about the save process. As far as I know, you cannot intercept the save event to prevent it from saving a file to the disk and instead save it elsewhere – please correct me if I’m wrong!

1 Like

@idleberg, thanks a lot for your extensive answer.

types to add (e.g. radio buttons, checkboxes, textareas)

Agreed. For my purpose ideal would be
a) to be able to generate suboptions of the same structure via a + button and
b) name-value fields.

I thought about the options you describe:

Arrays: uncomfortable for the user, indeed. Why not ask them to enter JSON code. :wink:

Custom HTML View, i.e. localStorage + extra view: I actually like that the config settings are in a standard and user-modifiable place. And users expect settings to be in the Settings dialog.

Sublime Text-inspired, i.e. user-edited config: Then I would have to think about the proper place to put it, maybe create `~/.config/pandoc-pdf/settings.cson, take care of other platforms…

All three are definitely possibilities, thanks! I guess it also depends on the complexity of the additional settings.


I have come up with another alternative, which I find semi-comfortable, and which is relatively easy to implement:

  1. Make the package activated on load. This is necessary for the manipulations below to affect the settings pane visible to users.

  2. Split the configuration into a static and a dynamic part:

  3. The static part contains a field where the user can enter a comma-delimited list of extensions:

    'pandocInputFormats': {
          'type': 'object',
          'order': 6,
          'properties': {
            'fileExtensions': {
              'title': 'File Extensions:',
              'type': 'string',
              'default': ''
            }
          }
        }
    

    In the example, the user would set "md,text".

  4. The dynamic part is generated by code on package activation = load:

    exts = atom.config.get('pandoc-pdf.pandocInputFormats.fileExtensions')
    props = this.config.pandocInputFormats.properties
    for (let ext of exts.split(',')) {
      if (ext != '') {
        props[ext] = {
          title: 'Input Format for .' + ext,
          type: 'string',
          default: ''
        }
      }
    }
    

    After modifying the list of extensions, the user has to restart / reload Atom so that the extra entries in the package config object are generated. That is the not-entirely-comfortable part.

Peek 2020-01-08 23-55

I experimented with re-creating the dynamic entries upon

atom.config.onDidChange('pandoc-pdf.pandocInputFormats.fileExtensions', ...)

That works as far as the config object is concerned, but the settings view is not updated accordingly. If anyone knows how to affect such an update, tell me.

I’m coming back to this thread as I’ve been further thinking about potential improvements for package settings. Maybe we can collect them here before writing a feature request or even contribute a PR to the settings-view package.

Here are some mentioned earlier and some new ones:

  • additional types
    • text areas
    • radio button groups
    • key / value pairs
    • file / folder selection (e.g. to select compilers, build folders etc.)
    • buttons / button groups
  • GUI
    • add / remove / edit array items (like in Visual Studio Code, see above)
    • ranges for numeric inputs with min / max value (like input type="range")
  • callback functions similar to inquirer.js
    • conditional disabling
    • conditional display (e.g. for OS-specific or interdependent settings)
    • input validation
    • filters (manipulate input prior to calling atom.config.get())
  • other
    • search filter for all settings, similar to Visual Studio Code
    • hidden settings (programmatic settings, hidden from the settings view)
    • descriptions for object type

Please add your ideas!

2 Likes

All good things.

I feel publishing a new package would be the quickest way to iterate and release changes. Things are slow as it is, and a massive change like this would probably take a long time to be reviewed. Then again, it’s also impactful, so it might be prioritised :man_shrugging:

1 Like