(cm, line, start, dir)
| 9372 | } |
| 9373 | |
| 9374 | function moveVisually(cm, line, start, dir) { |
| 9375 | var bidi = getOrder(line, cm.doc.direction) |
| 9376 | if (!bidi) { |
| 9377 | return moveLogically(line, start, dir) |
| 9378 | } |
| 9379 | if (start.ch >= line.text.length) { |
| 9380 | start.ch = line.text.length |
| 9381 | start.sticky = "before" |
| 9382 | } else if (start.ch <= 0) { |
| 9383 | start.ch = 0 |
| 9384 | start.sticky = "after" |
| 9385 | } |
| 9386 | var partPos = getBidiPartAt(bidi, start.ch, start.sticky), |
| 9387 | part = bidi[partPos] |
| 9388 | if (cm.doc.direction == "ltr" && part.level % 2 == 0 && (dir > 0 ? part.to > start.ch : part.from < start.ch)) { |
| 9389 | // Case 1: We move within an ltr part in an ltr editor. Even with wrapped lines, |
| 9390 | // nothing interesting happens. |
| 9391 | return moveLogically(line, start, dir) |
| 9392 | } |
| 9393 | |
| 9394 | var mv = function (pos, dir) { |
| 9395 | return moveCharLogically(line, pos instanceof Pos ? pos.ch : pos, dir) |
| 9396 | } |
| 9397 | var prep |
| 9398 | var getWrappedLineExtent = function (ch) { |
| 9399 | if (!cm.options.lineWrapping) { |
| 9400 | return { begin: 0, end: line.text.length } |
| 9401 | } |
| 9402 | prep = prep || prepareMeasureForLine(cm, line) |
| 9403 | return wrappedLineExtentChar(cm, line, prep, ch) |
| 9404 | } |
| 9405 | var wrappedLineExtent = getWrappedLineExtent(start.sticky == "before" ? mv(start, -1) : start.ch) |
| 9406 | |
| 9407 | if (cm.doc.direction == "rtl" || part.level == 1) { |
| 9408 | var moveInStorageOrder = (part.level == 1) == dir < 0 |
| 9409 | var ch = mv(start, moveInStorageOrder ? 1 : -1) |
| 9410 | if (ch != null && (!moveInStorageOrder ? ch >= part.from && ch >= wrappedLineExtent.begin : ch <= part.to && ch <= wrappedLineExtent.end)) { |
| 9411 | // Case 2: We move within an rtl part or in an rtl editor on the same visual line |
| 9412 | var sticky = moveInStorageOrder ? "before" : "after" |
| 9413 | return new Pos(start.line, ch, sticky) |
| 9414 | } |
| 9415 | } |
| 9416 | |
| 9417 | // Case 3: Could not move within this bidi part in this visual line, so leave |
| 9418 | // the current bidi part |
| 9419 | |
| 9420 | var searchInVisualLine = function (partPos, dir, wrappedLineExtent) { |
| 9421 | var getRes = function (ch, moveInStorageOrder) { |
| 9422 | return moveInStorageOrder ? new Pos(start.line, mv(ch, 1), "before") : new Pos(start.line, ch, "after") |
| 9423 | } |
| 9424 | |
| 9425 | for (; partPos >= 0 && partPos < bidi.length; partPos += dir) { |
| 9426 | var part = bidi[partPos] |
| 9427 | var moveInStorageOrder = dir > 0 == (part.level != 1) |
| 9428 | var ch = moveInStorageOrder ? wrappedLineExtent.begin : mv(wrappedLineExtent.end, -1) |
| 9429 | if (part.from <= ch && ch < part.to) { |
| 9430 | return getRes(ch, moveInStorageOrder) |
| 9431 | } |
no test coverage detected