functions to get information about the current matching texts of a SearchQuery #3

Closed
opened 2024-06-14 18:04:38 +02:00 by massifrg · 3 comments
massifrg commented 2024-06-14 18:04:38 +02:00 (Migrated from github.com)

In my editor, the search and replace dialog has a text showing information about the current match and the total number of texts matching. Something like "Occurence #3 of 23 matching texts".

I noticed you don't want to expose the deco field of decorations of the current SearchState.

So I'm proposing these functions to expose those infos, while keeping the decorations hidden:

/// Get the ranges of matching texts in the current active search.
/// Will return `undefined` is the search plugin isn't active.
export function getSearchMatchingRanges(state: EditorState): { from: number, to: number }[] | undefined {
  const searchState = searchKey.getState(state)
  return searchState && searchState.deco.find().map(({ from, to }) => ({ from, to }))
}

/// Get the number of matching texts in the current active search.
/// Will return `undefined` is the search plugin isn't active.
export function getSearchMatchesCount(state: EditorState): number | undefined {
  return getSearchMatchingRanges(state)?.length
}

/// Get the index of the match of the current active search
/// that has the same range of the current selection.
/// Will return -1 if no matching text matches the selection,
/// or `undefined` is the search plugin isn't active.
export function getSearchCurrentMatchIndex(state: EditorState): number | undefined {
  const ranges = getSearchMatchingRanges(state)
  const { from: selFrom, to: selTo } = state.selection
  return ranges && ranges.findIndex(({ from, to }) => from === selFrom && to === selTo)
}
In my editor, the search and replace dialog has a text showing information about the current match and the total number of texts matching. Something like "Occurence #3 of 23 matching texts". I noticed you don't want to expose the `deco` field of decorations of the current `SearchState`. So I'm proposing these functions to expose those infos, while keeping the decorations hidden: ```ts /// Get the ranges of matching texts in the current active search. /// Will return `undefined` is the search plugin isn't active. export function getSearchMatchingRanges(state: EditorState): { from: number, to: number }[] | undefined { const searchState = searchKey.getState(state) return searchState && searchState.deco.find().map(({ from, to }) => ({ from, to })) } /// Get the number of matching texts in the current active search. /// Will return `undefined` is the search plugin isn't active. export function getSearchMatchesCount(state: EditorState): number | undefined { return getSearchMatchingRanges(state)?.length } /// Get the index of the match of the current active search /// that has the same range of the current selection. /// Will return -1 if no matching text matches the selection, /// or `undefined` is the search plugin isn't active. export function getSearchCurrentMatchIndex(state: EditorState): number | undefined { const ranges = getSearchMatchingRanges(state) const { from: selFrom, to: selTo } = state.selection return ranges && ranges.findIndex(({ from, to }) => from === selFrom && to === selTo) } ```
marijnh commented 2024-06-16 14:38:24 +02:00 (Migrated from github.com)

I noticed you don't want to expose the deco field of decorations of the current SearchState.

Why not though? Wouldn't a getter that returns the decoration set be a lot easier and more efficient than this set of different function, which copy the ranges every time you read them?

> I noticed you don't want to expose the deco field of decorations of the current SearchState. Why not though? Wouldn't a getter that returns the decoration set be a lot easier and more efficient than this set of different function, which copy the ranges every time you read them?
massifrg commented 2024-06-16 22:02:18 +02:00 (Migrated from github.com)

When I saw this:

class SearchState {
  constructor(
    readonly query: SearchQuery,
    readonly range: {from: number, to: number} | null,
    readonly deco: DecorationSet
  ) {}
}

// ...

export function getSearchState(state: EditorState): {
  query: SearchQuery,
  range: {from: number, to: number} | null
} | undefined {
  return searchKey.getState(state)
}

the first change I made to get the number of matching texts was this:

export class SearchState {
  constructor(
    readonly query: SearchQuery,
    readonly range: {from: number, to: number} | null,
    readonly deco: DecorationSet
  ) {}
}

// ...

export function getSearchState(state: EditorState): SearchState | undefined {
  return searchKey.getState(state)
}

Then I asked myself why you did not do that, and the explanation I gave was that you did not want to expose the decorations, though getSearchState does return a complete SearchState, only as a more generic object, hiding the decorations in the return type of the function.

If I understand right, now you are saying something like this:

export function getSearchStateDecorations(state: EditorState): DecorationSet | undefined {
  return searchKey.getState(state)?.deco
}

without the need to export the SearchState class.

When I saw this: ```ts class SearchState { constructor( readonly query: SearchQuery, readonly range: {from: number, to: number} | null, readonly deco: DecorationSet ) {} } // ... export function getSearchState(state: EditorState): { query: SearchQuery, range: {from: number, to: number} | null } | undefined { return searchKey.getState(state) } ``` the first change I made to get the number of matching texts was this: ```ts export class SearchState { constructor( readonly query: SearchQuery, readonly range: {from: number, to: number} | null, readonly deco: DecorationSet ) {} } // ... export function getSearchState(state: EditorState): SearchState | undefined { return searchKey.getState(state) } ``` Then I asked myself why _you_ did not do that, and the explanation I gave was that you did not want to expose the decorations, though `getSearchState` does return a complete `SearchState`, only as a more generic object, hiding the decorations in the return type of the function. If I understand right, now you are saying something like this: ```ts export function getSearchStateDecorations(state: EditorState): DecorationSet | undefined { return searchKey.getState(state)?.deco } ``` without the need to export the `SearchState` class.
marijnh commented 2024-06-21 13:04:18 +02:00 (Migrated from github.com)

I've pushed a patch that adds a getMatchHighlights function (and tagged a version 0.1.0).

I've pushed a patch that adds a `getMatchHighlights` function (and tagged a version 0.1.0).
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
prosemirror/prosemirror-search#3
No description provided.