Sublime Forum

Navigate to previous/next line while word-wrap on

#1

Hi,

Is there a way to move cursor to previous/next line when word-wrap is on. The file has long lines & span across multiple lines when the word-wrap is on. In this case up & down arrow keys only move across same line.

0 Likes

#2

Been casually wondering the same. I know vim has a solution of sorts for this (if you’re willing to map some keybindings). The move command may hold the answer … don’t know any details though.

0 Likes

#3

At a basic level, this could be done using a 2-step .sublime-macro, e.g. for moving to the next line:

[
    {"command": "move_to", "args": {"to": "hardeol"}},
    {"command": "move", "args": {"by": "characters", "forward": true}},
]

But to also preserve the column that the caret was on (what the API calls xpos) then Python plugin code probably needs to be involved.


EDIT: Actually you can get the column preservation by taking advantage of the fact that word_wrap can be “atomically/invisibly” toggled off and then back on during the macro:

[
    {"command": "toggle_setting", "args": {"setting": "word_wrap"}},
    {"command": "move", "args": {"by": "lines", "forward": true}},
    {"command": "toggle_setting", "args": {"setting": "word_wrap"}},
]
2 Likes

#4

Thanks @frou. Based on your suggestion I ended up creating following command which works using row-col navigation. Playing with word-wrap was a little tricky (had to bring current cursor line in focus which didn’t work all the time) so didn’t go that route.

class MoveLineCursorCommand(sublime_plugin.TextCommand):
    def run(self, edit, forward):
        view = self.view
        (row, col) = view.rowcol(view.sel()[0].begin())
        if forward:
            if row == view.rowcol(view.size())[0]: return
            row = int(row) + 1
        else:
            if row == 0: return
            row = int(row) - 1
        view.run_command('move_to', {'to': 'hardbol', 'extend': False}),
        view.run_command('move', {'by': 'lines', 'forward': forward}),
        curr_row_len = len(self.view.substr(self.view.full_line(self.view.text_point(row,0)))) - 1
        col = min(col, curr_row_len)
        self.view.sel().clear()
        self.view.sel().add(sublime.Region(self.view.text_point(row, col)))
        self.view.show(self.view.text_point(row, col), animate=False)

And defined key-bindings as follows:

    { "keys": ["ctrl+up"], "command": "move_line_cursor", "args": {"forward": false} },
    { "keys": ["ctrl+down"], "command": "move_line_cursor", "args": {"forward": true} },
1 Like

#5

Cool - I don’t know if it actually makes sense to do the following, but it’s possible to make a key binding conditional based on a view setting, and reuse already bound keys:

{
    "keys": ["down"],
    "context": [{"key": "setting.word_wrap", "operator": "equal", "operand": true}],
    "command": "...",
    "args": { ... }
},
1 Like

#6

Thanks! will try that out.

0 Likes