# Undo and cursor position

**URL:** https://discuss.prosemirror.net/t/undo-and-cursor-position/677
**Category:** Uncategorized
**Created:** [March 9, 2017, 8:47am UTC](https://discuss.prosemirror.net/t/undo-and-cursor-position/677 "2017-03-09T08:47:27Z")
**Posts on this page:** 15
**Page:** 1

<div class="post-metadata">

### Author: ![kofifus](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/kofifus/32/288_2.png) [@kofifus](https://discuss.prosemirror.net/u/kofifus)
#### Post date: [March 9, 2017, 8:47am UTC](https://discuss.prosemirror.net/t/undo-and-cursor-position/677/1 "2017-03-09T08:47:27Z")

</div>

I load a checkpoint (doc + steps from it) into the state and history like this:

```
let state=EditorState.create({ schema, doc: doc, plugins: view.getState().plugins });
for (let i=0; i<steps.length; i++) {
	let tr=state.tr.step(pmJSON.from(ver.steps[i]));
	closeHistory(tr);
	state = state.apply(tr);
}

view.updateView(state);

```

the problem I have is that when pressing undo, the view changes correctly but the cursor jumps to the beginning of the document.

How can I get the cursor to move to the position of the step that was ‘undoed’ ?

Thx!

---

<div class="post-metadata">

### Author: ![marijn](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/marijn/32/15_2.png) [@marijn](https://discuss.prosemirror.net/u/marijn)
#### Post date: [March 9, 2017, 9:59am UTC](https://discuss.prosemirror.net/t/undo-and-cursor-position/677/2 "2017-03-09T09:59:58Z")

</div>

The undo history will store the _current_ selection in the history. Since the selection was at the default position (start of doc) when you fed it the changes, that’s where it’ll put it when you undo. You can use `setSelection` during replaying to work around this.

---

<div class="post-metadata">

### Author: ![kofifus](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/kofifus/32/288_2.png) [@kofifus](https://discuss.prosemirror.net/u/kofifus)
#### Post date: [March 9, 2017, 10:55pm UTC](https://discuss.prosemirror.net/t/undo-and-cursor-position/677/3 "2017-03-09T22:55:49Z")

</div>

I am not sure how to use setSelection here ☹

given a transaction, how do I change it’s position to another ? I looked at the doc and other discussions here but could not find a clear answer, any help appreciated.

thx!

---

<div class="post-metadata">

### Author: ![kofifus](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/kofifus/32/288_2.png) [@kofifus](https://discuss.prosemirror.net/u/kofifus)
#### Post date: [March 10, 2017, 12:51am UTC](https://discuss.prosemirror.net/t/undo-and-cursor-position/677/4 "2017-03-10T00:51:08Z")

</div>

I tried

```
let state=EditorState.create({ schema, doc: doc, plugins: view.getState().plugins });
for (let i=0; i<steps.length; i++) {
	let tr=state.tr.step(steps[i]));
        tr.setSelection(Selection.near(state.doc.resolve(step.to)));
	closeHistory(tr);
	state = state.apply(tr);
}

view.updateView(state);

```

but I get very strange results, if for example I load steps which just add to the end, undoing them seems to skip to one char before the end.

I also tried: `tr.setSelection(Selection.near(state.doc.resolve(step.getMap().map(step.to, 1))));`

but got the same result.

Is there a correct way of doing this ?

---

<div class="post-metadata">

### Author: ![kofifus](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/kofifus/32/288_2.png) [@kofifus](https://discuss.prosemirror.net/u/kofifus)
#### Post date: [March 10, 2017, 1:32am UTC](https://discuss.prosemirror.net/t/undo-and-cursor-position/677/5 "2017-03-10T01:32:09Z")

</div>

this seems to work:

```
let state=EditorState.create({ schema, doc: doc, plugins: view.getState().plugins });
for (let i=0; i<steps.length; i++) {
	let step=steps[i];
    let tr=state.tr.step(step));
	closeHistory(tr);
	state = state.apply(tr);
    let endPos=Selection.near(state.doc.resolve(step.getMap().map(step.to, 1)));
	state = state.apply(state.tr.setSelection(endPos));
}

view.updateView(state);

```

but seems a bit convulted, is that correct ? is there a simpler way ?

---

<div class="post-metadata">

### Author: ![marijn](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/marijn/32/15_2.png) [@marijn](https://discuss.prosemirror.net/u/marijn)
#### Post date: [March 10, 2017, 7:28am UTC](https://discuss.prosemirror.net/t/undo-and-cursor-position/677/6 "2017-03-10T07:28:59Z")

</div>

You can’t rely on steps having `from` or `to` properties (even for replace steps, those properties aren’t part of the public API). One way to get information about the extent of a step is to use its position map (see its `forEach` method). I assume you’re trying to get the position in the _old_ doc, before the step? But if so, I’m not sure why you are applying the step’s map – or are these inverted steps?

---

<div class="post-metadata">

### Author: ![kofifus](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/kofifus/32/288_2.png) [@kofifus](https://discuss.prosemirror.net/u/kofifus)
#### Post date: [March 10, 2017, 7:31am UTC](https://discuss.prosemirror.net/t/undo-and-cursor-position/677/7 "2017-03-10T07:31:29Z")

</div>

They are not inverted.

So how do I move the cursor to the end position of the result of applying the step ?

Any help ?

---

<div class="post-metadata">

### Author: ![kofifus](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/kofifus/32/288_2.png) [@kofifus](https://discuss.prosemirror.net/u/kofifus)
#### Post date: [March 10, 2017, 10:13am UTC](https://discuss.prosemirror.net/t/undo-and-cursor-position/677/8 "2017-03-10T10:13:49Z")

</div>

to put it more succinctly, how can I run `state.tr.step(step)` and then move the cursor to the position it would be if I entered that step manually ?

perhaps a flag to Transfrorm.step can be added ?

---

<div class="post-metadata">

### Author: ![marijn](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/marijn/32/15_2.png) [@marijn](https://discuss.prosemirror.net/u/marijn)
#### Post date: [March 10, 2017, 10:25am UTC](https://discuss.prosemirror.net/t/undo-and-cursor-position/677/9 "2017-03-10T10:25:01Z")

</div>

> [@kofifus](#):
>
> to put it more succinctly, how can I run state.tr.step(step) and then move the cursor to the position it would be if I entered that step manually ?

There is no single cursor position that can be derived from a step. As I said, you can use `step.getMap.forEach` to find out which parts of the document it touched.

> [@kofifus](#):
>
> perhaps a flag to Transfrorm.step can be added ?

Certainly not. The transform module doesn’t even know selections exist, and that’s how it should be.

---

<div class="post-metadata">

### Author: ![kofifus](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/kofifus/32/288_2.png) [@kofifus](https://discuss.prosemirror.net/u/kofifus)
#### Post date: [March 11, 2017, 1:46am UTC](https://discuss.prosemirror.net/t/undo-and-cursor-position/677/10 "2017-03-11T01:46:14Z")

</div>

> There is no single cursor position that can be derived from a step

I’m confused, doesn’t the editor calculate a new cursor position when the user manually creates the edit that the step is derived from ?

> The transform module doesn’t even know selections exist

got it thx

.

I played with this a lot and still can’t get it to work properly ☹ ☹I tried:

```
let state=EditorState.create({ schema, doc: doc, plugins: view.getState().plugins });

for (let i=0; i<steps.length; i++) {
	let step=steps[i];
	state = state.apply(state.tr.step(step));

	let pos=-1;
	step.getMap().forEach((oldStart, oldEnd, newStart, newEnd) => {
		if (newEnd>pos) pos=newEnd;
	});
	console.log(pos);

	tr=state.tr.setSelection(Selection.near(state.doc.resolve(pos)));
	closeHistory(tr);
	state = state.apply(tr);
}

view.updateView(state);

```

I now feed an empty doc, and a steps array created by typing 1 then 2 then {home} then x

the console shows 2, 3, 2 which is correct

but on pressing undo the cursor stays at the end - it does not jump to position 2

if I keep pressing undo further, the cursor moves correctly so the problem seems to be with the last setSelection not being remembered by history.

Any help ?

---

<div class="post-metadata">

### Author: ![marijn](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/marijn/32/15_2.png) [@marijn](https://discuss.prosemirror.net/u/marijn)
#### Post date: [March 12, 2017, 8:22pm UTC](https://discuss.prosemirror.net/t/undo-and-cursor-position/677/11 "2017-03-12T20:22:44Z")

</div>

> [@kofifus](#):
>
> I’m confused, doesn’t the editor calculate a new cursor position when the user manually creates the edit that the step is derived from ?

Sure, and it does so when you apply the step programatically too, but it computes it from the _old_ selection, so that doesn’t give you the selection you’re looking for (the cursor will probalby simply stay at the start of the document).

Your code is using a post-step position and applying it before the step, which is probably not what you mean and might produce an error if the position is out of range. You might get better results using `oldEnd`.

---

<div class="post-metadata">

### Author: ![kofifus](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/kofifus/32/288_2.png) [@kofifus](https://discuss.prosemirror.net/u/kofifus)
#### Post date: [March 13, 2017, 1:19am UTC](https://discuss.prosemirror.net/t/undo-and-cursor-position/677/12 "2017-03-13T01:19:25Z")

</div>

> [@marijn](#):
>
> Sure, and it does so when you apply the step programatically too

ok, so if that is so, given a start position and a step what is the correct way to calculate the cursor position after applying the step ? is that the maximum of all newEnd in all changed ranges ?

I ended up with code that works, though I’m not sure is correct: (I didn’t close the history properly above)

```
let state=EditorState.create({ schema, doc: doc, plugins: view.getState().plugins });

for (let i=0; i<steps.length; i++) {
	let step=steps[i];

	let tr=state.tr.step(step);
	state = state.apply(tr);

	let pos=-1;
	step.getMap().forEach((oldStart, oldEnd, newStart, newEnd) => {
		if (newEnd>pos) pos=newEnd;
	});
	tr=state.tr.setSelection(Selection.near(state.doc.resolve(pos)));
	state = state.apply(tr);

	state= state.apply(closeHistory(state));
}

view.updateView(state);

```

---

<div class="post-metadata">

### Author: ![marijn](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/marijn/32/15_2.png) [@marijn](https://discuss.prosemirror.net/u/marijn)
#### Post date: [March 13, 2017, 9:05am UTC](https://discuss.prosemirror.net/t/undo-and-cursor-position/677/13 "2017-03-13T09:05:03Z")

</div>

> [@kofifus](#):
>
> what is the correct way to calculate the cursor position after applying the step ?

Again, there is no ‘cursor position after applying the step’. If you want to map a given previous selection through a step, you use the selection’s `map` method. But it sounds like that’s not what you are talking about.

> [@kofifus](#):
>
> I ended up with code that works, though I’m not sure is correct

You could put the `.step` and `.setSelection` in the same transaction to save some transactions, but otherwise that looks sane.

---

<div class="post-metadata">

### Author: ![kofifus](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/kofifus/32/288_2.png) [@kofifus](https://discuss.prosemirror.net/u/kofifus)
#### Post date: [March 13, 2017, 9:52am UTC](https://discuss.prosemirror.net/t/undo-and-cursor-position/677/14 "2017-03-13T09:52:37Z")

</div>

> [@marijn](#):
>
> You could put the .step and .setSelection in the same transaction

No I can’t because I need state.doc passed to setSelection already updated with the step

It doesn’t seem to work otherwise, unless I’m missing something ?

---

<div class="post-metadata">

### Author: ![marijn](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/marijn/32/15_2.png) [@marijn](https://discuss.prosemirror.net/u/marijn)
#### Post date: [March 13, 2017, 10:07am UTC](https://discuss.prosemirror.net/t/undo-and-cursor-position/677/15 "2017-03-13T10:07:52Z")

</div>

You can pass `tr.doc`
