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 size_t len
= word
.end
- word
.start
;
14 char *buf
= malloc(len
+1);
17 len
= text_bytes_get(txt
, word
.start
, len
, buf
);
22 /** motion implementations */
24 static size_t search_word_forward(Vis
*vis
, Text
*txt
, size_t pos
) {
25 char *word
= get_word_at(txt
, pos
);
26 if (word
&& !text_regex_compile(vis
->search_pattern
, word
, REG_EXTENDED
))
27 pos
= text_search_forward(txt
, pos
, vis
->search_pattern
);
32 static size_t search_word_backward(Vis
*vis
, Text
*txt
, size_t pos
) {
33 char *word
= get_word_at(txt
, pos
);
34 if (word
&& !text_regex_compile(vis
->search_pattern
, word
, REG_EXTENDED
))
35 pos
= text_search_backward(txt
, pos
, vis
->search_pattern
);
40 static size_t search_forward(Vis
*vis
, Text
*txt
, size_t pos
) {
41 return text_search_forward(txt
, pos
, vis
->search_pattern
);
44 static size_t search_backward(Vis
*vis
, Text
*txt
, size_t pos
) {
45 return text_search_backward(txt
, pos
, vis
->search_pattern
);
48 static size_t mark_goto(Vis
*vis
, File
*file
, size_t pos
) {
49 return text_mark_get(file
->text
, file
->marks
[vis
->action
.mark
]);
52 static size_t mark_line_goto(Vis
*vis
, File
*file
, size_t pos
) {
53 return text_line_start(file
->text
, mark_goto(vis
, file
, pos
));
56 static size_t to(Vis
*vis
, Text
*txt
, size_t pos
) {
58 size_t hit
= text_line_find_next(txt
, pos
+1, vis
->search_char
);
59 if (!text_byte_get(txt
, hit
, &c
) || c
!= vis
->search_char
[0])
64 static size_t till(Vis
*vis
, Text
*txt
, size_t pos
) {
65 size_t hit
= to(vis
, txt
, pos
);
67 return text_char_prev(txt
, hit
);
71 static size_t to_left(Vis
*vis
, Text
*txt
, size_t pos
) {
75 size_t hit
= text_line_find_prev(txt
, pos
-1, vis
->search_char
);
76 if (!text_byte_get(txt
, hit
, &c
) || c
!= vis
->search_char
[0])
81 static size_t till_left(Vis
*vis
, Text
*txt
, size_t pos
) {
82 size_t hit
= to_left(vis
, txt
, pos
);
84 return text_char_next(txt
, hit
);
88 static size_t line(Vis
*vis
, Text
*txt
, size_t pos
) {
89 return text_pos_by_lineno(txt
, vis
->action
.count
);
92 static size_t column(Vis
*vis
, Text
*txt
, size_t pos
) {
93 return text_line_offset(txt
, pos
, vis
->action
.count
);
96 static size_t view_lines_top(Vis
*vis
, View
*view
) {
97 return view_screenline_goto(view
, vis
->action
.count
);
100 static size_t view_lines_middle(Vis
*vis
, View
*view
) {
101 int h
= view_height_get(view
);
102 return view_screenline_goto(view
, h
/2);
105 static size_t view_lines_bottom(Vis
*vis
, View
*view
) {
106 int h
= view_height_get(vis
->win
->view
);
107 return view_screenline_goto(vis
->win
->view
, h
- vis
->action
.count
);
110 static size_t window_changelist_next(Vis
*vis
, Win
*win
, size_t pos
) {
111 ChangeList
*cl
= &win
->changelist
;
112 Text
*txt
= win
->file
->text
;
113 time_t state
= text_state(txt
);
114 if (cl
->state
!= state
)
116 else if (cl
->index
> 0 && pos
== cl
->pos
)
118 size_t newpos
= text_history_get(txt
, cl
->index
);
127 static size_t window_changelist_prev(Vis
*vis
, Win
*win
, size_t pos
) {
128 ChangeList
*cl
= &win
->changelist
;
129 Text
*txt
= win
->file
->text
;
130 time_t state
= text_state(txt
);
131 if (cl
->state
!= state
)
133 else if (pos
== cl
->pos
)
134 win
->changelist
.index
++;
135 size_t newpos
= text_history_get(txt
, cl
->index
);
144 static size_t window_jumplist_next(Vis
*vis
, Win
*win
, size_t cur
) {
145 while (win
->jumplist
) {
146 Mark mark
= ringbuf_next(win
->jumplist
);
149 size_t pos
= text_mark_get(win
->file
->text
, mark
);
150 if (pos
!= EPOS
&& pos
!= cur
)
156 static size_t window_jumplist_prev(Vis
*vis
, Win
*win
, size_t cur
) {
157 while (win
->jumplist
) {
158 Mark mark
= ringbuf_prev(win
->jumplist
);
161 size_t pos
= text_mark_get(win
->file
->text
, mark
);
162 if (pos
!= EPOS
&& pos
!= cur
)
168 static size_t window_nop(Vis
*vis
, Win
*win
, size_t pos
) {
173 [VIS_MOVE_LINE_UP
] = { .cur
= view_line_up
, .type
= LINEWISE
},
174 [VIS_MOVE_LINE_DOWN
] = { .cur
= view_line_down
, .type
= LINEWISE
},
175 [VIS_MOVE_SCREEN_LINE_UP
] = { .cur
= view_screenline_up
, },
176 [VIS_MOVE_SCREEN_LINE_DOWN
] = { .cur
= view_screenline_down
, },
177 [VIS_MOVE_SCREEN_LINE_BEGIN
] = { .cur
= view_screenline_begin
, .type
= CHARWISE
},
178 [VIS_MOVE_SCREEN_LINE_MIDDLE
] = { .cur
= view_screenline_middle
, .type
= CHARWISE
},
179 [VIS_MOVE_SCREEN_LINE_END
] = { .cur
= view_screenline_end
, .type
= CHARWISE
|INCLUSIVE
},
180 [VIS_MOVE_LINE_PREV
] = { .txt
= text_line_prev
, },
181 [VIS_MOVE_LINE_BEGIN
] = { .txt
= text_line_begin
, },
182 [VIS_MOVE_LINE_START
] = { .txt
= text_line_start
, },
183 [VIS_MOVE_LINE_FINISH
] = { .txt
= text_line_finish
, .type
= INCLUSIVE
},
184 [VIS_MOVE_LINE_LASTCHAR
] = { .txt
= text_line_lastchar
, .type
= INCLUSIVE
},
185 [VIS_MOVE_LINE_END
] = { .txt
= text_line_end
, },
186 [VIS_MOVE_LINE_NEXT
] = { .txt
= text_line_next
, },
187 [VIS_MOVE_LINE
] = { .vis
= line
, .type
= LINEWISE
|IDEMPOTENT
|JUMP
},
188 [VIS_MOVE_COLUMN
] = { .vis
= column
, .type
= CHARWISE
|IDEMPOTENT
},
189 [VIS_MOVE_CHAR_PREV
] = { .txt
= text_char_prev
, .type
= CHARWISE
},
190 [VIS_MOVE_CHAR_NEXT
] = { .txt
= text_char_next
, .type
= CHARWISE
},
191 [VIS_MOVE_LINE_CHAR_PREV
] = { .txt
= text_line_char_prev
, .type
= CHARWISE
},
192 [VIS_MOVE_LINE_CHAR_NEXT
] = { .txt
= text_line_char_next
, .type
= CHARWISE
},
193 [VIS_MOVE_WORD_START_PREV
] = { .txt
= text_word_start_prev
, .type
= CHARWISE
},
194 [VIS_MOVE_WORD_START_NEXT
] = { .txt
= text_word_start_next
, .type
= CHARWISE
},
195 [VIS_MOVE_WORD_END_PREV
] = { .txt
= text_word_end_prev
, .type
= CHARWISE
|INCLUSIVE
},
196 [VIS_MOVE_WORD_END_NEXT
] = { .txt
= text_word_end_next
, .type
= CHARWISE
|INCLUSIVE
},
197 [VIS_MOVE_LONGWORD_START_PREV
] = { .txt
= text_longword_start_prev
, .type
= CHARWISE
},
198 [VIS_MOVE_LONGWORD_START_NEXT
] = { .txt
= text_longword_start_next
, .type
= CHARWISE
},
199 [VIS_MOVE_LONGWORD_END_PREV
] = { .txt
= text_longword_end_prev
, .type
= CHARWISE
|INCLUSIVE
},
200 [VIS_MOVE_LONGWORD_END_NEXT
] = { .txt
= text_longword_end_next
, .type
= CHARWISE
|INCLUSIVE
},
201 [VIS_MOVE_SENTENCE_PREV
] = { .txt
= text_sentence_prev
, .type
= LINEWISE
},
202 [VIS_MOVE_SENTENCE_NEXT
] = { .txt
= text_sentence_next
, .type
= LINEWISE
},
203 [VIS_MOVE_PARAGRAPH_PREV
] = { .txt
= text_paragraph_prev
, .type
= LINEWISE
|JUMP
},
204 [VIS_MOVE_PARAGRAPH_NEXT
] = { .txt
= text_paragraph_next
, .type
= LINEWISE
|JUMP
},
205 [VIS_MOVE_FUNCTION_START_PREV
] = { .txt
= text_function_start_prev
, .type
= LINEWISE
|JUMP
},
206 [VIS_MOVE_FUNCTION_START_NEXT
] = { .txt
= text_function_start_next
, .type
= LINEWISE
|JUMP
},
207 [VIS_MOVE_FUNCTION_END_PREV
] = { .txt
= text_function_end_prev
, .type
= LINEWISE
|JUMP
},
208 [VIS_MOVE_FUNCTION_END_NEXT
] = { .txt
= text_function_end_next
, .type
= LINEWISE
|JUMP
},
209 [VIS_MOVE_BRACKET_MATCH
] = { .txt
= text_bracket_match
, .type
= INCLUSIVE
|JUMP
},
210 [VIS_MOVE_FILE_BEGIN
] = { .txt
= text_begin
, .type
= LINEWISE
|JUMP
},
211 [VIS_MOVE_FILE_END
] = { .txt
= text_end
, .type
= LINEWISE
|JUMP
},
212 [VIS_MOVE_LEFT_TO
] = { .vis
= to_left
, },
213 [VIS_MOVE_RIGHT_TO
] = { .vis
= to
, .type
= INCLUSIVE
},
214 [VIS_MOVE_LEFT_TILL
] = { .vis
= till_left
, },
215 [VIS_MOVE_RIGHT_TILL
] = { .vis
= till
, .type
= INCLUSIVE
},
216 [VIS_MOVE_MARK
] = { .file
= mark_goto
, .type
= JUMP
|IDEMPOTENT
},
217 [VIS_MOVE_MARK_LINE
] = { .file
= mark_line_goto
, .type
= LINEWISE
|JUMP
|IDEMPOTENT
},
218 [VIS_MOVE_SEARCH_WORD_FORWARD
] = { .vis
= search_word_forward
, .type
= JUMP
},
219 [VIS_MOVE_SEARCH_WORD_BACKWARD
]= { .vis
= search_word_backward
, .type
= JUMP
},
220 [VIS_MOVE_SEARCH_NEXT
] = { .vis
= search_forward
, .type
= JUMP
},
221 [VIS_MOVE_SEARCH_PREV
] = { .vis
= search_backward
, .type
= JUMP
},
222 [VIS_MOVE_WINDOW_LINE_TOP
] = { .view
= view_lines_top
, .type
= LINEWISE
|JUMP
|IDEMPOTENT
},
223 [VIS_MOVE_WINDOW_LINE_MIDDLE
] = { .view
= view_lines_middle
, .type
= LINEWISE
|JUMP
|IDEMPOTENT
},
224 [VIS_MOVE_WINDOW_LINE_BOTTOM
] = { .view
= view_lines_bottom
, .type
= LINEWISE
|JUMP
|IDEMPOTENT
},
225 [VIS_MOVE_CHANGELIST_NEXT
] = { .win
= window_changelist_next
, .type
= INCLUSIVE
},
226 [VIS_MOVE_CHANGELIST_PREV
] = { .win
= window_changelist_prev
, .type
= INCLUSIVE
},
227 [VIS_MOVE_JUMPLIST_NEXT
] = { .win
= window_jumplist_next
, .type
= INCLUSIVE
},
228 [VIS_MOVE_JUMPLIST_PREV
] = { .win
= window_jumplist_prev
, .type
= INCLUSIVE
},
229 [VIS_MOVE_NOP
] = { .win
= window_nop
, .type
= IDEMPOTENT
},