Selaa lähdekoodia

The word-wise navigation using Ctrl+Arrow keys in TInputLine and TEditor was inconsistent with the behavior found in most modern text editors.
When the cursor was positioned at the first or last significant (non-whitespace) character, it would not proceed to the absolute start or end of the line on a subsequent keypress. This made it cumbersome to select an entire line easily.

This commit updates the logic to align with modern UI standards:
- In TInputLine, when the cursor is at the first significant character, the next Ctrl+Left press now moves it to the absolute beginning of the line. Similarly, Ctrl+Right from the last significant character moves it to the absolute end.
- In TEditor, the PrevWord and NextWord methods have been updated with the same logic, ensuring consistent behavior for Ctrl+Arrow navigation.

This enhancement provides a more intuitive and efficient user experience for text navigation and selection.

Ivan Sorokin 1 viikko sitten
vanhempi
commit
e17ee248c3
2 muutettua tiedostoa jossa 70 lisäystä ja 10 poistoa
  1. 24 10
      packages/fv/src/dialogs.inc
  2. 46 0
      packages/fv/src/editors.inc

+ 24 - 10
packages/fv/src/dialogs.inc

@@ -1973,12 +1973,19 @@ BEGIN
              if (Data <> Sw_PString_Empty) and (CurPos > 0) then
              begin
                S := Data Sw_PString_DeRef;
-               I := CurPos;
-               // Skip any delimiters immediately to the left
-               while (I > 0) and IsDelimiter(S[I]) do Dec(I);
-               // Skip any word characters to the left
-               while (I > 0) and not IsDelimiter(S[I]) do Dec(I);
-               CurPos := I;
+               I := 1;
+               while (I <= Length(S)) and IsDelimiter(S[I]) do Inc(I);
+               if CurPos = I - 1 then
+                 CurPos := 0
+               else
+               begin
+                 I := CurPos;
+                 // Skip any delimiters immediately to the left
+                 while (I > 0) and IsDelimiter(S[I]) do Dec(I);
+                 // Skip any word characters to the left
+                 while (I > 0) and not IsDelimiter(S[I]) do Dec(I);
+                 CurPos := I;
+               end;
              end;
            End;
            kbCtrlRight: Begin
@@ -1986,10 +1993,17 @@ BEGIN
              begin
                S := Data Sw_PString_DeRef;
                Len := Length(S);
-               I := CurPos;
-               while (I < Len) and IsDelimiter(S[I+1]) do Inc(I);
-               while (I < Len) and not IsDelimiter(S[I+1]) do Inc(I);
-               CurPos := I;
+               I := Len;
+               while (I > 0) and IsDelimiter(S[I]) do Dec(I);
+               if CurPos = I then
+                 CurPos := Len
+               else
+               begin
+                 I := CurPos;
+                 while (I < Len) and IsDelimiter(S[I+1]) do Inc(I);
+                 while (I < Len) and not IsDelimiter(S[I+1]) do Inc(I);
+                 CurPos := I;
+               end;
              end;
            End;
            kbHome: CurPos := 0;                       { Move to line start }

+ 46 - 0
packages/fv/src/editors.inc

@@ -3267,7 +3267,32 @@ end; { TEditor.NextLine }
 
 
 function TEditor.NextWord (P : Sw_Word) : Sw_Word;
+var
+  LineStartPtr, LineEndPtr, LastSignificantPtr: Sw_Word;
 begin
+  LineEndPtr   := LineEnd(P);
+
+  // Special case: if cursor is on the last word of the line, jump to the end of the line.
+  if P < LineEndPtr then
+  begin
+    LineStartPtr := LineStart(P);
+    // Find the position of the last significant character on the line.
+    LastSignificantPtr := LineEndPtr;
+    if LastSignificantPtr > LineStartPtr then
+      LastSignificantPtr := PrevChar(LastSignificantPtr); // Move before any EOL characters.
+
+    while (LastSignificantPtr > LineStartPtr) and IsDelimiter(BufChar(LastSignificantPtr)) do
+      LastSignificantPtr := PrevChar(LastSignificantPtr);
+
+    // If cursor is at or after the last significant character, the next word is the end of the line.
+    if P >= LastSignificantPtr then
+    begin
+      NextWord := LineEndPtr;
+      exit;
+    end;
+  end;
+
+  // Default to original behavior (which can cross lines).
   while (P < BufLen) and IsDelimiter(BufChar(P)) do
     P := NextChar(P);
   while (P < BufLen) and not IsDelimiter(BufChar(P)) do
@@ -3341,7 +3366,28 @@ end; { TEditor.PrevLine }
 
 
 function TEditor.PrevWord (P : Sw_Word) : Sw_Word;
+var
+  LineStartPtr, FirstSignificantPtr: Sw_Word;
 begin
+  LineStartPtr := LineStart(P);
+
+  // Special case: if cursor is on the first word of the line, jump to the start of the line.
+  if P > LineStartPtr then
+  begin
+    // Find the first significant character on the current line.
+    FirstSignificantPtr := LineStartPtr;
+    while (FirstSignificantPtr < P) and IsDelimiter(BufChar(FirstSignificantPtr)) do
+      FirstSignificantPtr := NextChar(FirstSignificantPtr);
+
+    // If the cursor is at or before the first significant character, move to the absolute beginning of the line.
+    if P <= FirstSignificantPtr then
+    begin
+      PrevWord := LineStartPtr;
+      exit;
+    end;
+  end;
+
+  // Default to original behavior (which can cross lines).
   // Skip any delimiters immediately to the left
   while (P > 0) and IsDelimiter(BufChar(PrevChar(P))) do
     P := PrevChar(P);