fix: handle edge cases syntax highlight (#3892)
* fix: handle edge cases syntax highlight * chore: remove unused import * chore: remove unused code * chore: reset type code when selection delete
This commit is contained in:
parent
267f3ab051
commit
a6ca2e2bf0
@ -5,7 +5,7 @@ import { MessageStatus } from '@janhq/core'
|
|||||||
import hljs from 'highlight.js'
|
import hljs from 'highlight.js'
|
||||||
|
|
||||||
import { useAtom, useAtomValue } from 'jotai'
|
import { useAtom, useAtomValue } from 'jotai'
|
||||||
import { BaseEditor, createEditor, Editor, Element, Transforms } from 'slate'
|
import { BaseEditor, createEditor, Editor, Transforms } from 'slate'
|
||||||
import { withHistory } from 'slate-history' // Import withHistory
|
import { withHistory } from 'slate-history' // Import withHistory
|
||||||
import {
|
import {
|
||||||
Editable,
|
Editable,
|
||||||
@ -129,14 +129,27 @@ const RichTextEditor = ({
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Editor.isBlock(editor, node) && node.type === 'code') {
|
if (Editor.isBlock(editor, node) && node.type === 'paragraph') {
|
||||||
node.children.forEach((child: { text: any }, childIndex: number) => {
|
node.children.forEach((child: { text: any }, childIndex: number) => {
|
||||||
const text = child.text
|
const text = child.text
|
||||||
|
const { selection } = editor
|
||||||
|
|
||||||
|
if (selection) {
|
||||||
|
const selectedNode = Editor.node(editor, selection)
|
||||||
|
|
||||||
|
if (Editor.isBlock(editor, selectedNode[0] as CustomElement)) {
|
||||||
|
const isNodeEmpty = Editor.string(editor, selectedNode[1]) === ''
|
||||||
|
|
||||||
|
if (isNodeEmpty) {
|
||||||
|
// Reset language when a node is cleared
|
||||||
|
currentLanguage.current = 'plaintext'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Match code block start and end
|
// Match code block start and end
|
||||||
const startMatch = text.match(/^```(\w*)$/)
|
const startMatch = text.match(/^```(\w*)$/)
|
||||||
const endMatch = text.match(/^```$/)
|
const endMatch = text.match(/^```$/)
|
||||||
const inlineMatch = text.match(/^`([^`]+)`$/) // Match inline code
|
|
||||||
|
|
||||||
if (startMatch) {
|
if (startMatch) {
|
||||||
// If it's the start of a code block, store the language
|
// If it's the start of a code block, store the language
|
||||||
@ -144,38 +157,6 @@ const RichTextEditor = ({
|
|||||||
} else if (endMatch) {
|
} else if (endMatch) {
|
||||||
// Reset language when code block ends
|
// Reset language when code block ends
|
||||||
currentLanguage.current = 'plaintext'
|
currentLanguage.current = 'plaintext'
|
||||||
} else if (inlineMatch) {
|
|
||||||
// Apply syntax highlighting to inline code
|
|
||||||
const codeContent = inlineMatch[1] // Get the content within the backticks
|
|
||||||
try {
|
|
||||||
hljs.highlight(codeContent, {
|
|
||||||
language:
|
|
||||||
currentLanguage.current.length > 1
|
|
||||||
? currentLanguage.current
|
|
||||||
: 'plaintext',
|
|
||||||
}).value
|
|
||||||
} catch (err) {
|
|
||||||
hljs.highlight(codeContent, {
|
|
||||||
language: 'javascript',
|
|
||||||
}).value
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate the range for the inline code
|
|
||||||
const length = codeContent.length
|
|
||||||
ranges.push({
|
|
||||||
anchor: {
|
|
||||||
path: [...path, childIndex],
|
|
||||||
offset: inlineMatch.index + 1,
|
|
||||||
},
|
|
||||||
focus: {
|
|
||||||
path: [...path, childIndex],
|
|
||||||
offset: inlineMatch.index + 1 + length,
|
|
||||||
},
|
|
||||||
type: 'code',
|
|
||||||
code: true,
|
|
||||||
language: currentLanguage.current,
|
|
||||||
className: '', // Specify class name if needed
|
|
||||||
})
|
|
||||||
} else if (currentLanguage.current !== 'plaintext') {
|
} else if (currentLanguage.current !== 'plaintext') {
|
||||||
// Highlight entire code line if in a code block
|
// Highlight entire code line if in a code block
|
||||||
const leadingSpaces = text.match(/^\s*/)?.[0] ?? '' // Capture leading spaces
|
const leadingSpaces = text.match(/^\s*/)?.[0] ?? '' // Capture leading spaces
|
||||||
@ -206,7 +187,7 @@ const RichTextEditor = ({
|
|||||||
anchor: { path: [...path, childIndex], offset: 0 },
|
anchor: { path: [...path, childIndex], offset: 0 },
|
||||||
focus: {
|
focus: {
|
||||||
path: [...path, childIndex],
|
path: [...path, childIndex],
|
||||||
offset: leadingSpaces.length,
|
offset: slateTextIndex,
|
||||||
},
|
},
|
||||||
type: 'code',
|
type: 'code',
|
||||||
code: true,
|
code: true,
|
||||||
@ -240,6 +221,7 @@ const RichTextEditor = ({
|
|||||||
slateTextIndex += length
|
slateTextIndex += length
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
|
currentLanguage.current = 'plaintext'
|
||||||
ranges.push({
|
ranges.push({
|
||||||
anchor: { path: [...path, childIndex], offset: 0 },
|
anchor: { path: [...path, childIndex], offset: 0 },
|
||||||
focus: { path: [...path, childIndex], offset: text.length },
|
focus: { path: [...path, childIndex], offset: text.length },
|
||||||
@ -341,35 +323,6 @@ const RichTextEditor = ({
|
|||||||
resetEditor()
|
resetEditor()
|
||||||
} else onStopInferenceClick()
|
} else onStopInferenceClick()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.key === '`') {
|
|
||||||
// Determine whether any of the currently selected blocks are code blocks.
|
|
||||||
const [match] = Editor.nodes(editor, {
|
|
||||||
match: (n) =>
|
|
||||||
Element.isElement(n) && (n as CustomElement).type === 'code',
|
|
||||||
})
|
|
||||||
// Toggle the block type dependsing on whether there's already a match.
|
|
||||||
Transforms.setNodes(
|
|
||||||
editor,
|
|
||||||
{ type: match ? 'paragraph' : 'code' },
|
|
||||||
{ match: (n) => Element.isElement(n) && Editor.isBlock(editor, n) }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (event.key === 'Tab') {
|
|
||||||
const [match] = Editor.nodes(editor, {
|
|
||||||
match: (n) => {
|
|
||||||
return (n as CustomElement).type === 'code'
|
|
||||||
},
|
|
||||||
mode: 'lowest',
|
|
||||||
})
|
|
||||||
|
|
||||||
if (match) {
|
|
||||||
event.preventDefault()
|
|
||||||
// Insert a tab character
|
|
||||||
Editor.insertText(editor, ' ') // Insert 2 spaces
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
[currentPrompt, editor, messages]
|
[currentPrompt, editor, messages]
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user