Page MenuHomePhabricator

Add preferences to select between available linters in CodeMirror
Open, Needs TriagePublic

Description

In T407153, we provided an additional lint source for wikitext editing, so now we have both WikiLint and Parsoid linting running side-by-side. They will often overlap, and potentially disagree.

We should provide preference(s) permitting users to select which linters they want (none, one or the other, or both).

Technical notes

We currently only support boolean preferences in CodeMirror. We can get away with the status quo here because we want to allow users to toggle each linter off independently, meaning they can live as separate preferences. However, it might make things a bit clunky; For example the new preferences for WikiLint and Parsoid would need to be dependent on the "Lint the code" preference.

I think more ideally, the existing lint preference could take a string or numerical ID, so 0 for no linting, wikilint / 1, or parsoid/ 2. Strings will be more future-proof as linters change, but IDs are better for storage. If we go the route of non-boolean preferences, this will need to be carefully thought out. $wgCodeMirrorDefaultPreferences is also ill-prepared for this, as it interprets true/false as whether the preference should be on or off by default, and string values as content models and numbers as namespace IDs. Thus we'll likely need something like $wgCodeMirrorDefaultPreferenceValues that supplements the existing config setting. It would only be used for preferences that take non-boolean values, as a means to specify which value should be the default. Whether the preference is on or off by default, and for which namespace and/or content model, would still be dictated by $wgCodeMirrorDefaultPreferences.

CodeMirrorPreferences should be able to interpret all config settings and generate a sensible UI without any knowledge of what the preferences are or what they mean. This will mean we can freely add and remove features without having to maintain anything beyond configuration.

Event Timeline

I think we can prepare a JS interface first so that experienced users can start customizing in their user scripts.

Change #1270190 had a related patch set uploaded (by Bhsd; author: Bhsd):

[mediawiki/extensions/CodeMirror@master] CodeMirrorLint: JavaScript interface to disable specific linters

https://gerrit.wikimedia.org/r/1270190

r1270190 proposes user script customization like this:

mw.hook( 'ext.CodeMirror.ready' ).add( ( cm ) => {
    // Disable the client-side linter using a web worker, including WikiLint, ESLint, Stylelint, Luacheck and AbuseFilter Analyzer
    // Further customization is possible by checking `cm.mode`
    if ( cm.lintSource ) {
        cm.lintSource.disabled = true;

        // WikiLint
        if ( cm.mode === 'mediawiki' ) {
            cm.lintSource.disabled = true;
        }

        // ESLint
        if ( cm.mode === 'javascript' ) {
            cm.lintSource.disabled = true;
        }

        // Stylelint
        if ( cm.mode === 'css' ) {
            cm.lintSource.disabled = true;
        }

        // Luacheck
        if ( cm.mode === 'lua' ) {
            cm.lintSource.disabled = true;
        }

        // AbuseFilter Analyzer
        if ( cm.mode === 'abusefilter' ) {
            cm.lintSource.disabled = true;
        }
    }

    // Disable the server-side linter using API, including Parsoid, Peast, Extension:TemplateStyles, Extension:Scribunto and Extension:AbuseFilter
    // Further customization is possible by checking `cm.mode`
    if ( cm.lintApi ) {
        cm.lintApi.disabled = true;

        // Parsoid
        if ( cm.mode === 'mediawiki' ) {
            cm.lintApi.disabled = true;
        }

        // Peast
        if ( cm.mode === 'javascript' ) {
            cm.lintApi.disabled = true;
        }

        // TemplateStyles (only available for sanitized-css)
        if ( cm.mode === 'css' ) {
            cm.lintApi.disabled = true;
        }

        // Scribunto
        if ( cm.mode === 'lua' ) {
            cm.lintApi.disabled = true;
        }

        // AbuseFilter
        if ( cm.mode === 'abusefilter' ) {
            cm.lintApi.disabled = true;
        }
    }
} );

I see value in the JS interface regardless, so yes, let's do it :)

I have not forgotten about the subtask T420429 and hope to have something show soon.

Change #1270190 merged by jenkins-bot:

[mediawiki/extensions/CodeMirror@master] CodeMirrorLint: JavaScript interface to disable specific linters

https://gerrit.wikimedia.org/r/1270190