UNPKG

@bhsd/codemirror-mediawiki

Version:

Modified CodeMirror mode based on wikimedia/mediawiki-extensions-CodeMirror

345 lines (344 loc) 12.4 kB
import { keymap, highlightSpecialChars, highlightActiveLine, highlightWhitespace, highlightTrailingWhitespace, scrollPastEnd, drawSelection, rectangularSelection, crosshairCursor, } from '@codemirror/view'; import { EditorState } from '@codemirror/state'; import { highlightSelectionMatches } from '@codemirror/search'; import { closeBrackets, autocompletion, acceptCompletion, completionKeymap, startCompletion, } from '@codemirror/autocomplete'; import { json } from '@codemirror/lang-json'; import { autoCloseTags } from '@codemirror/lang-html'; import { getLSP } from '@bhsd/browser'; import { colorPicker as cssColorPicker, colorPickerTheme, makeColorPicker } from '@bhsd/codemirror-css-color-picker'; import colorPicker, { discoverColors } from './color'; import { mediawiki } from './mediawiki'; import escape from './escape'; import codeFolding, { mediaWikiFold, foldHandler } from './fold'; import tagMatchingState from './matchTag'; import refHover from './ref'; import magicWordHover from './hover'; import signatureHelp from './signature'; import inlayHints from './inlay'; import { getWikiLintSource, getJsLintSource, getCssLintSource, getJsonLintSource, getLuaLintSource, getVueLintSource, getHTMLLintSource, } from './lintsource'; import openLinks from './openLinks'; import { tagModes, getStaticMwConfig } from './static'; import bidiIsolation from './bidi'; import toolKeymap from './keymap'; import bracketMatching from './matchBrackets'; import statusBar from './statusBar'; import { detectIndent } from './indent'; import javascript from './javascript'; import css from './css'; import lua from './lua'; import vue from './vue'; import html from './html'; import { CodeMirror6, avail, languages, linterRegistry, destroyListeners, plain, optionalFunctions, themes, } from './codemirror'; export { CodeMirror6 }; /** * 注册通用扩展 * @param name 扩展名 * @param ext 扩展 */ const registerExtension = (name, ext) => { avail[name] ??= []; const addon = avail[name]; addon[0] = ext; }; /** Register the `highlightSpecialChars` extension */ export const registerHighlightSpecialChars = () => { registerExtension('highlightSpecialChars', highlightSpecialChars); }; /** Register the `highlightActiveLine` extension */ export const registerHighlightActiveLine = () => { registerExtension('highlightActiveLine', highlightActiveLine); }; /** Register the `highlightWhitespace` extension */ export const registerHighlightWhitespace = () => { registerExtension('highlightWhitespace', highlightWhitespace); }; /** Register the `highlightTrailingWhitespace` extension */ export const registerHighlightTrailingWhitespace = () => { registerExtension('highlightTrailingWhitespace', highlightTrailingWhitespace); }; /** Register the `highlightSelectionMatches` extension */ export const registerHighlightSelectionMatches = () => { registerExtension('highlightSelectionMatches', highlightSelectionMatches); }; /** Register the `bracketMatching` extension */ export const registerBracketMatching = () => { registerExtension('bracketMatching', ([config, e = []] = []) => [ bracketMatching(config), e, ]); }; /** Register the `closeBrackets` extension */ export const registerCloseBrackets = () => { registerExtension('closeBrackets', (e = []) => [closeBrackets(), e]); }; /** Register the `scrollPastEnd` extension */ export const registerScrollPastEnd = () => { registerExtension('scrollPastEnd', scrollPastEnd); }; /** Register the `allowMultipleSelections` extension */ export const registerAllowMultipleSelections = () => { registerExtension('allowMultipleSelections', () => [ EditorState.allowMultipleSelections.of(true), drawSelection(), rectangularSelection(), crosshairCursor(), ]); }; /** Register the `autocompletion` extension */ export const registerAutocompletion = () => { registerExtension('autocompletion', () => [ autocompletion({ defaultKeymap: false }), keymap.of([ ...completionKeymap.filter(({ run }) => run !== startCompletion), { key: 'Shift-Enter', run: startCompletion }, { key: 'Tab', run: acceptCompletion }, ]), ]); }; /** Register the `codeFolding` extension */ export const registerCodeFolding = () => { registerExtension('codeFolding', codeFolding); }; /** Register the `colorPicker` extension */ export const registerColorPicker = () => { registerExtension('colorPicker', colorPicker); }; /** 注册所有通用扩展(除`colorPicker`) */ const registerExtensions = () => { registerHighlightSpecialChars(); registerHighlightActiveLine(); registerHighlightWhitespace(); registerHighlightTrailingWhitespace(); registerHighlightSelectionMatches(); registerBracketMatching(); registerCloseBrackets(); registerScrollPastEnd(); registerAllowMultipleSelections(); registerAutocompletion(); registerCodeFolding(); }; /** Register all common extensions */ export const registerCommonExtensions = () => { registerExtensions(); registerColorPicker(); }; function mediawikiOnly(ext) { return typeof ext === 'function' ? [(enable, cm) => enable ? ext(cm) : [], { mediawiki: true }] : [(e = []) => e, { mediawiki: ext }]; } /** * 注册特定语言的扩展 * @param lang 语言 * @param name 扩展名 * @param ext 扩展 */ const registerLangExtension = (lang, name, ext) => { avail[name] ??= [() => []]; const addon = avail[name]; addon[1] ??= {}; addon[1][lang] = ext; }; /** Register MediaWiki language support */ export const registerMediaWiki = () => { registerCommonExtensions(); registerMediaWikiCore(); registerOpenLinks(); registerEscape(); registerRefHover(); registerHover(); registerSignatureHelp(); registerInlayHints(); registerColorPickerForMediaWiki(); registerBracketMatchingForMediaWiki(); registerCodeFoldingForMediaWiki(); }; /** * 注册MediaWiki专用扩展 * @param name 扩展名 * @param ext 扩展 */ const registerExtensionForMediaWiki = (name, ext) => { avail[name] ??= mediawikiOnly(ext); }; /** Register the `openLinks` extension */ export const registerOpenLinks = () => { registerExtensionForMediaWiki('openLinks', openLinks); }; /** Register the `escape` extension */ export const registerEscape = () => { registerExtensionForMediaWiki('escape', escape); }; /** Register the `refHover` extension */ export const registerRefHover = () => { registerExtensionForMediaWiki('refHover', refHover); }; /** Register the `hover` extension */ export const registerHover = () => { registerExtensionForMediaWiki('hover', magicWordHover); }; /** Register the `signatureHelp` extension */ export const registerSignatureHelp = () => { registerExtensionForMediaWiki('signatureHelp', signatureHelp); }; /** Register the `inlayHints` extension */ export const registerInlayHints = () => { registerExtensionForMediaWiki('inlayHints', inlayHints); }; /** Register the `colorPicker` extension for MediaWiki */ export const registerColorPickerForMediaWiki = () => { registerLangExtension('mediawiki', 'colorPicker', [ [makeColorPicker({ discoverColors }), colorPickerTheme], { marginLeft: '.6ch' }, ]); }; /** Register the `bracketMatching` extension for MediaWiki */ export const registerBracketMatchingForMediaWiki = () => { registerLangExtension('mediawiki', 'bracketMatching', [ { brackets: '()[]{}()【】[]{}' }, tagMatchingState, ]); }; /** Register the `codeFolding` extension for MediaWiki */ export const registerCodeFoldingForMediaWiki = () => { registerLangExtension('mediawiki', 'codeFolding', mediaWikiFold); optionalFunctions.foldHandler = foldHandler; }; /** * 注册LintSource * @param lang 语言 * @param lintSource */ const registerLintSource = (lang, lintSource) => { linterRegistry[lang] = lintSource; optionalFunctions.statusBar = statusBar; }; /** Register MediaWiki core language support */ export const registerMediaWikiCore = () => { CodeMirror6.getMwConfig = (config) => getStaticMwConfig(config, tagModes); languages['mediawiki'] = (config) => [ mediawiki(config), plain(), bidiIsolation, toolKeymap, ]; registerLintSource('mediawiki', getWikiLintSource); destroyListeners.push(view => getLSP(view)?.destroy()); }; /** Register mixed MediaWiki-HTML language support */ export const registerHTML = () => { registerCommonExtensions(); registerHTMLCore(); registerCloseBracketsForHTML(); registerColorPickerForHTML(); }; /** Register the `closeBrackets` extension for mixed MediaWiki-HTML */ export const registerCloseBracketsForHTML = () => { registerLangExtension('html', 'closeBrackets', autoCloseTags); }; /** Register the `colorPicker` extension for mixed MediaWiki-HTML */ export const registerColorPickerForHTML = () => { registerLangExtension('html', 'colorPicker', [cssColorPicker]); }; /** Register mixed MediaWiki-HTML core language support */ export const registerHTMLCore = () => { languages['html'] = html; registerLintSource('html', getHTMLLintSource); optionalFunctions.detectIndent = detectIndent; }; /** Register JavaScript language support */ export const registerJavaScript = () => { registerExtensions(); registerJavaScriptCore(); }; /** Register JavaScript core language support */ export const registerJavaScriptCore = () => { languages['javascript'] = javascript; registerLintSource('javascript', getJsLintSource); optionalFunctions.detectIndent = detectIndent; }; /** Register CSS language support */ export const registerCSS = () => { registerCommonExtensions(); registerCSSCore(); registerColorPickerForCSS(); }; /** Register the `colorPicker` extension for CSS */ export const registerColorPickerForCSS = () => { registerLangExtension('css', 'colorPicker', [cssColorPicker]); }; /** Register CSS core language support */ export const registerCSSCore = () => { languages['css'] = css; registerLintSource('css', getCssLintSource); optionalFunctions.detectIndent = detectIndent; }; /** Register JSON language support */ export const registerJSON = () => { registerExtensions(); registerJSONCore(); }; /** Register JSON core language support */ export const registerJSONCore = () => { languages['json'] = json; registerLintSource('json', getJsonLintSource); optionalFunctions.detectIndent = detectIndent; }; /** Register Lua language support */ export const registerLua = () => { registerExtensions(); registerLuaCore(); }; /** Register Lua core language support */ export const registerLuaCore = () => { languages['lua'] = lua; registerLintSource('lua', getLuaLintSource); optionalFunctions.detectIndent = detectIndent; }; /** Register Vue language support */ export const registerVue = () => { registerCommonExtensions(); registerVueCore(); registerCloseBracketsForVue(); registerColorPickerForVue(); }; /** Register the `closeBrackets` extension for Vue */ export const registerCloseBracketsForVue = () => { registerLangExtension('vue', 'closeBrackets', autoCloseTags); }; /** Register the `colorPicker` extension for Vue */ export const registerColorPickerForVue = () => { registerLangExtension('vue', 'colorPicker', [cssColorPicker]); }; /** Register Vue core language support */ export const registerVueCore = () => { languages['vue'] = vue; registerLintSource('vue', getVueLintSource); optionalFunctions.detectIndent = detectIndent; }; /** * Register a custom language support * @param name language name * @param lang language support * @param lintSource optional linter */ export const registerLanguage = (name, lang, lintSource) => { registerCommonExtensions(); registerLanguageCore(name, lang, lintSource); }; /** * Register a custom language support without common extensions * @param name language name * @param lang language support * @param lintSource optional linter */ export const registerLanguageCore = (name, lang, lintSource) => { languages[name] = lang; if (lintSource) { registerLintSource(name, lintSource); } }; export const registerTheme = (name, theme) => { themes[name] = theme; }; export { nord } from './theme';