Community
    • Login

    improve SCI_LINEDELETE shortcut

    Scheduled Pinned Locked Moved Help wanted · · · – – – · · ·
    27 Posts 4 Posters 2.8k Views
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • Earth InvaderE
      Earth Invader @Alan Kilborn
      last edited by Earth Invader

      @alan-kilborn ok thanks

      Alan KilbornA 1 Reply Last reply Reply Quote 0
      • Alan KilbornA
        Alan Kilborn @Earth Invader
        last edited by Alan Kilborn

        Here’s a PythonScript called LineDelete.py that implements the functionality:

        # -*- coding: utf-8 -*-
        #-------------------------------------------------------------------------------
        
        class LD(object):
        
            def __init__(self):
                if editor.getSelections() > 1 and not editor.selectionIsRectangle(): return  # unsupported for now
                editor.beginUndoAction()
                if editor.getCurrentPos() != editor.getAnchor():
                    (line_start, line_end) = editor.getUserLineSelection()
                    if line_start != line_end:
                        start_pos = editor.positionFromLine(line_start)
                        end_pos = editor.getLineEndPosition(line_end)
                        editor.deleteRange(start_pos, end_pos - start_pos)
                editor.lineDelete()
                editor.endUndoAction()
        
        #-------------------------------------------------------------------------------
        
        if __name__ == '__main__': LD()
        
        Victorel PetrovichV 1 Reply Last reply Reply Quote 3
        • Alan KilbornA
          Alan Kilborn @Earth Invader
          last edited by

          @earth-invader said in improve SCI_LINEDELETE shortcut:

          It only deletes the 1st line of the selection in the current version.

          Actually, it deletes the line of the caret, which isn’t always the 1st line.

          If you start making your selection from the top of your window and then lengthen it towards the bottom, when you stop your caret position will be on the bottom-most line, so that one will be the one deleted with SCI_LINEDELETE.

          If you do it the other way, from lower on the window toward the upper part of the window, then yes, you are correct, the 1st line of the selection will be the one deleted with SCI_LINEDELETE.

          Earth InvaderE 1 Reply Last reply Reply Quote 2
          • Earth InvaderE
            Earth Invader @Alan Kilborn
            last edited by

            @alan-kilborn

            How do I use your script? I installed PythonScript plugin and placed the script in the script folder but after restart, it still only delete one line.

            Alan KilbornA 1 Reply Last reply Reply Quote 0
            • Alan KilbornA
              Alan Kilborn @Earth Invader
              last edited by

              @earth-invader said in improve SCI_LINEDELETE shortcut:

              How do I use your script? I installed PythonScript plugin and placed the script in the script folder but after restart, it still only delete one line.

              See HERE.

              Earth InvaderE 1 Reply Last reply Reply Quote 2
              • Earth InvaderE
                Earth Invader @Alan Kilborn
                last edited by

                @alan-kilborn
                Thanks. it works.

                1 Reply Last reply Reply Quote 2
                • Victorel PetrovichV
                  Victorel Petrovich @Alan Kilborn
                  last edited by Victorel Petrovich

                  @Alan-Kilborn
                  At your script, is it necessary to wrap the core of it inside a class?
                  And generally, for any pythonscripts?
                  Because I try just this and seems to work:

                  if editor.getSelections() == 1 or editor.selectionIsRectangle(): # else, unsupported for now
                      editor.beginUndoAction()
                      if editor.getCurrentPos() != editor.getAnchor():
                          (line_start, line_end) = editor.getUserLineSelection()
                          if line_start != line_end:
                              start_pos = editor.positionFromLine(line_start)
                              end_pos = editor.getLineEndPosition(line_end)
                              editor.deleteRange(start_pos, end_pos - start_pos)
                      editor.lineDelete()
                      editor.endUndoAction()
                  

                  I’ve read PythonScript 2.0.0.0 documentation , nothing on that.

                  PeterJonesP 1 Reply Last reply Reply Quote 0
                  • PeterJonesP
                    PeterJones @Victorel Petrovich
                    last edited by PeterJones

                    @Victorel-Petrovich said in improve SCI_LINEDELETE shortcut:

                    @Alan-Kilborn
                    At your script, is it necessary to wrap the core of it inside a class?
                    And generally, for any pythonscripts?

                    It’s not necessary. But if you’ve got a lot of scripts, there are potentials for namespace collisions (“is the line_start variable in script1.py going to mess up a variable of the same name in script2.py?”). Alan, and other of us regulars, have lots of scripts that we use on a regular basis, and namespace collisions can create nasty bugs. By wrapping in a class with a name unique to the script, there is virtually no danger of a namespace collision (unless you don’t pick a unique class name).

                    So those of us who write and/or use lots of scripts tend to wrap them in some way: either in a class, or at least wrapping them in functions and giving the functions long, annoying-to-type names… I used to use a suffix of which Community “topic” number it was (as seen in the URL for each topic) when I would write a function in response to a post here, because that’s a safe way to guarantee that neither I nor the recipient has a function with that exact name already loaded in their PythonScript environment.

                    Victorel PetrovichV 1 Reply Last reply Reply Quote 4
                    • Victorel PetrovichV
                      Victorel Petrovich @PeterJones
                      last edited by Victorel Petrovich

                      @PeterJones
                      Oh, so it’s standard python scoping rules at work.
                      Makes sense. Those classes probably look spooky for beginners :)

                      I’ll stick to functions, at least for now: I can name them same as filename of the script (which needs to be unique anyway).

                      Thank you for the good reply.

                      EDIT: def main(): ... main() should also be enough, provided I do so in EVERY script (as explained by Alan here )

                      1 Reply Last reply Reply Quote 2
                      • Victorel PetrovichV
                        Victorel Petrovich
                        last edited by Victorel Petrovich

                        2 other versions:

                        def main():
                            if editor.getSelections() > 1 and not editor.selectionIsRectangle(): 
                                return  # unsupported for now
                        
                            editor.beginUndoAction()
                            
                            p1=editor.getSelectionStart()
                            p2=editor.getSelectionEnd()
                            editor.deleteRange(p1,p2-p1)
                            editor.lineDelete()
                            
                            editor.endUndoAction()
                        
                        main()
                        

                        and:

                        def main(): 
                            if editor.getSelections() > 1:
                                return # unsupported
                        
                            editor.beginUndoAction()
                        
                            editor.deleteBackNotLine()
                            editor.lineDelete()
                        
                            editor.endUndoAction()
                          
                        main()
                        

                        The 2nd one doesn’t work for rectangle selections (column mode), but this is consistent with cutting lines in selection using SCI_LINECUT.

                        1 Reply Last reply Reply Quote 0
                        • Victorel PetrovichV
                          Victorel Petrovich
                          last edited by Victorel Petrovich

                          This post is deleted!
                          1 Reply Last reply Reply Quote 0
                          • Victorel PetrovichV
                            Victorel Petrovich
                            last edited by

                            This one, almost works even for multiple selections (multiple carets).
                            The only problem is that in such case, the last command editor.clear() refuses to delete the EOL-s, thus it leaves multiple carets in place:

                            def main():
                                editor.beginUndoAction()
                                
                                editor.deleteBackNotLine()
                                editor.delLineLeft()
                                editor.delLineRight()
                                editor.clear()
                            
                                editor.endUndoAction()
                                
                            main()
                            

                            I should look in how to focus on one selection at a time, in a loop.

                            1 Reply Last reply Reply Quote 0
                            • Victorel PetrovichV
                              Victorel Petrovich
                              last edited by Victorel Petrovich

                              I hope that those who think I’m spamming here, have unsubscribed from the topic :) .

                              Next “works” for all kinds of selections (column, not column, mixed…)… BUT … has a little glitch at Ist line in doc for the case of multiple non-column selections: won’t remove EOL for that particular case

                              def main():
                                  editor.beginUndoAction()
                              
                                  if editor.selectionIsRectangle(): 
                                      p1=editor.getSelectionStart()
                                      p2=editor.getSelectionEnd()
                                      editor.deleteRange(p1,p2-p1)
                                      editor.lineDelete()    
                                  else:
                                      editor.deleteBackNotLine()
                                      editor.delLineLeft()
                                      editor.delLineRight()
                                      if editor.getCurrentPos()!=0: 
                                          editor.deleteBack()
                                          editor.charRight()
                                      else:
                                          editor.clear()
                                          # compromise: makes it work for single selection, at expense of multi-selections
                                          
                                  editor.endUndoAction()
                              
                              main()
                              

                              Okay, probably can’t do better without looping over selections…

                              Alan KilbornA 1 Reply Last reply Reply Quote 0
                              • Alan KilbornA
                                Alan Kilborn @Victorel Petrovich
                                last edited by

                                @Victorel-Petrovich

                                No one thinks you are spamming…

                                Are you just practicing your scripting skills in case Scintilla doesn’t address your concern about SCI_LINEDELETE?

                                Ref: https://sourceforge.net/p/scintilla/feature-requests/1489/
                                Ref: https://github.com/notepad-plus-plus/notepad-plus-plus/issues/13921

                                Victorel PetrovichV 1 Reply Last reply Reply Quote 1
                                • Victorel PetrovichV
                                  Victorel Petrovich @Alan Kilborn
                                  last edited by Victorel Petrovich

                                  @Alan-Kilborn said in improve SCI_LINEDELETE shortcut:

                                  No one thinks you are spamming…

                                  Nice to know.

                                  Are you just practicing your scripting skills in case Scintilla doesn’t address your concern about SCI_LINEDELETE?

                                  That’s right; and who knows how many months till that change will be accepted?
                                  Also, it’s a good general practice, and … a fun challenge :-).

                                  Hope will be instructive for others as well happening on this thread.

                                  For example, the glitch in my last script:
                                  at first seemed insurmountable, editor.clear() (which is just “delete” function) just doesn’t want to work with several carets
                                  on EOL…
                                  But this morning I thought: what would I do if on keyboard, my “delete” key didn’t work (say, temporarily) ?
                                  Little easy puzzle … and the glitch is gone :) :

                                  def main():
                                      editor.beginUndoAction()
                                  
                                      if editor.selectionIsRectangle(): 
                                          p1=editor.getSelectionStart()
                                          p2=editor.getSelectionEnd()
                                          editor.deleteRange(p1,p2-p1)
                                          editor.lineDelete()    
                                      else:
                                          editor.deleteBackNotLine()
                                          editor.delLineLeft()
                                          editor.delLineRight()
                                          editor.charRight()
                                          editor.deleteBack()
                                              
                                      editor.endUndoAction()
                                  
                                  main()
                                  
                                  Alan KilbornA 1 Reply Last reply Reply Quote 0
                                  • Alan KilbornA
                                    Alan Kilborn @Victorel Petrovich
                                    last edited by

                                    @Victorel-Petrovich said in improve SCI_LINEDELETE shortcut:

                                    and who knows how many months till that change will be accepted?

                                    I don’t see (at that Scintilla issue) that you submitted the patch? Hard to be accepted if nothing is submitted. :-)

                                    1 Reply Last reply Reply Quote 0
                                    • Alan KilbornA
                                      Alan Kilborn
                                      last edited by

                                      If I were updating my original LineDelete.py script to handle all types of selections that could be active when the user invokes the script, maybe this is how I’d do it:

                                      # -*- coding: utf-8 -*-
                                      from __future__ import print_function
                                      
                                      # references:
                                      #  https://community.notepad-plus-plus.org/topic/23096/improve-sci_linedelete-shortcut
                                      
                                      from Npp import *
                                      
                                      #-------------------------------------------------------------------------------
                                      
                                      class LD(object):
                                      
                                          def __init__(self):
                                              line_range_tup_list = []
                                              for sel_num in range(editor.getSelections()):
                                                  sel_start_pos = editor.getSelectionNStart(sel_num)
                                                  sel_end_pos = editor.getSelectionNEnd(sel_num)
                                                  sel_line_start = editor.lineFromPosition(sel_start_pos)
                                                  sel_line_end = editor.lineFromPosition(sel_end_pos)
                                                  if sel_start_pos != sel_end_pos and sel_end_pos == editor.positionFromLine(sel_line_end):
                                                      # adjust for case where there is some selected text and caret is on a line by itself, i.e., no actual selected text on line of caret:
                                                      sel_line_end -= 1
                                                  line_range_tup_list.append( (sel_line_start, sel_line_end) )
                                              editor.beginUndoAction()
                                              # delete lines from bottom of doc towards the top, to avoid having to constantly adjust for previously deleted lines:
                                              for __ in sorted(list(self.consolidate_tup_list(line_range_tup_list)), reverse=True):
                                                  self.del_line_range(*__)
                                              editor.endUndoAction()
                                              # leave single caret:
                                              __ = editor.getCurrentPos()
                                              editor.setSel(__, __)
                                              editor.chooseCaretX()
                                      
                                          def del_line_range(self, start_line_to_del, end_line_to_del):
                                              #print('start_line_to_del:', start_line_to_del+1, 'end_line_to_del:', end_line_to_del+1)
                                              start_pos_to_del = editor.positionFromLine(start_line_to_del)
                                              end_pos_to_del = editor.positionFromLine(end_line_to_del) + editor.lineLength(end_line_to_del)
                                              #print('start_pos_to_del:', start_pos_to_del+1, 'end_pos_to_del:', end_pos_to_del+1)
                                              editor.deleteRange(start_pos_to_del, end_pos_to_del - start_pos_to_del)
                                      
                                          def consolidate_tup_list(self, tup_list):
                                              # inspired by https://stackoverflow.com/questions/5679638/merging-a-list-of-time-range-tuples-that-have-overlapping-time-ranges
                                              tup_list = sorted(tup_list)
                                              held_list = list(tup_list[0])
                                              for (start, end) in tup_list[1:]:
                                                  if held_list[1] <= start <= held_list[1] + 1:
                                                      held_list[1] = end
                                                  else:
                                                      yield tuple(held_list)
                                                      held_list[0] = start
                                                      held_list[1] = end
                                              yield tuple(held_list)
                                      
                                      #-------------------------------------------------------------------------------
                                      
                                      if __name__ == '__main__': LD()
                                      
                                      Victorel PetrovichV 1 Reply Last reply Reply Quote 0
                                      • Alan KilbornA Alan Kilborn referenced this topic on
                                      • Victorel PetrovichV
                                        Victorel Petrovich @Alan Kilborn
                                        last edited by Victorel Petrovich

                                        That’s advanced; I’ll look into it.

                                        Meanwhile, I’ve also been working on a version with looping over selections.

                                        """
                                        This does not work correctly if some selections share one line (examples: 2 selections or just 2 carets on same line; a selection begins/ends on same line that  another ends/begins); 
                                        In such cases, the program will delete more lines than necessary. 
                                        To solve this, I think would need more than one loop. 
                                        """
                                        def main():
                                            editor.beginUndoAction()
                                            
                                            selN=editor.getSelections()-1
                                            while selN>-1:
                                                p1=editor.getSelectionNStart(selN)
                                                p2=editor.getSelectionNEnd(selN)
                                                editor.deleteRange(p1,p2-p1)
                                                editor.lineDelete() 
                                                editor.dropSelectionN(selN)
                                                selN-=1
                                                
                                            editor.endUndoAction()
                                        main()
                                        
                                        Alan KilbornA 1 Reply Last reply Reply Quote 0
                                        • Alan KilbornA
                                          Alan Kilborn @Victorel Petrovich
                                          last edited by

                                          @Victorel-Petrovich said in improve SCI_LINEDELETE shortcut:

                                          That’s advanced

                                          :-)

                                          Victorel PetrovichV 1 Reply Last reply Reply Quote 0
                                          • Victorel PetrovichV
                                            Victorel Petrovich @Alan Kilborn
                                            last edited by Victorel Petrovich

                                            Who doesn’t like a bit of praise :)
                                            From my tests of your script, in following cases:

                                            1. put caret on start of a line, press shift+Down one or more times; the script doesn’t delete the line where the caret end
                                            2. Similarly for the line where anchor is at column0, when press shift+Up 1+ times.

                                            It appears you did so on purpose with these lines:

                                            if sel_start_pos != sel_end_pos and sel_end_pos == editor.positionFromLine(sel_line_end):
                                                # adjust for case where there is some selected text and caret is on a line by itself, i.e., no actual selected text on line of caret:
                                                sel_line_end -= 1
                                            

                                            Although, I agree it’s debatable whether that line should be deleted in case 2. above : in that case, it doesn’t look like the second line has been touched by selection at all. It looks almost same as when fully select first line from End to Start:
                                            87ef58e1-7e93-42a6-beac-06bdc8b8ea8a-Capture.PNG

                                            On the other hand, in case 1. above, it is clear that the line has been marked:
                                            30d5e542-87a9-4cf7-8ee7-69b6f7e1e2d1-Capture.PNG

                                            So, perhaps the ideal rule would be:
                                            Delete all lines either with selection within or where caret resides.

                                            But, for patch to Scintilla, I’ll probably have to delete the line in both cases, for consistency with SCI_LINECOPY and SCI_LINECUT.

                                            Alan KilbornA 2 Replies Last reply Reply Quote 0
                                            • First post
                                              Last post
                                            The Community of users of the Notepad++ text editor.
                                            Powered by NodeBB | Contributors