Python icon indicating copy to clipboard operation
Python copied to clipboard

Smart-indent not outdenting correctly with Python

Open kenny-evitt opened this issue 9 years ago • 9 comments

Copied from the original comment on LightTable/LightTable#1627:

I'm running into a roadblock using Light Table with python because the smart-indent feature isn't out-denting when it should after functions or classes.

Ex. before smart-indent:

class Dog:
    kind = 'canine'
    def __init__(self, name):
        self.name = name

class Cat:
    kind = 'feline'
    def __init__(self, name):
        self.name = name

After smart-indent:

class Dog:
  kind = 'canine'
  def __init__(self, name):
    self.name = name

    class Cat:
      kind = 'feline'
      def __init__(self, name):
        self.name = name

Not only did it reduce the tabs down to 2 spaces, it also didn't pickup on when to outdent causing the sibling classes to become nested.

This is a major blocker for polyglot Light Table users who use python.

LightTable 0.6.7

kenny-evitt avatar Jan 06 '16 17:01 kenny-evitt

I just confirmed that the CodeMirror Python demo (Light Table uses CodeMirror) also suffers from this problem.

kenny-evitt avatar Jan 06 '16 19:01 kenny-evitt

@kenny-evitt so does that mean that if the next release of LightTable has updated codemirror as was mentioned in the blog that it would still suffer this problem?

MortalCatalyst avatar Jan 08 '16 09:01 MortalCatalyst

@MortalCatalyst Yes. We should submit a fix for this, if it's possible, upstream to CodeMirror and then pull in the new version to LT. Would you mind checking for an existing issue for CodeMirror that covers this?

kenny-evitt avatar Jan 09 '16 20:01 kenny-evitt

@kenny-evitt is this a codemirror error or do we need to define the indentation, I found this answer on SO http://stackoverflow.com/a/15969118/461887

If you want your mode to provide smart indentation (through the indentLine method and the indentAuto and newlineAndIndent commands, to which keys can be bound), you must define an indent(state, textAfter) method on your mode object. After applying a mode that defines indent(state, textAfter), and assuming smartIndent is set to true (which is the default value), auto indentation should be provided transparently, no extra effort on your side.

If a mode does not support smart indentation out of the box, you can always implement it yourself. See the section on writing CodeMirror modes in the docs.

MortalCatalyst avatar Jan 09 '16 22:01 MortalCatalyst

This is the mode in codemirror http://codemirror.net/mode/python/python.js are the extra codemirror settings defined in LT?

http://codemirror.net/doc/manual.html#indentLine

MortalCatalyst avatar Jan 09 '16 22:01 MortalCatalyst

@MortalCatalyst Interesting – thanks for looking into this. If extra settings are required by CodeMirror, e.g. for Python, I'm confused why their Python demo doesn't provide them.

More generally, is it even possible to indent Python code correctly for these scenarios? Is there some way to know, apart from existing indentation or other scoping info, that a subsequent class defined in a file is or is not nested inside the former class? Or, in other words, why is this failing at all?

kenny-evitt avatar Jan 10 '16 21:01 kenny-evitt

Well indentation works perfectly in LT when typing the code, except for if/else, a lot of editors get that wrong though. It's actually only when running the smart indent does the error occur, so the error likely occurs only in its version.

MortalCatalyst avatar Jan 12 '16 10:01 MortalCatalyst

As a test I loaded the latest pyhon.js from https://github.com/codemirror/CodeMirror/edit/master/mode/python/python.js into LT 0.8.0 . Still works fine on indent but smart indent a fail. It's like smart indent keeps resetting what it thinks column 0 is and adds 2 over and over again.

MortalCatalyst avatar Jan 12 '16 10:01 MortalCatalyst

@kenny-evitt I did post in the gitter tonight no one around currently. It seems that in pool.cljs the trigger to subtract indentation for line is not met in python and so the continual add.

This is the code I am referring to

(cmd/command {:command :indent-selection
              :desc "Editor: Indent line(s)"
              :exec (fn []
                      (when-let [cur (last-active)]
                        (let [line (-> cur (editor/->cursor "start") :line)]
                          (if (editor/selection? cur)
                            (editor/indent-selection cur "add")
                            (editor/indent-line cur line "add")))))})

(cmd/command {:command :unindent-selection
              :desc "Editor: Unindent line(s)"
              :exec (fn []
                      (when-let [cur (last-active)]
                        (let [line (-> cur (editor/->cursor "start") :line)]
                          (if (editor/selection? cur)
                            (editor/indent-selection cur "subtract")
                            (editor/indent-line cur line "subtract")))))})

MortalCatalyst avatar Jan 12 '16 10:01 MortalCatalyst