diff --git a/src/editor.cc b/src/editor.cc
index 5d2e4a81c..13253ae2e 100644
--- a/src/editor.cc
+++ b/src/editor.cc
@@ -168,16 +168,20 @@ void sort_and_merge_overlapping(SelectionList& selections, size_t& main_selectio
     merge_overlapping(selections, main_selection, overlaps);
 }
 
+BufferCoord Editor::offset_coord(const BufferCoord& coord, CharCount offset)
+{
+    auto& line = buffer()[coord.line];
+    auto character = std::max(0_char, std::min(line.char_count_to(coord.column) + offset,
+                                               line.char_length() - 2));
+    return {coord.line, line.byte_count_to(character)};
+}
+
 void Editor::move_selections(CharCount offset, SelectMode mode)
 {
     kak_assert(mode == SelectMode::Replace or mode == SelectMode::Extend);
     for (auto& sel : m_selections)
     {
-        auto last = sel.last();
-        auto& line = buffer()[last.line];
-        auto character = std::max(0_char, std::min(line.char_count_to(last.column) + offset,
-                                                   line.char_length() - 2));
-        last.column = line.byte_count_to(character);
+        auto last = offset_coord(sel.last(), offset);
         sel.first() = mode == SelectMode::Extend ? sel.first() : last;
         sel.last()  = last;
         avoid_eol(*m_buffer, sel);
@@ -185,17 +189,22 @@ void Editor::move_selections(CharCount offset, SelectMode mode)
     sort_and_merge_overlapping(m_selections, m_main_sel);
 }
 
+BufferCoord Editor::offset_coord(const BufferCoord& coord, LineCount offset)
+{
+    auto character = (*m_buffer)[coord.line].char_count_to(coord.column);
+    auto line = clamp(coord.line + offset, 0_line, m_buffer->line_count()-1);
+    auto& content = (*m_buffer)[line];
+
+    character = std::max(0_char, std::min(character, content.char_length() - 2));
+    return {line, content.byte_count_to(character)};
+}
+
 void Editor::move_selections(LineCount offset, SelectMode mode)
 {
     kak_assert(mode == SelectMode::Replace or mode == SelectMode::Extend);
     for (auto& sel : m_selections)
     {
-        auto character = (*m_buffer)[sel.last().line].char_count_to(sel.last().column);
-        auto line = clamp(sel.last().line + offset, 0_line, m_buffer->line_count()-1);
-        auto& content = (*m_buffer)[line];
-
-        character = std::max(0_char, std::min(character, content.char_length() - 2));
-        BufferCoord pos{line, content.byte_count_to(character)};
+        auto pos = offset_coord(sel.last(), offset);
         sel.first() = mode == SelectMode::Extend ? sel.first() : pos;
         sel.last()  = pos;
         avoid_eol(*m_buffer, sel);
diff --git a/src/editor.hh b/src/editor.hh
index d8785a875..95ddd2b10 100644
--- a/src/editor.hh
+++ b/src/editor.hh
@@ -91,6 +91,9 @@ private:
     void begin_edition();
     void end_edition();
 
+    virtual BufferCoord offset_coord(const BufferCoord& coord, LineCount move);
+    virtual BufferCoord offset_coord(const BufferCoord& coord, CharCount move);
+
     int m_edition_level;
 
     void check_invariant() const;
diff --git a/src/window.cc b/src/window.cc
index 8e8f2ee8d..6c73e11f7 100644
--- a/src/window.cc
+++ b/src/window.cc
@@ -167,31 +167,81 @@ void Window::scroll_to_keep_cursor_visible_ifn()
     }
 }
 
+namespace
+{
+CharCount find_display_column(const DisplayLine& line, const Buffer& buffer,
+                              const BufferCoord& coord)
+{
+    kak_assert(coord.line == line.buffer_line());
+    CharCount column = 0;
+    for (auto& atom : line)
+    {
+        auto& content = atom.content;
+        if (content.has_buffer_range() and
+            coord >= content.begin() and coord < content.end())
+        {
+            if (content.type() == AtomContent::BufferRange)
+                column += utf8::distance(buffer.iterator_at(content.begin()),
+                                         buffer.iterator_at(coord));
+            return column;
+        }
+        column += content.length();
+    }
+    return column;
+}
+
+BufferCoord find_buffer_coord(const DisplayLine& line, const Buffer& buffer,
+                              CharCount column)
+{
+    LineCount l = line.buffer_line();
+    for (auto& atom : line)
+    {
+        auto& content = atom.content;
+        CharCount len = content.length();
+        if (content.has_buffer_range() and column < len)
+        {
+            if (content.type() == AtomContent::BufferRange)
+                return utf8::advance(buffer.iterator_at(content.begin()), buffer.iterator_at(l+1),
+                                     std::max(0_char, column)).coord();
+             return content.begin();
+         }
+        column -= len;
+    }
+    return buffer.clamp({l, buffer[l].length()});
+}
+}
+
 DisplayCoord Window::display_position(const BufferCoord& coord)
 {
-    DisplayCoord res{0,0};
+    LineCount l = 0;
     for (auto& line : m_display_buffer.lines())
     {
         if (line.buffer_line() == coord.line)
-        {
-            for (auto& atom : line)
-            {
-                auto& content = atom.content;
-                if (content.has_buffer_range() and
-                    coord >= content.begin() and coord < content.end())
-                {
-                    res.column += utf8::distance(buffer().iterator_at(content.begin()),
-                                                 buffer().iterator_at(coord));
-                    return res;
-                }
-                res.column += content.length();
-            }
-        }
-        ++res.line;
+            return {l, find_display_column(line, buffer(), coord)};
+        ++l;
     }
     return { 0, 0 };
 }
 
+BufferCoord Window::offset_coord(const BufferCoord& coord, LineCount offset)
+{
+    auto line = clamp(coord.line + offset, 0_line, buffer().line_count()-1);
+    DisplayBuffer display_buffer;
+    DisplayBuffer::LineList& lines = display_buffer.lines();
+    {
+        lines.emplace_back(coord.line);
+        lines.back().push_back({AtomContent(buffer(), coord.line, coord.line+1)});
+        lines.emplace_back(line);
+        lines.back().push_back({AtomContent(buffer(), line, line+1)});
+    }
+    display_buffer.compute_range();
+    m_highlighters(*this, display_buffer);
+    m_builtin_highlighters(*this, display_buffer);
+
+    CharCount column = find_display_column(lines[0], buffer(), coord);
+    return find_buffer_coord(lines[1], buffer(), column);
+}
+
 void Window::on_option_changed(const Option& option)
 {
     String desc = option.name() + "=" + option.get_as_string();
diff --git a/src/window.hh b/src/window.hh
index 25890e81e..08ee23f07 100644
--- a/src/window.hh
+++ b/src/window.hh
@@ -56,6 +56,8 @@ private:
 
     void scroll_to_keep_cursor_visible_ifn();
 
+    BufferCoord offset_coord(const BufferCoord& coord, LineCount move) override;
+
     DisplayCoord  m_position;
     DisplayCoord  m_dimensions;
     DisplayBuffer m_display_buffer;