Skip to content

Commit

Permalink
feat: finalise cursor movement
Browse files Browse the repository at this point in the history
feat: option to treat range as separate word group
chore: performance considerations
chore: change default for cursor comment movement
fix: prevent cursor from clipping outside document
  • Loading branch information
Fevol committed Jan 16, 2024
1 parent f32a035 commit 806226d
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 18 deletions.
5 changes: 5 additions & 0 deletions src/api/suggest.ts
@@ -0,0 +1,5 @@
export function suggestAddition(from: number, to: number, text: string) {
/**
* @todo
*/
}
2 changes: 1 addition & 1 deletion src/constants.ts
Expand Up @@ -39,7 +39,7 @@ export const DEFAULT_SETTINGS: PluginSettings = {
[SuggestionType.DELETION]: RANGE_CURSOR_MOVEMENT_OPTION.IGNORE_METADATA,
[SuggestionType.SUBSTITUTION]: RANGE_CURSOR_MOVEMENT_OPTION.IGNORE_METADATA,
[SuggestionType.HIGHLIGHT]: RANGE_CURSOR_MOVEMENT_OPTION.IGNORE_METADATA,
[SuggestionType.COMMENT]: RANGE_CURSOR_MOVEMENT_OPTION.IGNORE_METADATA,
[SuggestionType.COMMENT]: RANGE_CURSOR_MOVEMENT_OPTION.IGNORE_COMPLETELY,
},
bracket_movement: {
[SuggestionType.ADDITION]: RANGE_BRACKET_MOVEMENT_OPTION.STAY_INSIDE,
Expand Down
6 changes: 6 additions & 0 deletions src/editor/base/suggestion-handler/base.ts
@@ -0,0 +1,6 @@
import { SuggestionType } from '../ranges';


function markAs(from: number, to: number, type: SuggestionType) {

}
68 changes: 56 additions & 12 deletions src/editor/base/suggestion-handler/movement.ts
Expand Up @@ -20,16 +20,59 @@ function cat_different(old_cat: CharCategory | null, new_cat: CharCategory | nul
return old_cat !== null && old_cat !== CharCategory.Space && old_cat !== new_cat;
}

/**
* Attempt to efficiently find the new suggestion range after a cursor movement
* @param cursor_head - Current cursor head
* @param ranges - All suggestion ranges in the document
* @param range - Current suggestion range
* @remark This function exists to prevent having to iterate through all suggestion ranges when trying to find the new range after a cursor movement
*/
function find_range_cursor(cursor_head: number, ranges: CriticMarkupRanges, range: CriticMarkupRange) {
if (range.cursor_inside(cursor_head)) {
return range;
} else {
const check_direction = range.cursor_before_range(cursor_head);
let range_idx = ranges.ranges.indexOf(range) + (check_direction ? -1 : 1);

while (range_idx >= 0 && range_idx < ranges.ranges.length) {
range = ranges.ranges[range_idx];
if (check_direction ? range.cursor_before_range(cursor_head) : range.cursor_after_range(cursor_head))
range_idx += check_direction ? -1 : 1;
else
return range.cursor_inside(cursor_head) ? range : undefined;
}
}

return undefined;
}


/**
* Advance the cursor through CriticMarkup syntax, based on the movement options for the range type
* @param cursor_head - Current cursor head
* @param move_forwards - Whether the cursor movement is forwards or backwards
* @param ranges - All suggestion ranges in the document
* @param range - Current suggestion range
* @param movement_options - Options for cursor movement through suggestion ranges
* @param bracket_options - Options for cursor movement between different suggestion ranges
*/
function cursor_advance_through_syntax(cursor_head: number, move_forwards: boolean, ranges: CriticMarkupRanges, range: CriticMarkupRange | undefined, movement_options: RangeCursorMovementOptionsMap, bracket_options: RangeBracketMovementOptionsMap | null): [number, CriticMarkupRange | undefined] {
if (!range)
range = ranges.range_adjacent_to_cursor(cursor_head, !move_forwards, true, true);
else
range = find_range_cursor(cursor_head, ranges, range);

function cursor_advance_through_syntax(cursor_head: number, move_forwards: boolean, ranges: CriticMarkupRanges, movement_options: RangeCursorMovementOptionsMap): [number, CriticMarkupRange | undefined] {
let range = ranges.range_adjacent_to_cursor(cursor_head, !move_forwards, true, true);
let cursor_changed = true;
while (cursor_changed && range) {
const old_cursor_head = cursor_head;
cursor_head = range!.cursor_pass_syntax(cursor_head, move_forwards, movement_options[range!.type]);
cursor_changed = cursor_head !== old_cursor_head;
if (cursor_changed && cursor_head === (move_forwards ? range.to : range.from))
if (cursor_changed && cursor_head === (move_forwards ? range.to : range.from)) {
range = ranges.adjacent_range(range!, !move_forwards, true);
if (range && bracket_options && bracket_options[range.type] === RANGE_BRACKET_MOVEMENT_OPTION.STAY_OUTSIDE) {
break;
}
}
}

return [cursor_head, range];
Expand Down Expand Up @@ -68,42 +111,43 @@ export function cursor_move(original_range: EditorRange, new_range: EditorRange,

// Check if difference in movement is only one character (single character movement)
if (!by_word_group && Math.abs(original_range.head! - new_range.head!) === 1) {
cursor_head = cursor_advance_through_syntax(original_range.head!, move_forwards, ranges, movement_options)[0];
[cursor_head, suggestion_range] = cursor_advance_through_syntax(original_range.head!, move_forwards, ranges, suggestion_range, movement_options, bracket_options);
cursor_head = cursor_head + (move_forwards ? 1 : -1);
} else if (!by_word_group) {
cursor_head = cursor_advance_through_syntax(cursor_head, move_forwards, ranges, movement_options)[0];
[cursor_head, suggestion_range] = cursor_advance_through_syntax(cursor_head, move_forwards, ranges, suggestion_range, movement_options, bracket_options);
} else {
let previous_reg_char = cursor_advance_through_syntax(cursor_head, !move_forwards, ranges, movement_options)[0];
let previous_reg_char = cursor_advance_through_syntax(cursor_head, !move_forwards, ranges, suggestion_range, movement_options, null)[0];
let previous_cat = null,
current_cat = (previous_reg_char === original_range.head!) ? null : getCharCategory(previous_reg_char, state, move_forwards);
let next_cursor_head = cursor_head;

while (!cat_different(previous_cat, current_cat)) {
cursor_head = next_cursor_head;
previous_cat = current_cat;
cursor_head = cursor_advance_through_syntax(cursor_head, move_forwards, ranges, movement_options)[0];
[cursor_head, suggestion_range] = cursor_advance_through_syntax(cursor_head, move_forwards, ranges, suggestion_range, movement_options, bracket_options);
next_cursor_head = findBlockingChar(cursor_head, move_forwards, state, cat_ignore_ws(previous_cat), previous_cat)[0];
if (next_cursor_head === cursor_head)
break;
previous_reg_char = cursor_advance_through_syntax(next_cursor_head, !move_forwards, ranges, movement_options)[0];
previous_reg_char = cursor_advance_through_syntax(next_cursor_head, !move_forwards, ranges, suggestion_range, movement_options, null)[0];
current_cat = getCharCategory(previous_reg_char, state, move_forwards);
}
}

suggestion_range = ranges.range_adjacent_to_cursor(cursor_head, !move_forwards, true, false);
if (suggestion_range) {
// Post-processing step: move cursor back to inside range if necessary
if (suggestion_range && !(cursor_head === 0 || cursor_head === state.doc.length)) {
const range_back = move_forwards ? suggestion_range.to : suggestion_range.from;
// const range_front = move_forwards ? suggestion_range.from : suggestion_range.to;
const offset = move_forwards ? 1 : -1;
if (cursor_head === range_back) {
if (bracket_options[suggestion_range.type] === RANGE_BRACKET_MOVEMENT_OPTION.STAY_INSIDE)
cursor_head = range_back - 3 * offset;
} else if (suggestion_range.touches_bracket(cursor_head, move_forwards, false, true)) {
cursor_head = move_forwards ? suggestion_range.from : suggestion_range.to;
}

}

// Sanity check: clamp cursor to document length
cursor_head = Math.clamp(cursor_head, 0, state.doc.length);

// If the cursor is not a selection, then the cursor anchor should be moved to the cursor head
if (!is_selection)
cursor_anchor = cursor_head;
Expand Down
10 changes: 5 additions & 5 deletions src/ui/pages/settings/tabs/AdvancedSettings.svelte
Expand Up @@ -14,14 +14,14 @@
};
const cursor_movement_options = [
{ value: "unchanged", text: 'Unchanged' },
{ value: "ignore_bracket", text: 'Skip syntax brackets' },
{ value: "ignore_metadata", text: 'Skip syntax brackets and metadata' },
{ value: "ignore_completely", text: 'Skip entire suggestion' },
{ value: "unchanged", text: 'Regular movement' },
{ value: "ignore_bracket", text: 'Skip brackets' },
{ value: "ignore_metadata", text: 'Skip brackets and metadata' },
{ value: "ignore_completely", text: 'Skip completely' },
];
const bracket_movement_options = [
{ value: "unchanged", text: 'Unchanged' },
{ value: "unchanged", text: 'Regular movement' },
{ value: "stay_inside", text: 'Keep cursor within range' },
{ value: "stay_outside", text: 'Treat range as word group' },
];
Expand Down

0 comments on commit 806226d

Please sign in to comment.