Help with cursor position

This is bugging me. This is the second part of a two part action script— the first allows me to select a position in my current draft, this moves selected line(s) to the selected position. I want the moved line to be selected, but no matter what I’m doing, the cursor ends up at the end of the draft. I feel like I might be overlooking something obvious, just not sure what…


if (context.previewValues["selectedLine"] !== undefined) {
    let selectedLine = JSON.parse(context.previewValues["selectedLine"]);

    if (selectedLine) {
        let targetLineIndex = parseInt(selectedLine.lineNumber);  
        
        // Get the text content of the draft
        let content = draft.content;
        let lines = content.split("\n");
        
        // Get the current selection range
        let selectionRange = editor.getSelectedRange();
        let selectionStart = selectionRange[0];
        let selectionEnd = selectionRange[0] + selectionRange[1];
        
        // Find the start and end line indices
        let textBeforeStart = content.substring(0, selectionStart);
        let textBeforeEnd = content.substring(0, selectionEnd);
        let startLineIndex = textBeforeStart.split('\n').length - 1;
        let endLineIndex = textBeforeEnd.split('\n').length - 1;
        
        // Only proceed if target is not within the selected range
        if (!(targetLineIndex >= startLineIndex && targetLineIndex <= endLineIndex)) {	
        	// save current version
        	draft.saveVersion()

            // Extract the lines to move
            let linesToMove = lines.slice(startLineIndex, endLineIndex + 1);
            
            // Remove the lines from their current position
            lines.splice(startLineIndex, endLineIndex - startLineIndex + 1);
            
            // Adjust target index if we removed lines before it
            let adjustedTargetIndex = targetLineIndex;
            if (startLineIndex <= targetLineIndex) {
                adjustedTargetIndex -= (endLineIndex - startLineIndex + 1);
            }
            
            // Insert the lines at the new position (after the target line)
            lines.splice(adjustedTargetIndex + 1, 0, ...linesToMove);
            
            // Update the draft content
            draft.content = lines.join("\n");
            
            // Calculate new cursor position (at the start of moved lines)
            let linesBeforeMovedLines = lines.slice(0, adjustedTargetIndex + 1);
            let newCursorPos = linesBeforeMovedLines.join("\n").length + 1;
            
            // Calculate the length of the moved content for selection
            let movedContent = linesToMove.join("\n");
            
            // Select the entire moved block
            editor.setSelectedRange(newCursorPos, movedContent.length);
        }
	} else {
        context.fail("No heading was selected or passed correctly.");
    }
}

else if (context.previewValues["moveToEnd"] !== undefined) {
    let selectionData = JSON.parse(context.previewValues["moveToEnd"]);
    let startLineIndex = parseInt(selectionData.startLine);
    let endLineIndex = parseInt(selectionData.endLine);

    let content = draft.content;
    let lines = content.split('\n');

    // Validate line indices
    if (startLineIndex >= 0 && startLineIndex < lines.length && 
        endLineIndex >= 0 && endLineIndex < lines.length &&
        startLineIndex <= endLineIndex) {
        
        // Save current version
        draft.saveVersion();
        
        // Extract the lines to move
        let linesToMove = lines.slice(startLineIndex, endLineIndex + 1);
        
        // Remove the lines from their current position
        lines.splice(startLineIndex, endLineIndex - startLineIndex + 1);
        
        // Trim empty lines from the end before appending
        while (lines.length > 0 && lines[lines.length - 1].trim() === '') {
            lines.pop();
        }
        
        // Append the moved lines to the end
        lines.push(...linesToMove);
        
        // Update the draft content
        draft.content = lines.join('\n');
        
        // Calculate new cursor position (at the start of moved lines at the end)
        let linesBeforeMovedLines = lines.slice(0, lines.length - linesToMove.length);
        let newCursorPos = linesBeforeMovedLines.length > 0 ? 
            linesBeforeMovedLines.join('\n').length + 1 : 0;
        
        // Calculate the length of the moved content for selection
        let movedContent = linesToMove.join('\n');
        
        // Select the entire moved block
        editor.setSelectedRange(newCursorPos, movedContent.length);
    } else {
        context.fail("Invalid line selection.");
    }

}

draft.update();
editor.activate();    

I didn’t do a detailed analysis, but from a quick look, I’d say your problem likely derives from mixing and matching manipulation of the draft and the editor object. Typically, you should only work with one, at least for updates.

If you are doing updates that manipulate the editor, like changing ranges, you should also be using editor.setText to make updates to the draft.

This is for a couple of reasons, the biggest one being there’s no guarantee the draft object is actually referring to the draft that is loaded in the editor. It usually is, if you run an action from inside drafts via the action list, but if you run “Run Action” from the draft list, or call and action via URL or Shortcuts, that may not always be true.

The more important reason, in this case, is that changing the content of the draft does not update the editor in real time. It’s a bit more complex than this, but think of it like the action will clean up at the end of an action and if a change is made to a draft object that happens to be the one loaded in the editor, the editor will reload it at the end of the action.

1 Like

(PS, it’s worth noting also, that editor calls that change text participate in the undo stack, so, after the action is performed, if you don’t like the resulting change, you can hit “undo” to back out the changes)

Aha. This answers another question that had been brewing. Thanks.