@@ -821,6 +821,17 @@ protected JMenu buildEditMenu() {
821821 editMenuUpdatable .add (action );
822822 menu .add (item );
823823
824+ item = new JMenuItem ("Move Selected Lines Up" );
825+ item .setAccelerator (KeyStroke .getKeyStroke (KeyEvent .VK_UP , InputEvent .ALT_DOWN_MASK ));
826+ item .addActionListener (e -> handleMoveLines (true ));
827+ menu .add (item );
828+
829+ item = new JMenuItem ("Move Selected Lines Down" );
830+ item .setAccelerator (KeyStroke .getKeyStroke (KeyEvent .VK_DOWN , InputEvent .ALT_DOWN_MASK ));
831+ item .addActionListener (e -> handleMoveLines (false ));
832+ menu .add (item );
833+
834+
824835 // Update copy/cut state on selection/de-selection
825836 menu .addMenuListener (new MenuListener () {
826837 // UndoAction and RedoAction do this for themselves.
@@ -1865,6 +1876,7 @@ protected void handleCommentUncomment() {
18651876 }
18661877
18671878
1879+
18681880 public void handleIndent () {
18691881 handleIndentOutdent (true );
18701882 }
@@ -1918,6 +1930,84 @@ public void handleIndentOutdent(boolean indent) {
19181930 stopCompoundEdit ();
19191931 sketch .setModified (true );
19201932 }
1933+ /**
1934+ * Moves the selected lines up or down in the text editor.
1935+ *
1936+ * <p>If {@code moveUp} is true, the selected lines are moved up. If false, they move down.</p>
1937+ * <p>This method ensures proper selection updates and handles edge cases like moving
1938+ * the first or last line.</p>
1939+ *
1940+ * @param moveUp {@code true} to move the selection up, {@code false} to move it down.
1941+ */
1942+ public void handleMoveLines (boolean moveUp ) {
1943+ startCompoundEdit ();
1944+
1945+ int startLine = textarea .getSelectionStartLine ();
1946+ int stopLine = textarea .getSelectionStopLine ();
1947+
1948+ // Adjust selection if the last line isn't fully selected
1949+ if (startLine != stopLine &&
1950+ textarea .getSelectionStop () == textarea .getLineStartOffset (stopLine )) {
1951+ stopLine --;
1952+ }
1953+
1954+ int replacedLine = moveUp ? startLine - 1 : stopLine + 1 ;
1955+ if (replacedLine < 0 || replacedLine >= textarea .getLineCount ()) {
1956+ stopCompoundEdit ();
1957+ return ;
1958+ }
1959+
1960+ final String source = textarea .getText (); // Get full text from textarea
1961+
1962+ int replaceStart = textarea .getLineStartOffset (replacedLine );
1963+ int replaceEnd = textarea .getLineStopOffset (replacedLine );
1964+ if (replaceEnd > source .length ()) {
1965+ replaceEnd = source .length ();
1966+ }
1967+
1968+ int selectionStart = textarea .getLineStartOffset (startLine );
1969+ int selectionEnd = textarea .getLineStopOffset (stopLine );
1970+ if (selectionEnd > source .length ()) {
1971+ selectionEnd = source .length ();
1972+ }
1973+
1974+ String replacedText = source .substring (replaceStart , replaceEnd );
1975+ String selectedText = source .substring (selectionStart , selectionEnd );
1976+
1977+ if (replacedLine == textarea .getLineCount () - 1 ) {
1978+ replacedText += "\n " ;
1979+ selectedText = selectedText .substring (0 , Math .max (0 , selectedText .length () - 1 ));
1980+ } else if (stopLine == textarea .getLineCount () - 1 ) {
1981+ selectedText += "\n " ;
1982+ replacedText = replacedText .substring (0 , Math .max (0 , replacedText .length () - 1 ));
1983+ }
1984+
1985+ int newSelectionStart , newSelectionEnd ;
1986+ if (moveUp ) {
1987+ textarea .select (selectionStart , selectionEnd );
1988+ textarea .setSelectedText (replacedText ); // Use setSelectedText()
1989+
1990+ textarea .select (replaceStart , replaceEnd );
1991+ textarea .setSelectedText (selectedText );
1992+
1993+ newSelectionStart = textarea .getLineStartOffset (startLine - 1 );
1994+ newSelectionEnd = textarea .getLineStopOffset (stopLine - 1 );
1995+ } else {
1996+ textarea .select (replaceStart , replaceEnd );
1997+ textarea .setSelectedText (selectedText );
1998+
1999+ textarea .select (selectionStart , selectionEnd );
2000+ textarea .setSelectedText (replacedText );
2001+
2002+ newSelectionStart = textarea .getLineStartOffset (startLine + 1 );
2003+ newSelectionEnd = stopLine + 1 < textarea .getLineCount ()
2004+ ? Math .min (textarea .getLineStopOffset (stopLine + 1 ), source .length ())
2005+ : textarea .getLineStopOffset (stopLine ); // Prevent out-of-bounds
2006+ }
2007+
2008+ textarea .select (newSelectionStart , newSelectionEnd );
2009+ stopCompoundEdit ();
2010+ }
19212011
19222012
19232013 static public boolean checkParen (char [] array , int index , int stop ) {
0 commit comments