Fixed the empty input segfault
[iomenu.git] / draw.c
blob1158733165d73e32557539f078464a950b5a340e
1 #include <stdlib.h>
2 #include <string.h>
3 #include <stdio.h>
4 #include <sys/ioctl.h>
6 #include "draw.h"
7 #include "util.h"
9 /*
10 * Replace tab as a multiple of 8 spaces in a line.
12 char *
13 expand_tabs(char *line)
15 size_t i, n;
16 char *converted = malloc(sizeof(char) * (strlen(line) * 8 + 1));
18 for (i = 0, n = 0; i < strlen(line); i++, n++) {
19 if (line[i] == '\t') {
20 for (; (n) % 8 != 0; n++) {
21 converted[n] = ' ';
24 n--;
25 } else {
26 converted[n] = line[i];
30 converted[n] = '\0';
32 return converted;
36 * Print a line to stderr.
38 void
39 draw_line(Line *line, int current, int cols, Opt *opt)
41 size_t i;
42 int n = 0;
43 char *content = expand_tabs(line->content);
44 char *comment = expand_tabs(line->comment);
46 /* clean the line in case it was not empty */
47 fputs("\033[K", stderr);
49 /* line number if option set */
50 if (opt->line_numbers) {
51 if (current) {
52 fputs("\033[1m", stderr);
53 } else {
54 fputs("\033[1;30m", stderr);
57 fprintf(stderr, "%7d\033[0m ", line->number);
60 n += 8;
63 /* highlight current line */
64 if (current) {
65 fputs("\033[1;33m", stderr);
68 /* print content without overflowing terminal width */
69 for (i = 0; i < strlen(content) && n < cols; n++, i++) {
70 fputc(content[i], stderr);
73 /* print spaces without overflowing terminal width */
74 for (i = n; i <= 40 && n < cols; n++, i++) {
75 fputc(' ', stderr);
78 /* comments in grey */
79 fputs("\033[1;30m", stderr);
81 /* print comment without overflowing terminal width */
82 for (i = 0; i < strlen(comment) && n < cols; n++, i++) {
83 fputc(comment[i], stderr);
86 fputs("\033[0m\n", stderr);
88 free(content);
89 free(comment);
93 * Print a header title.
95 void
96 draw_header()
101 * Print all the lines from an array of pointer to lines.
103 * The total number oflines printed shall not excess 'count'.
105 void
106 draw_lines(Buffer *buffer, int count, int offset, int cols, Opt *opt)
108 Line *line = buffer->current;
109 int i = 0;
110 int j = 0;
112 /* seek back from current line to the first line to print */
113 while (line && i < count - offset) {
114 i = line->matches ? i + 1 : i;
115 line = line->prev;
117 line = line ? line : buffer->first;
119 /* print up to count lines that match the input */
120 while (line && j < count) {
121 if (line->matches) {
122 draw_line(line, line == buffer->current, cols, opt);
123 j++;
126 line = line->next;
129 /* continue up to the end of the screen clearing it */
130 for (; j < count; j++) {
131 fputs("\r\033[K\n", stderr);
136 * Update the screen interface and print all candidates.
138 * This also has to clear the previous lines.
140 void
141 draw_screen(Buffer *buffer, int offset, int tty_fd, Opt *opt)
143 struct winsize w;
144 int count;
146 ioctl(tty_fd, TIOCGWINSZ, &w);
147 count = MIN(opt->lines, w.ws_row - 2);
149 fputs("\n", stderr);
150 draw_lines(buffer, count, offset, w.ws_col, opt);
152 /* go up to the prompt position and update it */
153 fprintf(stderr, "\033[%dA", count + 1);
154 draw_prompt(buffer, w.ws_col, opt);
157 void draw_clear(int count)
159 int i;
160 for (i = 0; i < count + 1; i++) {
161 fputs("\r\033[K\n", stderr);
164 fprintf(stderr, "\033[%dA", count + 1);
169 * Print the prompt, before the input, with the number of candidates that
170 * match.
172 void
173 draw_prompt(Buffer *buffer, int cols, Opt *opt)
175 size_t i;
176 int matching = buffer->matching;
177 int total = buffer->total;
178 char *input = expand_tabs(buffer->input);
179 char *suggest = expand_tabs(buffer->current->content);
181 /* for the '/' separator between the numbers */
182 cols--;
184 /* number of digits */
185 for (i = matching; i; i /= 10, cols--)
187 for (i = total; i; i /= 10, cols--)
190 /* 0 also has one digit*/
191 cols -= !matching ? 1 : 0;
193 /* actual prompt */
194 fprintf(stderr, "\r%s\033[K> ", opt->prompt);
195 cols -= 2 + strlen(opt->prompt);
197 /* input without overflowing terminal width */
198 for (i = 0; i < strlen(input) && cols > 0; cols--, i++) {
199 fputc(input[i], stderr);
202 /* save the cursor position at the end of the input */
203 fputs("\033[s", stderr);
205 /* grey */
206 fputs("\033[1;30m", stderr);
208 /* suggest without overflowing terminal width */
209 if (opt->complete_mode) {
210 for (; i < strlen(suggest) && cols > 0; cols--, i++) {
211 fputc(suggest[i], stderr);
215 /* go to the end of the line */
216 for (i = 0; cols > 0; cols--, i++) {
217 fputc(' ', stderr);
220 /* total match and line count at the end of the line */
221 fprintf(stderr, "%d/%d", matching, total);
223 /* restore cursor position at the end of the input */
224 fputs("\033[0m\033[u", stderr);
226 free(input);
227 free(suggest);