spyder-ide / spyder

Official repository for Spyder - The Scientific Python Development Environment
https://www.spyder-ide.org
MIT License
8.22k stars 1.59k forks source link

Typed parenthesis ignored when all parentheses are matched #12018

Open MortenHannemose opened 4 years ago

MortenHannemose commented 4 years ago

Issue Report Checklist

Problem Description

Enabling Automatic insertion of parentheses, braces and brackets causes typed parentheses to be ignored when all parentheses are currently matched and the cursor is in front of an ). The character is not typed, the cursor is only advanced.

This is something I often want to do, when I have a line of code already and want to call a function on it, and start by typing the ).

What steps reproduce the problem?

  1. Enable Automatic insertion of parentheses, braces and brackets
  2. Type fun(val|) (| indicates cursor position)
  3. Now type )

What is the expected output? What do you see instead?

After typing ), I expect Spyder to insert a ), like so: fun(val)|) Instead the cursor moves one position to the right, without adding a ) like so: fun(val)|

Versions

Dependencies


# Mandatory:
atomicwrites >=1.2.0           :  1.3.0 (OK)
chardet >=2.0.0                :  3.0.4 (OK)
cloudpickle >=0.5.0            :  1.3.0 (OK)
diff_match_patch >=20181111    :  20181111 (OK)
intervaltree                   :  None (OK)
IPython >=4.0                  :  7.13.0 (OK)
jedi =0.15.2                   :  0.15.2 (OK)
nbconvert >=4.0                :  5.6.1 (OK)
numpydoc >=0.6.0               :  0.9.2 (OK)
paramiko >=2.4.0               :  2.7.1 (OK)
parso =0.5.2                   :  0.5.2 (OK)
pexpect >=4.4.0                :  4.8.0 (OK)
pickleshare >=0.4              :  0.7.5 (OK)
psutil >=5.3                   :  5.7.0 (OK)
pygments >=2.0                 :  2.6.1 (OK)
pylint >=0.25                  :  2.4.4 (OK)
pyls >=0.31.9;<0.32.0          :  0.31.9 (OK)
qdarkstyle >=2.8               :  2.8 (OK)
qtawesome >=0.5.7              :  0.7.0 (OK)
qtconsole >=4.6.0              :  4.7.2 (OK)
qtpy >=1.5.0                   :  1.9.0 (OK)
rtree >=0.8.3                  :  0.9.3 (OK)
sphinx >=0.6.6                 :  2.4.4 (OK)
spyder_kernels >=1.9.0;<1.10.0 :  1.9.0 (OK)
watchdog                       :  None (OK)
zmq >=17                       :  18.1.1 (OK)

# Optional:
cython >=0.21                  :  0.29.15 (OK)
matplotlib >=2.0.0             :  3.1.3 (OK)
numpy >=1.7                    :  1.18.1 (OK)
pandas >=0.13.1                :  1.0.1 (OK)
scipy >=0.17.0                 :  1.4.1 (OK)
sympy >=0.7.3                  :  1.5.1 (OK)
ccordoba12 commented 4 years ago

This is a very minor bug, so unless you help us to fix it, I'm afraid it'll take us a long time to do it ourselves.

If you want to do that and need help, we can let you know where in our code you can start looking at.

bcolsen commented 4 years ago

Automatic insertion of parentheses, braces and brackets enforces this because it allows you to keep typing on a line after an auto completed () set by typing ) instead of the arrow key. In fact the current code goes out of it's way to implement this bracket matching. (I know I just said it's a feature and not a bug. sorry)

I'm not suggesting that Automatic insertion of parentheses, braces and brackets is perfect. It could be improved, but you would have to "know" that it was an automatically inserted bracket or have another way of moving the cursor.

Possible Solution

One Idea that could work would be to have the auto completed bracket only become "real" after the cursor is no longer beside it after creation. For example: If I type print( if auto matches to print(|) with my cursor as | and I keep typing print("a"|) my cursor is still next to the bracket that was auto created. If I type ) at this point the bracket will be replaced by the real bracket I typed, if the cursor moves a real bracket will be inserted. The auto bracket would have to be grayed out to indicated that it's not real.

This could also be implemented with any of our completions where text is placed after the cursor.

MortenHannemose commented 4 years ago

The solution suggested by bcolsen seems like a good idea. I can try taking a look. spyder/plugins/editor/extensions/closebrackets.py seems like the main place to look. Do you have any ideas for where to keep track of whether the bracket is "real"?

Akashtyagi commented 4 years ago

@goanpeca I would like to contribute to this, if no one is working on this.

goanpeca commented 4 years ago

Sure thing! Let me know if you need some pointers. Thanks :-)

bcolsen commented 4 years ago

I think the simplest approach here would be to keep a list of automatically inserted characters in the editor object. When a bracket or quote is typed it checks the list if it matches the last character in the list then delete the character in front of the cursor. It is important that the list would be emptied every time the cursor is moved manually(arrow keys, enter, the mouse)

For example the user types: (bar character | shows cursor)

print("Hello|")

At this point the editor object would have a list like [')','"'] If the user types " at this point we would check against the last item in the list. Since it matches a quote is deleted in front of the cursor and the quote is removed from the list. Resulting in:

print("Hello"|)

The list would be: [')']

Knowing when the cursor moved is the trickiest part of this.

The "fake" character object is more advanced but I don't know of a simple way of implementing it without using syntax highlighting checks. Can you make a single character an object in Qt?