Peer's tooltip uncommon shifting occurs in co-editor

Hi,

I used the CM6 collaborative package to implement my co-editor.

Each tooltip represents a user, The tooltip’s pos is each user’s current cursor position.

The problem is if user A is inputting on line 11, User B’s tooltip will move at the same time, in fact, user B didn’t do anything while A was inputting.

Don’t have a clue why this is happening, hope for your reply.

toolTip

This looks like you’re not properly mapping tooltip positions through changes—as more characters are inserted in front of it, its position needs to be moved forward to stay in the same place in the document.

Tried to use mapping like tooltip examples.

Still didn’t work, wondering if I missed something. (Sorry for the basic question)

function getCursorTooltips(state) {
  const cursors = [];
  const myMap = tooltipMap
  for (const [key, value] of myMap) {
    state.selection.ranges
    .filter(range => range.empty)
    .map(range => {
    cursors.push({
      pos: value.anchor, // collaborative user's tooltip position
      above: true,
      strictSide: true,
      arrow: true,
      create: () => {
        let dom = document.createElement("div");
        dom.className = "cm-tooltip-cursor";
        dom.textContent = value.name;
        return { dom };
      },
    });
  })

  }

  return state.selection.ranges
  .filter(range => range.empty)
  .map(range => {
    cursors.push( {
      pos: range.head, // userself's tooltip position
      above: true,
      strictSide: true,
      arrow: true,
      overlap: true,
      create: () => {
        if (tooltipMap.size !== 0) {
          let dom = document.createElement("div");
          dom.className = "cm-tooltip-cursor";
          dom.textContent = uName; 
          return { dom };
        }
      }
    })
}), cursors

}

I don’t know what you’re trying to do, and the rather confusing structure of that code doesn’t help make things clear (why map over the local selection to get remote user cursor? why map over it twice? why use map if you’re just going to push to an array? why the odd return statement with the side-effecting map followed by , cursors?)

Sorry about these misunderstandings, didn’t quite sure about how to map tooltip positions through changes to avoid this uncommon shifting? Could you please give some advice?

Back then I want to create one tooltip that represents the author, another for co-users. Turns out it’s unnecessary.

Here’s the new code about creating the collaborative user’s cursor on co-editor. The problem in the editor under collaborative status looks like this. A -myself , tooltip- other user.
tooltip2

export const cursorTooltipField = StateField.define({ // as extension
  create: getCursorTooltips,

  update(tr) {
    return getCursorTooltips(tr.changes);
  },

  provide: (f) => showTooltip.computeN([f], (state) => state.field(f)),
});

function getCursorTooltips() {
  let cursors = [];
  const myMap = tooltipMap
  for (const [key, value] of myMap) {
    cursors.push({
      pos: value.anchor,
      above: true,
      strictSide: true,
      arrow: true,
      create: () => {
          let dom = document.createElement("div");
          dom.className = "cm-tooltip-cursor";
          dom.textContent = value.name;
          return { dom };
      },
    });
  }
  return cursors
}

Here is a simplified explanation of what i think is happening

lets say you have a document of 4 characters
1234<-cursor at pos 4
Now if you insert some text at the beginning say 0 and the new document becomes
01234
If you do nothing to the cursor position, your cursor stays at pos 4, which is now the character 3
0123<-4

If instead of a single line if each of these letters were on separate line, and the cursor was at character 4, you can probably see why adding some characters to line 1 will move the cursor above, if you do nothing to the cursor position.

What you need to do is, as changes are made to the document, somehow map the old cursor position to the new position after the change. To do this the library provides a map function in various classes like RangeSet and SelectionRange, and on every transaction you need to map the position to the new position, using for eg selectionRange=selectionRange.map(tr.changes) or rangeSet=rangeSet.map(tr.changes)

Since I don’t see the cursor position being mapped through document changes, you are probably confusing mapping concept with array.map or Map data structure maybe?

You can probably see the map used in the examples on decorators

Hey, thank you so much for your kind explanations!!!

It really helped me, first I did feel confusing about the mapping concept, thought it was the js map thing.

Thanks for the tips!!! After reading the documents page you recommend, Finally, the problem is solved! I should read the docs more carefully :smiling_face_with_tear:

Hope you have a nice day! Again, really appreciate your help:)