CSED - move lines

Started by Paul Squires, September 12, 2015, 02:23:24 AM

Previous topic - Next topic

Paul Squires

Hi Jose,

I am re-writing my JellyFish Editor for FreeBASIC and I implemented code to move line(s) in the edit window using the keyboard shortcuts CTRL+SHIFT+UP and CTRL+SHIFT+DOWN. It is a very convenient feature because otherwise you need to cut the line, move cursor to insert line, and then paste. It also works with multiple lines.

I have been stealing so much from your CSED Editor (especially the Scintilla stuff) that I thought I would post it here in case you would ever like to add it to your editor. This code is based on C++ code found in the NotePad++ editor.

My code uses the SendMessage functionality rather than the Scintilla direct function pointers.



' call the functions
'      Case IDC_FRMMAIN_MNUMOVEUPCURRENTLINE
'         Function = Doc_MoveCurrentLines(GetCodeWindowFromCurrentTab, False)
'      Case IDC_FRMMAIN_MNUMOVEDOWNCURRENTLINE
'         Function = Doc_MoveCurrentLines(GetCodeWindowFromCurrentTab, True)


''
''
Function Doc_GetSelectedLineRange( ByVal hWindow   as HWnd, _
                                   ByRef startLine as Integer, _
                                   ByRef endLine   as Integer, _
                                   ByRef startPos  as Integer, _
                                   ByRef endPos    as Integer _
                                   ) as Integer
   
   startPos  = SendMessage(hWindow, SCI_GETSELECTIONSTART, 0, 0)
   endPos    = SendMessage(hWindow, SCI_GETSELECTIONEND, 0, 0)
   startLine = SendMessage(hWindow, SCI_LINEFROMPOSITION, startPos, 0)
   endLine   = SendMessage(hWindow, SCI_LINEFROMPOSITION, endPos, 0)

   Dim nCol as Integer = SendMessage(hWindow, SCI_GETCOLUMN, endPos, 0)
   If (nCol = 0) And (endLine > startLine) Then endLine = endLine - 1

   Function = 0
End Function

''
''
Function Doc_CurrentLineUp( ByVal hWindow as HWnd ) as Integer
   Dim currentLine as Integer = Doc_GetCurrentLineNumber(hWindow)
   If (currentLine <> 0) Then
      SendMessage(hWindow, SCI_BEGINUNDOACTION, 0, 0)
      currentLine = currentLine -1
      SendMessage(hWindow, SCI_LINETRANSPOSE, 0, 0)
      SendMessage(hWindow, SCI_GOTOLINE, currentLine, 0)
      SendMessage(hWindow, SCI_ENDUNDOACTION, 0, 0)
   End If
   Function = 0
End Function

''
''
Function Doc_CurrentLineDown( ByVal hWindow as HWnd ) as Integer
   Dim currentLine as Integer = Doc_GetCurrentLineNumber(hWindow)
   If currentLine <> SendMessage(hWindow, SCI_GETLINECOUNT, 0, 0) - 1 Then
      SendMessage(hWindow, SCI_BEGINUNDOACTION, 0, 0)
      currentLine = currentLine + 1
      SendMessage(hWindow, SCI_GOTOLINE, currentLine, 0)
      SendMessage(hWindow, SCI_LINETRANSPOSE, 0, 0)
      SendMessage(hWindow, SCI_ENDUNDOACTION, 0, 0)
   End If
   Function = 0
End Function
 
''
''
Function Doc_MoveCurrentLines( ByVal hWindow as HWnd, ByVal flagMoveDown as Integer  ) as Integer

   Dim startPos    as Integer     ' // Starting position
   Dim endPos      as Integer     ' // Ending position
   Dim startLine   as Integer     ' // Starting line
   Dim endLine     as Integer     ' // Ending line
   Dim line2swap   as Integer
   Dim nbChar      as Integer
   Dim nTextLen    as Integer
   
   Doc_GetSelectedLineRange( hWindow, startLine, endLine, startPos, endPos )

   Dim noSel      as Integer = (startLine = endLine)
   Dim nbSelLines as Integer = (endLine - startLine + 1)

   If flagMoveDown Then
      nTextLen  = SendMessage(hWindow, SCI_GETTEXTLENGTH, 0, 0)
      If (startLine = -1) Or (endLine >= SendMessage(hWindow, SCI_LINEFROMPOSITION, nTextLen, 0)) Then
           Exit Function
      End If
     line2swap = endLine + 1
      If (line2swap + 1) = SendMessage(hWindow, SCI_GETLINECOUNT, 0, 0) Then nbChar += 2    ' cr/lf
   Else
      If (startLine <= 0) Then Exit Function
      line2swap = startLine - 1
   End If
   
   nbChar = nbChar + SendMessage(hWindow, SCI_LINELENGTH, line2swap, 0)
   
   SendMessage(hWindow, SCI_BEGINUNDOACTION, 0, 0)
   SendMessage(hWindow, SCI_GOTOLINE, line2swap, 0)

   For i as Integer = 0 To nbSelLines - 1
      If flagMoveDown Then
         Doc_CurrentLineUp(hWindow)
      Else
         Doc_CurrentLineDown(hWindow)
      End If   
   Next
   SendMessage(hWindow, SCI_ENDUNDOACTION, 0, 0)

   If flagMoveDown Then
      SendMessage(hWindow, SCI_SETSELECTIONSTART, startPos + nbChar, 0)
      SendMessage(hWindow, SCI_SETSELECTIONEND, IIf(noSel, startPos + nbChar, endPos + nbChar), 0)
   Else
      SendMessage(hWindow, SCI_SETSELECTIONSTART, startPos - nbChar, 0)
      SendMessage(hWindow, SCI_SETSELECTIONEND, IIf(noSel, startPos - nbChar, endPos - nbChar), 0)
   End If
   
   Function = 0
End Function



Paul Squires
PlanetSquires Software

José Roca

Good tip. Thanks for sharing.

I'm no longer in the business of making code editors. Too time consuming.

So if you are writing one in FreeBasic, maybe I will end using it. Currently, I'm using an adaptation of CSED for my FreeBasic tests.

I wrote CSED for PB during the beta testing of the PBWin 10 / PBCC 6 compilers as a non trivial way of thorughly testing both the compilers and my new headers. This is why it uses many of the new features, such classes, unicode, collections, etc. This way, I discovered many bugs that maybe I could have not discover using trivial tests.

When I released it, I said that it was a "template" that others could use as a starting point to build other versions.