@@ -561,16 +561,23 @@ contains |
| 561 | pos = cursor%column | 561 | pos = cursor%column |
| 562 | | 562 | |
| 563 | if (pos <= len(line)) then | 563 | if (pos <= len(line)) then |
| 564 | - ! Skip current word | 564 | + ! Check what we're currently on |
| 565 | - in_word = is_word_char(line(pos:pos)) | 565 | + if (pos <= len(line) .and. is_word_char(line(pos:pos))) then |
| 566 | - do while (pos <= len(line) .and. is_word_char(line(pos:pos)) .eqv. in_word) | 566 | + ! We're on a word character - skip to end of word |
| 567 | - pos = pos + 1 | 567 | + do while (pos <= len(line) .and. is_word_char(line(pos:pos))) |
| 568 | - end do | 568 | + pos = pos + 1 |
| 569 | - | 569 | + end do |
| 570 | - ! Skip whitespace | 570 | + else |
| 571 | - do while (pos <= len(line) .and. line(pos:pos) == ' ') | 571 | + ! We're on whitespace or punctuation - skip to next word |
| 572 | - pos = pos + 1 | 572 | + ! Skip non-word characters |
| 573 | - end do | 573 | + do while (pos <= len(line) .and. .not. is_word_char(line(pos:pos))) |
| | 574 | + pos = pos + 1 |
| | 575 | + end do |
| | 576 | + ! Then skip to end of that word |
| | 577 | + do while (pos <= len(line) .and. is_word_char(line(pos:pos))) |
| | 578 | + pos = pos + 1 |
| | 579 | + end do |
| | 580 | + end if |
| 574 | | 581 | |
| 575 | cursor%column = pos | 582 | cursor%column = pos |
| 576 | else if (cursor%line < line_count) then | 583 | else if (cursor%line < line_count) then |
@@ -2114,15 +2121,17 @@ contains |
| 2114 | type(buffer_t), intent(in) :: buffer | 2121 | type(buffer_t), intent(in) :: buffer |
| 2115 | integer, intent(in) :: line, column | 2122 | integer, intent(in) :: line, column |
| 2116 | integer :: pos | 2123 | integer :: pos |
| 2117 | - integer :: current_line, i | 2124 | + integer :: current_line, i, col_in_line |
| 2118 | character :: ch | 2125 | character :: ch |
| 2119 | | 2126 | |
| 2120 | pos = 1 | 2127 | pos = 1 |
| 2121 | current_line = 1 | 2128 | current_line = 1 |
| | 2129 | + col_in_line = 1 |
| 2122 | | 2130 | |
| 2123 | ! Find the position for the given line and column | 2131 | ! Find the position for the given line and column |
| 2124 | do i = 1, get_buffer_content_size(buffer) | 2132 | do i = 1, get_buffer_content_size(buffer) |
| 2125 | - if (current_line == line .and. pos == column) then | 2133 | + if (current_line == line .and. col_in_line == column) then |
| | 2134 | + pos = i |
| 2126 | return | 2135 | return |
| 2127 | end if | 2136 | end if |
| 2128 | | 2137 | |
@@ -2130,21 +2139,18 @@ contains |
| 2130 | if (ch == char(10)) then | 2139 | if (ch == char(10)) then |
| 2131 | if (current_line == line) then | 2140 | if (current_line == line) then |
| 2132 | ! We're at the end of the target line | 2141 | ! We're at the end of the target line |
| | 2142 | + pos = i |
| 2133 | return | 2143 | return |
| 2134 | end if | 2144 | end if |
| 2135 | current_line = current_line + 1 | 2145 | current_line = current_line + 1 |
| 2136 | - pos = 1 | 2146 | + col_in_line = 1 |
| 2137 | - else if (current_line == line) then | 2147 | + else |
| 2138 | - pos = pos + 1 | 2148 | + col_in_line = col_in_line + 1 |
| 2139 | end if | 2149 | end if |
| 2140 | end do | 2150 | end do |
| 2141 | | 2151 | |
| 2142 | ! If we reach here, we're at the end of the buffer | 2152 | ! If we reach here, we're at the end of the buffer |
| 2143 | - if (current_line == line) then | 2153 | + pos = get_buffer_content_size(buffer) + 1 |
| 2144 | - pos = i | | |
| 2145 | - else | | |
| 2146 | - pos = get_buffer_content_size(buffer) + 1 | | |
| 2147 | - end if | | |
| 2148 | end function get_buffer_position | 2154 | end function get_buffer_position |
| 2149 | | 2155 | |
| 2150 | function get_buffer_content_size(buffer) result(size) | 2156 | function get_buffer_content_size(buffer) result(size) |
@@ -2622,7 +2628,7 @@ contains |
| 2622 | type(cursor_t), intent(inout) :: cursor | 2628 | type(cursor_t), intent(inout) :: cursor |
| 2623 | type(buffer_t), intent(inout) :: buffer | 2629 | type(buffer_t), intent(inout) :: buffer |
| 2624 | character(len=:), allocatable :: current_line, next_line | 2630 | character(len=:), allocatable :: current_line, next_line |
| 2625 | - integer :: line_count, current_len | 2631 | + integer :: line_count, current_len, leading_spaces |
| 2626 | | 2632 | |
| 2627 | line_count = buffer_get_line_count(buffer) | 2633 | line_count = buffer_get_line_count(buffer) |
| 2628 | | 2634 | |
@@ -2634,19 +2640,25 @@ contains |
| 2634 | next_line = buffer_get_line(buffer, cursor%line + 1) | 2640 | next_line = buffer_get_line(buffer, cursor%line + 1) |
| 2635 | current_len = len(current_line) | 2641 | current_len = len(current_line) |
| 2636 | | 2642 | |
| 2637 | - ! Delete the newline at the end of the current line | 2643 | + ! Count leading whitespace in next line |
| 2638 | - call buffer_delete_range(buffer, cursor%line, current_len + 1, cursor%line + 1, 1) | 2644 | + leading_spaces = 0 |
| | 2645 | + do while (leading_spaces < len(next_line) .and. & |
| | 2646 | + (next_line(leading_spaces + 1:leading_spaces + 1) == ' ' .or. & |
| | 2647 | + next_line(leading_spaces + 1:leading_spaces + 1) == char(9))) |
| | 2648 | + leading_spaces = leading_spaces + 1 |
| | 2649 | + end do |
| 2639 | | 2650 | |
| 2640 | - ! If the next line wasn't empty, insert a space between the lines | 2651 | + ! Delete the newline and leading whitespace from next line |
| 2641 | - if (len(trim(next_line)) > 0) then | 2652 | + if (leading_spaces > 0) then |
| 2642 | - ! Find first non-whitespace character in next line | 2653 | + call buffer_delete_range(buffer, cursor%line, current_len + 1, cursor%line + 1, leading_spaces + 1) |
| 2643 | - do while (len(next_line) > 0 .and. & | 2654 | + else |
| 2644 | - (next_line(1:1) == ' ' .or. next_line(1:1) == char(9))) | 2655 | + call buffer_delete_range(buffer, cursor%line, current_len + 1, cursor%line + 1, 1) |
| 2645 | - next_line = next_line(2:) | 2656 | + end if |
| 2646 | - end do | | |
| 2647 | | 2657 | |
| 2648 | - ! Insert a space if current line doesn't end with space and next line has content | 2658 | + ! If the next line had non-whitespace content, insert a space between the lines |
| 2649 | - if (current_len > 0 .and. len(next_line) > 0) then | 2659 | + if (leading_spaces < len(next_line)) then |
| | 2660 | + ! Insert a space if current line doesn't end with space |
| | 2661 | + if (current_len > 0) then |
| 2650 | if (current_line(current_len:current_len) /= ' ') then | 2662 | if (current_line(current_len:current_len) /= ' ') then |
| 2651 | call buffer_insert_text_at(buffer, cursor%line, current_len + 1, ' ') | 2663 | call buffer_insert_text_at(buffer, cursor%line, current_len + 1, ' ') |
| 2652 | end if | 2664 | end if |