Menu

#182 kb shortcut: tab indent selection (Shift Left/Right)

development
open
nobody
None
5
2022-10-05
2020-01-02
No

I have created a patch for Nedit 5.6 that changes the "Shift Left/Right" tab indentation keyboard shortcuts from Ctrl-Shift-9/Ctrl-Shift-0 to Shift Tab/Tab respectively. This makes the [Shift] Tab key indent selected text when text is selected (rather than simply inserting a tab character). These keyboard shortcuts are commonly used in modern text editors (e.g. TextPad/MS Visual Studio/etc).

Here is a summary of the changes;

nedit.h;

~l45: 
    #define TAB_SELECT_SHIFT_TEXT_PATCH


nedit.c;

~l266:
    #ifdef TAB_SELECT_SHIFT_TEXT_PATCH
    "*editMenu.shiftLeft.accelerator: Ctrl<Key>9",
    "*editMenu.shiftLeft.acceleratorText: Shift Tab",
    "*editMenu.shiftLeftShift.accelerator: Shift<Key>Tab",
    "*editMenu.shiftRight.accelerator: Ctrl<Key>0",
    "*editMenu.shiftRight.acceleratorText: Tab",
    "*editMenu.shiftRightShift.accelerator: <Key>Tab",
    #else
    "*editMenu.shiftLeft.accelerator: Ctrl<Key>9",
    "*editMenu.shiftLeft.acceleratorText: [Shift]Ctrl+9",
    "*editMenu.shiftLeftShift.accelerator: Shift Ctrl<Key>9",
    "*editMenu.shiftRight.accelerator: Ctrl<Key>0",
    "*editMenu.shiftRight.acceleratorText: [Shift]Ctrl+0",
    "*editMenu.shiftRightShift.accelerator: Shift Ctrl<Key>0",
    #endif


menu.c;    

~l107;
#ifdef TAB_SELECT_SHIFT_TEXT_PATCH
static void shiftLeftShiftCB(Widget w, XtPointer clientData, XtPointer callData);
static void shiftRightShiftCB(Widget w, XtPointer clientData, XtPointer callData);
#endif

~l741;
#ifdef TAB_SELECT_SHIFT_TEXT_PATCH 
    createFakeMenuItem(menuPane, "shiftLeftShift", shiftLeftShiftCB, window);
#else
    createFakeMenuItem(menuPane, "shiftLeftShift", shiftLeftCB, window);
#endif
...
#ifdef TAB_SELECT_SHIFT_TEXT_PATCH 
    createFakeMenuItem(menuPane, "shiftRightShift", shiftRightShiftCB, window);
#else
    createFakeMenuItem(menuPane, "shiftRightShift", shiftRightCB, window);
#endif

~1413;
#ifdef TAB_SELECT_SHIFT_TEXT_PATCH
static void shiftLeftShiftCB(Widget w, XtPointer clientData, XtPointer callData)
{   
    HidePointerOnKeyedEvent(WidgetToWindow(MENU_WIDGET(w))->lastFocus,
            ((XmAnyCallbackStruct *)callData)->event);
    XtCallActionProc(WidgetToWindow(MENU_WIDGET(w))->lastFocus,
            "shift_left_by_tab",
            ((XmAnyCallbackStruct *)callData)->event, NULL, 0);
}

static void shiftRightShiftCB(Widget w, XtPointer clientData, XtPointer callData)
{
    WindowInfo *window = WidgetToWindow(MENU_WIDGET(w));
    if(window->buffer->primary.selected)
    {
        HidePointerOnKeyedEvent(WidgetToWindow(MENU_WIDGET(w))->lastFocus,
                ((XmAnyCallbackStruct *)callData)->event);
        XtCallActionProc(WidgetToWindow(MENU_WIDGET(w))->lastFocus,
                "shift_right_by_tab",
                ((XmAnyCallbackStruct *)callData)->event, NULL, 0);    
    }
    else
    {
        /*just add the 'tab' character as normal*/
    XEvent *event = ((XmAnyCallbackStruct *)callData)->event;
    /*
    tw->text.autoWrapPastedText
    */
    Widget tw = window->textArea;
    TextInsertAtCursor(tw, "\t", event, True, True);
    }
}
#endif 
1 Attachments

Discussion

  • TK Soh

    TK Soh - 2020-06-21

    I like this. Will try it out. BTW, what's the reason for those "#ifdef TAB_SELECT_SHIFT_TEXT_PATCH"? Not sure why they are needed.

     
    • BAI Research

      BAI Research - 2020-07-06

      Hi TK Soh. The preprocessor defs are added for development purposes only (the patch is under testing). I have been testing this patch for 6 months now, and have detected these issues;

      1. The patch doesn't currently work with emulated tab stops. Assume the cursor is at some position on a line, and the user presses the tab key, an actual tab character will be added (rather than a section of white space emulated the tab character). This limitation does not apply to (de)indenting selected text.
      2. The patch doesn't currently work with with split pane mode. In split screen mode ("Windows - Split Pane"), a) setting the cursor position to some position in the second pane and then b) pressing the tab (indentation) key, will apply the tab (indentation) operation to the previous cursor position of the first pane.
      3. Unintuitive single line text subset indentation implementation. When selecting some subset of text on a line, and pressing the 'tab' button to indent this text, nedit will then proceed to a) indent the entire line and b) select the entire line. This implementation has not changed, but it would be better if it a) indented only the selected text and b) maintained the selection. Note: Textpad deletes the selected text and replaces it with a tab character.
      4. Unintuitive single line deindentation implementation. Assume the current line has some indented text, and the cursor is at the start of the indented text. When the user presses "shift tab" (deindent), nedit deindents the text but then proceeds to select the entire line. This implementation has not changed, but it would be better if it a) deindented the text and b) did not select the line. Note 1: Textpad currently shifts cursor to the previous indentation position without deindenting the text. Note 2: This is particularly unintuitive if for example a line of text includes "[cell1Text] [tab] {cursorPos}[cell2Text]", and the user presses "shift tab" (deindent): because the line is not prefixed with any indentation, no operation will be applied.
       
      • TK Soh

        TK Soh - 2020-07-08

        Thanks for the detail summary. Given the issues you experienced, with respect, I took a different approach by overloading the action procedure of tab key with a wrapper that calls "shift_right_by_tab" (or "shift_left_by_tab", on shift-tab) when user selected one line or more, or else call "process_tab" as done originally. I have compared it to notepad++ and it behaves similarly.

        My hope is that this will maintain the backward compatibility to the original behavior, and let nedit handle the tab emulation accordingly too.

        I've attached patch against the latest rev of nedit source. Please give it a try if you can. Let me know if you have any comment/concerns.

         
        • BAI Research

          BAI Research - 2020-07-21

          Cheers TK Soh - I have started to test the patch. Some issues I have noticed with this version;

          1. It doesn't support deindentation (shift-tab) of indented text when the cursor is placed on the line that is desired to be deindented (e.g. at the end of the indentation/tab characters, the position which is desired to be deindented). It only works when the line(s) are selected/highlighted.
          2. Either the entire line must be selected (with cursor position on start of next line) or multiple lines must be selected for indentation/deindentation to work.
           
          • TK Soh

            TK Soh - 2020-07-23

            Hi Richard. Thanks for testing and spotting the issue. Before we move further, perhaps we should first define the behavior of tab & shift-tab more clearly. I start by looking at the Qt Creator 4.12.2, Visual Studio 2019 v16.6.1 and Notepad++ on how they handle tab & shift-tab.

            On Tab:

            • Basically all three editors just insert tab characters.
            • Any 'short-range' selection on the line will be deleted (there seems to be a bug in Qt where it does not insert a tab char).
            • multi-line selection will be indented.

            On Shift-Tab:

            • when the cursor is placed (without selecting text) at the begining or in the middle of a line:
              • Qt and VS would delete the preceding tab chars when shift-tab is pressed, otherwise they do nothing
              • notepad++ would start shifting the cursor to the left by following the tab postions.
            • multi-line selection will be un-indented.

            Personally I feel Qt and VS is more consistent and intuitive. Please share your thought. Thanks.

             

            Last edit: TK Soh 2020-07-23
            • BAI Research

              BAI Research - 2020-07-24

              Thank you for performing this detailed experiment. I have added my preferred behaviour below, although the chosen "select part of line" behaviour is somewhat unique and is disputable as a reasonable development target.

              Visual Studio 2017;
              select multiple lines:

              • tab: indents
              • shift tab: deindents
                select whole of line;
              • tab: adds tab
              • shift tab: no change
                select part of line;
              • tab: adds tab
              • shift tab: deindents
                position cursor:
              • tab: indents
              • shift tab: deindents

              Textpad 4;
              select multiple lines:

              • tab: indents
              • shift tab: deindents
                select whole of line;
              • tab: adds tab
              • shift tab: deindents
                select part of line;
              • tab: adds tab
              • shift tab: deindents and selects whole line
                position cursor:
              • tab: indents
              • shift tab: shifts cursor back

              Qt Creator;
              select multiple lines:

              • tab: indents
              • shift tab: deindents
                select whole of line;
              • tab: indents
              • shift tab: deindents
                select part of line;
              • tab: deletes text
              • shift tab: deletes text
                position cursor:
              • tab: indents
              • shift tab: deindents

              Notepad++;
              select multiple lines:

              • tab: indents
              • shift tab: deindents
                select whole of line;
              • tab: adds tab
              • shift tab: deindents [and unselects text, placing cursor at start of indented text]
                select part of line;
              • tab: adds tab
              • shift tab: shifts cursor forward by a tab
                position cursor:
              • tab: indents
              • shift tab: deindents

              RB patch #1 (nedit5.6UB-withSelectTab.patch);
              select multiple lines:

              • tab: indents
              • shift tab: deindents
                select whole of line;
              • tab: indents
              • shift tab: deindents
                select part of line;
              • tab: indents and selects whole line
              • shift tab: deindents and selects whole line
                position cursor:
              • tab: indents
              • shift tab: deindents and selects whole line

              TK Soh patch #1 (nedit-tab-indent-tksoh-08072020.diff);
              select multiple lines:

              • tab: indents
              • shift tab: deindents
                select whole of line;
              • tab: adds tab
              • shift tab: adds tab
                select part of line;
              • tab: adds tab
              • shift tab: adds tab
                cursor:
              • tab: adds tab
              • shift tab: adds tab

              RB preferred (theoretical);
              select multiple lines:

              • tab: indents {same as all: VS, Qt, Notepad++, TextPad, RB#1, TK#1}
              • shift tab: deindents {same as all: VS, Qt, Notepad++, TextPad, RB#1, TK#1}
                select whole of line;
              • tab: indents {same as VS, Qt, Notepad++, TextPad, RB#1}
              • shift tab: deindents {same as Qt, Textpad, RB#1, similar to Notepad++}
                select part of line;
              • tab: indents {similar to RB#1}
              • shift tab: deindents {same as VS, similar to RB#1}
                position cursor:
              • tab: indents {same as VS, Qt, Notepad++, TextPad, RB#1, TK#1}
              • shift tab: deindents {same as VS, Qt, Notepad++, similar to RB#1}
               

              Last edit: BAI Research 2020-07-24
              • TK Soh

                TK Soh - 2020-11-08

                My apology on the long silence, as I have been busy on the other projects that pay the bills.

                Thanks for putting this very nice analysis together. Truth to be told, I am having a slight second thought on this feature, especially to this legacy NEdit (maybe the nedit-ng team can take on it instead). The good news is that NEdit already is able to achieve the purpose, just not what the users are used to when coming from using other more 'modern' editors. Perhaps it can wait a little.

                 
  • BAI Research

    BAI Research - 2022-07-14

    Hi TK Soh, thanks for your analysis.

    I recommend implementing your version (TK#1; nedit-tab-indent-tksoh-08072020.diff); it provides the core patch functionality with minimum behavioural changes to the original.

     
    • BAI Research

      BAI Research - 2022-10-05

      Patch against 5.7 release.

       

Log in to post a comment.

MongoDB Logo MongoDB