Repository: spyder-ide/spyder

Issue:
Inserting a line-break in code/comment with parenthesis deletes part of the code/comment
## Description of your problem

I have a comment that is too long so I want to break it into two lines - this comment also contains parenthesis which seems to be causing the bug.  I go to where I want to break it and when I hit enter, it chops off some of the text from the line that is moved down a row.  Removing the parenthesis stops the strange behavior.  The example should explain it.

**What steps will reproduce the problem?**

1. enter this comment with all the preceding tabs (it's wrapped when I entered it):

```
								#verify that file has station name in it (just to be sure we're not accidentally pulling the wrong station)
```

2. place your cursor just in front of "pulling" and hit enter

3. you will end up with this:

```
								#verify that file has station name in it (just to be sure we're not accidentally 
												  lling the wrong station)
```

4. As you can see "pulling" has been chopped and it also has the incorrect indentation.  Now put your cursor in front of "lling" and hit backspace a lot of times to try and get "lling" to merge back up with the previous line - it will get "stuck" at the left margin.  It will look like this:

```
								#verify that file has station name in it (just to be sure we're not accidentally 
  lling the wrong station)
```

**What is the expected output? What do you see instead?**

It should insert a clean line break, properly tabbed.  Backspace should be able to merge it with the previous line.

**Please provide any additional information below**

## Versions and main components

* Spyder Version: v3.1.4
* Python Version: 3.6.0 64bit
* Qt Version: 5.6.2
* PyQt Version: 5.6
* Operating system: Windows 10


## Dependencies

Please go to the menu entry `Help > Optional Dependencies` (or
`Help > Dependencies`), press the button `Copy to clipboard`
and paste the contents below:

jedi >=0.9.0     :  0.9.0 (OK)
matplotlib >=1.0 :  2.0.0 (OK)
nbconvert >=4.0  :  4.2.0 (OK)
numpy >=1.7      :  1.11.3 (OK)
pandas >=0.13.1  :  0.19.2 (OK)
pep8 >=0.6       :  1.7.0 (OK)
pyflakes >=0.6.0 :  1.5.0 (OK)
pygments >=2.0   :  2.1.3 (OK)
pylint >=0.25    :  1.6.4 (OK)
qtconsole >=4.2.0:  4.2.1 (OK)
rope >=0.9.4     :  0.9.4-1 (OK)
sphinx >=0.6.6   :  1.5.1 (OK)
sympy >=0.7.3    :  1.0 (OK)



Discussion:
Thanks for reporting. We'll see what we can do about this in a future release.
It turns out this isn't just limited to comments.  I had the following:

```
	print(strStationProjectPath)
	with open(strProjectFile, "r") as fShowTemplate, \
```

I put my cursor just before the closing parenthesis after "strStationProjectPath" and hit enter and I end up with this (notice the closing parenthesis disappeared):

```
	print(strStationProjectPath
	   with open(strProjectFile, "r") as fShowTemplate, \
```

If I put my cursor in front of "with" and hit backspace forever, I end up with this:

```
	print(strStationProjectPath
   with open(strProjectFile, "r") as fShowTemplate, \
```

It should join the second line with the first line, but there's something stopping it from backspacing any further.


So there's some kinda weirdness going on that has to do with parenthesis and indentation.  Subject has been updated to indicate that isn't just limited to comments.  Let me know if you need any more info.

Thanks!


So.. more weirdness.  I'm not sure if this issue is only limited to parenthesis.  Take this line of code:

```
						print("\"" + conPathToReaper + """ -renderproject """ & strMasterProjectPath & "TEMP-" & UCase(arrStationTracks(intStation)) & "-" & ReaperFile & """", ShowWindow, WaitUntilFinished
```

Which I know isn't legitimate code (I'm porting a script over from VBScript).  Put your cursor to the right of the three quotes that are just to the left of "-renderproject", hit backspace, and you end up with this:

```
						print("\"" + conPathToReaper + " -renderproject """ & strMasterProjectPath & "TEMP-" & UCase(arrStationTracks(intStation)) & "-" & ReaperFile & """", ShowWindow, WaitUntilFinished
```

Notice how there is only one quote to the left of "-renderproject" - and no, I did not hit backspace twice.
@rlaverde, please take a look at this one too.
Here's another one for you.  Type the following:

```
print(
```

spyder will autocomplete and you will end up with the following (with the cursor between the parenthesis):

```
print()
```

hit enter

You'd expect something like this:

```
print(
)
```

But you get this:

```
print(
	  
```

If you try and press backspace, it will move back once (about two spaces worth), but if you backspace again, it won't do anything.  Btw, I am using tabs, not spaces, for my indentation.  Let me know if you need any more testing.

Resolving patch:
diff --git a/spyder/widgets/sourcecode/codeeditor.py b/spyder/widgets/sourcecode/codeeditor.py
--- a/spyder/widgets/sourcecode/codeeditor.py
+++ b/spyder/widgets/sourcecode/codeeditor.py
@@ -1925,6 +1925,11 @@ def fix_indent(self, forward=True, comment_or_string=False):
             cursor.movePosition(QTextCursor.PreviousBlock)
             prevtext = to_text_string(cursor.block().text()).rstrip()
 
+            # Remove inline comment
+            inline_comment = prevtext.find('#')
+            if inline_comment != -1:
+                prevtext = prevtext[:inline_comment]
+
             if ((self.is_python_like() and
                not prevtext.strip().startswith('#') and prevtext) or
                prevtext):
@@ -2067,8 +2072,7 @@ def fix_indent(self, forward=True, comment_or_string=False):
             cursor = self.textCursor()
             cursor.movePosition(QTextCursor.StartOfBlock)
             if self.indent_chars == '\t':
-                indent = indent // self.tab_stop_width_spaces \
-                + correct_indent % self.tab_stop_width_spaces
+                indent = indent // self.tab_stop_width_spaces
             cursor.setPosition(cursor.position()+indent, QTextCursor.KeepAnchor)
             cursor.removeSelectedText()
             if self.indent_chars == '\t':


Test patch:
diff --git a/spyder/widgets/sourcecode/tests/test_autoindent.py b/spyder/widgets/sourcecode/tests/test_autoindent.py
--- a/spyder/widgets/sourcecode/tests/test_autoindent.py
+++ b/spyder/widgets/sourcecode/tests/test_autoindent.py
@@ -160,19 +160,14 @@ def test_first_line():
          "test_return"),
         ("def some_func():\n    returns = 10\n", "def some_func():\n    returns = 10\n    ",
          "test_return_not_keyword"),
-
-        pytest.mark.xfail(
-            ("foo = 1  # Comment open parenthesis (\n",
+        ("foo = 1  # Comment open parenthesis (\n",
              "foo = 1  # Comment open parenthesis (\n",
-             "test_comment_with parenthesis")),
+             "test_comment_with parenthesis"),
     ])
 def test_indentation_with_spaces(text_input, expected, test_text):
     text = get_indent_fix(text_input)
     assert text == expected, test_text
 
-# --- Failing tests
-# -----------------------------------------------------------------------------
-@pytest.mark.xfail
 def test_def_with_unindented_comment():
     text = get_indent_fix("def function():\n# Comment\n")
     assert text == "def function():\n# Comment\n    ", repr(text)
@@ -202,14 +197,8 @@ def test_def_with_unindented_comment():
          "test_return"),
         ("def some_func():\n\treturns = 10\n", "def some_func():\n\treturns = 10\n\t",
          "test_return_not_keyword"),
-
-        # Failing test
-        pytest.mark.xfail(
-            ("def function():\n# Comment\n", "def function():\n# Comment\n\t",
-             "test_def_with_unindented_comment")),
-        pytest.mark.xfail(
-            ("a = (a  #  some comment\n", "a = (a  #  some comment\n\t ",
-             "test_inline_comment")),
+        ("def function():\n# Comment\n", "def function():\n# Comment\n\t",
+             "test_def_with_unindented_comment"),
     ])
 def test_indentation_with_tabs(text_input, expected, test_text,
                                tab_stop_width_spaces):
@@ -218,6 +207,27 @@ def test_indentation_with_tabs(text_input, expected, test_text,
     assert text == expected, test_text
 
 
+@pytest.mark.parametrize(
+    "text_input, expected, tab_stop_width_spaces",
+    [
+        ("print(\n)", "print(\n\t\t)", 1),
+        ("print(\n)", "print(\n\t\t)", 2),
+        ("print(\n)", "print(\n\t\t)", 3),
+        ("print(\n)", "print(\n\t  )", 4),
+        ("print(\n)", "print(\n\t )", 5),
+        ("print(\n)", "print(\n\t)", 6),
+        ("print(\n)", "print(\n      )", 7),
+        ("print(\n)", "print(\n      )", 8),
+        ("a = (a  #  some comment\n", "a = (a  #  some comment\n\t ", 4),
+    ])
+def test_indentation_with_tabs_parenthesis(text_input, expected,
+                                           tab_stop_width_spaces):
+    """Simple parenthesis indentation test with different tab stop widths."""
+    text = get_indent_fix(text_input, indent_chars="\t",
+                          tab_stop_width_spaces=tab_stop_width_spaces)
+    assert text == expected, tab_stop_width_spaces
+
+
 @pytest.mark.parametrize("tab_stop_width_spaces", [1,2,3,4,5,6,7,8])
 @pytest.mark.parametrize(
     "text_input, expected, test_text",