int (@NotNull Editor editor, int caretOffset, @NotNull LogicalPosition logicalPosition, @NotNull VisualPosition visualPosition) { Document document = editor.getDocument(); int lineNumber = logicalPosition.line; int columnNumber = logicalPosition.column; if (lineNumber >= document.getLineCount()) { return columnNumber; } int anchorLineEndOffset = document.getLineEndOffset(lineNumber); List<? extends SoftWrap> softWraps = editor.getSoftWrapModel().getSoftWrapsForLine(logicalPosition.line); for (SoftWrap softWrap : softWraps) { if (!editor.getSoftWrapModel().isVisible(softWrap)) { continue; } int softWrapOffset = softWrap.getStart(); if (softWrapOffset == caretOffset) { // There are two possible situations: // *) caret is located on a visual line before soft wrap-introduced line feed; // *) caret is located on a visual line after soft wrap-introduced line feed; VisualPosition position = editor.offsetToVisualPosition(caretOffset - 1); if (position.line == visualPosition.line) { return visualPosition.column - position.column - 1; } } if (softWrapOffset > caretOffset) { anchorLineEndOffset = softWrapOffset; break; } // Same offset corresponds to all soft wrap-introduced symbols, however, current method should behave differently in // situations when the caret is located just before the soft wrap and at the next visual line. if (softWrapOffset == caretOffset) { boolean visuallyBeforeSoftWrap = visualPosition.line < editor.offsetToVisualPosition(caretOffset).line; if (visuallyBeforeSoftWrap) { anchorLineEndOffset = softWrapOffset; break; } } } int lineEndColumnNumber = editor.offsetToLogicalPosition(anchorLineEndOffset).column; return columnNumber - lineEndColumnNumber; }