3 #include "text-motions.h"
4 #include "text-objects.h"
7 /** utility functions */
9 static char *get_word_at(Text
*txt
, size_t pos
) {
10 Filerange word
= text_object_word(txt
, pos
);
11 if (!text_range_valid(&word
))
13 return text_bytes_alloc0(txt
, word
.start
, word
.end
- word
.start
);
16 /** motion implementations */
18 static size_t search_word_forward(Vis
*vis
, Text
*txt
, size_t pos
) {
19 char *word
= get_word_at(txt
, pos
);
20 if (word
&& !text_regex_compile(vis
->search_pattern
, word
, REG_EXTENDED
))
21 pos
= text_search_forward(txt
, pos
, vis
->search_pattern
);
26 static size_t search_word_backward(Vis
*vis
, Text
*txt
, size_t pos
) {
27 char *word
= get_word_at(txt
, pos
);
28 if (word
&& !text_regex_compile(vis
->search_pattern
, word
, REG_EXTENDED
))
29 pos
= text_search_backward(txt
, pos
, vis
->search_pattern
);
34 static size_t search_forward(Vis
*vis
, Text
*txt
, size_t pos
) {
35 return text_search_forward(txt
, pos
, vis
->search_pattern
);
38 static size_t search_backward(Vis
*vis
, Text
*txt
, size_t pos
) {
39 return text_search_backward(txt
, pos
, vis
->search_pattern
);
42 static size_t mark_goto(Vis
*vis
, File
*file
, size_t pos
) {
43 return text_mark_get(file
->text
, file
->marks
[vis
->action
.mark
]);
46 static size_t mark_line_goto(Vis
*vis
, File
*file
, size_t pos
) {
47 return text_line_start(file
->text
, mark_goto(vis
, file
, pos
));
50 static size_t to(Vis
*vis
, Text
*txt
, size_t pos
) {
52 size_t hit
= text_line_find_next(txt
, pos
+1, vis
->search_char
);
53 if (!text_byte_get(txt
, hit
, &c
) || c
!= vis
->search_char
[0])
58 static size_t till(Vis
*vis
, Text
*txt
, size_t pos
) {
59 size_t hit
= to(vis
, txt
, pos
);
61 return text_char_prev(txt
, hit
);
65 static size_t to_left(Vis
*vis
, Text
*txt
, size_t pos
) {
69 size_t hit
= text_line_find_prev(txt
, pos
-1, vis
->search_char
);
70 if (!text_byte_get(txt
, hit
, &c
) || c
!= vis
->search_char
[0])
75 static size_t till_left(Vis
*vis
, Text
*txt
, size_t pos
) {
76 size_t hit
= to_left(vis
, txt
, pos
);
78 return text_char_next(txt
, hit
);
82 static size_t line(Vis
*vis
, Text
*txt
, size_t pos
) {
83 return text_pos_by_lineno(txt
, vis
->action
.count
);
86 static size_t column(Vis
*vis
, Text
*txt
, size_t pos
) {
87 return text_line_offset(txt
, pos
, vis
->action
.count
);
90 static size_t view_lines_top(Vis
*vis
, View
*view
) {
91 return view_screenline_goto(view
, vis
->action
.count
);
94 static size_t view_lines_middle(Vis
*vis
, View
*view
) {
95 int h
= view_height_get(view
);
96 return view_screenline_goto(view
, h
/2);
99 static size_t view_lines_bottom(Vis
*vis
, View
*view
) {
100 int h
= view_height_get(vis
->win
->view
);
101 return view_screenline_goto(vis
->win
->view
, h
- vis
->action
.count
);
104 static size_t window_changelist_next(Vis
*vis
, Win
*win
, size_t pos
) {
105 ChangeList
*cl
= &win
->changelist
;
106 Text
*txt
= win
->file
->text
;
107 time_t state
= text_state(txt
);
108 if (cl
->state
!= state
)
110 else if (cl
->index
> 0 && pos
== cl
->pos
)
112 size_t newpos
= text_history_get(txt
, cl
->index
);
121 static size_t window_changelist_prev(Vis
*vis
, Win
*win
, size_t pos
) {
122 ChangeList
*cl
= &win
->changelist
;
123 Text
*txt
= win
->file
->text
;
124 time_t state
= text_state(txt
);
125 if (cl
->state
!= state
)
127 else if (pos
== cl
->pos
)
128 win
->changelist
.index
++;
129 size_t newpos
= text_history_get(txt
, cl
->index
);
138 static size_t window_jumplist_next(Vis
*vis
, Win
*win
, size_t cur
) {
139 while (win
->jumplist
) {
140 Mark mark
= ringbuf_next(win
->jumplist
);
143 size_t pos
= text_mark_get(win
->file
->text
, mark
);
144 if (pos
!= EPOS
&& pos
!= cur
)
150 static size_t window_jumplist_prev(Vis
*vis
, Win
*win
, size_t cur
) {
151 while (win
->jumplist
) {
152 Mark mark
= ringbuf_prev(win
->jumplist
);
155 size_t pos
= text_mark_get(win
->file
->text
, mark
);
156 if (pos
!= EPOS
&& pos
!= cur
)
162 static size_t window_nop(Vis
*vis
, Win
*win
, size_t pos
) {
167 [VIS_MOVE_LINE_UP
] = { .cur
= view_line_up
, .type
= LINEWISE
},
168 [VIS_MOVE_LINE_DOWN
] = { .cur
= view_line_down
, .type
= LINEWISE
},
169 [VIS_MOVE_SCREEN_LINE_UP
] = { .cur
= view_screenline_up
, },
170 [VIS_MOVE_SCREEN_LINE_DOWN
] = { .cur
= view_screenline_down
, },
171 [VIS_MOVE_SCREEN_LINE_BEGIN
] = { .cur
= view_screenline_begin
, .type
= CHARWISE
},
172 [VIS_MOVE_SCREEN_LINE_MIDDLE
] = { .cur
= view_screenline_middle
, .type
= CHARWISE
},
173 [VIS_MOVE_SCREEN_LINE_END
] = { .cur
= view_screenline_end
, .type
= CHARWISE
|INCLUSIVE
},
174 [VIS_MOVE_LINE_PREV
] = { .txt
= text_line_prev
, },
175 [VIS_MOVE_LINE_BEGIN
] = { .txt
= text_line_begin
, },
176 [VIS_MOVE_LINE_START
] = { .txt
= text_line_start
, },
177 [VIS_MOVE_LINE_FINISH
] = { .txt
= text_line_finish
, .type
= INCLUSIVE
},
178 [VIS_MOVE_LINE_LASTCHAR
] = { .txt
= text_line_lastchar
, .type
= INCLUSIVE
},
179 [VIS_MOVE_LINE_END
] = { .txt
= text_line_end
, },
180 [VIS_MOVE_LINE_NEXT
] = { .txt
= text_line_next
, },
181 [VIS_MOVE_LINE
] = { .vis
= line
, .type
= LINEWISE
|IDEMPOTENT
|JUMP
},
182 [VIS_MOVE_COLUMN
] = { .vis
= column
, .type
= CHARWISE
|IDEMPOTENT
},
183 [VIS_MOVE_CHAR_PREV
] = { .txt
= text_char_prev
, .type
= CHARWISE
},
184 [VIS_MOVE_CHAR_NEXT
] = { .txt
= text_char_next
, .type
= CHARWISE
},
185 [VIS_MOVE_LINE_CHAR_PREV
] = { .txt
= text_line_char_prev
, .type
= CHARWISE
},
186 [VIS_MOVE_LINE_CHAR_NEXT
] = { .txt
= text_line_char_next
, .type
= CHARWISE
},
187 [VIS_MOVE_WORD_START_PREV
] = { .txt
= text_word_start_prev
, .type
= CHARWISE
},
188 [VIS_MOVE_WORD_START_NEXT
] = { .txt
= text_word_start_next
, .type
= CHARWISE
},
189 [VIS_MOVE_WORD_END_PREV
] = { .txt
= text_word_end_prev
, .type
= CHARWISE
|INCLUSIVE
},
190 [VIS_MOVE_WORD_END_NEXT
] = { .txt
= text_word_end_next
, .type
= CHARWISE
|INCLUSIVE
},
191 [VIS_MOVE_LONGWORD_START_PREV
] = { .txt
= text_longword_start_prev
, .type
= CHARWISE
},
192 [VIS_MOVE_LONGWORD_START_NEXT
] = { .txt
= text_longword_start_next
, .type
= CHARWISE
},
193 [VIS_MOVE_LONGWORD_END_PREV
] = { .txt
= text_longword_end_prev
, .type
= CHARWISE
|INCLUSIVE
},
194 [VIS_MOVE_LONGWORD_END_NEXT
] = { .txt
= text_longword_end_next
, .type
= CHARWISE
|INCLUSIVE
},
195 [VIS_MOVE_SENTENCE_PREV
] = { .txt
= text_sentence_prev
, .type
= LINEWISE
},
196 [VIS_MOVE_SENTENCE_NEXT
] = { .txt
= text_sentence_next
, .type
= LINEWISE
},
197 [VIS_MOVE_PARAGRAPH_PREV
] = { .txt
= text_paragraph_prev
, .type
= LINEWISE
|JUMP
},
198 [VIS_MOVE_PARAGRAPH_NEXT
] = { .txt
= text_paragraph_next
, .type
= LINEWISE
|JUMP
},
199 [VIS_MOVE_FUNCTION_START_PREV
] = { .txt
= text_function_start_prev
, .type
= LINEWISE
|JUMP
},
200 [VIS_MOVE_FUNCTION_START_NEXT
] = { .txt
= text_function_start_next
, .type
= LINEWISE
|JUMP
},
201 [VIS_MOVE_FUNCTION_END_PREV
] = { .txt
= text_function_end_prev
, .type
= LINEWISE
|JUMP
},
202 [VIS_MOVE_FUNCTION_END_NEXT
] = { .txt
= text_function_end_next
, .type
= LINEWISE
|JUMP
},
203 [VIS_MOVE_BRACKET_MATCH
] = { .txt
= text_bracket_match
, .type
= INCLUSIVE
|JUMP
},
204 [VIS_MOVE_FILE_BEGIN
] = { .txt
= text_begin
, .type
= LINEWISE
|JUMP
},
205 [VIS_MOVE_FILE_END
] = { .txt
= text_end
, .type
= LINEWISE
|JUMP
},
206 [VIS_MOVE_LEFT_TO
] = { .vis
= to_left
, },
207 [VIS_MOVE_RIGHT_TO
] = { .vis
= to
, .type
= INCLUSIVE
},
208 [VIS_MOVE_LEFT_TILL
] = { .vis
= till_left
, },
209 [VIS_MOVE_RIGHT_TILL
] = { .vis
= till
, .type
= INCLUSIVE
},
210 [VIS_MOVE_MARK
] = { .file
= mark_goto
, .type
= JUMP
|IDEMPOTENT
},
211 [VIS_MOVE_MARK_LINE
] = { .file
= mark_line_goto
, .type
= LINEWISE
|JUMP
|IDEMPOTENT
},
212 [VIS_MOVE_SEARCH_WORD_FORWARD
] = { .vis
= search_word_forward
, .type
= JUMP
},
213 [VIS_MOVE_SEARCH_WORD_BACKWARD
]= { .vis
= search_word_backward
, .type
= JUMP
},
214 [VIS_MOVE_SEARCH_NEXT
] = { .vis
= search_forward
, .type
= JUMP
},
215 [VIS_MOVE_SEARCH_PREV
] = { .vis
= search_backward
, .type
= JUMP
},
216 [VIS_MOVE_WINDOW_LINE_TOP
] = { .view
= view_lines_top
, .type
= LINEWISE
|JUMP
|IDEMPOTENT
},
217 [VIS_MOVE_WINDOW_LINE_MIDDLE
] = { .view
= view_lines_middle
, .type
= LINEWISE
|JUMP
|IDEMPOTENT
},
218 [VIS_MOVE_WINDOW_LINE_BOTTOM
] = { .view
= view_lines_bottom
, .type
= LINEWISE
|JUMP
|IDEMPOTENT
},
219 [VIS_MOVE_CHANGELIST_NEXT
] = { .win
= window_changelist_next
, .type
= INCLUSIVE
},
220 [VIS_MOVE_CHANGELIST_PREV
] = { .win
= window_changelist_prev
, .type
= INCLUSIVE
},
221 [VIS_MOVE_JUMPLIST_NEXT
] = { .win
= window_jumplist_next
, .type
= INCLUSIVE
},
222 [VIS_MOVE_JUMPLIST_PREV
] = { .win
= window_jumplist_prev
, .type
= INCLUSIVE
},
223 [VIS_MOVE_NOP
] = { .win
= window_nop
, .type
= IDEMPOTENT
},