2 * Copyright (C) 2008 - 2012 Diego Hernan Borghetti.
20 E_Line
*e_line_alloc(void)
24 ln
= (E_Line
*)malloc(sizeof(E_Line
));
30 ln
->text
= (char *)malloc(16);
34 void e_line_realloc(E_Line
*ln
)
37 ln
->text
= (char *)realloc((void *)ln
->text
, ln
->size
);
40 void e_line_free(E_Line
*ln
)
42 free((void *)ln
->text
);
46 void e_line_add(E_Buffer
*bf
, E_Line
*ln
)
48 ln
->next
= bf
->line
->next
;
58 void e_line_add_first(E_Buffer
*bf
, E_Line
*ln
)
67 bf
->first
= ln
; /* auto-reframe. */
71 void e_line_remove(E_Buffer
*bf
, E_Line
*ln
)
74 ln
->next
->prev
= ln
->prev
;
76 ln
->prev
->next
= ln
->next
;
81 if (bf
->first
== ln
) {
83 bf
->first
= bf
->first
->prev
;
85 bf
->first
= bf
->first
->next
;
90 bf
->line
= bf
->line
->next
;
92 bf
->line
= bf
->line
->prev
;
100 E_Buffer
*e_buffer_new(char *file
)
104 bf
= (E_Buffer
*)malloc(sizeof(E_Buffer
));
106 bf
->paths
= e_file_get_paths(file
);
113 if (!bf
->paths
->path
) {
114 free((void *)bf
->paths
);
119 if (!bf
->paths
->file
) {
120 free((void *)bf
->paths
->path
);
121 free((void *)bf
->paths
);
125 /* remove the full path, only show the name. */
126 bf
->name
= strrchr(bf
->paths
->file
, '/');
128 bf
->name
= bf
->paths
->file
;
132 e_debug_printf("path: %s\n", bf
->paths
->path
);
133 e_debug_printf("file: %s\n", bf
->paths
->file
);
134 e_debug_printf("name: %s\n", bf
->name
);
136 bf
->lines
= e_line_alloc();
137 bf
->first
= bf
->lines
;
147 void e_buffer_free(E_Buffer
*bf
)
151 /* only remove the lock when we free the buffer. */
152 e_file_lock_rem(bf
->paths
);
154 free((void *)bf
->paths
->path
);
155 free((void *)bf
->paths
->file
);
156 free((void *)bf
->paths
->lock_file
);
157 free((void *)bf
->paths
);
161 e_line_free(bf
->lines
);
167 void e_buffer_recalc(E_Buffer
*bf
)
181 /* Add a new line at the current position in the buffer. */
182 void e_buffer_newline(E_Buffer
*bf
)
186 BUFFER_SET(bf
, BUFFER_FLUSH
);
188 /* save the current line. */
194 /* Always clean the current position, the new line don't
200 BUFFER_SET(bf
, BUFFER_DOWN
);
202 if (!(bf
->flag
& BUFFER_NOIDENT
)) {
205 /* Check if we have tabs on the current line
206 * to insert in the next.
208 for (i
= 0, tot
= 0; i
< lnp
->used
; i
++) {
209 /* If the line don't have any tab at
210 * the start there is nothing to do.
212 if (i
== 0 && lnp
->text
[i
] != '\t')
214 else if (lnp
->text
[i
] == '\t')
221 e_buffer_insert(bf
, '\t', tot
);
223 /* If the last line finish with a { add an extra tab. */
224 if (lnp
->text
[lnp
->used
-1] == '{')
225 e_buffer_insert(bf
, '\t', 1);
227 /* If the last line was empty, remove all the tabs. */
228 if (tot
== lnp
->used
)
234 /* Add a new line at the begin of the buffer. */
235 void e_buffer_newline_first(E_Buffer
*bf
)
239 BUFFER_SET(bf
, BUFFER_FLUSH
);
242 e_line_add_first(bf
, ln
);
247 /* Split the current line in two line, the starting
248 * point for split is the current cursor position.
250 void e_buffer_splitline(E_Buffer
*bf
)
255 /* save the current line. */
258 /* and the cursor position. */
261 /* insert a new line and add all the character
262 * from the current position, to the end.
264 e_buffer_newline(bf
);
265 for (i
= dot
; i
< ln
->used
; i
++)
266 e_buffer_insert(bf
, ln
->text
[i
], 1);
270 /* Always go to the begin of the line. */
274 /* Join two line, the source line is the current line and
275 * the dest line is the prev.
277 void e_buffer_joinline(E_Buffer
*bf
)
282 /* if we are at the begin, return. */
286 /* save the current line. */
289 /* move to the previous. */
292 /* put the cursor to the end of the line. */
293 bf
->dot
= bf
->line
->used
;
295 /* and save the position. */
298 /* insert all the characters. */
299 for (i
= 0; i
< ln
->used
; i
++)
300 e_buffer_insert(bf
, ln
->text
[i
], 1);
302 /* remove the unused line. */
303 e_line_remove(bf
, ln
);
306 /* restore the original cursor position. */
311 /* Remove the current line from the buffer, this also
312 * can save the line in the cut-buffer.
314 * If 'cut' is equal to two, only copy the line to the
317 void e_buffer_killline(E_Buffer
*bf
, int cut
)
322 e_kill_cut(bf
->line
);
330 if ((!bf
->line
->prev
) && (!bf
->line
->next
)) {
331 /* If we don't have previous or next line,
332 * the only thing to do is clean the
335 e_buffer_cleanline(bf
);
338 else if (!bf
->line
->next
) {
339 /* If we don't have next line, only clean. */
340 e_buffer_cleanline(bf
);
344 if (bf
->line
->used
) {
345 /* This work like emacs, if the line have text
346 * first clean the text.
348 e_buffer_cleanline(bf
);
352 /* And if the line don't have text, remove it. */
353 BUFFER_SET(bf
, BUFFER_FLUSH
);
357 e_line_remove(bf
, ln
);
362 /* Insert a character in the current line at the current
365 void e_buffer_insert(E_Buffer
*bf
, int c
, int repeat
)
369 BUFFER_SET(bf
, BUFFER_FLUSH
);
371 if (!(bf
->flag
& BUFFER_NOIDENT
)) {
372 if (bf
->line
->text
[bf
->dot
] == ')' && c
== ')') {
373 if (bf
->dot
< bf
->line
->used
)
377 else if (bf
->line
->text
[bf
->dot
] == ';' && c
== ';') {
378 if (bf
->dot
< bf
->line
->used
)
384 for (j
= 0; j
< repeat
; j
++) {
385 /* check if we need reallocate the line. */
386 if ((bf
->line
->used
+1) >= bf
->line
->size
)
387 e_line_realloc(bf
->line
);
389 /* if the cursor is not at the end of the line,
390 * we need scroll the text to the right.
392 if (bf
->dot
!= bf
->line
->used
) {
393 for (i
= bf
->line
->used
; i
> bf
->dot
; i
--)
394 bf
->line
->text
[i
]= bf
->line
->text
[i
-1];
397 /* insert the new character. */
398 bf
->line
->text
[bf
->dot
]= c
;
403 if (!(bf
->flag
& BUFFER_NOIDENT
)) {
405 /* save the current position. */
408 /* insert the second part. */
409 e_buffer_insert(bf
, ')', 1);
411 /* and move back the cursor. */
418 * Insert multiples characters in the current line at
419 * the current cursor position ('\n' are valid here!).
421 void e_buffer_insert_str(E_Buffer
*bf
, char *str
, int len
)
426 BUFFER_SET(bf
, BUFFER_FLUSH
);
431 e_buffer_newline(bf
);
433 /* check if we need reallocate the line. */
434 if ((bf
->line
->used
+1) >= bf
->line
->size
)
435 e_line_realloc(bf
->line
);
437 /* if the cursor is not at the end of the line,
438 * we need scroll the text to the right.
440 if (bf
->dot
!= bf
->line
->used
) {
441 for (i
= bf
->line
->used
; i
> bf
->dot
; i
--)
442 bf
->line
->text
[i
]= bf
->line
->text
[i
-1];
445 /* insert the new character. */
446 bf
->line
->text
[bf
->dot
]= *p
;
455 /* Just that, insert a backspace ;) */
456 void e_buffer_backspace(E_Buffer
*bf
)
460 /* The only case that we have here is if the cursor position
461 * is at the begin of the line, in that case we need join
465 BUFFER_SET(bf
, BUFFER_FLUSH
);
467 /* If the cursor is not at the end of the line,
468 * we need scroll the text.
470 for (i
= bf
->dot
; i
< bf
->line
->used
; i
++)
471 bf
->line
->text
[i
-1]= bf
->line
->text
[i
];
476 e_buffer_joinline(bf
);
479 void e_buffer_del(E_Buffer
*bf
)
482 e_buffer_backspace(bf
);
485 void e_buffer_up(E_Buffer
*bf
)
487 if (bf
->line
->prev
) {
488 bf
->line
= bf
->line
->prev
;
489 if (bf
->dot
> bf
->line
->used
)
490 bf
->dot
= bf
->line
->used
;
492 BUFFER_SET(bf
, BUFFER_UP
);
496 void e_buffer_down(E_Buffer
*bf
)
498 if (bf
->line
->next
) {
499 bf
->line
= bf
->line
->next
;
500 if (bf
->dot
> bf
->line
->used
)
501 bf
->dot
= bf
->line
->used
;
503 BUFFER_SET(bf
, BUFFER_DOWN
);
507 void e_buffer_left(E_Buffer
*bf
)
517 void e_buffer_right(E_Buffer
*bf
)
519 if (bf
->dot
< bf
->line
->used
)
527 void e_buffer_goto_begin(E_Buffer
*bf
)
534 void e_buffer_goto_end(E_Buffer
*bf
)
544 bf
->nl
= bf
->nlines
+1; /* zero */
547 void e_buffer_bol(E_Buffer
*bf
)
552 void e_buffer_eol(E_Buffer
*bf
)
554 bf
->dot
= bf
->line
->used
;
557 void e_buffer_scroll(E_Buffer
*bf
, int nline
, int dir
)
561 for(i
= 0; i
< nline
; i
++) {
563 if (!bf
->first
->prev
)
565 bf
->first
= bf
->first
->prev
;
567 bf
->line
= bf
->line
->prev
;
570 if (!bf
->first
->next
)
572 bf
->first
= bf
->first
->next
;
574 bf
->line
= bf
->line
->next
;
577 if (bf
->dot
> bf
->line
->used
)
578 bf
->dot
= bf
->line
->used
;
582 void e_buffer_goto(E_Buffer
*bf
, int line
)
601 if (bf
->dot
> bf
->line
->used
)
605 void e_buffer_cleanline(E_Buffer
*bf
)
607 BUFFER_SET(bf
, BUFFER_FLUSH
);
613 static E_Line
*__e_buffer_search(E_Buffer
*bf
, char *pattern
, int *dot_found
, int dir
)
616 int i
, e
, a
, len
, dot
, found
;
618 len
= strlen(pattern
);
622 /* I know.. this is not the best backward.. but work. */
623 if (dir
== BUFFER_SEARCH_FORWARD
)
629 if (dir
== BUFFER_SEARCH_FORWARD
&& ln
== bf
->line
)
634 for (; i
< ln
->used
; i
++) {
635 if (ln
->text
[i
] == pattern
[0]) {
636 /* save the current position of the cursor. */
641 for (e
= 0; e
< len
; e
++) {
642 if (ln
->text
[i
] != pattern
[e
]) {
664 if (dir
== BUFFER_SEARCH_FORWARD
)
670 if (dir
== BUFFER_SEARCH_FORWARD
)
671 *dot_found
= (dot
+len
);
678 void e_buffer_search(E_Buffer
*bf
, char *pattern
, int dir
)
683 ln
= __e_buffer_search(bf
, pattern
, &dot
, dir
);
692 int e_buffer_replace(E_Buffer
*bf
, char *pattern
, char *replace
)
695 int i
, c
, len
, ncount
, dot
;
697 /* Avoid identation during the replace. */
698 bf
->flag
|= BUFFER_NOIDENT
;
701 len
= strlen(replace
);
704 ln
= __e_buffer_search(bf
, pattern
, &dot
, BUFFER_SEARCH_FORWARD
);
706 /* first set the line, so all the next call
714 /* now remove the pattern. */
715 for (i
= 0; i
< c
; i
++)
716 e_buffer_backspace(bf
);
718 /* and now insert the new string. */
719 for (i
= 0; i
< len
; i
++)
720 e_buffer_insert(bf
, replace
[i
], 1);
723 ln
= __e_buffer_search(bf
, pattern
, &dot
, BUFFER_SEARCH_FORWARD
);
726 /* and remove the flag. */
727 bf
->flag
&= ~BUFFER_NOIDENT
;
732 void e_buffer_rem_empty_lines(E_Buffer
*bf
)
741 for (i
= 0; i
< ln
->used
; i
++) {
742 if (ln
->text
[i
] != ' ' && ln
->text
[i
] != '\t') {
748 /* If the line is empty, remove any ' ' or '\t' character. */
758 BUFFER_SET(bf
, BUFFER_FLUSH
);