From e6a97804908eae3795f84b199eff5c4a2b668909 Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Tue, 10 Jun 2014 13:30:37 +0100 Subject: [PATCH 1/8] Fix tabs-to-spaces an spaces-to-tabs with the selection refactor --- src/normal.cc | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/src/normal.cc b/src/normal.cc index 0e4498c50..316f657fd 100644 --- a/src/normal.cc +++ b/src/normal.cc @@ -1105,23 +1105,24 @@ void tabs_to_spaces(Context& context, int ts) auto& buffer = context.buffer(); const CharCount opt_tabstop = context.options()["tabstop"].get(); const CharCount tabstop = ts == 0 ? opt_tabstop : ts; + std::vector tabs; + std::vector spaces; for (auto& sel : context.selections()) { for (auto it = buffer.iterator_at(sel.min()), - end = buffer.iterator_at(sel.max())+1; it != end;) + end = buffer.iterator_at(sel.max())+1; it != end; ++it) { if (*it == '\t') { CharCount col = get_column(buffer, opt_tabstop, it.coord()); CharCount end_col = (col / tabstop + 1) * tabstop; - it = buffer.erase(it, it+1); - it = buffer.insert(it, String{ ' ', end_col - col }) + (int)(end_col - col); - end = buffer.iterator_at(sel.max())+1; + tabs.push_back({ it.coord() }); + spaces.push_back(String{ ' ', end_col - col }); } - else - ++it; } } + if (not tabs.empty()) + SelectionList{ buffer, std::move(tabs) }.insert(spaces, InsertMode::Replace); } void spaces_to_tabs(Context& context, int ts) @@ -1129,6 +1130,7 @@ void spaces_to_tabs(Context& context, int ts) auto& buffer = context.buffer(); const CharCount opt_tabstop = context.options()["tabstop"].get(); const CharCount tabstop = ts == 0 ? opt_tabstop : ts; + std::vector spaces; for (auto& sel : context.selections()) { for (auto it = buffer.iterator_at(sel.min()), @@ -1144,20 +1146,16 @@ void spaces_to_tabs(Context& context, int ts) ++spaces_end; ++col; } - if ((col % tabstop) == 0) - { - it = buffer.erase(spaces_beg, spaces_end); - it = buffer.insert(it, "\t") + 1; - end = buffer.iterator_at(sel.max())+1; - } - else - it = spaces_end; + spaces.push_back({spaces_beg.coord(), (spaces_end-1).coord()}); + it = spaces_end; } else ++it; } } + if (not spaces.empty()) + SelectionList{ buffer, std::move(spaces) }.insert("\t"_str, InsertMode::Replace); } void undo(Context& context, int) From 847fc0512b2dce96d56e5446a340a8a29b8b1c1c Mon Sep 17 00:00:00 2001 From: Alex Leferry 2 Date: Wed, 11 Jun 2014 14:58:09 +0200 Subject: [PATCH 2/8] Alex Leferry 2> Copyright Waiver I dedicate any and all copyright interest in this software to the public domain. I make this dedication for the benefit of the public at large and to the detriment of my heirs and successors. I intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law. From d5b1605df57d62f953424bb33f6b7e7df7c234f5 Mon Sep 17 00:00:00 2001 From: Alex Leferry 2 Date: Wed, 11 Jun 2014 15:00:45 +0200 Subject: [PATCH 3/8] add ' ' for whitespaces object --- README.asciidoc | 1 + src/normal.cc | 2 ++ src/selectors.cc | 29 +++++++++++++++++++++++++++++ src/selectors.hh | 4 ++++ 4 files changed, 36 insertions(+) diff --git a/README.asciidoc b/README.asciidoc index 6fac63d57..add67f68a 100644 --- a/README.asciidoc +++ b/README.asciidoc @@ -339,6 +339,7 @@ object you want. * _W_: select the whole WORD * _s_: select the sentence * _p_: select the paragraph + * _␣_: select the whitespaces * _i_: select the current indentation block * _n_: select the number diff --git a/src/normal.cc b/src/normal.cc index 316f657fd..be6703976 100644 --- a/src/normal.cc +++ b/src/normal.cc @@ -839,6 +839,7 @@ void select_object(Context& context, int param) { 'W', select_word }, { 's', select_sentence }, { 'p', select_paragraph }, + { ' ', select_whitespaces }, { 'i', select_indent }, { 'n', select_number }, }; @@ -880,6 +881,7 @@ void select_object(Context& context, int param) "W: WORD \n" "s: sentence \n" "p: paragraph \n" + "␣: whitespaces \n" "i: indent \n"); } diff --git a/src/selectors.cc b/src/selectors.cc index ca85142ab..bd1acc010 100644 --- a/src/selectors.cc +++ b/src/selectors.cc @@ -377,6 +377,35 @@ static CharCount get_indent(const String& str, int tabstop) return indent; } +Selection select_whitespaces(const Buffer& buffer, const Selection& selection, ObjectFlags flags) +{ + auto is_whitespace = [&](char c) { + return c == ' ' or c == '\t' or + (not (flags & ObjectFlags::Inner) and c == '\n'); + }; + BufferIterator first = buffer.iterator_at(selection.cursor()); + BufferIterator last = first; + if (flags & ObjectFlags::ToBegin) + { + if (is_whitespace(*first)) + { + skip_while_reverse(first, buffer.begin(), is_whitespace); + if (not is_whitespace(*first)) + ++first; + } + } + if (flags & ObjectFlags::ToEnd) + { + if (is_whitespace(*last)) + { + skip_while(last, buffer.end(), is_whitespace); + --last; + } + } + return (flags & ObjectFlags::ToEnd) ? utf8_range(first, last) + : utf8_range(last, first); +} + static bool is_only_whitespaces(const String& str) { auto it = str.begin(); diff --git a/src/selectors.hh b/src/selectors.hh index 7e86a7386..d9e5f770d 100644 --- a/src/selectors.hh +++ b/src/selectors.hh @@ -212,6 +212,10 @@ Selection select_paragraph(const Buffer& buffer, const Selection& selection, ObjectFlags flags); +Selection select_whitespaces(const Buffer& buffer, + const Selection& selection, + ObjectFlags flags); + Selection select_indent(const Buffer& buffer, const Selection& selection, ObjectFlags flags); From fa5b6b716d373061ab371128ffab6fbf8c430b18 Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Sat, 14 Jun 2014 14:07:03 +0100 Subject: [PATCH 4/8] Fix crash in paragraph selection --- src/selectors.cc | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/selectors.cc b/src/selectors.cc index bd1acc010..838f1de18 100644 --- a/src/selectors.cc +++ b/src/selectors.cc @@ -346,9 +346,7 @@ Selection select_paragraph(const Buffer& buffer, const Selection& selection, Obj ++last; while (last != buffer.end()) { - char cur = *last; - char prev = *(last-1); - if (is_eol(cur) and is_eol(prev)) + if (last != buffer.begin() and is_eol(*last) and is_eol(*(last-1))) { if (not (flags & ObjectFlags::Inner)) skip_while(last, buffer.end(), is_eol); From 89d30cbb212fac0c15245138d469d9d4763bdc69 Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Thu, 12 Jun 2014 21:23:49 +0100 Subject: [PATCH 5/8] Fix selection update --- src/selection.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/selection.cc b/src/selection.cc index 95b4e3444..d88080545 100644 --- a/src/selection.cc +++ b/src/selection.cc @@ -163,7 +163,7 @@ struct ForwardChangesTracker bool relevant(const Buffer::Change& change, ByteCoord old_coord) const { - auto new_coord = get_new_coord(old_coord); + auto new_coord = get_new_coord_tolerant(old_coord); return change.type == Buffer::Change::Insert ? change.begin <= new_coord : change.begin < new_coord; } From c87e81e8de470f74ae5f2137764e8c38fc3b4989 Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Mon, 16 Jun 2014 00:53:25 +0100 Subject: [PATCH 6/8] Use zstr instead of c_str in ncurses addutf8str --- src/ncurses.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ncurses.cc b/src/ncurses.cc index 78e967462..539e8fca6 100644 --- a/src/ncurses.cc +++ b/src/ncurses.cc @@ -211,7 +211,7 @@ using Utf8Policy = utf8::InvalidBytePolicy::Pass; using Utf8Iterator = utf8::utf8_iterator; void addutf8str(WINDOW* win, Utf8Iterator begin, Utf8Iterator end) { - waddstr(win, std::string(begin.base(), end.base()).c_str()); + waddstr(win, StringView(begin.base(), end.base()).zstr()); } static CharCoord window_size(WINDOW* win) From 2acfe852818c6002067e9425bfa432c90abc51c8 Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Mon, 16 Jun 2014 00:59:05 +0100 Subject: [PATCH 7/8] Highlight selection cursors in a second pass This allows cursors to overlap on next selection and still be visible. --- src/highlighters.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/highlighters.cc b/src/highlighters.cc index ab765bb2e..3f97df847 100644 --- a/src/highlighters.cc +++ b/src/highlighters.cc @@ -522,6 +522,11 @@ void highlight_selections(const Context& context, HighlightFlags flags, DisplayB ColorPair sel_colors = get_color(primary ? "PrimarySelection" : "SecondarySelection"); highlight_range(display_buffer, begin, end, false, [&](DisplayAtom& atom) { atom.colors = sel_colors; }); + } + for (size_t i = 0; i < context.selections().size(); ++i) + { + auto& sel = context.selections()[i]; + const bool primary = (i == context.selections().main_index()); ColorPair cur_colors = get_color(primary ? "PrimaryCursor" : "SecondaryCursor"); highlight_range(display_buffer, sel.cursor(), buffer.char_next(sel.cursor()), false, [&](DisplayAtom& atom) { atom.colors = cur_colors; }); From e78fd2d23523b78c9629b0e8a13a1c338225fd6b Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Mon, 16 Jun 2014 01:00:00 +0100 Subject: [PATCH 8/8] Do not merge overlapping selection when entering append mode Fixes #163 --- src/input_handler.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/input_handler.cc b/src/input_handler.cc index d96a8f10e..b5b6a8477 100644 --- a/src/input_handler.cc +++ b/src/input_handler.cc @@ -842,7 +842,8 @@ private: kak_assert(false); // invalid for interactive insert break; } - selections.sort_and_merge_overlapping(); + if (mode != InsertMode::Append) + selections.sort_and_merge_overlapping(); selections.check_invariant(); buffer.check_invariant(); }