Эффективное редактирование вики-текстов — плагин CodeEditor

From Wiki4Intranet
Jump to: navigation, search
This wikilog article is a draft, it was not published yet.

Вики-статьи, с их возможностью включений, шаблонов, макросов отлично подходят для формирования целостной, самособираемой технической документации по различным проектам. Ведь альтернативы:

  • Офисные форматы с слабыми возможностями включения документов (OpenOffice, Word) — не дотягивают по гибкости.
  • SGML Docbook — было неплохо для 90ых, но протухло и сдохло.
  • LaTeX — неплохо, но наследие ужасной разметки и слабая генерация html-контента — не то.
  • Pandoc-стек с Markdown — очень перспективно, но до сих пор нет стандарта на включение документов (куча фильтров, у каждого свои проблемы).

Основные проблемы написания технических документов с вики-системами и вообще любыми веб-CMS — не очень удобно использовать стандартную textare для разметки (хотя бы из-за того, что там нельзя нажимать «TAB», и она не на полный экран), хочется заюзать все пространство вкладки браузера, и возможности нормального редактора, типа VS Code. Есть всякие такие интеграторы с VS Code, но все-таки не особо удобно, отдельно VS Code с его мешаниной вкладок, отдельно броузер с его вкладками, особенно когда редактируешь кучу документов — надо бы чтобы это было встроено в броузер, чтобы как-то рулить ими (расширение «Tree Style Tab» — почему еще не все с этим живут?).

Для последний версий MediaWiki уже есть https://www.mediawiki.org/wiki/Extension:CodeEditor — очень похоже на то что надо, но наша сборка пока еще (все сил нет обновлять) на замороженных старых версиях MediaWiki, наверно не сработает.

С другой стороны, а почему бы не поставить экстенш прямо в броузер? Собственно более умные редакторы textarea всегда были тем, что хотелось опытным пользователям (сам в нулевых писал на первом механизме FF extension-ов интеграцию с notepad++…), и вот, есть расширение https://addons.mozilla.org/en-US/firefox/addon/code-editor/ , которое затаскивает «почти VS Code» (ну вернее «Monaco Editor», на котором он основан, туда не так легко затаскивать языки из VSCode), прямо в Firefox.

Осталось чуть настроить его, чтобы было удобней русскоязычным пользователям MediaWiki (да, без этого будет не оч)

  • отключить ругань на русские буквы и на непонятное (чортовы «ambigious characters», «invisible characters»)
  • отключить сраный minimap (как я его ненавижу, отключать в каждой новой инсталляции VS Code)
  • включить wordwrap


Скопируйте в настройки экстеншна (moz-extension://9007abec-06c1-4fbe-9dbe-f03ea790271a/view/options.html, в «Default Context») — проще скопировать все, чем обьяснять, что там поменял.

/**
 * @type {Context}
 */
({
    /**
     * {@link https://microsoft.github.io/monaco-editor/docs.html#interfaces/editor.IStandaloneEditorConstructionOptions.html}
     * {@link https://microsoft.github.io/monaco-editor/docs.html#interfaces/editor.IStandaloneDiffEditorConstructionOptions.html}
     */
    options: {
        minimap: {
            enabled: false,
        },
        unicodeHighlight: {
            ambiguousCharacters: false,
            invisibleCharacters: false,
        },        
        lineNumbers: "off",
        theme: "wiki-theme",
        language: "wikitext",
        wordWrap: "on",
        accessibilitySupport: "on",
        accessibilityPageSize: 20,
        scrollBeyondLastLine: true,
        ignoreTrimWhitespace: true,
        useInlineViewWhenSpaceIsLimited: true,
    },
    /**
     * {@link https://microsoft.github.io/monaco-editor/docs.html#interfaces/editor.IActionDescriptor.html}
     */
    actions: {
        "user.toggleWordWarp": {
            label: "Toggle Word Wrap",
            keybindings: [
                "Alt+KeyZ",
            ],
            contextMenuGroupId: "view",
            contextMenuOrder: 4.5,
            run(editor) {
                let wrappingInfo = editor.getOption(monaco.editor.EditorOption.wrappingInfo);
                editor.updateOptions({
                    wordWrapOverride2: wrappingInfo.wrappingColumn == -1 ? 'on' : 'off',
                });
            },
        },
        "user.toggleIgnoreTrimWhitespace": {
            label: "Toggle Show Trim Whitespace Diff",
            precondition: "isInDiffEditor",
            contextMenuGroupId: "view",
            contextMenuOrder: 4.6,
            run() {
                let editor = editorUtil.editor;
                let value = editor._options?.ignoreTrimWhitespace?.value;
                editor.updateOptions({
                    ignoreTrimWhitespace: !value,
                });
            },
        },
    },
    init: [
        {
            func() {
                monaco.languages.register({ id: 'wikitext' });
                monaco.languages.setMonarchTokensProvider("wikitext", {
                    tokenizer: {
                        root: [
                            [/'''[^']+'''/, "bold-quote"],
                        ],
                        whitespace: [
                            [/[ \t\r\n]+/, 'white'],
                            [/<!--/, 'comment', '@comment']
                        ],
                        comment: [
                            [/[^<\-]+/, 'comment.content'],
                            [/-->/, 'comment', '@pop'],
                            [/<!--/, 'comment.content.invalid'],
                            [/[<\-]/, 'comment.content']
                        ],
 
                    },
                });
                // Define a new theme that contains only rules that match this language
                monaco.editor.defineTheme("wiki-theme", {
                    base: "vs",
                    inherit: true,
                    rules: [
                        { token: "bold-quote", foreground: "008800", fontStyle: "bold"  },
                    ],
                    colors: {
                        "editor.foreground": "#000000",
                    },
                });
 
            },
            injectImmediately: true,
        },            
        {
            injectImmediately: true,
            func() {
                let addTouchTools = () => {
                    self.removeEventListener('touchstart', addTouchTools, true);
                    console.debug('addTouchTools');
                    editorUtil.addActions({
                        "user.undo": {
                            label: "Undo",
                            precondition: "textInputFocus && !editorReadonly",
                            contextMenuGroupId: " 1_modification",
                            contextMenuOrder: 11,
                            run(editor) {
                                editor.trigger("", "undo");
                            },
                        },
                        "user.redo": {
                            label: "Redo",
                            precondition: "textInputFocus && !editorReadonly",
                            contextMenuGroupId: " 1_modification",
                            contextMenuOrder: 12,
                            run(editor) {
                                editor.trigger("", "redo");
                            },
                        },
                        "user.paste": {
                            label: "Paste Clipboard Text",
                            precondition: "textInputFocus && !editorReadonly",
                            contextMenuGroupId: "9_cutcopypaste",
                            contextMenuOrder: 4,
                            async run(editor) {
                                // Requires ACCESS_LEVEL >=30
                                if (self.browser) {
                                    try {
                                        await browser.permissions.request({ permissions: ['clipboardRead'] });
                                    } catch (e) {
                                        console.warn(e);
                                    }
                                }
                                try {
                                    let text = await navigator.clipboard.readText();
                                    if (!text) return;
                                    editor.executeEdits("", [{
                                        forceMoveMarkers: true,
                                        range: editor.getSelection(),
                                        text,
                                    }]);
                                } catch (e) {
                                    console.warn(e);
                                } finally {
                                    // await browser.permissions.remove({ permissions: ['clipboardRead'] });
                                }
                            },
                        },
                        "user.delete": {
                            label: "Delete",
                            precondition: "!editorReadonly && editorHasSelection",
                            contextMenuGroupId: "9_cutcopypaste",
                            contextMenuOrder: 5,
                            run(editor) {
                                editor.executeEdits("", [{
                                    forceMoveMarkers: true,
                                    range: editor.getSelection(),
                                    text: "",
                                }]);
                            },
                        },
                        "user.selectAll": {
                            label: "Select All",
                            precondition: "textInputFocus",
                            contextMenuGroupId: "9_cutcopypaste",
                            contextMenuOrder: 6,
                            run(editor) {
                                editor.setSelection(editor.getModel().getFullModelRange());
                            },
                        },
                        "user.find": {
                            label: "Find...",
                            precondition: "textInputFocus && !findWidgetVisible",
                            contextMenuGroupId: "view",
                            contextMenuOrder: 4.9,
                            run() {
                                editor.trigger("", "actions.find");
                            },
                        },
                    });
                };
                self.addEventListener('touchstart', addTouchTools, true);
            },
        },
    ],
})

Ну и при редактировании длинной статьи в наших виках, делайте так:

  • время от времени нажимайте на кнопку «Save» в окне Code-Editor — это еще будет не сохранение статьи, а сохранение в textarea вкладки с открытой на редактирование статьей.
  • а вот в этой вкладке, нажмите на нашу доработку — кнопку «Publish/Опубликовать» справа вверху — т.е. без выхода из режима редактирования вы обновите статью
  • и ее можно превьювить в какой-нибудь другой открытой вкладке — и все это без выхода из режима редактирования без потери контекста где вы находитесь и т.п.
  • если эти вкладки в FF запинить первыми, там можно переключаться между ними с помощью хоткеев «ALT-1», … «ALT-9».

[ List view ]Comments

(no items)

Please login to comment.