Skip to content

Tab should indent highlighted text or move it to the left! #110

Open
@AmirTallap

Description

@AmirTallap

Feature request
Tab should indent highlighted text or move it to the left!
EDIT:
Sorry guys, I meant to the right

Activity

stianhoiland

stianhoiland commented on May 20, 2025

@stianhoiland

Big +1 for this one.

added
E-help-wantedWe encourage you to jump in on these!
I-taskSmaller tasks. Requires work in the 100s of LOC (usually).
on May 20, 2025
lhecker

lhecker commented on May 20, 2025

@lhecker
Member

To solve this we need to duplicate the existing unindent method:

edit/src/buffer/mod.rs

Lines 1965 to 2040 in d832058

/// Unindents the current selection or line.
///
/// TODO: This function is ripe for some optimizations:
/// * Instead of replacing the entire selection,
/// it should unindent each line directly (as if multiple cursors had been used).
/// * The cursor movement at the end is rather costly, but at least without word wrap
/// it should be possible to calculate it directly from the removed amount.
pub fn unindent(&mut self) {
let mut selection_beg = self.cursor.logical_pos;
let mut selection_end = selection_beg;
if let Some(TextBufferSelection { beg, end }) = self.selection {
selection_beg = beg;
selection_end = end;
}
let [beg, end] = minmax(selection_beg, selection_end);
let beg = self.cursor_move_to_logical_internal(self.cursor, Point { x: 0, y: beg.y });
let end = self.cursor_move_to_logical_internal(beg, Point { x: CoordType::MAX, y: end.y });
let mut replacement = Vec::new();
self.buffer.extract_raw(beg.offset, end.offset, &mut replacement, 0);
let initial_len = replacement.len();
let mut offset = 0;
let mut y = beg.logical_pos.y;
loop {
if offset >= replacement.len() {
break;
}
let mut remove = 0;
if replacement[offset] == b'\t' {
remove = 1;
} else {
while remove < self.tab_size as usize
&& offset + remove < replacement.len()
&& replacement[offset + remove] == b' '
{
remove += 1;
}
}
if remove > 0 {
replacement.drain(offset..offset + remove);
}
if y == selection_beg.y {
selection_beg.x -= remove as CoordType;
}
if y == selection_end.y {
selection_end.x -= remove as CoordType;
}
(offset, y) = unicode::newlines_forward(&replacement, offset, y, y + 1);
}
if replacement.len() == initial_len {
// Nothing to do.
return;
}
self.edit_begin(HistoryType::Other, beg);
self.edit_delete(end);
self.edit_write(&replacement);
self.edit_end();
if let Some(TextBufferSelection { beg, end }) = &mut self.selection {
*beg = selection_beg;
*end = selection_end;
}
self.set_cursor_internal(self.cursor_move_to_logical_internal(self.cursor, selection_end));
}

+1000 bonus points if we can do this by abstracting this into a single change_indent function that takes the change as a CoordType (aka i32) and solves everything neatly. 😅

liltrendi

liltrendi commented on May 23, 2025

@liltrendi
liltrendi

liltrendi commented on Jun 14, 2025

@liltrendi

@AmirTallap was this ever implemented (perhaps by some other PR)? Haven't seen much activity here.

kayahr

kayahr commented on Jun 16, 2025

@kayahr

For motivation a reminder from the good old days 👴 :

Screencast.From.2025-06-16.14-53-09.mp4
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    E-help-wantedWe encourage you to jump in on these!I-taskSmaller tasks. Requires work in the 100s of LOC (usually).

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      Participants

      @kayahr@stianhoiland@lhecker@AmirTallap@liltrendi

      Issue actions

        Tab should indent highlighted text or move it to the left! · Issue #110 · microsoft/edit