2 #include "text-motions.h"
3 #include "text-objects.h"
6 /** utility functions */
8 static char *get_word_at(Text
*txt
, size_t pos
) {
9 Filerange word
= text_object_word(txt
, pos
);
10 if (!text_range_valid(&word
))
12 size_t len
= word
.end
- word
.start
;
13 char *buf
= malloc(len
+1);
16 len
= text_bytes_get(txt
, word
.start
, len
, buf
);
21 /** motion implementations */
23 static size_t search_word_forward(Vis
*vis
, Text
*txt
, size_t pos
) {
24 char *word
= get_word_at(txt
, pos
);
25 if (word
&& !text_regex_compile(vis
->search_pattern
, word
, REG_EXTENDED
))
26 pos
= text_search_forward(txt
, pos
, vis
->search_pattern
);
31 static size_t search_word_backward(Vis
*vis
, Text
*txt
, size_t pos
) {
32 char *word
= get_word_at(txt
, pos
);
33 if (word
&& !text_regex_compile(vis
->search_pattern
, word
, REG_EXTENDED
))
34 pos
= text_search_backward(txt
, pos
, vis
->search_pattern
);
39 static size_t search_forward(Vis
*vis
, Text
*txt
, size_t pos
) {
40 return text_search_forward(txt
, pos
, vis
->search_pattern
);
43 static size_t search_backward(Vis
*vis
, Text
*txt
, size_t pos
) {
44 return text_search_backward(txt
, pos
, vis
->search_pattern
);
47 static size_t mark_goto(Vis
*vis
, File
*file
, size_t pos
) {
48 return text_mark_get(file
->text
, file
->marks
[vis
->action
.mark
]);
51 static size_t mark_line_goto(Vis
*vis
, File
*file
, size_t pos
) {
52 return text_line_start(file
->text
, mark_goto(vis
, file
, pos
));
55 static size_t to(Vis
*vis
, Text
*txt
, size_t pos
) {
57 size_t hit
= text_line_find_next(txt
, pos
+1, vis
->search_char
);
58 if (!text_byte_get(txt
, hit
, &c
) || c
!= vis
->search_char
[0])
63 static size_t till(Vis
*vis
, Text
*txt
, size_t pos
) {
64 size_t hit
= to(vis
, txt
, pos
);
66 return text_char_prev(txt
, hit
);
70 static size_t to_left(Vis
*vis
, Text
*txt
, size_t pos
) {
74 size_t hit
= text_line_find_prev(txt
, pos
-1, vis
->search_char
);
75 if (!text_byte_get(txt
, hit
, &c
) || c
!= vis
->search_char
[0])
80 static size_t till_left(Vis
*vis
, Text
*txt
, size_t pos
) {
81 size_t hit
= to_left(vis
, txt
, pos
);
83 return text_char_next(txt
, hit
);
87 static size_t line(Vis
*vis
, Text
*txt
, size_t pos
) {
88 return text_pos_by_lineno(txt
, vis
->action
.count
);
91 static size_t column(Vis
*vis
, Text
*txt
, size_t pos
) {
92 return text_line_offset(txt
, pos
, vis
->action
.count
);
95 static size_t view_lines_top(Vis
*vis
, View
*view
) {
96 return view_screenline_goto(view
, vis
->action
.count
);
99 static size_t view_lines_middle(Vis
*vis
, View
*view
) {
100 int h
= view_height_get(view
);
101 return view_screenline_goto(view
, h
/2);
104 static size_t view_lines_bottom(Vis
*vis
, View
*view
) {
105 int h
= view_height_get(vis
->win
->view
);
106 return view_screenline_goto(vis
->win
->view
, h
- vis
->action
.count
);
109 static size_t window_changelist_next(Vis
*vis
, Win
*win
, size_t pos
) {
110 ChangeList
*cl
= &win
->changelist
;
111 Text
*txt
= win
->file
->text
;
112 time_t state
= text_state(txt
);
113 if (cl
->state
!= state
)
115 else if (cl
->index
> 0 && pos
== cl
->pos
)
117 size_t newpos
= text_history_get(txt
, cl
->index
);
126 static size_t window_changelist_prev(Vis
*vis
, Win
*win
, size_t pos
) {
127 ChangeList
*cl
= &win
->changelist
;
128 Text
*txt
= win
->file
->text
;
129 time_t state
= text_state(txt
);
130 if (cl
->state
!= state
)
132 else if (pos
== cl
->pos
)
133 win
->changelist
.index
++;
134 size_t newpos
= text_history_get(txt
, cl
->index
);
143 static size_t window_jumplist_next(Vis
*vis
, Win
*win
, size_t cur
) {
144 while (win
->jumplist
) {
145 Mark mark
= ringbuf_next(win
->jumplist
);
148 size_t pos
= text_mark_get(win
->file
->text
, mark
);
149 if (pos
!= EPOS
&& pos
!= cur
)
155 static size_t window_jumplist_prev(Vis
*vis
, Win
*win
, size_t cur
) {
156 while (win
->jumplist
) {
157 Mark mark
= ringbuf_prev(win
->jumplist
);
160 size_t pos
= text_mark_get(win
->file
->text
, mark
);
161 if (pos
!= EPOS
&& pos
!= cur
)
167 static size_t window_nop(Vis
*vis
, Win
*win
, size_t pos
) {
172 [VIS_MOVE_LINE_UP
] = { .cur
= view_line_up
, .type
= LINEWISE
},
173 [VIS_MOVE_LINE_DOWN
] = { .cur
= view_line_down
, .type
= LINEWISE
},
174 [VIS_MOVE_SCREEN_LINE_UP
] = { .cur
= view_screenline_up
, },
175 [VIS_MOVE_SCREEN_LINE_DOWN
] = { .cur
= view_screenline_down
, },
176 [VIS_MOVE_SCREEN_LINE_BEGIN
] = { .cur
= view_screenline_begin
, .type
= CHARWISE
},
177 [VIS_MOVE_SCREEN_LINE_MIDDLE
] = { .cur
= view_screenline_middle
, .type
= CHARWISE
},
178 [VIS_MOVE_SCREEN_LINE_END
] = { .cur
= view_screenline_end
, .type
= CHARWISE
|INCLUSIVE
},
179 [VIS_MOVE_LINE_PREV
] = { .txt
= text_line_prev
, },
180 [VIS_MOVE_LINE_BEGIN
] = { .txt
= text_line_begin
, },
181 [VIS_MOVE_LINE_START
] = { .txt
= text_line_start
, },
182 [VIS_MOVE_LINE_FINISH
] = { .txt
= text_line_finish
, .type
= INCLUSIVE
},
183 [VIS_MOVE_LINE_LASTCHAR
] = { .txt
= text_line_lastchar
, .type
= INCLUSIVE
},
184 [VIS_MOVE_LINE_END
] = { .txt
= text_line_end
, },
185 [VIS_MOVE_LINE_NEXT
] = { .txt
= text_line_next
, },
186 [VIS_MOVE_LINE
] = { .vis
= line
, .type
= LINEWISE
|IDEMPOTENT
|JUMP
},
187 [VIS_MOVE_COLUMN
] = { .vis
= column
, .type
= CHARWISE
|IDEMPOTENT
},
188 [VIS_MOVE_CHAR_PREV
] = { .txt
= text_char_prev
, .type
= CHARWISE
},
189 [VIS_MOVE_CHAR_NEXT
] = { .txt
= text_char_next
, .type
= CHARWISE
},
190 [VIS_MOVE_LINE_CHAR_PREV
] = { .txt
= text_line_char_prev
, .type
= CHARWISE
},
191 [VIS_MOVE_LINE_CHAR_NEXT
] = { .txt
= text_line_char_next
, .type
= CHARWISE
},
192 [VIS_MOVE_WORD_START_PREV
] = { .txt
= text_word_start_prev
, .type
= CHARWISE
},
193 [VIS_MOVE_WORD_START_NEXT
] = { .txt
= text_word_start_next
, .type
= CHARWISE
},
194 [VIS_MOVE_WORD_END_PREV
] = { .txt
= text_word_end_prev
, .type
= CHARWISE
|INCLUSIVE
},
195 [VIS_MOVE_WORD_END_NEXT
] = { .txt
= text_word_end_next
, .type
= CHARWISE
|INCLUSIVE
},
196 [VIS_MOVE_LONGWORD_START_PREV
] = { .txt
= text_longword_start_prev
, .type
= CHARWISE
},
197 [VIS_MOVE_LONGWORD_START_NEXT
] = { .txt
= text_longword_start_next
, .type
= CHARWISE
},
198 [VIS_MOVE_LONGWORD_END_PREV
] = { .txt
= text_longword_end_prev
, .type
= CHARWISE
|INCLUSIVE
},
199 [VIS_MOVE_LONGWORD_END_NEXT
] = { .txt
= text_longword_end_next
, .type
= CHARWISE
|INCLUSIVE
},
200 [VIS_MOVE_SENTENCE_PREV
] = { .txt
= text_sentence_prev
, .type
= LINEWISE
},
201 [VIS_MOVE_SENTENCE_NEXT
] = { .txt
= text_sentence_next
, .type
= LINEWISE
},
202 [VIS_MOVE_PARAGRAPH_PREV
] = { .txt
= text_paragraph_prev
, .type
= LINEWISE
|JUMP
},
203 [VIS_MOVE_PARAGRAPH_NEXT
] = { .txt
= text_paragraph_next
, .type
= LINEWISE
|JUMP
},
204 [VIS_MOVE_FUNCTION_START_PREV
] = { .txt
= text_function_start_prev
, .type
= LINEWISE
|JUMP
},
205 [VIS_MOVE_FUNCTION_START_NEXT
] = { .txt
= text_function_start_next
, .type
= LINEWISE
|JUMP
},
206 [VIS_MOVE_FUNCTION_END_PREV
] = { .txt
= text_function_end_prev
, .type
= LINEWISE
|JUMP
},
207 [VIS_MOVE_FUNCTION_END_NEXT
] = { .txt
= text_function_end_next
, .type
= LINEWISE
|JUMP
},
208 [VIS_MOVE_BRACKET_MATCH
] = { .txt
= text_bracket_match
, .type
= INCLUSIVE
|JUMP
},
209 [VIS_MOVE_FILE_BEGIN
] = { .txt
= text_begin
, .type
= LINEWISE
|JUMP
},
210 [VIS_MOVE_FILE_END
] = { .txt
= text_end
, .type
= LINEWISE
|JUMP
},
211 [VIS_MOVE_LEFT_TO
] = { .vis
= to_left
, },
212 [VIS_MOVE_RIGHT_TO
] = { .vis
= to
, .type
= INCLUSIVE
},
213 [VIS_MOVE_LEFT_TILL
] = { .vis
= till_left
, },
214 [VIS_MOVE_RIGHT_TILL
] = { .vis
= till
, .type
= INCLUSIVE
},
215 [VIS_MOVE_MARK
] = { .file
= mark_goto
, .type
= JUMP
|IDEMPOTENT
},
216 [VIS_MOVE_MARK_LINE
] = { .file
= mark_line_goto
, .type
= LINEWISE
|JUMP
|IDEMPOTENT
},
217 [VIS_MOVE_SEARCH_WORD_FORWARD
] = { .vis
= search_word_forward
, .type
= JUMP
},
218 [VIS_MOVE_SEARCH_WORD_BACKWARD
]= { .vis
= search_word_backward
, .type
= JUMP
},
219 [VIS_MOVE_SEARCH_NEXT
] = { .vis
= search_forward
, .type
= JUMP
},
220 [VIS_MOVE_SEARCH_PREV
] = { .vis
= search_backward
, .type
= JUMP
},
221 [VIS_MOVE_WINDOW_LINE_TOP
] = { .view
= view_lines_top
, .type
= LINEWISE
|JUMP
|IDEMPOTENT
},
222 [VIS_MOVE_WINDOW_LINE_MIDDLE
] = { .view
= view_lines_middle
, .type
= LINEWISE
|JUMP
|IDEMPOTENT
},
223 [VIS_MOVE_WINDOW_LINE_BOTTOM
] = { .view
= view_lines_bottom
, .type
= LINEWISE
|JUMP
|IDEMPOTENT
},
224 [VIS_MOVE_CHANGELIST_NEXT
] = { .win
= window_changelist_next
, .type
= INCLUSIVE
},
225 [VIS_MOVE_CHANGELIST_PREV
] = { .win
= window_changelist_prev
, .type
= INCLUSIVE
},
226 [VIS_MOVE_JUMPLIST_NEXT
] = { .win
= window_jumplist_next
, .type
= INCLUSIVE
},
227 [VIS_MOVE_JUMPLIST_PREV
] = { .win
= window_jumplist_prev
, .type
= INCLUSIVE
},
228 [VIS_MOVE_NOP
] = { .win
= window_nop
, .type
= IDEMPOTENT
},