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

From Wiki4Intranet
Jump to: navigation, search
This wikilog article is a draft, it was not published yet.
 
(13 intermediate revisions by the same user not shown)
Line 5: Line 5:
 
* Pandoc-стек с Markdown — очень перспективно, но до сих пор нет стандарта на включение документов (куча фильтров, у каждого свои проблемы).
 
* Pandoc-стек с Markdown — очень перспективно, но до сих пор нет стандарта на включение документов (куча фильтров, у каждого свои проблемы).
  
Основные проблемы написания технических документов с вики-системами и вообще любыми веб-CMS — не очень удобно использовать стандартную textare для разметки, хочется заюзать все пространство вкладки браузера, и возможности нормального редактора, типа VS Code.  
+
Основные проблемы написания технических документов с вики-системами и вообще любыми веб-CMS — не очень удобно использовать стандартную textare для разметки (хотя бы из-за того, что там нельзя нажимать «TAB», и она не на полный экран), хочется заюзать все пространство вкладки браузера, и возможности нормального редактора, типа VS Code.  
Есть [https://github.com/Frederisk/Wikitext-Extension-Gadget всякие такие] интеграторы с VS Code, но все-таки не особо удобно, отдельно VS Code с его мешаниной вкладок, отдельно броузер с его вкладками, особенно когда редактируешь кучу документов — надо бы чтобы это было встроено в броузер, чтобы как-то рулить ими («Tree Style Tab» — почему еще не все с этим живут?).
+
Есть [https://github.com/Frederisk/Wikitext-Extension-Gadget всякие такие] интеграторы с VS Code, но все-таки не особо удобно, отдельно VS Code с его мешаниной вкладок, отдельно броузер с его вкладками, особенно когда редактируешь кучу документов — надо бы чтобы это было встроено в броузер, чтобы как-то рулить ими (расширение «[https://addons.mozilla.org/en-US/firefox/addon/tree-style-tab/ Tree Style Tab]» — почему еще не все с этим живут?).
  
 
Для последний версий MediaWiki уже есть https://www.mediawiki.org/wiki/Extension:CodeEditor — очень похоже на то что надо, но наша сборка пока еще (все сил нет обновлять) на замороженных старых версиях MediaWiki, наверно не сработает.
 
Для последний версий MediaWiki уже есть https://www.mediawiki.org/wiki/Extension:CodeEditor — очень похоже на то что надо, но наша сборка пока еще (все сил нет обновлять) на замороженных старых версиях MediaWiki, наверно не сработает.
  
С другой стороны, а почему бы не поставить экстенш прямо в броузер? Собственно более умные редакторы textarea всегда были тем, что хотелось опытным пользователям (сам в нулевых писал на первом механизме FF extensionнов интеграцию с notepad++…), и вот, есть расширение  
+
С другой стороны, а почему бы не поставить экстенш прямо в броузер? Собственно более умные редакторы textarea всегда были тем, что хотелось опытным пользователям (сам в нулевых писал на первом механизме FF extension-ов интеграцию с notepad++…), и вот, есть расширение  
https://addons.mozilla.org/en-US/firefox/addon/code-editor/ , которое затаскивает «почти VS Code» (ну вернее «Monaco Editor», на котором он основан), прямо в Firefox.  
+
https://addons.mozilla.org/en-US/firefox/addon/code-editor/ , которое затаскивает «почти VS Code» (ну вернее «Monaco Editor», на котором он основан, [https://stackoverflow.com/questions/56254150/how-do-textmate-grammars-and-themes-work-with-vscode туда не так легко затаскивать языки из VSCode]), прямо в Firefox.  
  
 
Осталось чуть настроить его, чтобы было удобней русскоязычным пользователям MediaWiki (да, без этого будет не оч)
 
Осталось чуть настроить его, чтобы было удобней русскоязычным пользователям MediaWiki (да, без этого будет не оч)
 +
* отключить ругань на русские буквы и на непонятное (чортовы «ambigious characters», «invisible characters»)
 +
* отключить сраный minimap (как я его ненавижу, отключать в каждой новой инсталляции VS Code)
 +
* включить wordwrap
 +
  
<source code="javascript">
+
 
/**
+
Скопируйте в настройки экстеншна (moz-extension://9007abec-06c1-4fbe-9dbe-f03ea790271a/view/options.html, в «Default Context») — проще скопировать все, чем обьяснять, что там поменял.
* @type {Context}
+
{{:code-editor-firefox-default-context-for-mediawiki}}
*/
+
 
({
+
Ну и при редактировании длинной статьи в наших виках, делайте так:
    /**
+
* время от времени нажимайте на кнопку «Save» в окне Code-Editor — это еще будет не сохранение статьи, а сохранение в textarea вкладки с открытой на редактирование статьей.
    * {@link https://microsoft.github.io/monaco-editor/docs.html#interfaces/editor.IStandaloneEditorConstructionOptions.html}
+
* а вот в этой вкладке, нажмите на нашу доработку — кнопку «Publish/Опубликовать» справа вверху — т.е. без выхода из режима редактирования вы обновите статью
    * {@link https://microsoft.github.io/monaco-editor/docs.html#interfaces/editor.IStandaloneDiffEditorConstructionOptions.html}
+
* и ее можно превьювить в какой-нибудь другой открытой вкладке — и все это без выхода из режима редактирования без потери контекста где вы находитесь и т.п.  
    */
+
* если эти вкладки в FF запинить первыми, там можно переключаться между ними с помощью хоткеев «ALT-1», … «ALT-9».
    options: {
+
        minimap: {
+
            enabled: false,
+
        },
+
        unicodeHighlight: {
+
            ambiguousCharacters: false,
+
        },       
+
        theme: "vs",
+
        language: "plaintext",
+
        wordWrap: "off",
+
        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() {
+
                // console.log("ext-code-editor.init");
+
            },
+
            args: [],
+
            injectImmediately: false,
+
        },
+
        {
+
            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);
+
            },
+
        },
+
    ],
+
})
+
</source>
+

Latest revision as of 12:02, 17 April 2024

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

  • Офисные форматы с слабыми возможностями включения документов (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».