Jump to content

Help talk:Extension:CodeMirror

Add topic
From mediawiki.org
Latest comment: 7 days ago by Alien333 in topic What I'd like to see

What I'd like to see

[edit]

I've been developping my own syntax highlighter (still quite bugged, but haven't had much time to work on it) these days, because this has issues:

  • the highlighting is not fully recursive (e.g. italics in templates)
  • the table attributes do not have separate styling
  • the header/footers of Extension:ProofreadPage are not supported, although it doesn't seem that it'd be complicated (phab:T380262)

The new version looked good, and brought features, but it has no script compatibility, as .val()ing the textarea(s) does not do anything anymore. This makes it unusable to me.

(I am aware that not everyone has the same opinions as I do or considers all of these issues, just giving some user feedback.) — Alien  3
3 3
08:44, 2 December 2024 (UTC)Reply

Hi @Alien333!
  • the highlighting is not fully recursive (e.g. italics in templates)
    This may be possible, but I fear it could come with performance problems. There's also the issue that folks want to know if a chunk of text is part of a template call (what we call in the code as "grounding"), so there might be visual conflicts that could lead to confusion. Anyway, please feel free to file a task :)

    The larger issue here is that wikitext is difficult to parse into a grammar-based language tree due to it's superb oddities (consider the image syntax, for example). This is why in CodeMirror 6 we still use a StreamParser – essentially meaning the syntax highlighter tokenizes from "front-to-back", as opposed to MediaWiki which expands variables and templates "inside-out" (something deemed too inefficient for real-time syntax highlighting). So there will always be some tokenizing issues with CodeMirror, I'm afraid.

  • the table attributes do not have separate styling
    That sounds more doable. .cm-mw-table-definition is already applied to attributes, so you can already style them as you see fit. It shouldn't be too difficult to make a separate token for the attribute and its value, so we would be able to style them separately. Please free to create a task for this request as well!
  • the header/footers of Extension:ProofreadPage are not supported, although it doesn't seem that it'd be complicated (phab:T380262)
    Indeed, this should be a straightforward integration. I'll make a patch to ProofreadPage when I find the time. Or if you're interested in helping, I think what we'd want is a CodeMirror PluginModule in ProofreadPage that essentially does the same as the first example at Extension:CodeMirror#JavaScript.

    Slowly but surely, my hope is to have CodeMirror enabled just about everywhere you see wikitext in an editor (DiscussionTools, MobileFrontend editor, etc.).

  • The new version looked good, and brought features, but it has no script compatibility, as .val()ing the textarea(s) does not do anything anymore. This makes it unusable to me.
    I assume you mean like jQuery's val() method? For CodeMirror 6 (and 5) as well as any editor in MediaWiki, the preferred means to fetch or make changes to the document is through jQuery.textSelection. So for example $( '#wpTextbox1' ).textSelection( 'getContents' ) works for CodeMirror (v5 or v6), WikiEditor, the 2003 editor, and even the 2017 wikitext editor. I'll add some notes about this to the docs.
Hopefully this helps. And please, keep the feedback coming! :) MusikAnimal talk 19:14, 3 December 2024 (UTC)Reply
(Thanks for answering. It doesn't look like much, but it is certainly refreshing after facing multiple walls of indifference on the MW side, most notably with V22 recently. Thanks for your work, also.)
For parsing, it is true that we on WS have a peculiar relation to that. Most content pages are quite small (about 600b-2kb), so (in most cases) something that treats the text is unlikely to take too long. Moreover, on the other side, these pages are often markup-heavy (formatting templates all over the place). These two things lead me to preferring thorougher highlighting, but I can understand why it's not the majority opinion. (I don't like grounding, as I find it visually polluting, but that's just my opinion).
For the tasks, I'll create them at some point, but a bit busy right now.
Absolutely agree on the putting CM everywhere.
On textSelection, was aware of its existence, and already used it for caretPosition &c, but didn't think of using it like this. — Alien  3
3 3
18:14, 4 December 2024 (UTC)Reply
I've documented usage of jQuery.textSelection at Extension:CodeMirror#Using jQuery.textSelection. MusikAnimal talk 19:27, 3 December 2024 (UTC)Reply

JS customisation

[edit]

Currently, the section on customising the editor with scripts before/on runtime is very lacking. There is a script on how to call the editor on a random textarea, and there is one on how to write a CodeMirror extension or listen to events, but what if I, for example, want to provide custom keyboard shortcuts to an existing editor? Do I have to write all of that code every single time? Do I need to pass it $( '#wpTextbox1' )? How does it look like, at all? It feels like extending the editor became more complex but the documentation became much more simple at the same time. stjn[ru] 10:26, 3 December 2024 (UTC)Reply

Additionally, ext.codeMirror.initialize hook does not actually give out a CodeMirror instance as written in the table. The only parameter in the relevant code is this.textarea. @MusikAnimal. stjn[ru] 10:42, 3 December 2024 (UTC)Reply
Indeed! The docs were mostly written ahead of development in the spirit of DDD (documentation-driven development – kind of sad there isn't a WP article for this!). ext.codeMirror.initialize is one such example; I just missed it when I finalized the docs. Anyway, the CodeMirror instance will be returned for this hook following gerrit:1099840 (phab:T380913), and incidentally that improvement will make it easier to add custom shortcuts as well. I will add examples to the docs once it is merged.
Generally speaking though, we don't yet have a whole lot of abstraction from the native CodeMirror interface (which is admittedly quite complex). Any and all feedback you have related to that would be great to hear. Some complexity is necessary (there is no global CodeMirror object anymore, for example), but I still want to make it easy to work with as possible.
So without gerrit:1099840, you'd have to add keyboard shortcuts as an Extension using the KeyBinding interface and the keymap Facet:
mw.loader.using( [ 'ext.CodeMirror.v6', 'ext.CodeMirror.v6.mode.mediawiki' ] ).then( ( require ) => {
	const CodeMirror = require( 'ext.CodeMirror.v6' );
	const { EditorView, keymap } = require( 'ext.CodeMirror.v6.lib' );
	const myKeybindingExtension = keymap.of( /** @type {KeyBinding} */ {
		key: 'F1',
		run( /** @type {EditorView} */ view ) {
			// Do stuff
		}
	} );
	const mediawikiLang = require( 'ext.CodeMirror.v6.mode.mediawiki' );
	const cm = new CodeMirror( $( 'textarea' ) );
	cm.initialize( [ cm.defaultExtensions, mediawikiLang(), myKeybindingExtension ] );
} );
or append your Extension after initialization, assuming you still have the CodeMirror instance:
codeMirrorInstance.view.dispatch( {
	effects: StateEffect.appendConfig.of( myKeybindingExtension )
} );
And later, after we have the CodeMirrorKeymap interface:
codeMirrorInstance.keymap.registerKeymapHelp( 'other', 'unique-id', myKeybindingExtension, codeMirrorInstance.view );
But as I'm writing this out, I'm realizing I could make this even simpler. I also don't know that every client who wants to add a keystroke will want it to be documented in the keyboard shortcuts dialog, so there might be a separate registerKeymap() method, too. MusikAnimal talk 18:34, 3 December 2024 (UTC)Reply