diff options
Diffstat (limited to 'app/assets/javascripts/content_editor/extensions/code_suggestion.js')
-rw-r--r-- | app/assets/javascripts/content_editor/extensions/code_suggestion.js | 81 |
1 files changed, 81 insertions, 0 deletions
diff --git a/app/assets/javascripts/content_editor/extensions/code_suggestion.js b/app/assets/javascripts/content_editor/extensions/code_suggestion.js new file mode 100644 index 00000000000..c70a96769fb --- /dev/null +++ b/app/assets/javascripts/content_editor/extensions/code_suggestion.js @@ -0,0 +1,81 @@ +import { lowlight } from 'lowlight/lib/core'; +import { textblockTypeInputRule } from '@tiptap/core'; +import { PARSE_HTML_PRIORITY_HIGHEST } from '../constants'; +import { memoizedGet } from '../services/utils'; +import CodeBlockHighlight from './code_block_highlight'; + +const backtickInputRegex = /^```suggestion[\s\n]$/; + +export default CodeBlockHighlight.extend({ + name: 'codeSuggestion', + + isolating: true, + + addOptions() { + return { + lowlight, + config: {}, + }; + }, + + addAttributes() { + return { + ...this.parent?.(), + language: { + default: 'suggestion', + }, + isCodeSuggestion: { + default: true, + }, + }; + }, + + addCommands() { + const ext = this; + + return { + insertCodeSuggestion: (attributes) => async ({ editor }) => { + // do not insert a new suggestion if already inside a suggestion + if (editor.isActive('codeSuggestion')) return false; + + const rawPath = ext.options.config.diffFile.view_path.replace('/blob/', '/raw/'); + const allLines = (await memoizedGet(rawPath)).split('\n'); + const { line } = ext.options.config; + let { lines } = ext.options.config; + + if (!lines.length) lines = [line]; + + const content = lines.map((l) => allLines[l.new_line - 1]).join('\n'); + const lineNumbers = `-${lines.length - 1}+0`; + + editor.commands.insertContent({ + type: 'codeSuggestion', + attrs: { langParams: lineNumbers, ...attributes }, + // empty strings are not allowed in text nodes + content: [{ type: 'text', text: content || ' ' }], + }); + + return true; + }, + }; + }, + + parseHTML() { + return [ + { + priority: PARSE_HTML_PRIORITY_HIGHEST, + tag: 'pre[lang="suggestion"]', + }, + ]; + }, + + addInputRules() { + return [ + textblockTypeInputRule({ + find: backtickInputRegex, + type: this.type, + getAttributes: () => ({ language: 'suggestion', langParams: '-0+0' }), + }), + ]; + }, +}); |