Move Cursor to the Next/Previous Paragraph in Kate

It kind of irritates me that Kate doesn’t have a builtin functionality to move cursor to the next/previous paragraph. Fortunately, as with most KDE SC applications, Kate is extendable with custom scripts. So here’s my solution for the mentioned problem.

/* kate-script
 * author: Dzikri Aziz 
 * license: GPLv2
 * revision: 3
 * kate-version: 3.4
 * type: commands
 * functions: jumpUp, jumpDown
 *
 * Move cursor to next/previous paragraph
 */

function jumpDown() {
  return _jump();
}


function jumpUp() {
  return _jump( true );
}


function action( cmd ) {
  var a = new Object();
  if ( cmd == 'jumpUp' ) {
    a.text = i18n('Move cursor to previous paragraph');
    a.shortcut = 'Alt+Up';
    a.icon = "";
    a.category = "";
    a.interactive = false;
  }
  else if ( cmd == 'jumpDown' ) {
    a.text = i18n('Move cursor to next paragraph');
    a.shortcut = 'Alt+Down';
    a.icon = "";
    a.category = "";
    a.interactive = false;
  }

  return a;
}


function help( cmd ) {
  if (cmd == 'jumpUp') {
    return i18n('Move cursor to previous paragraph');
  }
  else if (cmd == 'jumpDown') {
    return i18n('Move cursor to next paragraph');
  }
}


function _jump( up ) {
  var init   = curPos = view.cursorPosition().line,
      lines  = document.lines(),
      target;

  if ( document.firstColumn(curPos) == -1 )
    curPos = document.prevNonEmptyLine(curPos);

  if ( up === true ) {
    target = 0;
    while ( curPos-- > 0 ) {
      if ( document.firstColumn(curPos) == -1 && document.nextNonEmptyLine(curPos) != init ) {
        target = document.nextNonEmptyLine(curPos);
        break;
      }
    }
  }

  else {
    lines--;
    target = lines;
    while ( curPos++ < lines ) {
      if ( document.firstColumn(curPos) == -1 && document.nextNonEmptyLine(curPos) != init ) {
        target = document.nextNonEmptyLine(curPos);
        break;
      }
    }
  }

  view.setCursorPosition(target, 0);
}

Save this script as jump.js inside katepart directory in your KDE user directory, eg: $KDEHOME/share/apps/katepart/script (just create the sub-directories if they don't exist yet) and relaunch Kate. Now you can move the cursor to the next paragraph by pressing Alt+Up or the previous one by pressing Alt+Down. You can freely customize the shortcut from Settings » Configure Shortcuts.

Any improvements are welcome!

As a bonus, here's the scripting guide I printed from Google cache.

4 Comments

  1. Hi,

    thanks for sharing this script. There is one little problem, though: it does not jump to the previous paragraph if it starts on line 1. Is there any way to fix this?

    Greetings!

    Reply

    1. Dzikri Aziz 2012/01/22 at 5:23 am

      Hi Chris,
      I fixed the script. Now it should always take you to the first/last line if there are no paragraphs left.

      Reply

  2. Here is the code for paragraph selection:

    /* kate-script
     * author: Dzikri Aziz 
     * license: GPLv2
     * revision: 3
     * kate-version: 3.4
     * type: commands
     * functions: jumpUpp, jumpDownp
     *
     * Selects to next/previous paragraph
     */
    
    require("cursor.js");
    require("range.js");
    
    function jumpDownp() {
      return _jumpp();
    }
    
    
    function jumpUpp() {
      return _jumpp( true );
    }
    
    
    function action( cmd ) {
      var a = new Object();
      if ( cmd == 'jumpUpp' ) {
        a.text = i18n('Select cursor to previous paragraph');
        a.shortcut = 'Ctrl+Shift+Up';
        a.icon = "";
        a.category = "";
        a.interactive = false;
      }
      else if ( cmd == 'jumpDownp' ) {
        a.text = i18n('Select cursor to next paragraph');
        a.shortcut = 'Ctrl+Shift+Down';
        a.icon = "";
        a.category = "";
        a.interactive = false;
      }
    
      return a;
    }
    
    
    function help( cmd ) {
      if (cmd == 'jumpUpp') {
        return i18n('Select cursor to previous paragraph');
      }
      else if (cmd == 'jumpDownp') {
        return i18n('Select cursor to next paragraph');
      }
    }
    
    
    function _jumpp( up ) {
      var init   = curPos = view.cursorPosition().line,
          lines  = document.lines(),
          target;
    
      if ( document.firstColumn(curPos) == -1 )
        curPos = document.prevNonEmptyLine(curPos);
    
      if ( up === true ) {
         
        target = 0;
        while ( curPos-- > 0 ) {
          if ( document.firstColumn(curPos) == -1 && document.nextNonEmptyLine(curPos) != init ) {
            target = document.nextNonEmptyLine(curPos);
            break;
          }
        }
        
        var cc = view.cursorPosition();
        var p = new Cursor(target, 0);
        var beg;
        var end;
        
        if (view.hasSelection()) {
           selbeg = view.selection().start;
           selend = view.selection().end;
           if (p.compareTo(selbeg) == -1) {
              if (selbeg.compareTo(cc) == -1) {
                 beg = p;
                 end = selbeg;
              } else {
                 beg = p;
                 end = selend;             
              }
           } else if (selend.compareTo(p) == 0) {
              beg = p;
              end = p;
           } else {
              beg = selbeg;
              end = p;
           }
        } else {
           beg = p;
           end = view.cursorPosition();
        }
        
        view.setSelection(new Range(beg, end));
        view.setCursorPosition(target, 0);
        
        
      } else {
        
        while ( curPos++ < lines ) {
          if ( document.firstColumn(curPos) == -1 && document.nextNonEmptyLine(curPos) != init ) {
            target = document.nextNonEmptyLine(curPos);
            break;
          }
        }
        
        var cc = view.cursorPosition();
        
        if (target == -1) {
           target = lines - 1;       
           if (cc.compareTo(new Cursor(target, 0)) == 0)
              return;
        }
        
        var p = new Cursor(target, 0);
        var beg;
        var end;
        
        if (view.hasSelection()) {
           selbeg = view.selection().start;
           selend = view.selection().end;
           if (selend.compareTo(p) == -1) {
              if (cc.compareTo(selend) == -1) {
                 beg = selend;
                 end = p;
              } else {
                 beg = selbeg;
                 end = p;             
              }
           } else if (selend.compareTo(p) == 0) {
              beg = p;
              end = p;
           } else {
              beg = p;
              end = selend;
           }
        } else {
           beg = view.cursorPosition();
           end = p;
        }
        
        view.setSelection(new Range(beg, end));
        view.setCursorPosition(target, 0);
      }
      
    }
    

    Reply

    1. Dzikri Aziz 2014/06/17 at 2:24 pm

      Thanks Mohsen! I’ve yet to test it, but I think you should submit this to the maintainers so other people can use it too!

      Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>