| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768 |
- import { EditorState } from '@codemirror/state'
- import { isCursorOnEmptyLine } from './is-cursor-on-empty-line'
- /**
- * Returns the current highlighted range, or the nearest non-whitespace token
- * to the cursor when there is no active selection.
- *
- * "Token" here means any contiguous run of non-whitespace characters (`/\S+/`),
- * not necessarily an alphanumeric word. When two tokens are equidistant the
- * earlier one (closer to document start) wins.
- *
- * Only searches the current line.
- *
- * Only called on user-initiated actions (e.g. "Add comment"), not on every render.
- * Returns null when the cursor is on an empty/whitespace-only line.
- */
- export function selectHighlightedOrNearestToken(
- state: EditorState
- ): { from: number; to: number } | null {
- if (isCursorOnEmptyLine(state)) {
- return null
- }
- const { main } = state.selection
- if (!main.empty) {
- return { from: main.from, to: main.to }
- }
- const pos = main.head
- const line = state.doc.lineAt(pos)
- let bestFrom = 0
- let bestTo = 0
- let bestDist = Infinity
- for (const match of line.text.matchAll(/\S+/g)) {
- const from = line.from + match.index!
- const to = from + match[0].length
- let dist = 0
- if (pos < from) {
- dist = from - pos
- } else if (pos > to) {
- dist = pos - to
- }
- if (dist === 0) {
- return { from, to }
- }
- if (dist < bestDist) {
- bestFrom = from
- bestTo = to
- bestDist = dist
- }
- // Past the cursor — no closer match possible on this line
- if (from > pos) {
- break
- }
- }
- if (bestDist < Infinity) {
- return { from: bestFrom, to: bestTo }
- }
- return null
- }
|