// If we have a proper syntax node with a specific type
if (node.name && node.name !== 'Document' && node.from !== node.to) {
const tokenText = this.state.doc.sliceString(node.from, node.to);
return {
start: node.from,
end: node.to,
string: tokenText,
type: node.name
};
}
// For unknown tokens or plain text, find word boundaries manually
const line = this.state.doc.lineAt(offset);
const lineText = line.text;
const posInLine = offset - line.from;
// Find word boundaries - similar to CM v5 behavior
let start = posInLine;
let end = posInLine;
// Move start backwards to find word start
while (start > 0 && /\w/.test(lineText[start - 1])) {
start--;
}
// Move end forwards to find word end
while (end < lineText.length && /\w/.test(lineText[end])) {
end++;
}
// If we're not in a word, try to get the character at cursor
if (start === end) {
if (posInLine < lineText.length) {
end = posInLine + 1;
start = posInLine;
} else if (posInLine > 0) {
start = posInLine - 1;
end = posInLine;
}
}
const tokenText = lineText.slice(start, end);
return {
start: line.from + start,
end: line.from + end,
string: tokenText,
type: null
};
}