react-native-code-editor icon indicating copy to clipboard operation
react-native-code-editor copied to clipboard

Cursor jumps to the start when typing code

Open HarunKaranja opened this issue 3 years ago • 7 comments

https://user-images.githubusercontent.com/98604306/176841761-af583e08-9508-4780-b3c2-0fb53c736305.mp4

How do I solve this

The code

<CodeEditor
  style={Styles.codeEditorStyles}
  language="html"
  syntaxStyle={CodeEditorSyntaxStyles.atomOneDark}
  showLineNumbers
  initialValue={ htmlCode }
/>

Styles

codeEditorStyles: {
  fontFamily: 'Muli',
  fontSize: 20,
  inputLineHeight: 28,
  highlighterLineHeight: 28,
}

HarunKaranja avatar Jul 01 '22 07:07 HarunKaranja

Hello! Thanks for pointing that out. This doesn't seem to be an issue with iOS, and I do not have the necessary tools to test it out on Android.

Help would be appreciated to get this resolved. All of the cursor movements are controlled in the "CodeEditor.tsx" file. There is a method moveCursor(...) that is responsible for moving the cursor around (see here). I would suggest tracing all of the places that use the method and seeing where the issue is occurring.

RivasCVA avatar Jul 01 '22 17:07 RivasCVA

Hi, I just solved this problem with removing some lines of CodeEditor.tsx file which is in the TextInput component. I commented below which lines removed. It's not a real solve but works for me.

Accually, you need to edit moveCursor function. If I can find some time, I'll try to solve at core.

<View style={{ width, height, marginTop, marginBottom }}>
            <SyntaxHighlighter
                language={language}
                addedStyle={addedStyle}
                syntaxStyle={syntaxStyle}
                scrollEnabled={false}
                showLineNumbers={showLineNumbers}
                ref={highlighterRef}
            >
                {value}
            </SyntaxHighlighter>
            <TextInput
                style={[
                    styles.input,
                    {
                        lineHeight: inputLineHeight,
                        color: inputColor,
                        fontFamily: fontFamily,
                        fontSize: fontSize,
                        padding,
                        paddingTop: padding,
                        paddingLeft: lineNumbersPadding,
                    },
                ]}
                value={value}
                onChangeText={handleChangeText}
                onScroll={handleScroll}
                onKeyPress={handleKeyPress}
                onSelectionChange={handleSelectionChange}
                autoCapitalize="none"
                autoComplete="off"
                autoCorrect={false}
                autoFocus={autoFocus}
                // keyboardType="ascii-capable"
                editable={!readOnly}
                // ref={inputRef}
                multiline
            />
        </View>

removed lines

// keyboardType="ascii-capable"
// ref={inputRef}

DeveloperInside avatar Jul 06 '22 16:07 DeveloperInside

Interesting... I'm certain it's fixed because moveCursor(...) requires the inputRef in order to move the cursor. It would be nice to have a solution that doesn't require removing ref={inputRef}.

RivasCVA avatar Jul 07 '22 16:07 RivasCVA

@RivasCVA Please update this library and fix this bug

Ritikkk-09 avatar Apr 11 '23 14:04 Ritikkk-09

It seems to be a bug of setNativeProps. Using the method makes the selection value a fixed value.

Writing the selection changes in props solved the problem while removing the inputRef losses the moveCursor feature of the editor.

Check the changes below.

const CodeEditor = (props: PropsWithForwardRef): JSX.Element => {
    // ...

    const [value, setValue] = useState<string>(initialValue);
    const highlighterRef = useRef<ScrollView>(null);
    const inputRef = useRef<TextInput>(null);
    const [inputSelection, setSelection] = useState({start: 0, end: 0});

    // ...

    const moveCursor = (current: number, amount: number) => {
        const newPosition = current + amount;

        setSelection({
            start: newPosition,
            end: newPosition
        });

        return newPosition;
    };

    const addIndentation = (val: string) => {
        let cursorPosition = inputSelection.start - 1;
        // ...
    };

    const addClosingBrace = (val: string, key: string) => {
        let cursorPosition = inputSelection.start;
        return Strings.insertStringAt(val, cursorPosition, Braces.getCloseBrace(key));
    };

    // ...

    const handleSelectionChange = (e: NativeSyntheticEvent<TextInputSelectionChangeEventData>) => {
        setSelection(e.nativeEvent.selection);
    };

    return (
        <View style={{ width, height, marginTop, marginBottom }}>
            <SyntaxHighlighter
                // ...
            >
                {value}
            </SyntaxHighlighter>
            <TextInput
                // ...
                selection={inputSelection}
            />
        </View>
    );
};

Kim1254 avatar Jun 15 '23 19:06 Kim1254

@KyeongMin5307 Can you make the changes a PR?

RivasCVA avatar Jun 18 '23 17:06 RivasCVA

@KyeongMin5307 Can you make the changes a PR?

Using selection props seems to make critical problems. I met race conditions in cursor selection. I could find that it is a bug of TextInput in react-native: https://github.com/facebook/react-native/issues/29063#issuecomment-658615266

Therefore, I rewrote the code using setNativeProps for every handleChangeText call. Referenced: https://github.com/facebook/react-native/issues/29063#issuecomment-792955726

const handleChangeText = (text: string) => {
	const diff = text.length - value.length;
	setValue(Strings.convertTabsToSpaces(text));
	
	inputRef.current?.setNativeProps({
		selection: {
			start: inputSelection.current.start + diff,
			end: inputSelection.current.start + diff,
		},
	});
};

Check the details in the PR.

  • PostScript: The PR contains changes of addIndentation and addClosingBrace. I've changed the position value in those functions since it made serval position mismatches. (Maybe it is related to the TextInput difference between Android and iOS.) Please ignore extra changes if the indentation changes are incorrect.

Here's a demo video.

https://github.com/RivasCVA/react-native-code-editor/assets/93812148/4a37e01f-98bd-49c1-86bf-06105fb7f68a

  • Execution environment: Samsung Galaxy Z Flip 5G (SM-F707) Android 13 (One UI 4.1.1) "react": "17.0.2" "react-native": "^0.68.5"

Kim1254 avatar Jun 19 '23 14:06 Kim1254